From 61cecbd7ee79ced9157be866d1db51f7a8ce5092 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 5 Dec 2025 14:26:13 +0900 Subject: [PATCH] sorta works --- mdm/config.c | 2 +- milkwm/config.c | 30 +++++++++++++ milkwm/main.c | 3 ++ milkwm/milkwm.h | 11 +++++ milkwm/milkwmrc.in | 16 +++++++ milkwm/wm.c | 57 +++++++++++++++++++++++- milkwm/xserver.c | 106 ++++++++++++++++++++++++++++++--------------- 7 files changed, 188 insertions(+), 37 deletions(-) create mode 100644 milkwm/config.c diff --git a/mdm/config.c b/mdm/config.c index bfb3f9e..10864d5 100644 --- a/mdm/config.c +++ b/mdm/config.c @@ -15,5 +15,5 @@ static int dumper(void* user, const char* section, const char* name, const char* } void parse_config(void) { - ini_parse(CONFDIR "/mdm/mdmrc", dumper, NULL); + ini_parse(SYSCONFDIR "/mdm/mdmrc", dumper, NULL); } diff --git a/milkwm/config.c b/milkwm/config.c new file mode 100644 index 0000000..59cbe41 --- /dev/null +++ b/milkwm/config.c @@ -0,0 +1,30 @@ +#include "milkwm.h" + +/* we prefix them for reasons */ + +config_t wm_config; + +void wm_config_init(void) { + config_init(&wm_config); +} + +static void read_config(const char* path) { + if(!config_read_file(&wm_config, path)) { + fprintf(stderr, "MilkWM config error: file %s at line %d: %s\n", path, config_error_line(&wm_config), config_error_text(&wm_config)); + } +} + +void wm_config_read(void) { + char* conf = MDEDirectoryConfigPath(); + char* dir = MwDirectoryJoin(conf, "milkwm"); + char* path = MwDirectoryJoin(dir, "milkwmrc"); + + free(dir); + free(conf); + + config_clear(&wm_config); + read_config(SYSCONFDIR "/milkwm/milkwmrc"); + read_config(path); + + free(path); +} diff --git a/milkwm/main.c b/milkwm/main.c index 78a2dbe..c61f9ca 100644 --- a/milkwm/main.c +++ b/milkwm/main.c @@ -3,6 +3,9 @@ int main() { int st; + wm_config_init(); + wm_config_read(); + if((st = init_x()) != 0) return st; loop_wm(); diff --git a/milkwm/milkwm.h b/milkwm/milkwm.h index 788fd26..f6070bc 100644 --- a/milkwm/milkwm.h +++ b/milkwm/milkwm.h @@ -8,11 +8,15 @@ #include /* External */ +#include #include #include #include /* Standard */ +#include +#include +#include #include #define TitleBarHeight 16 @@ -28,6 +32,13 @@ void loop_x(void); /* wm.c */ void loop_wm(void); MwWidget wm_frame(int w, int h); +void wm_destroy(MwWidget widget); void wm_set_name(MwWidget widget, const char* name); +/* config.c */ +extern config_t wm_config; + +void wm_config_init(void); +void wm_config_read(void); + #endif diff --git a/milkwm/milkwmrc.in b/milkwm/milkwmrc.in index 3f6c6f9..e1ca406 100644 --- a/milkwm/milkwmrc.in +++ b/milkwm/milkwmrc.in @@ -1,3 +1,5 @@ +# This file should be copied to .config/milkwm/milkwmrc + Window: { TitleBar: { Buttons: { @@ -12,5 +14,19 @@ Window: { "Iconify" ]; }; + Background: { + # Just don't write anything if you want default background + #Inactive: "white"; + Active: "blue"; + }; + Foreground: { + # Just don't write anything if you want default background + #Inactive: "black"; + Active: "white"; + }; + + # Left, Right, or Center + # Default is Center + Align = "Left"; }; }; diff --git a/milkwm/wm.c b/milkwm/wm.c index 1bfaaa3..65c19fa 100644 --- a/milkwm/wm.c +++ b/milkwm/wm.c @@ -5,6 +5,10 @@ static MwWidget root; typedef struct wmframe { MwWidget titlebar; + MwWidget title; + + int left_space; + int right_space; } wmframe_t; void loop_wm(void) { @@ -45,6 +49,36 @@ static void resize(MwWidget handle, void* user, void* client) { MwNwidth, ww - MwDefaultBorderWidth(handle) * 2, MwNheight, TitleBarHeight + MwDefaultBorderWidth(handle) * 2, NULL); + + MwVaApply(f->title, + MwNx, MwDefaultBorderWidth(f->titlebar) + f->left_space + 8, + MwNy, MwDefaultBorderWidth(f->titlebar), + MwNwidth, MwGetInteger(f->titlebar, MwNwidth) - MwDefaultBorderWidth(f->titlebar) * 2 - f->left_space - f->right_space - 16, + MwNheight, MwGetInteger(f->titlebar, MwNheight) - MwDefaultBorderWidth(f->titlebar) * 2, + NULL); +} + +static int alignment(const char* str) { + if(strcmp(str, "Left") == 0) return MwALIGNMENT_BEGINNING; + if(strcmp(str, "Right") == 0) return MwALIGNMENT_END; + if(strcmp(str, "Center") == 0) return MwALIGNMENT_CENTER; + + return MwALIGNMENT_CENTER; +} + +static void apply_config(MwWidget wnd) { + wmframe_t* f = wnd->opaque; + const char* str; + + if(config_lookup_string(&wm_config, "Window.TitleBar.Align", &str)) { + MwVaApply(f->title, + MwNalignment, alignment(str), + NULL); + } else { + MwVaApply(f->title, + MwNalignment, MwALIGNMENT_CENTER, + NULL); + } } MwWidget wm_frame(int w, int h) { @@ -60,13 +94,20 @@ MwWidget wm_frame(int w, int h) { NULL); wnd->opaque = f; + f->left_space = TitleBarHeight; + f->right_space = 0; + f->titlebar = MwVaCreateWidget(MwFrameClass, "titlebar", wnd, 0, 0, 0, 0, MwNhasBorder, 1, MwNinverted, 1, NULL); + f->title = MwCreateWidget(MwLabelClass, "title", f->titlebar, 0, 0, 0, 0); + MwCreateWidget(MwButtonClass, "button", f->titlebar, MwDefaultBorderWidth(wnd), MwDefaultBorderWidth(wnd), TitleBarHeight, TitleBarHeight); + apply_config(wnd); + resize(wnd, NULL, NULL); pthread_mutex_unlock(&xmutex); @@ -74,5 +115,19 @@ MwWidget wm_frame(int w, int h) { return wnd; } -void wm_set_name(MwWidget widget, const char* name) { +void wm_destroy(MwWidget widget) { + pthread_mutex_lock(&xmutex); + free(widget->opaque); + MwDestroyWidget(widget); + pthread_mutex_unlock(&xmutex); +} + +void wm_set_name(MwWidget widget, const char* name) { + wmframe_t* f = widget->opaque; + + pthread_mutex_lock(&xmutex); + MwVaApply(f->title, + MwNtext, name, + NULL); + pthread_mutex_unlock(&xmutex); } diff --git a/milkwm/xserver.c b/milkwm/xserver.c index f12e316..9bbbf1f 100644 --- a/milkwm/xserver.c +++ b/milkwm/xserver.c @@ -8,12 +8,21 @@ 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 void* old_handler; +static int error_happened = 0; +static int ignore_error(Display* disp, XErrorEvent* ev) { + error_happened = 1; + return 0; } -static int ignore_error(Display* disp, XErrorEvent* ev) { +static void begin_error(void) { + old_handler = XSetErrorHandler(ignore_error); + error_happened = 0; +} + +static void end_error(void) { + XSync(xdisplay, False); + XSetErrorHandler(old_handler); } static void* x11_thread_routine(void* arg) { @@ -40,12 +49,11 @@ int init_x(void) { xdisplay = XOpenDisplay(NULL); - old = XSetErrorHandler(wm_detect); + begin_error(); XSelectInput(xdisplay, DefaultRootWindow(xdisplay), SubstructureRedirectMask); - XSync(xdisplay, False); - XSetErrorHandler(old); + end_error(); - if(wm_detected) return 1; + if(error_happened) return 1; nofocus = XCreateSimpleWindow(xdisplay, DefaultRootWindow(xdisplay), -10, -10, 1, 1, 0, 0, 0); XChangeWindowAttributes(xdisplay, nofocus, CWOverrideRedirect, &xswa); @@ -75,7 +83,7 @@ static void save(Window w) { XAddToSaveSet(xdisplay, w); } -int parent_eq(Window wnd, Window might_be_parent) { +static int parent_eq(Window wnd, Window might_be_parent) { Window root, parent; Window* children; unsigned int nchildren; @@ -88,6 +96,24 @@ int parent_eq(Window wnd, Window might_be_parent) { return 0; } +static void set_name(Window wnd) { + Atom type; + int format; + unsigned long nitem, after; + unsigned char* buf; + Atom atom = XInternAtom(xdisplay, "WM_NAME", False); + int i; + + for(i = 0; i < arrlen(windows); i++) { + if(windows[i].client == wnd) { + if(XGetWindowProperty(xdisplay, wnd, atom, 0, 1024, False, XA_STRING, &type, &format, &nitem, &after, &buf) == Success) { + wm_set_name(windows[i].frame, buf); + XFree(buf); + } + } + } +} + void loop_x(void) { XEvent ev; Window root, parent; @@ -95,23 +121,28 @@ void loop_x(void) { unsigned int nchildren; int i; + begin_error(); + 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; + if(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]; + w.frame = wm_frame(xwa.width, xwa.height); + w.client = children[i]; - XUnmapWindow(xdisplay, children[i]); + XUnmapWindow(xdisplay, children[i]); - save(w.client); + save(w.client); - arrput(windows, w); + arrput(windows, w); + + set_name(w.client); + } } XFree(children); } @@ -181,11 +212,12 @@ void loop_x(void) { int ret = 0; XWindowAttributes xwa; - XGetWindowAttributes(xdisplay, ev.xmaprequest.window, &xwa); + if(!XGetWindowAttributes(xdisplay, ev.xmaprequest.window, &xwa)) continue; 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) { + /* what? */ ret = 1; break; } @@ -193,15 +225,28 @@ void loop_x(void) { if(ret) continue; if(i != arrlen(windows)) { XWindowAttributes xwa; - XGetWindowAttributes(xdisplay, windows[i].client, &xwa); + if(!XGetWindowAttributes(xdisplay, windows[i].client, &xwa)) { + wm_destroy(windows[i].frame); + arrdel(windows, i); + continue; + } 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); + if(!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); + wm_destroy(windows[i].frame); + arrdel(windows, i); + continue; + } pthread_mutex_unlock(&xmutex); - XMapWindow(xdisplay, windows[i].client); + if(!XMapWindow(xdisplay, windows[i].client)) { + wm_destroy(windows[i].frame); + arrdel(windows, i); + continue; + } XFlush(xdisplay); continue; } @@ -211,6 +256,8 @@ void loop_x(void) { save(w.client); arrput(windows, w); + + set_name(w.client); } else if(ev.type == PropertyNotify) { int i; for(i = 0; i < arrlen(windows); i++) { @@ -221,15 +268,7 @@ void loop_x(void) { 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); - } + set_name(windows[i].client); } } else if(ev.type == MapNotify) { int i; @@ -243,19 +282,15 @@ void loop_x(void) { 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); + + wm_destroy(windows[i].frame); arrdel(windows, i); break; } @@ -278,4 +313,5 @@ void loop_x(void) { } } } + end_error(); }