From: Michael D. Lowis Date: Thu, 1 Aug 2024 02:48:24 +0000 (-0400) Subject: reworked client handling X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=cfb8c12465b0294869bde61f6c75a2d7bf93f259;p=proto%2Fanvil.git reworked client handling --- diff --git a/anvil.c b/anvil.c index 435bd65..c976eae 100644 --- a/anvil.c +++ b/anvil.c @@ -80,7 +80,7 @@ Client* Focused = NULL; static void check_for_wm(void) { error_default = XSetErrorHandler(error_init); - XSelectInput(X.disp, X.root, SubstructureRedirectMask); + XSelectInput(X.disp, X.root, SubstructureRedirectMask|SubstructureNotifyMask); XSync(X.disp, False); XSetErrorHandler(error_panic); XSync(X.disp, False); @@ -162,22 +162,22 @@ static void xconfigrequest(XEvent* e) wc.border_width = ev->border_width; wc.sibling = ev->above; wc.stack_mode = ev->detail; - Location loc = {0}; - if (mons_find(ev->window, &loc)) - { - /* only allow floating clients to resize on their own */ - if ((loc.client->win == ev->window) && !loc.column) - { - loc.client->w = wc.width + FRAME_WIDTH_SUM; - loc.client->h = wc.height + FRAME_HEIGHT_SUM; - client_adjust(loc.client); - if (X.mode == M_RESIZE && Focused == loc.client) - { - mouse_tocorner(loc.client); - } - } - } - else +// Location loc = {0}; +// if (mons_find(ev->window, &loc)) +// { +// /* only allow floating clients to resize on their own */ +// if ((loc.client->win == ev->window) && !loc.column) +// { +// loc.client->w = wc.width + FRAME_WIDTH_SUM; +// loc.client->h = wc.height + FRAME_HEIGHT_SUM; +// client_adjust(loc.client); +// if (X.mode == M_RESIZE && Focused == loc.client) +// { +// mouse_tocorner(loc.client); +// } +// } +// } +// else { XConfigureWindow(X.disp, ev->window, ev->value_mask, &wc); } @@ -190,7 +190,7 @@ static void xclientmsg(XEvent* e) printf("CLIENT_MSG(w: 0x%lx a: '%s')\n", ev->window, XGetAtomName(X.disp, ev->message_type)); if (ev->message_type == _NET_ACTIVE_WINDOW) { - mons_activate(ev->window); +// mons_activate(ev->window); } } @@ -198,23 +198,23 @@ static void xpropnotify(XEvent* e) { XPropertyEvent* ev = &(e->xproperty); printf("PROP_NOTIFY(w: 0x%lx)\n", ev->window); - Location loc = {0}; - if (mons_find(ev->window, &loc)) - { - client_readprops(loc.client); - client_draw(loc.client); - } +// Location loc = {0}; +// if (mons_find(ev->window, &loc)) +// { +// client_readprops(loc.client); +// client_draw(loc.client); +// } } static void xenternotify(XEvent* e) { XCrossingEvent* ev = &(e->xcrossing); - Location loc = {0}; +// Location loc = {0}; printf("ENTER(w: 0x%lx s: %d m: %d d: %d)\n", ev->window, ev->state, ev->mode, ev->detail); - if (mons_find(ev->window, &loc)) - { - client_focus(loc.client); - } +// if (mons_find(ev->window, &loc)) +// { +// client_focus(loc.client); +// } } static void xexpose(XEvent* e) @@ -223,11 +223,11 @@ static void xexpose(XEvent* e) if (ev->count == 0) { printf("EXPOSE(w: 0x%lx)\n", ev->window); - Location loc = {0}; - if (mons_find(ev->window, &loc)) - { - client_draw(loc.client); - } +// Location loc = {0}; +// if (mons_find(ev->window, &loc)) +// { +// client_draw(loc.client); +// } } } @@ -235,11 +235,11 @@ static void xmapnotify(XEvent* e) { XMapEvent* ev = &(e->xmap); printf("MAP(e: 0x%lx w: 0x%lx)\n", ev->event, ev->window); - Location loc = {0}; - if (mons_find(ev->window, &loc))// && loc.client->win == ev->window) - { - client_draw(loc.client); - } +// Location loc = {0}; +// if (mons_find(ev->window, &loc))// && loc.client->win == ev->window) +// { +// client_draw(loc.client); +// } } diff --git a/atoms b/atoms index 15ef57f..8bdfbf3 100644 --- a/atoms +++ b/atoms @@ -1,3 +1,4 @@ +WM_STATE WM_NAME WM_ICON_NAME WM_NORMAL_HINTS diff --git a/atoms.c b/atoms.c index 7df75ef..c4cbc1f 100644 --- a/atoms.c +++ b/atoms.c @@ -1,4 +1,5 @@ #include "anvil.h" +Atom WM_STATE; Atom WM_NAME; Atom WM_ICON_NAME; Atom WM_NORMAL_HINTS; @@ -14,6 +15,7 @@ Atom _NET_WM_WINDOW_TYPE; Atom _NET_WM_WINDOW_TYPE_DIALOG; void atoms_init(void) { + WM_STATE = XInternAtom(X.disp, "WM_STATE", False); WM_NAME = XInternAtom(X.disp, "WM_NAME", False); WM_ICON_NAME = XInternAtom(X.disp, "WM_ICON_NAME", False); WM_NORMAL_HINTS = XInternAtom(X.disp, "WM_NORMAL_HINTS", False); diff --git a/atoms.h b/atoms.h index a907d6a..017f717 100644 --- a/atoms.h +++ b/atoms.h @@ -1,4 +1,5 @@ +extern Atom WM_STATE; extern Atom WM_NAME; extern Atom WM_ICON_NAME; extern Atom WM_NORMAL_HINTS; diff --git a/client.c b/client.c index aabfef7..6b7e8e9 100644 --- a/client.c +++ b/client.c @@ -1,5 +1,37 @@ #include "anvil.h" +static Client* FindClient(Window win); +static void ReadProps(Client* c); +static void Redraw(Client* c); + +void SetWMState(Client *c, int state) +{ + CARD32 data[2] = {state, None}; + XChangeProperty(X.disp, c->win, WM_STATE, WM_STATE, 32, PropModeReplace, (unsigned char *)data, 2); +} + +///* If we can't find a WM_STATE we're going to have to assume +// * Withdrawn. This is not exactly optimal, since we can't really +// * distinguish between the case where no WM has run yet and when the +// * state was explicitly removed (Clients are allowed to either set the +// * atom to Withdrawn or just remove it... yuck.) */ +// +//long GetWMState(Client *c) +//{ +// Atom real_type; +// int real_format; +// long state = WithdrawnState; +// unsigned long items_read, items_left; +// unsigned char *data; +// +// if (XGetWindowProperty(dsply, c->window, wm_state, 0L, 2L, False, wm_state, &real_type, &real_format, &items_read, &items_left, &data) == Success && items_read) +// { +// state = *(long *)data; +// XFree(data); +// } +// return state; +//} + void Client_Create(Window win) { (void)win; @@ -18,6 +50,7 @@ void Client_Create(Window win) /* Reparent the window if applicable */ c->frame = XCreateSimpleWindow(X.disp, X.root, c->x, c->y, c->w, c->h, 1, X.clr_bdr, X.clr_bg); + XAddToSaveSet(X.disp, c->win); XSelectInput(X.disp, c->frame, ExposureMask | EnterWindowMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | @@ -28,13 +61,26 @@ void Client_Create(Window win) wa.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; XChangeWindowAttributes(X.disp, c->win, CWEventMask | CWDontPropagate, &wa); XReparentWindow(X.disp, c->win, c->frame, BORDER_WIDTH, MIN_HEIGHT); + SetWMState(c, WithdrawnState); -// /* Map the window and draw the frame */ -// XAddToSaveSet(X.disp, c->win); -// client_readprops(c); -// mons_addclient(c); -// client_show(c, 1); -// client_draw(c); +// /* set the state now based on attributes and hints */ +// if (attr.map_state == IsUnmapped) +// { +// SetWMState(c, WithdrawnState); +// } +// else +// { +// SetWMState(c, NormalState); +// XWMHints* hints = XGetWMHints(X.disp, c->win); +// if (hints) +// { +// if (hints->flags & StateHint) +// { +// SetWMState(c, hints->initial_state); +// } +// XFree(hints); +// } +// } } } @@ -45,7 +91,15 @@ void Client_Destroy(Window win) void Client_Show(Window win) { - (void)win; + Client* c = FindClient(win); + printf("%p %p\n", Withdrawn, c); + if (c) + { + ReadProps(c); + XMapWindow(X.disp, c->frame); + XMapWindow(X.disp, c->win); + Redraw(c); + } } void Client_Hide(Window win) @@ -72,6 +126,130 @@ void Client_Hide(Window win) } +static void ReadProps(Client* c) +{ + Atom *protos = NULL, actual_type, *wintype; + int format, nprotos = 0; + unsigned long n, extra; + + /* WM_NAME - window title */ + xfree(c->name); + c->name = NULL; + XGetWindowProperty( + X.disp, c->win, XA_WM_NAME, 0, -1, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **)&c->name); + + /* WM_HINTS - other non-dimensional attributes of the window */ + XWMHints* hints = XGetWMHints(X.disp, c->win); + if (hints) + { + int ignored = (Focused == c ? XUrgencyHint : 0); + c->wm_flags = (hints->flags & ~ignored); + c->hints = *hints; + } + xfree(hints); + + /* WM_NORMAL_HINTS - desired dimensional attributes of the window */ + XGetWMNormalHints(X.disp, c->win, &(c->size_hints), &(c->hint_flags)); + + /* WM_PROTOCOLS - list of client message protocols this window responds to */ + XGetWMProtocols(X.disp, c->win, &protos, &nprotos); + for (int i = 0; i < nprotos; i++) + { + if (protos[i] == WM_DELETE_WINDOW) + { + c->flags |= F_WM_DELETE; + } + + // TODO: handle WM_TAKE_FOCUS + } + xfree(protos); + + /* WM_CLASS - instance and class names of the window. informs WM about behavior of window */ + // TODO: Read the class and instance of the window + + /* WM_TRANSIENT_FOR - marks the window as a pop-up for another window */ + // TODO: read the transient_for property and use ti to handle pop-ups better + + /* WM_CLIENT_MACHINE - */ + // TODO: read client machine property + + /* check if the window is a dialog */ + XGetWindowProperty( + X.disp, c->win, _NET_WM_WINDOW_TYPE, 0L, -1, False, XA_ATOM, &actual_type, &format, &n, &extra, (unsigned char **)&wintype); + if (wintype && *wintype == _NET_WM_WINDOW_TYPE_DIALOG) + { + c->flags |= F_DIALOG|F_FLOATING; + } + xfree(wintype); + + /* The following properties are unused currently */ + /* WM_ICON_NAME - window title when iconified */ + /* WM_COLORMAP_WINDOWS - */ +} + +static void Redraw(Client* c) +{ + if (c->frame) + { + XSetWindowBackground(X.disp, c->frame, ((c->wm_flags & XUrgencyHint) ? X.clr_urgent : X.clr_bg)); + XSetWindowBorderWidth(X.disp, c->frame, 0); + XSetWindowBorderWidth(X.disp, c->win, 0); + XDefineCursor(X.disp, c->frame, X.csr_point); + XClearWindow(X.disp, c->frame); + + /* set border color */ + XSetForeground(X.disp, DefaultGC(X.disp, X.screen), BlackPixel(X.disp, X.screen)); + XSetFillStyle(X.disp, DefaultGC(X.disp, X.screen), FillSolid); + + /* draw outer border */ + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), 0, 0, c->w, 0); + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), 0, c->h-1, c->w, c->h-1); + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), 0, 0, 0, c->h); + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), c->w-1, 0, c->w-1, c->h); + + /* draw inner border */ + if (!(c->flags & F_SHADED)) + { + int bw = BORDER_WIDTH; + int mh = MIN_HEIGHT; + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), + bw-1, mh-1, c->w-bw, mh-1); + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), + bw-1, c->h-bw, c->w-bw, c->h-bw); + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), + bw-1, mh-1, bw-1, c->h-bw); + XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), + c->w-bw, mh-1, c->w-bw, c->h-bw); + } + + /* draw title text */ + if (c->name) { + int ascent = abs(X.font_ext->max_logical_extent.y); + Xutf8DrawString(X.disp, c->frame, X.font, + DefaultGC(X.disp, X.screen), + BORDER_WIDTH, + 2 + ascent, + c->name, strlen(c->name)); + } + } + + /* tell the window to redraw itself */ +// XClearArea(X.disp, c->win, 0, 0, 0, 0, True); +} + +static Client* FindClient(Window win) +{ + Client* curr = Withdrawn; + for (; curr; curr = curr->next) + { + if (curr->win == win || curr->frame == win) + { + break; + } + } + return curr; +} + @@ -111,7 +289,7 @@ Client* client_add(Window win, XWindowAttributes* attr) c->y = attr->y; c->w = attr->width + FRAME_WIDTH_SUM; c->h = attr->height + FRAME_HEIGHT_SUM; - client_readprops(c); + ReadProps(c); /* Reparent the window if applicable */ c->frame = XCreateSimpleWindow(X.disp, X.root, c->x, c->y, c->w, c->h, 1, X.clr_bdr, X.clr_bg); @@ -130,59 +308,10 @@ Client* client_add(Window win, XWindowAttributes* attr) XAddToSaveSet(X.disp, c->win); mons_addclient(c); client_show(c, 1); - client_draw(c); + Redraw(c); return c; } -void client_draw(Client* c) -{ - if (c->frame) - { - XSetWindowBackground(X.disp, c->frame, ((c->wm_flags & XUrgencyHint) ? X.clr_urgent : X.clr_bg)); - XSetWindowBorderWidth(X.disp, c->frame, 0); - XSetWindowBorderWidth(X.disp, c->win, 0); - XDefineCursor(X.disp, c->frame, X.csr_point); - XClearWindow(X.disp, c->frame); - - /* set border color */ - XSetForeground(X.disp, DefaultGC(X.disp, X.screen), BlackPixel(X.disp, X.screen)); - XSetFillStyle(X.disp, DefaultGC(X.disp, X.screen), FillSolid); - - /* draw outer border */ - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), 0, 0, c->w, 0); - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), 0, c->h-1, c->w, c->h-1); - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), 0, 0, 0, c->h); - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), c->w-1, 0, c->w-1, c->h); - - /* draw inner border */ - if (!(c->flags & F_SHADED)) - { - int bw = BORDER_WIDTH; - int mh = MIN_HEIGHT; - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), - bw-1, mh-1, c->w-bw, mh-1); - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), - bw-1, c->h-bw, c->w-bw, c->h-bw); - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), - bw-1, mh-1, bw-1, c->h-bw); - XDrawLine(X.disp, c->frame, DefaultGC(X.disp, X.screen), - c->w-bw, mh-1, c->w-bw, c->h-bw); - } - - /* draw title text */ - if (c->name) { - int ascent = abs(X.font_ext->max_logical_extent.y); - Xutf8DrawString(X.disp, c->frame, X.font, - DefaultGC(X.disp, X.screen), - BORDER_WIDTH, - 2 + ascent, - c->name, strlen(c->name)); - } - } - - /* tell the window to redraw itself */ -// XClearArea(X.disp, c->win, 0, 0, 0, 0, True); -} void client_adjust(Client* c) { @@ -203,7 +332,7 @@ printf("XResize(0x%lx, %d, %d)\n", c->win, c->w, c->h); XResizeWindow(X.disp, c->win, child_w, child_h); } mons_place(c); -// client_draw(c); +// Redraw(c); } void client_move(Client* c, int xdiff, int ydiff) @@ -237,10 +366,10 @@ void client_focus(Client* c) Client* prev = Focused; Focused = c; XSetInputFocus(X.disp, c->win, RevertToPointerRoot, CurrentTime); - client_draw(Focused); + Redraw(Focused); if (prev) { - client_draw(prev); + Redraw(prev); } } @@ -251,66 +380,6 @@ void client_show(Client* c, int show) mapfn(X.disp, c->win); } -void client_readprops(Client* c) -{ - Atom *protos = NULL, actual_type, *wintype; - int format, nprotos = 0; - unsigned long n, extra; - - /* WM_NAME - window title */ - xfree(c->name); - c->name = NULL; - XGetWindowProperty( - X.disp, c->win, XA_WM_NAME, 0, -1, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **)&c->name); - - /* WM_HINTS - other non-dimensional attributes of the window */ - XWMHints* hints = XGetWMHints(X.disp, c->win); - if (hints) - { - int ignored = (Focused == c ? XUrgencyHint : 0); - c->wm_flags = (hints->flags & ~ignored); - c->hints = *hints; - } - xfree(hints); - - /* WM_NORMAL_HINTS - desired dimensional attributes of the window */ - XGetWMNormalHints(X.disp, c->win, &(c->size_hints), &(c->hint_flags)); - - /* WM_PROTOCOLS - list of client message protocols this window responds to */ - XGetWMProtocols(X.disp, c->win, &protos, &nprotos); - for (int i = 0; i < nprotos; i++) - { - if (protos[i] == WM_DELETE_WINDOW) - { - c->flags |= F_WM_DELETE; - } - - // TODO: handle WM_TAKE_FOCUS - } - xfree(protos); - - /* WM_CLASS - instance and class names of the window. informs WM about behavior of window */ - // TODO: Read the class and instance of the window - - /* WM_TRANSIENT_FOR - marks the window as a pop-up for another window */ - // TODO: read the transient_for property and use ti to handle pop-ups better - - /* WM_CLIENT_MACHINE - */ - // TODO: read client machine property - - /* check if the window is a dialog */ - XGetWindowProperty( - X.disp, c->win, _NET_WM_WINDOW_TYPE, 0L, -1, False, XA_ATOM, &actual_type, &format, &n, &extra, (unsigned char **)&wintype); - if (wintype && *wintype == _NET_WM_WINDOW_TYPE_DIALOG) - { - c->flags |= F_DIALOG|F_FLOATING; - } - xfree(wintype); - - /* The following properties are unused currently */ - /* WM_ICON_NAME - window title when iconified */ - /* WM_COLORMAP_WINDOWS - */ -} void client_shade(Client* c) {