kind of works

This commit is contained in:
Nishi 2025-12-07 10:42:45 +09:00
commit 9cb052fd7a
Signed by: nishi
GPG key ID: 27EF69B208EB9343
4 changed files with 236 additions and 41 deletions

View file

@ -34,6 +34,7 @@ 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);
void wm_focus(MwWidget widget, int focus);
/* config.c */
extern config_t wm_config;

View file

@ -14,15 +14,12 @@ Window: {
"Iconify"
];
};
Background: {
# Just don't write anything if you want default background
#Inactive: "white";
Active: "blue";
Active: {
Background = "dark blue";
Foreground = "white";
};
Foreground: {
# Just don't write anything if you want default background
#Inactive: "black";
Active: "white";
Inactive: {
# Just don't write anything if you want default background/foreground
};
# Left, Right, or Center

View file

@ -1,14 +1,22 @@
#define _MILSKO
#include "milkwm.h"
#include <stb_ds.h>
static MwWidget root;
typedef struct wmframe {
MwWidget titlebar;
MwWidget title;
int left_space;
int right_space;
MwWidget* left;
MwWidget* right;
MwLLPixmap maximize;
MwLLPixmap iconify;
int dragging;
MwPoint drag_point;
} wmframe_t;
void loop_wm(void) {
@ -42,6 +50,8 @@ static void resize(MwWidget handle, void* user, void* client) {
wmframe_t* f = handle->opaque;
int ww = MwGetInteger(handle, MwNwidth);
int wh = MwGetInteger(handle, MwNheight);
int x;
int i;
MwVaApply(f->titlebar,
MwNx, MwDefaultBorderWidth(handle),
@ -50,10 +60,26 @@ static void resize(MwWidget handle, void* user, void* client) {
MwNheight, TitleBarHeight + MwDefaultBorderWidth(handle) * 2,
NULL);
x = MwDefaultBorderWidth(handle);
for(i = 0; i < arrlen(f->left); i++) {
MwVaApply(f->left[i],
MwNx, x,
NULL);
x += TitleBarHeight;
}
x = MwGetInteger(f->titlebar, MwNwidth) - MwDefaultBorderWidth(handle);
for(i = 0; i < arrlen(f->right); i++) {
x -= TitleBarHeight;
MwVaApply(f->right[i],
MwNx, x,
NULL);
}
MwVaApply(f->title,
MwNx, MwDefaultBorderWidth(f->titlebar) + f->left_space + 8,
MwNx, MwDefaultBorderWidth(f->titlebar) + arrlen(f->left) * TitleBarHeight,
MwNy, MwDefaultBorderWidth(f->titlebar),
MwNwidth, MwGetInteger(f->titlebar, MwNwidth) - MwDefaultBorderWidth(f->titlebar) * 2 - f->left_space - f->right_space - 16,
MwNwidth, MwGetInteger(f->titlebar, MwNwidth) - MwDefaultBorderWidth(f->titlebar) * 2 - arrlen(f->left) * TitleBarHeight - arrlen(f->right) * TitleBarHeight,
MwNheight, MwGetInteger(f->titlebar, MwNheight) - MwDefaultBorderWidth(f->titlebar) * 2,
NULL);
}
@ -81,10 +107,88 @@ static void apply_config(MwWidget wnd) {
}
}
static void apply_button(MwWidget widget, const char* str) {
MwWidget w = widget;
wmframe_t* f;
MwLLPixmap px = NULL;
while(w != NULL && strcmp(MwGetName(w), "frame") != 0) w = MwGetParent(w);
f = w->opaque;
if(strcmp(str, "Maximize") == 0) {
px = f->maximize;
} else if(strcmp(str, "Iconify") == 0) {
px = f->iconify;
}
if(px != NULL) {
int p = (MwGetInteger(widget, MwNwidth) - MwDefaultBorderWidth(widget) * 2 - px->common.width) / 2;
MwVaApply(widget,
MwNpixmap, px,
MwNpadding, p,
NULL);
}
}
static void drag_down(MwWidget handle, void* user, void* client) {
MwWidget w = handle;
wmframe_t* f;
int x = 0;
int y = 0;
MwPoint c;
while(w != NULL && strcmp(MwGetName(w), "frame") != 0) w = MwGetParent(w);
x += MwGetInteger(w, MwNx);
y += MwGetInteger(w, MwNy);
f = w->opaque;
MwGetCursorCoord(w, &c);
f->dragging = 1;
f->drag_point.x = c.x - x;
f->drag_point.y = c.y - y;
}
static void drag_up(MwWidget handle, void* user, void* client) {
MwWidget w = handle;
wmframe_t* f;
while(w != NULL && strcmp(MwGetName(w), "frame") != 0) w = MwGetParent(w);
f = w->opaque;
f->dragging = 0;
}
static void drag(MwWidget handle, void* user, void* client) {
MwWidget w = handle;
wmframe_t* f;
while(w != NULL && strcmp(MwGetName(w), "frame") != 0) w = MwGetParent(w);
f = w->opaque;
if(f->dragging) {
MwPoint c;
MwGetCursorCoord(w, &c);
MwVaApply(w,
MwNx, c.x - f->drag_point.x,
MwNy, c.y - f->drag_point.y,
NULL);
}
}
MwWidget wm_frame(int w, int h) {
MwWidget wnd, titlebar;
int i;
wmframe_t* f = malloc(sizeof(*f));
MwWidget wnd, titlebar;
int i;
config_setting_t* s;
const char* str;
wmframe_t* f = malloc(sizeof(*f));
unsigned char* icon;
int y, x;
pthread_mutex_lock(&xmutex);
@ -94,17 +198,66 @@ MwWidget wm_frame(int w, int h) {
NULL);
wnd->opaque = f;
f->left_space = TitleBarHeight;
f->right_space = 0;
MwAddUserHandler(wnd, MwNresizeHandler, resize, NULL);
f->dragging = 0;
icon = malloc(6 * 6 * 4);
memset(icon, 0, 6 * 6 * 4);
for(y = 0; y < 6; y++) {
for(x = 0; x < 6; x++) {
if((y == 0 || y == 5 || x == 0 || x == 5) && !(2 <= y && y <= 3) && !(2 <= x && x <= 3)) icon[(y * 6 + x) * 4 + 3] = 255;
}
}
f->iconify = MwLoadRaw(wnd, icon, 6, 6);
memset(icon, 0, 6 * 6 * 4);
for(y = 0; y < 6; y++) {
for(x = 0; x < 6; x++) {
if(y == 0 || y == 5 || x == 0 || x == 5) icon[(y * 6 + x) * 4 + 3] = 255;
}
}
f->maximize = MwLoadRaw(wnd, icon, 6, 6);
free(icon);
f->left = NULL;
f->right = NULL;
f->titlebar = MwVaCreateWidget(MwFrameClass, "titlebar", wnd, 0, 0, 0, 0,
MwNhasBorder, 1,
MwNinverted, 1,
NULL);
MwAddUserHandler(f->titlebar, MwNmouseUpHandler, drag_up, NULL);
MwAddUserHandler(f->titlebar, MwNmouseMoveHandler, drag, NULL);
MwAddUserHandler(f->titlebar, MwNmouseDownHandler, drag_down, NULL);
f->title = MwCreateWidget(MwLabelClass, "title", f->titlebar, 0, 0, 0, 0);
MwAddUserHandler(f->title, MwNmouseUpHandler, drag_up, NULL);
MwAddUserHandler(f->title, MwNmouseMoveHandler, drag, NULL);
MwAddUserHandler(f->title, MwNmouseDownHandler, drag_down, NULL);
MwCreateWidget(MwButtonClass, "button", f->titlebar, MwDefaultBorderWidth(wnd), MwDefaultBorderWidth(wnd), TitleBarHeight, TitleBarHeight);
s = config_lookup(&wm_config, "Window.TitleBar.Buttons.Left");
for(i = 0; (str = config_setting_get_string_elem(s, i)) != NULL; i++) {
MwWidget w = MwVaCreateWidget(MwButtonClass, "button", f->titlebar, 0, MwDefaultBorderWidth(wnd), TitleBarHeight, TitleBarHeight,
MwNborderWidth, 1,
NULL);
apply_button(w, str);
arrput(f->left, w);
}
s = config_lookup(&wm_config, "Window.TitleBar.Buttons.Right");
for(i = 0; (str = config_setting_get_string_elem(s, i)) != NULL; i++) {
MwWidget w = MwVaCreateWidget(MwButtonClass, "button", f->titlebar, 0, MwDefaultBorderWidth(wnd), TitleBarHeight, TitleBarHeight,
MwNborderWidth, 1,
NULL);
apply_button(w, str);
arrput(f->right, w);
}
apply_config(wnd);
@ -116,7 +269,14 @@ MwWidget wm_frame(int w, int h) {
}
void wm_destroy(MwWidget widget) {
wmframe_t* f = widget->opaque;
pthread_mutex_lock(&xmutex);
arrfree(f->left);
arrfree(f->right);
MwLLDestroyPixmap(f->maximize);
MwLLDestroyPixmap(f->iconify);
free(widget->opaque);
MwDestroyWidget(widget);
pthread_mutex_unlock(&xmutex);
@ -124,10 +284,35 @@ void wm_destroy(MwWidget widget) {
void wm_set_name(MwWidget widget, const char* name) {
wmframe_t* f = widget->opaque;
char* s = MDEStringConcatenate(" ", name);
pthread_mutex_lock(&xmutex);
MwVaApply(f->title,
MwNtext, name,
MwNtext, s,
NULL);
pthread_mutex_unlock(&xmutex);
free(s);
}
void wm_focus(MwWidget widget, int focus) {
wmframe_t* f = widget->opaque;
const char* bg = NULL;
const char* fg = NULL;
pthread_mutex_lock(&xmutex);
if(focus) {
config_lookup_string(&wm_config, "Window.TitleBar.Active.Background", &bg);
config_lookup_string(&wm_config, "Window.TitleBar.Active.Foreground", &fg);
} else {
config_lookup_string(&wm_config, "Window.TitleBar.Inactive.Background", &bg);
config_lookup_string(&wm_config, "Window.TitleBar.Inactive.Foreground", &fg);
}
MwVaApply(f->title,
MwNbackground, bg,
MwNforeground, fg,
NULL);
pthread_mutex_unlock(&xmutex);
}

View file

@ -8,6 +8,12 @@ Display* xdisplay;
pthread_t xthread;
pthread_mutex_t xmutex;
typedef struct window {
MwWidget frame;
Window client;
} window_t;
static window_t* windows = NULL;
static void* old_handler;
static int error_happened = 0;
static int ignore_error(Display* disp, XErrorEvent* ev) {
@ -32,13 +38,23 @@ static void* x11_thread_routine(void* arg) {
}
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;
static void set_focus(Window w) {
int i;
for(i = 0; i < arrlen(windows); i++) {
if(windows[i].client == w) {
wm_focus(windows[i].frame, 1);
} else if(focus == windows[i].client) {
wm_focus(windows[i].frame, 0);
}
}
if(w == None) {
XSetInputFocus(xdisplay, nofocus, RevertToParent, CurrentTime);
} else {
XSetInputFocus(xdisplay, w, RevertToParent, CurrentTime);
}
focus = w;
}
int init_x(void) {
@ -71,12 +87,6 @@ int init_x(void) {
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);
@ -100,13 +110,13 @@ static void set_name(Window wnd) {
Atom type;
int format;
unsigned long nitem, after;
unsigned char* buf;
unsigned char* buf = NULL;
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) {
if(XGetWindowProperty(xdisplay, wnd, atom, 0, 1024, False, XA_STRING, &type, &format, &nitem, &after, &buf) == Success && buf != NULL) {
wm_set_name(windows[i].frame, buf);
XFree(buf);
}
@ -169,8 +179,13 @@ void loop_x(void) {
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;
if(windows[i].frame->lowlevel->x11.window == w) {
xwc.x = ev.xconfigurerequest.x;
xwc.y = ev.xconfigurerequest.y;
xwc.width = ev.xconfigurerequest.width - MwDefaultBorderWidth(windows[i].frame) * 2;
xwc.height = ev.xconfigurerequest.height - MwDefaultBorderWidth(windows[i].frame) * 4 - TitleBarHeight;
XConfigureWindow(xdisplay, windows[i].client, CWX | CWY | CWWidth | CWHeight, &xwc);
break;
}
}
@ -187,6 +202,7 @@ void loop_x(void) {
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;
@ -203,6 +219,7 @@ void loop_x(void) {
} else if(xwa.width != xwc.width || xwa.height != xwc.height) {
XConfigureWindow(xdisplay, windows[i].frame->lowlevel->x11.window, CWWidth | CWHeight, &xwc);
}
break;
}
}
@ -234,14 +251,11 @@ void loop_x(void) {
XMoveWindow(xdisplay, windows[i].frame->lowlevel->x11.window, xwa.x, xwa.y);
XMapWindow(xdisplay, ev.xmaprequest.window);
pthread_mutex_lock(&xmutex);
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);
if(!XMapWindow(xdisplay, windows[i].client)) {
wm_destroy(windows[i].frame);
arrdel(windows, i);
@ -285,9 +299,7 @@ void loop_x(void) {
XWindowAttributes xwa;
if(XGetWindowAttributes(xdisplay, windows[i].frame->lowlevel->x11.window, &xwa)) {
pthread_mutex_lock(&xmutex);
XReparentWindow(xdisplay, windows[i].client, DefaultRootWindow(xdisplay), xwa.x, xwa.y);
pthread_mutex_unlock(&xmutex);
}
wm_destroy(windows[i].frame);