sorta works

This commit is contained in:
Nishi 2025-12-05 14:26:13 +09:00
commit 61cecbd7ee
Signed by: nishi
GPG key ID: 27EF69B208EB9343
7 changed files with 187 additions and 36 deletions

View file

@ -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);
}

30
milkwm/config.c Normal file
View file

@ -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);
}

View file

@ -3,6 +3,9 @@
int main() {
int st;
wm_config_init();
wm_config_read();
if((st = init_x()) != 0) return st;
loop_wm();

View file

@ -8,11 +8,15 @@
#include <Mw/Milsko.h>
/* External */
#include <libconfig.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
/* Standard */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#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

View file

@ -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";
};
};

View file

@ -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);
}

View file

@ -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();
}