can move window and stuff

This commit is contained in:
Nishi 2025-12-08 01:06:48 +09:00
commit c271de7e52
Signed by: nishi
GPG key ID: 27EF69B208EB9343
3 changed files with 144 additions and 29 deletions

View file

@ -20,6 +20,7 @@
#include <pthread.h>
#define TitleBarHeight 16
#define Gap 1
/* xserver.c */
extern pthread_t xthread;
@ -28,6 +29,7 @@ extern Display* xdisplay;
int init_x(void);
void loop_x(void);
void set_focus_x(MwWidget widget);
/* wm.c */
void loop_wm(void);
@ -35,6 +37,13 @@ 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);
MwWidget wm_get_inside(MwWidget widget); /* make client area child of this widget, at (wm_content_x(),wm_content_y) */
int wm_entire_width(int content);
int wm_entire_height(int content);
int wm_content_width(int entire);
int wm_content_height(int entire);
int wm_content_x(void);
int wm_content_y(void);
/* config.c */
extern config_t wm_config;

View file

@ -6,6 +6,7 @@
static MwWidget root;
typedef struct wmframe {
MwWidget inside;
MwWidget titlebar;
MwWidget title;
@ -53,14 +54,19 @@ static void resize(MwWidget handle, void* user, void* client) {
int x;
int i;
MwVaApply(f->inside,
MwNwidth, ww - MwDefaultBorderWidth(handle) * 2 - Gap * 2,
MwNheight, wh - MwDefaultBorderWidth(handle) * 2 - Gap * 2,
NULL);
MwVaApply(f->titlebar,
MwNx, MwDefaultBorderWidth(handle),
MwNy, MwDefaultBorderWidth(handle),
MwNwidth, ww - MwDefaultBorderWidth(handle) * 2,
MwNheight, TitleBarHeight + MwDefaultBorderWidth(handle) * 2,
MwNwidth, ww - MwDefaultBorderWidth(handle) * 4 - Gap * 2,
MwNheight, TitleBarHeight,
NULL);
x = MwDefaultBorderWidth(handle);
x = 0;
for(i = 0; i < arrlen(f->left); i++) {
MwVaApply(f->left[i],
MwNx, x,
@ -68,7 +74,7 @@ static void resize(MwWidget handle, void* user, void* client) {
x += TitleBarHeight;
}
x = MwGetInteger(f->titlebar, MwNwidth) - MwDefaultBorderWidth(handle);
x = MwGetInteger(f->titlebar, MwNwidth);
for(i = 0; i < arrlen(f->right); i++) {
x -= TitleBarHeight;
MwVaApply(f->right[i],
@ -77,10 +83,10 @@ static void resize(MwWidget handle, void* user, void* client) {
}
MwVaApply(f->title,
MwNx, MwDefaultBorderWidth(f->titlebar) + arrlen(f->left) * TitleBarHeight,
MwNy, MwDefaultBorderWidth(f->titlebar),
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,
MwNx, arrlen(f->left) * TitleBarHeight,
MwNy, 0,
MwNwidth, MwGetInteger(f->titlebar, MwNwidth) - arrlen(f->left) * TitleBarHeight - arrlen(f->right) * TitleBarHeight,
MwNheight, MwGetInteger(f->titlebar, MwNheight),
NULL);
}
@ -148,6 +154,8 @@ static void drag_down(MwWidget handle, void* user, void* client) {
f->dragging = 1;
f->drag_point.x = c.x - x;
f->drag_point.y = c.y - y;
set_focus_x(w);
}
static void drag_up(MwWidget handle, void* user, void* client) {
@ -192,7 +200,7 @@ MwWidget wm_frame(int w, int h) {
pthread_mutex_lock(&xmutex);
wnd = MwVaCreateWidget(MwWindowClass, "frame", root, MwDEFAULT, MwDEFAULT, w + MwDefaultBorderWidth(root) * 2, h + MwDefaultBorderWidth(root) * 4 + TitleBarHeight,
wnd = MwVaCreateWidget(MwWindowClass, "frame", root, MwDEFAULT, MwDEFAULT, wm_entire_width(w), wm_entire_height(h),
MwNhasBorder, 1,
MwNinverted, 0,
NULL);
@ -224,10 +232,12 @@ MwWidget wm_frame(int w, int h) {
f->left = NULL;
f->right = NULL;
f->titlebar = MwVaCreateWidget(MwFrameClass, "titlebar", wnd, 0, 0, 0, 0,
MwNhasBorder, 1,
MwNinverted, 1,
NULL);
f->inside = MwVaCreateWidget(MwFrameClass, "inside", wnd, MwDefaultBorderWidth(wnd) + Gap, MwDefaultBorderWidth(wnd) + Gap, 0, 0,
MwNhasBorder, 1,
MwNinverted, 1,
NULL);
f->titlebar = MwCreateWidget(MwFrameClass, "titlebar", f->inside, 0, 0, 0, 0);
MwAddUserHandler(f->titlebar, MwNmouseUpHandler, drag_up, NULL);
MwAddUserHandler(f->titlebar, MwNmouseMoveHandler, drag, NULL);
MwAddUserHandler(f->titlebar, MwNmouseDownHandler, drag_down, NULL);
@ -239,7 +249,7 @@ MwWidget wm_frame(int w, int h) {
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,
MwWidget w = MwVaCreateWidget(MwButtonClass, "button", f->titlebar, 0, 0, TitleBarHeight, TitleBarHeight,
MwNborderWidth, 1,
NULL);
@ -250,7 +260,7 @@ MwWidget wm_frame(int w, int h) {
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,
MwWidget w = MwVaCreateWidget(MwButtonClass, "button", f->titlebar, 0, 0, TitleBarHeight, TitleBarHeight,
MwNborderWidth, 1,
NULL);
@ -316,3 +326,37 @@ void wm_focus(MwWidget widget, int focus) {
pthread_mutex_unlock(&xmutex);
}
MwWidget wm_get_inside(MwWidget widget) {
MwWidget ret;
pthread_mutex_lock(&xmutex);
ret = ((wmframe_t*)widget->opaque)->inside;
pthread_mutex_unlock(&xmutex);
return ret;
}
int wm_entire_width(int content) {
return content + MwDefaultBorderWidth(root) * 4 + Gap * 2;
}
int wm_entire_height(int content) {
return content + MwDefaultBorderWidth(root) * 4 + Gap * 2 + TitleBarHeight;
}
int wm_content_width(int entire) {
return entire - wm_entire_width(0);
}
int wm_content_height(int entire) {
return entire - wm_entire_height(0);
}
int wm_content_x(void) {
return MwDefaultBorderWidth(root);
}
int wm_content_y(void) {
return MwDefaultBorderWidth(root) + TitleBarHeight;
}

View file

@ -8,6 +8,10 @@ Display* xdisplay;
pthread_t xthread;
pthread_mutex_t xmutex;
static pthread_mutex_t focusmutex;
static Atom milkwm_set_focus;
typedef struct window {
MwWidget frame;
Window client;
@ -42,19 +46,26 @@ static Window focus = None, nofocus;
static void set_focus(Window w) {
int i;
for(i = 0; i < arrlen(windows); i++) {
pthread_mutex_lock(&focusmutex);
if(windows[i].client == w) {
pthread_mutex_unlock(&focusmutex);
wm_focus(windows[i].frame, 1);
} else if(focus == windows[i].client) {
} else if(focus != w && focus == windows[i].client) {
pthread_mutex_unlock(&focusmutex);
wm_focus(windows[i].frame, 0);
} else {
pthread_mutex_unlock(&focusmutex);
}
}
pthread_mutex_lock(&focusmutex);
focus = w;
if(w == None) {
XSetInputFocus(xdisplay, nofocus, RevertToParent, CurrentTime);
} else {
XSetInputFocus(xdisplay, w, RevertToParent, CurrentTime);
}
focus = w;
pthread_mutex_unlock(&focusmutex);
}
int init_x(void) {
@ -80,7 +91,10 @@ int init_x(void) {
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);
milkwm_set_focus = XInternAtom(xdisplay, "MILKWM_SET_FOCUS", False);
pthread_mutex_init(&xmutex, NULL);
pthread_mutex_init(&focusmutex, NULL);
pthread_create(&xthread, NULL, x11_thread_routine, NULL);
@ -88,6 +102,7 @@ int init_x(void) {
}
static void save(Window w) {
XGrabButton(xdisplay, 1, 0, w, True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None);
XSelectInput(xdisplay, w, StructureNotifyMask | FocusChangeMask | PropertyChangeMask);
XSetWindowBorderWidth(xdisplay, w, 0);
XAddToSaveSet(xdisplay, w);
@ -159,17 +174,37 @@ void loop_x(void) {
while(1) {
XNextEvent(xdisplay, &ev);
if(ev.type == ButtonPress) {
if((ev.type == ButtonPress || ev.type == ButtonRelease) && ev.xbutton.subwindow != None && ev.xbutton.button == Button1) {
Window w = None;
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)) {
if(windows[i].frame->lowlevel->x11.window == ev.xbutton.subwindow || parent_eq(ev.xbutton.subwindow, windows[i].frame->lowlevel->x11.window)) {
set_focus(windows[i].client);
w = windows[i].frame->lowlevel->x11.window;
break;
}
}
if(i != arrlen(windows)) continue;
set_focus(ev.xbutton.window);
}
ev.xbutton.window = ev.xbutton.subwindow;
ev.xbutton.subwindow = None;
XSendEvent(xdisplay, ev.xbutton.window, False, 0, &ev);
if(w != None) XRaiseWindow(xdisplay, w);
} else if(ev.type == MotionNotify && ev.xmotion.subwindow != None) {
Window w = None;
for(i = 0; i < arrlen(windows); i++) {
if(windows[i].frame->lowlevel->x11.window == ev.xbutton.subwindow || parent_eq(ev.xbutton.subwindow, windows[i].frame->lowlevel->x11.window)) {
w = windows[i].frame->lowlevel->x11.window;
break;
}
}
ev.xmotion.window = ev.xmotion.subwindow;
ev.xmotion.subwindow = None;
XSendEvent(xdisplay, ev.xmotion.window, False, 0, &ev);
if(w != None) XRaiseWindow(xdisplay, w);
} else if(ev.type == FocusIn && ev.xfocus.window != focus) {
set_focus(focus);
} else if(ev.type == FocusOut && focus != None) {
@ -182,8 +217,8 @@ void loop_x(void) {
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;
xwc.width = wm_content_width(ev.xconfigurerequest.width);
xwc.height = wm_content_height(ev.xconfigurerequest.height);
XConfigureWindow(xdisplay, windows[i].client, CWX | CWY | CWWidth | CWHeight, &xwc);
break;
@ -205,16 +240,16 @@ void loop_x(void) {
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;
xwc.width = wm_entire_width(ev.xconfigure.width);
xwc.height = wm_entire_height(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)) {
if(xwc.x != wm_content_x() || xwc.y != wm_content_y()) {
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;
xwc.x = wm_content_x();
xwc.y = wm_content_y();
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);
@ -251,7 +286,7 @@ void loop_x(void) {
XMoveWindow(xdisplay, windows[i].frame->lowlevel->x11.window, xwa.x, xwa.y);
XMapWindow(xdisplay, ev.xmaprequest.window);
if(!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, wm_get_inside(windows[i].frame)->lowlevel->x11.window, wm_content_x(), wm_content_y())) {
wm_destroy(windows[i].frame);
arrdel(windows, i);
continue;
@ -323,7 +358,34 @@ void loop_x(void) {
set_focus(w);
}
} else if(ev.type == ClientMessage) {
if(ev.xclient.message_type == milkwm_set_focus && ev.xclient.data.l[0] == milkwm_set_focus) {
set_focus(ev.xclient.data.l[1]);
}
}
}
end_error();
}
void set_focus_x(MwWidget widget) {
int i;
for(i = 0; i < arrlen(windows); i++) {
if(windows[i].frame == widget) {
XEvent ev;
ev.type = ClientMessage;
ev.xclient.window = nofocus;
ev.xclient.message_type = milkwm_set_focus;
ev.xclient.format = 32;
ev.xclient.data.l[0] = ev.xclient.message_type;
ev.xclient.data.l[1] = windows[i].client;
XSendEvent(xdisplay, nofocus, False, 0, &ev);
XRaiseWindow(xdisplay, windows[i].frame->lowlevel->x11.window);
break;
}
}
}