wip
This commit is contained in:
parent
e3edcfa7e1
commit
6b05ca3263
7 changed files with 416 additions and 3 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#define _MILSKO
|
#define _MILSKO
|
||||||
#define USE_X11
|
#define USE_X11
|
||||||
#include "mdm.h"
|
#include "mdm.h"
|
||||||
|
|
@ -53,6 +52,7 @@ static int wm_detect(Display* disp, XErrorEvent* ev) {
|
||||||
static void* x11_thread_routine(void* arg) {
|
static void* x11_thread_routine(void* arg) {
|
||||||
loop_x();
|
loop_x();
|
||||||
XCloseDisplay(xdisplay);
|
XCloseDisplay(xdisplay);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_x(void) {
|
int init_x(void) {
|
||||||
|
|
@ -114,9 +114,10 @@ void loop_x(void) {
|
||||||
pthread_mutex_lock(&xmutex);
|
pthread_mutex_lock(&xmutex);
|
||||||
for(i = 0; i < arrlen(frames); i++) {
|
for(i = 0; i < arrlen(frames); i++) {
|
||||||
if(frames[i].frame->lowlevel->x11.window == ev.xmaprequest.window) {
|
if(frames[i].frame->lowlevel->x11.window == ev.xmaprequest.window) {
|
||||||
XReparentWindow(xdisplay, frames[i].client, frames[i].frame->lowlevel->x11.window, MwDefaultBorderWidth(root), MwDefaultBorderWidth(root));
|
|
||||||
XMapWindow(xdisplay, ev.xmaprequest.window);
|
XMapWindow(xdisplay, ev.xmaprequest.window);
|
||||||
XMapWindow(xdisplay, frames[i].client);
|
XMapWindow(xdisplay, frames[i].client);
|
||||||
|
XReparentWindow(xdisplay, frames[i].client, frames[i].frame->lowlevel->x11.window, MwDefaultBorderWidth(root), MwDefaultBorderWidth(root));
|
||||||
|
XFlush(xdisplay);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,12 @@
|
||||||
include(MDEBase)
|
include(MDEBase)
|
||||||
|
include(MDEPkgConfig)
|
||||||
setup_project(milkwm ${CMAKE_INSTALL_BINDIR})
|
setup_project(milkwm ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
|
pkg_config_add(milkwm x11)
|
||||||
|
pkg_config_add(milkwm inih)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
milkwm
|
||||||
|
PRIVATE
|
||||||
|
pthread
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1 +1,9 @@
|
||||||
int main() {}
|
#include "milkwm.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int st;
|
||||||
|
|
||||||
|
if((st = init_x()) != 0) return st;
|
||||||
|
|
||||||
|
loop_wm();
|
||||||
|
}
|
||||||
|
|
|
||||||
33
milkwm/milkwm.h
Normal file
33
milkwm/milkwm.h
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef __MILKWM_H__
|
||||||
|
#define __MILKWM_H__
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/* Milsko */
|
||||||
|
#include <MDE/Foundation.h>
|
||||||
|
#include <Mw/Milsko.h>
|
||||||
|
|
||||||
|
/* External */
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
|
/* Standard */
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define TitleBarHeight 16
|
||||||
|
|
||||||
|
/* xserver.c */
|
||||||
|
extern pthread_t xthread;
|
||||||
|
extern pthread_mutex_t xmutex;
|
||||||
|
extern Display* xdisplay;
|
||||||
|
|
||||||
|
int init_x(void);
|
||||||
|
void loop_x(void);
|
||||||
|
|
||||||
|
/* wm.c */
|
||||||
|
void loop_wm(void);
|
||||||
|
MwWidget wm_frame(int w, int h);
|
||||||
|
void wm_set_name(MwWidget widget, const char* name);
|
||||||
|
|
||||||
|
#endif
|
||||||
2
milkwm/stb_ds.c
Normal file
2
milkwm/stb_ds.c
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#define STB_DS_IMPLEMENTATION
|
||||||
|
#include <stb_ds.h>
|
||||||
78
milkwm/wm.c
Normal file
78
milkwm/wm.c
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#define _MILSKO
|
||||||
|
#include "milkwm.h"
|
||||||
|
|
||||||
|
static MwWidget root;
|
||||||
|
|
||||||
|
typedef struct wmframe {
|
||||||
|
MwWidget titlebar;
|
||||||
|
} wmframe_t;
|
||||||
|
|
||||||
|
void loop_wm(void) {
|
||||||
|
void* out;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&xmutex);
|
||||||
|
|
||||||
|
MwLibraryInit();
|
||||||
|
|
||||||
|
root = MwCreateWidget(NULL, "root", NULL, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&xmutex);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
int s = 0;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&xmutex);
|
||||||
|
while(MwPending(root)) {
|
||||||
|
if((s = MwStep(root)) != 0) break;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&xmutex);
|
||||||
|
if(s != 0) break;
|
||||||
|
|
||||||
|
MwTimeSleep(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_join(xthread, &out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resize(MwWidget handle, void* user, void* client) {
|
||||||
|
wmframe_t* f = handle->opaque;
|
||||||
|
int ww = MwGetInteger(handle, MwNwidth);
|
||||||
|
int wh = MwGetInteger(handle, MwNheight);
|
||||||
|
|
||||||
|
MwVaApply(f->titlebar,
|
||||||
|
MwNx, MwDefaultBorderWidth(handle),
|
||||||
|
MwNy, MwDefaultBorderWidth(handle),
|
||||||
|
MwNwidth, ww - MwDefaultBorderWidth(handle) * 2,
|
||||||
|
MwNheight, TitleBarHeight + MwDefaultBorderWidth(handle) * 2,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MwWidget wm_frame(int w, int h) {
|
||||||
|
MwWidget wnd, titlebar;
|
||||||
|
int i;
|
||||||
|
wmframe_t* f = malloc(sizeof(*f));
|
||||||
|
|
||||||
|
pthread_mutex_lock(&xmutex);
|
||||||
|
|
||||||
|
wnd = MwVaCreateWidget(MwWindowClass, "frame", root, MwDEFAULT, MwDEFAULT, w + MwDefaultBorderWidth(root) * 2, h + MwDefaultBorderWidth(root) * 4 + TitleBarHeight,
|
||||||
|
MwNhasBorder, 1,
|
||||||
|
MwNinverted, 0,
|
||||||
|
NULL);
|
||||||
|
wnd->opaque = f;
|
||||||
|
|
||||||
|
f->titlebar = MwVaCreateWidget(MwFrameClass, "titlebar", wnd, 0, 0, 0, 0,
|
||||||
|
MwNhasBorder, 1,
|
||||||
|
MwNinverted, 1,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
MwCreateWidget(MwButtonClass, "button", f->titlebar, MwDefaultBorderWidth(wnd), MwDefaultBorderWidth(wnd), TitleBarHeight, TitleBarHeight);
|
||||||
|
|
||||||
|
resize(wnd, NULL, NULL);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&xmutex);
|
||||||
|
|
||||||
|
return wnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_set_name(MwWidget widget, const char* name) {
|
||||||
|
}
|
||||||
281
milkwm/xserver.c
Normal file
281
milkwm/xserver.c
Normal file
|
|
@ -0,0 +1,281 @@
|
||||||
|
#define _MILSKO
|
||||||
|
#define USE_X11
|
||||||
|
#include "milkwm.h"
|
||||||
|
|
||||||
|
#include <stb_ds.h>
|
||||||
|
|
||||||
|
Display* xdisplay;
|
||||||
|
pthread_t xthread;
|
||||||
|
pthread_mutex_t xmutex;
|
||||||
|
|
||||||
|
static int wm_detected = 0;
|
||||||
|
static int wm_detect(Display* disp, XErrorEvent* ev) {
|
||||||
|
wm_detected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ignore_error(Display* disp, XErrorEvent* ev) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* x11_thread_routine(void* arg) {
|
||||||
|
loop_x();
|
||||||
|
XCloseDisplay(xdisplay);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Window focus = None, nofocus;
|
||||||
|
static void set_focus(Window w) {
|
||||||
|
if(w == None) {
|
||||||
|
XSetInputFocus(xdisplay, nofocus, RevertToParent, CurrentTime);
|
||||||
|
} else {
|
||||||
|
XSetInputFocus(xdisplay, w, RevertToParent, CurrentTime);
|
||||||
|
}
|
||||||
|
focus = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_x(void) {
|
||||||
|
void* old;
|
||||||
|
XSetWindowAttributes xswa;
|
||||||
|
|
||||||
|
xswa.override_redirect = True;
|
||||||
|
|
||||||
|
xdisplay = XOpenDisplay(NULL);
|
||||||
|
|
||||||
|
old = XSetErrorHandler(wm_detect);
|
||||||
|
XSelectInput(xdisplay, DefaultRootWindow(xdisplay), SubstructureRedirectMask);
|
||||||
|
XSync(xdisplay, False);
|
||||||
|
XSetErrorHandler(old);
|
||||||
|
|
||||||
|
if(wm_detected) return 1;
|
||||||
|
|
||||||
|
nofocus = XCreateSimpleWindow(xdisplay, DefaultRootWindow(xdisplay), -10, -10, 1, 1, 0, 0, 0);
|
||||||
|
XChangeWindowAttributes(xdisplay, nofocus, CWOverrideRedirect, &xswa);
|
||||||
|
XMapWindow(xdisplay, nofocus);
|
||||||
|
set_focus(None);
|
||||||
|
|
||||||
|
XChangeProperty(xdisplay, DefaultRootWindow(xdisplay), XInternAtom(xdisplay, "_NET_SUPPORTING_WM_CHECK", False), XA_WINDOW, 32, PropModeReplace, (unsigned char*)&nofocus, 1);
|
||||||
|
XChangeProperty(xdisplay, nofocus, XInternAtom(xdisplay, "_NET_SUPPORTING_WM_CHECK", False), XA_WINDOW, 32, PropModeReplace, (unsigned char*)&nofocus, 1);
|
||||||
|
XChangeProperty(xdisplay, nofocus, XInternAtom(xdisplay, "_NET_WM_NAME", False), XInternAtom(xdisplay, "UTF8_STRING", False), 8, PropModeReplace, (unsigned char*)"milkwm", 6);
|
||||||
|
|
||||||
|
pthread_mutex_init(&xmutex, NULL);
|
||||||
|
|
||||||
|
pthread_create(&xthread, NULL, x11_thread_routine, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct window {
|
||||||
|
MwWidget frame;
|
||||||
|
Window client;
|
||||||
|
} window_t;
|
||||||
|
static window_t* windows = NULL;
|
||||||
|
|
||||||
|
static void save(Window w) {
|
||||||
|
XSelectInput(xdisplay, w, StructureNotifyMask | FocusChangeMask | PropertyChangeMask);
|
||||||
|
XSetWindowBorderWidth(xdisplay, w, 0);
|
||||||
|
XAddToSaveSet(xdisplay, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
int parent_eq(Window wnd, Window might_be_parent) {
|
||||||
|
Window root, parent;
|
||||||
|
Window* children;
|
||||||
|
unsigned int nchildren;
|
||||||
|
|
||||||
|
XQueryTree(xdisplay, wnd, &root, &parent, &children, &nchildren);
|
||||||
|
if(children != NULL) XFree(children);
|
||||||
|
|
||||||
|
if(parent == might_be_parent) return 1;
|
||||||
|
if(parent != root) return parent_eq(parent, might_be_parent);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop_x(void) {
|
||||||
|
XEvent ev;
|
||||||
|
Window root, parent;
|
||||||
|
Window* children;
|
||||||
|
unsigned int nchildren;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
XQueryTree(xdisplay, DefaultRootWindow(xdisplay), &root, &parent, &children, &nchildren);
|
||||||
|
if(children != NULL) {
|
||||||
|
for(i = 0; i < nchildren; i++) {
|
||||||
|
window_t w;
|
||||||
|
XWindowAttributes xwa;
|
||||||
|
|
||||||
|
XGetWindowAttributes(xdisplay, children[i], &xwa);
|
||||||
|
if(xwa.override_redirect || xwa.map_state != IsViewable) continue;
|
||||||
|
|
||||||
|
w.frame = wm_frame(xwa.width, xwa.height);
|
||||||
|
w.client = children[i];
|
||||||
|
|
||||||
|
XUnmapWindow(xdisplay, children[i]);
|
||||||
|
|
||||||
|
save(w.client);
|
||||||
|
|
||||||
|
arrput(windows, w);
|
||||||
|
}
|
||||||
|
XFree(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
XNextEvent(xdisplay, &ev);
|
||||||
|
if(ev.type == ButtonPress) {
|
||||||
|
if(ev.type == ButtonPress) {
|
||||||
|
for(i = 0; i < arrlen(windows); i++) {
|
||||||
|
if(windows[i].frame->lowlevel->x11.window == ev.xbutton.window || parent_eq(ev.xbutton.window, windows[i].frame->lowlevel->x11.window)) {
|
||||||
|
set_focus(windows[i].client);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i != arrlen(windows)) continue;
|
||||||
|
set_focus(ev.xbutton.window);
|
||||||
|
}
|
||||||
|
} else if(ev.type == FocusIn && ev.xfocus.window != focus) {
|
||||||
|
set_focus(focus);
|
||||||
|
} else if(ev.type == FocusOut && focus != None) {
|
||||||
|
set_focus(focus);
|
||||||
|
} else if(ev.type == ConfigureRequest) {
|
||||||
|
XWindowChanges xwc;
|
||||||
|
int i;
|
||||||
|
Window w = ev.xconfigurerequest.window;
|
||||||
|
for(i = 0; i < arrlen(windows); i++) {
|
||||||
|
if(windows[i].client == w) {
|
||||||
|
w = windows[i].frame->lowlevel->x11.window;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xwc.x = ev.xconfigurerequest.x;
|
||||||
|
xwc.y = ev.xconfigurerequest.y;
|
||||||
|
xwc.width = ev.xconfigurerequest.width;
|
||||||
|
xwc.height = ev.xconfigurerequest.height;
|
||||||
|
|
||||||
|
XConfigureWindow(xdisplay, w, CWX | CWY | CWWidth | CWHeight, &xwc);
|
||||||
|
} else if(ev.type == ConfigureNotify) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < arrlen(windows); i++) {
|
||||||
|
if(windows[i].client == ev.xconfigure.window) {
|
||||||
|
XWindowChanges xwc;
|
||||||
|
XWindowAttributes xwa;
|
||||||
|
xwc.x = ev.xconfigure.x;
|
||||||
|
xwc.y = ev.xconfigure.y;
|
||||||
|
xwc.width = MwDefaultBorderWidth(windows[i].frame) * 2 + ev.xconfigure.width;
|
||||||
|
xwc.height = MwDefaultBorderWidth(windows[i].frame) * 4 + TitleBarHeight + ev.xconfigure.height;
|
||||||
|
|
||||||
|
XGetWindowAttributes(xdisplay, windows[i].frame->lowlevel->x11.window, &xwa);
|
||||||
|
|
||||||
|
if(xwc.x != MwDefaultBorderWidth(windows[i].frame) || xwc.y != (MwDefaultBorderWidth(windows[i].frame) * 3 + TitleBarHeight)) {
|
||||||
|
XConfigureWindow(xdisplay, windows[i].frame->lowlevel->x11.window, CWX | CWY | CWWidth | CWHeight, &xwc);
|
||||||
|
|
||||||
|
xwc.x = MwDefaultBorderWidth(windows[i].frame);
|
||||||
|
xwc.y = MwDefaultBorderWidth(windows[i].frame) * 3 + TitleBarHeight;
|
||||||
|
XConfigureWindow(xdisplay, windows[i].client, CWX | CWY, &xwc);
|
||||||
|
} else if(xwa.width != xwc.width || xwa.height != xwc.height) {
|
||||||
|
XConfigureWindow(xdisplay, windows[i].frame->lowlevel->x11.window, CWWidth | CWHeight, &xwc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(ev.type == MapRequest) {
|
||||||
|
window_t w;
|
||||||
|
int i;
|
||||||
|
int ret = 0;
|
||||||
|
XWindowAttributes xwa;
|
||||||
|
|
||||||
|
XGetWindowAttributes(xdisplay, ev.xmaprequest.window, &xwa);
|
||||||
|
|
||||||
|
for(i = 0; i < arrlen(windows); i++) {
|
||||||
|
if(windows[i].frame->lowlevel->x11.window == ev.xmaprequest.window) break;
|
||||||
|
if(windows[i].client == ev.xmaprequest.window) {
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ret) continue;
|
||||||
|
if(i != arrlen(windows)) {
|
||||||
|
XWindowAttributes xwa;
|
||||||
|
XGetWindowAttributes(xdisplay, windows[i].client, &xwa);
|
||||||
|
|
||||||
|
XMoveWindow(xdisplay, windows[i].frame->lowlevel->x11.window, xwa.x, xwa.y);
|
||||||
|
|
||||||
|
XMapWindow(xdisplay, ev.xmaprequest.window);
|
||||||
|
pthread_mutex_lock(&xmutex);
|
||||||
|
XReparentWindow(xdisplay, windows[i].client, windows[i].frame->lowlevel->x11.window, MwDefaultBorderWidth(windows[i].frame), MwDefaultBorderWidth(windows[i].frame) * 3 + TitleBarHeight);
|
||||||
|
pthread_mutex_unlock(&xmutex);
|
||||||
|
XMapWindow(xdisplay, windows[i].client);
|
||||||
|
XFlush(xdisplay);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
w.frame = wm_frame(xwa.width, xwa.height);
|
||||||
|
w.client = ev.xmaprequest.window;
|
||||||
|
save(w.client);
|
||||||
|
|
||||||
|
arrput(windows, w);
|
||||||
|
} else if(ev.type == PropertyNotify) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < arrlen(windows); i++) {
|
||||||
|
if(windows[i].client == ev.xproperty.window) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(arrlen(windows) == i) continue;
|
||||||
|
|
||||||
|
if(ev.xproperty.atom == XInternAtom(xdisplay, "WM_NAME", False)) {
|
||||||
|
Atom type;
|
||||||
|
int format;
|
||||||
|
unsigned long nitem, after;
|
||||||
|
unsigned char* buf;
|
||||||
|
|
||||||
|
if(XGetWindowProperty(xdisplay, ev.xproperty.window, ev.xproperty.atom, 0, 1024, False, XA_STRING, &type, &format, &nitem, &after, &buf) == Success) {
|
||||||
|
wm_set_name(windows[i].frame, buf);
|
||||||
|
XFree(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(ev.type == MapNotify) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < arrlen(windows); i++) {
|
||||||
|
if(windows[i].client == ev.xmap.window) {
|
||||||
|
set_focus(windows[i].client);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(ev.type == UnmapNotify) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < arrlen(windows); i++) {
|
||||||
|
if(windows[i].client == ev.xunmap.window) {
|
||||||
|
void* old;
|
||||||
|
XWindowAttributes xwa;
|
||||||
|
|
||||||
|
XGetWindowAttributes(xdisplay, windows[i].frame->lowlevel->x11.window, &xwa);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&xmutex);
|
||||||
|
old = XSetErrorHandler(ignore_error);
|
||||||
|
XReparentWindow(xdisplay, windows[i].client, DefaultRootWindow(xdisplay), xwa.x, xwa.y);
|
||||||
|
XSync(xdisplay, False);
|
||||||
|
XSetErrorHandler(old);
|
||||||
|
|
||||||
|
MwDestroyWidget(windows[i].frame);
|
||||||
|
pthread_mutex_unlock(&xmutex);
|
||||||
|
arrdel(windows, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(focus == ev.xunmap.window) {
|
||||||
|
Window w = None;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = arrlen(windows) - 1; i >= 0; i--) {
|
||||||
|
XWindowAttributes xwa;
|
||||||
|
|
||||||
|
XGetWindowAttributes(xdisplay, windows[i].client, &xwa);
|
||||||
|
if(xwa.map_state == IsViewable) {
|
||||||
|
w = windows[i].client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_focus(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue