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 USE_X11
|
||||
#include "mdm.h"
|
||||
|
|
@ -53,6 +52,7 @@ static int wm_detect(Display* disp, XErrorEvent* ev) {
|
|||
static void* x11_thread_routine(void* arg) {
|
||||
loop_x();
|
||||
XCloseDisplay(xdisplay);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int init_x(void) {
|
||||
|
|
@ -114,9 +114,10 @@ void loop_x(void) {
|
|||
pthread_mutex_lock(&xmutex);
|
||||
for(i = 0; i < arrlen(frames); i++) {
|
||||
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, frames[i].client);
|
||||
XReparentWindow(xdisplay, frames[i].client, frames[i].frame->lowlevel->x11.window, MwDefaultBorderWidth(root), MwDefaultBorderWidth(root));
|
||||
XFlush(xdisplay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,12 @@
|
|||
include(MDEBase)
|
||||
include(MDEPkgConfig)
|
||||
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