From ea3eb1a8c13c65e9c3b9dc2bfe6c6540019038eb Mon Sep 17 00:00:00 2001 From: Mike Lowis Date: Fri, 9 Aug 2024 16:13:00 -0400 Subject: [PATCH] added ewmh.c file and added some handling of those hints --- anvil.c | 1 + anvil.h | 17 +++++ atoms | 1 + atoms.c | 2 + atoms.h | 1 + client.c | 128 ++++------------------------------ ewmh.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ monitors.c | 4 +- 8 files changed, 240 insertions(+), 115 deletions(-) create mode 100644 ewmh.c diff --git a/anvil.c b/anvil.c index f3653de..6f11a30 100644 --- a/anvil.c +++ b/anvil.c @@ -318,6 +318,7 @@ int main(void) /* initialize all the things */ Atoms_Init(); + EWMH_Init(); InitCursors(); InitFont(); Client_InitAll(); diff --git a/anvil.h b/anvil.h index d417cb3..71e3f08 100644 --- a/anvil.h +++ b/anvil.h @@ -19,6 +19,7 @@ #define min(a,b) (a < b ? a : b) #define max(a,b) (a > b ? a : b) +#define nelem(a) (sizeof(a)/sizeof(a[0])) #define BORDER_WIDTH 5 #define TITLE_HEIGHT (X.font_ext->max_logical_extent.height) @@ -96,6 +97,9 @@ typedef struct Client { struct Client* col_prev; char* name; Window frame, win, transient_for; + int wm_types; + int wm_state; + int state, flags, wspace, x, y, w, h, rel_x, rel_y; long hint_flags, wm_flags; XWMHints hints; @@ -176,5 +180,18 @@ void Mouse_GetLocation(int* ptrx, int* ptry); void Monitors_Init(void); void Monitors_SetWorkspace(int id); void Monitors_SendToWorkspace(Client* c, int id); +int Monitors_GetActiveMonitor(void); + +/* ewmh.c */ +void EWMH_Init(void); +void EWMH_SetClientList(void); +void EWMH_SetActiveWindow(Window w); +char* EWMH_GetName(Window w); +int EWMH_GetWindowTypeFlags(Window w); +int EWMH_GetWindowStateFlags(Window w); +void EWMH_SetWindowStateFlags(Window w, int flags); +//void EWMH_GetWindowStrut(Strut* strut); +int EWMH_GetWindowPid(Window w); +void EWMH_SetWindowFrameExtents(Window w, int left, int right, int top, int bottom); #endif diff --git a/atoms b/atoms index bddebae..3db2a50 100644 --- a/atoms +++ b/atoms @@ -9,6 +9,7 @@ WM_PROTOCOLS WM_COLORMAP_WINDOWS WM_CLIENT_MACHINE WM_DELETE_WINDOW +_NET_WM_NAME _NET_ACTIVE_WINDOW _NET_WM_WINDOW_TYPE _NET_WM_WINDOW_TYPE_DESKTOP diff --git a/atoms.c b/atoms.c index 7f9a684..2e9e98f 100644 --- a/atoms.c +++ b/atoms.c @@ -10,6 +10,7 @@ Atom WM_PROTOCOLS; Atom WM_COLORMAP_WINDOWS; Atom WM_CLIENT_MACHINE; Atom WM_DELETE_WINDOW; +Atom _NET_WM_NAME; Atom _NET_ACTIVE_WINDOW; Atom _NET_WM_WINDOW_TYPE; Atom _NET_WM_WINDOW_TYPE_DESKTOP; @@ -46,6 +47,7 @@ void Atoms_Init(void) { WM_COLORMAP_WINDOWS = XInternAtom(X.disp, "WM_COLORMAP_WINDOWS", False); WM_CLIENT_MACHINE = XInternAtom(X.disp, "WM_CLIENT_MACHINE", False); WM_DELETE_WINDOW = XInternAtom(X.disp, "WM_DELETE_WINDOW", False); + _NET_WM_NAME = XInternAtom(X.disp, "_NET_WM_NAME", False); _NET_ACTIVE_WINDOW = XInternAtom(X.disp, "_NET_ACTIVE_WINDOW", False); _NET_WM_WINDOW_TYPE = XInternAtom(X.disp, "_NET_WM_WINDOW_TYPE", False); _NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom(X.disp, "_NET_WM_WINDOW_TYPE_DESKTOP", False); diff --git a/atoms.h b/atoms.h index e71cdf5..bf83d0b 100644 --- a/atoms.h +++ b/atoms.h @@ -10,6 +10,7 @@ extern Atom WM_PROTOCOLS; extern Atom WM_COLORMAP_WINDOWS; extern Atom WM_CLIENT_MACHINE; extern Atom WM_DELETE_WINDOW; +extern Atom _NET_WM_NAME; extern Atom _NET_ACTIVE_WINDOW; extern Atom _NET_WM_WINDOW_TYPE; extern Atom _NET_WM_WINDOW_TYPE_DESKTOP; diff --git a/client.c b/client.c index 539ceb7..58bf229 100644 --- a/client.c +++ b/client.c @@ -5,8 +5,6 @@ #define LIST_FOR_EACH(val,list) \ for (val = list; (val != NULL); val = val->next) -static void ReadWindowTypes(Client* c); -static void ReadWindowState(Client* c); static void ReadProps(Client* c); static void Redraw(Client* c); static void LayerWindows(void); @@ -17,38 +15,6 @@ static void SendMessage(Window win, Atom proto, Atom type); static void SetWMState(Client *c, int state); static void* ListDelete(void* list, void* node); -typedef struct { - Atom* atom; - int flags; -} AtomMap; - -static AtomMap WindowTypes[] = { - { .atom = &_NET_WM_WINDOW_TYPE, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_DESKTOP, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_DOCK, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_TOOLBAR, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_MENU, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_UTILITY, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_SPLASH, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_DIALOG, .flags = 0 }, - { .atom = &_NET_WM_WINDOW_TYPE_NORMAL, .flags = 0 }, -}; - -static AtomMap WindowStates[] = { - { .atom = &_NET_WM_STATE_MODAL, .flags = 0 }, - { .atom = &_NET_WM_STATE_STICKY, .flags = 0 }, - { .atom = &_NET_WM_STATE_MAXIMIZED_VERT, .flags = 0 }, - { .atom = &_NET_WM_STATE_MAXIMIZED_HORZ, .flags = 0 }, - { .atom = &_NET_WM_STATE_SHADED, .flags = 0 }, - { .atom = &_NET_WM_STATE_SKIP_TASKBAR, .flags = 0 }, - { .atom = &_NET_WM_STATE_SKIP_PAGER, .flags = 0 }, - { .atom = &_NET_WM_STATE_HIDDEN, .flags = 0 }, - { .atom = &_NET_WM_STATE_FULLSCREEN, .flags = 0 }, - { .atom = &_NET_WM_STATE_ABOVE, .flags = 0 }, - { .atom = &_NET_WM_STATE_BELOW, .flags = 0 }, - { .atom = &_NET_WM_STATE_DEMANDS_ATTENTION, .flags = 0 }, -}; - Client* Client_Find(Window win) { Client* curr = AllClients; @@ -124,6 +90,11 @@ void Client_Show(Client* c) /* set mouse to titlebar if mapping for first time */ if (!(c->wm_flags & F_MAPPED_ONCE)) { + int mon = Monitors_GetActiveMonitor(); + c->wspace = Monitors[mon].wspace; + c->x = Monitors[mon].midx - c->w/2; + c->y = Monitors[mon].midy - c->h/2; + Client_MoveResize(c); Mouse_ToTitle(c); c->wm_flags |= F_MAPPED_ONCE; } @@ -148,6 +119,7 @@ void Client_Destroy(Client* c) if (Focused == c) { Focused = NULL; + EWMH_SetActiveWindow(None); } AllClients = ListDelete(AllClients, c); xfree(c->name); @@ -214,6 +186,7 @@ void Client_Focus(Client* client) { Client* prev = Focused; Focused = client; + EWMH_SetActiveWindow(Focused->win); XSetInputFocus(X.disp, client->win, RevertToPointerRoot, CurrentTime); Redraw(client); if (prev) @@ -327,15 +300,12 @@ void Client_UpdateAll(void) static void ReadProps(Client* c) { - Atom actual_type, *protos = NULL; - int format, nprotos = 0; - unsigned long n, extra; + Atom *protos = NULL; + int nprotos = 0; /* 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); + c->name = EWMH_GetName(c->win); /* WM_HINTS - other non-dimensional attributes of the window */ XWMHints* hints = XGetWMHints(X.disp, c->win); @@ -374,86 +344,18 @@ static void ReadProps(Client* c) // TODO: read client machine property /* check if the window is a dialog */ - ReadWindowTypes(c); + c->wm_types = EWMH_GetWindowTypeFlags(c->win); + c->wm_state = EWMH_GetWindowStateFlags(c->win); - ReadWindowState(c); +// ReadWindowTypes(c); +// +// ReadWindowState(c); /* The following properties are unused currently */ /* WM_ICON_NAME - window title when iconified */ /* WM_COLORMAP_WINDOWS - */ } -static void ReadFlagHint(Client* c, Atom hint, AtomMap* known, unsigned long nknown, int* flags) -{ - Atom actual_type, *atoms; - int format; - unsigned long natoms, extra; - - XGetWindowProperty( - X.disp, c->win, hint, 0L, -1, False, XA_ATOM, &actual_type, &format, &natoms, &extra, (unsigned char **)&atoms); - - for (unsigned long i = 0; i < natoms; i++) - { - for (unsigned long x = 0; x < nknown; x++) - { - if (*known[x].atom == atoms[i]) - { - *flags |= known[x].flags; - } - } - } - xfree(atoms); -} - -static void ReadWindowTypes(Client* c) -{ - ReadFlagHint(c, _NET_WM_WINDOW_TYPE, WindowTypes, sizeof(WindowTypes)/sizeof(WindowTypes[0]), &(c->flags)); - -// for (unsigned long i = 0; i < ntypes; i++) -// { -// if (types[i] == _NET_WM_WINDOW_TYPE_DIALOG) -// { -// c->flags |= F_DIALOG|F_FLOATING; -// } -// if (types[i] == _NET_WM_WINDOW_TYPE_DESKTOP) -// { -// c->flags |= F_FLOATING|F_NO_FRAME; -// } -// if (types[i] == _NET_WM_WINDOW_TYPE_DOCK) -// { -// c->flags |= F_DIALOG|F_FLOATING|F_NO_FRAME; -// } -// if (types[i] == _NET_WM_WINDOW_TYPE_TOOLBAR) -// { -// c->flags |= F_DIALOG|F_FLOATING; -// } -// if (types[i] == _NET_WM_WINDOW_TYPE_MENU) -// { -// c->flags |= F_DIALOG|F_FLOATING|F_NO_FRAME; -// } -// if (types[i] == _NET_WM_WINDOW_TYPE_UTILITY) -// { -// c->flags |= F_DIALOG|F_FLOATING; -// } -// if (types[i] == _NET_WM_WINDOW_TYPE_SPLASH) -// { -// c->flags |= F_DIALOG|F_FLOATING|F_NO_FRAME; -// } -// if (types[i] == _NET_WM_WINDOW_TYPE_NORMAL) -// { -// c->flags |= 0; -// } -// } -// xfree(atoms); -} - -static void ReadWindowState(Client* c) -{ - ReadFlagHint(c, _NET_WM_STATE, WindowStates, sizeof(WindowStates)/sizeof(WindowStates[0]), &(c->flags)); - -} - - static void Redraw(Client* c) { if (c->frame) diff --git a/ewmh.c b/ewmh.c new file mode 100644 index 0000000..acd4bad --- /dev/null +++ b/ewmh.c @@ -0,0 +1,201 @@ +#include "anvil.h" + +//DWM supports only these: +// NetSupported, +// NetWMName, +// NetWMState, +// NetWMCheck, +// NetWMFullscreen, +// NetActiveWindow, +// NetWMWindowType, +// NetWMWindowTypeDialog, +// NetClientList, + +static Atom* WindowTypes[] = { + &_NET_WM_WINDOW_TYPE, + &_NET_WM_WINDOW_TYPE_DESKTOP, + &_NET_WM_WINDOW_TYPE_DOCK, + &_NET_WM_WINDOW_TYPE_TOOLBAR, + &_NET_WM_WINDOW_TYPE_MENU, + &_NET_WM_WINDOW_TYPE_UTILITY, + &_NET_WM_WINDOW_TYPE_SPLASH, + &_NET_WM_WINDOW_TYPE_DIALOG, + &_NET_WM_WINDOW_TYPE_NORMAL, +}; + +static Atom* WindowStates[] = { + &_NET_WM_STATE_MODAL, + &_NET_WM_STATE_STICKY, + &_NET_WM_STATE_MAXIMIZED_VERT, + &_NET_WM_STATE_MAXIMIZED_HORZ, + &_NET_WM_STATE_SHADED, + &_NET_WM_STATE_SKIP_TASKBAR, + &_NET_WM_STATE_SKIP_PAGER, + &_NET_WM_STATE_HIDDEN, + &_NET_WM_STATE_FULLSCREEN, + &_NET_WM_STATE_ABOVE, + &_NET_WM_STATE_BELOW, + &_NET_WM_STATE_DEMANDS_ATTENTION, +}; + +static void ReplaceProp(Window w, Atom prop, Atom type, void* elems, int nelems, int format) +{ + XChangeProperty( + X.disp, + w, + prop, + type, + format, + PropModeReplace, + (unsigned char *) elems, + nelems); +} + +static int ReadFlagHint(Window w, Atom hint, Atom** known, unsigned long nknown) +{ + Atom actual_type, *atoms; + int format, flags = 0; + unsigned long natoms, extra; + + XGetWindowProperty( + X.disp, w, hint, 0L, -1, False, XA_ATOM, &actual_type, &format, &natoms, &extra, (unsigned char **)&atoms); + + for (unsigned long i = 0; i < natoms; i++) + { + for (unsigned long x = 0; x < nknown; x++) + { + if (*known[x] == atoms[i]) + { + flags |= (1 << x); + } + } + } + if (atoms) + { + XFree(atoms); + } + return flags; +} + + +static void WriteFlagHint(Window w, Atom hint, Atom** known, unsigned long nknown, int flags) +{ + Atom* to_write = calloc(sizeof(Atom), nknown); + int n_to_write = 0; + if (to_write) + { + for (unsigned long i = 0; i < nknown; i++) + { + if (flags & (1 << i)) + { + to_write[n_to_write++] = *known[i]; + } + } + ReplaceProp(w, hint, XA_ATOM, to_write, n_to_write, 32); + free(to_write); + } +} + +/* + We might not use these properties? + + _NET_VIRTUAL_ROOTS + _NET_DESKTOP_LAYOUT + _NET_SHOWING_DESKTOP +*/ + +/* + Client messages to root we may need to listen for + + _NET_WM_STATE + +*/ + +/* + Protocols we do not intend to support... + + _NET_WM_PING + _NET_WM_SYNC_REQUEST +*/ + + +void EWMH_Init(void) +{ + // Write _NET_SUPPORTED - array of all hints we support... + // Write _NET_NUMBER_OF_DESKTOPS - total number of workspaces (10) + // Write _NET_DESKTOP_NAMES - names of workspaces... + // Write _NET_DESKTOP_VIEWPORT - always 0,0. write it here + + // _NET_SUPPORTING_WM_CHECK + // Set this to the id of a window we create and own + // Set _NET_WM_NAME on said window to name of WM + // Tells clients we are alive and kicking... +} + +void EWMH_SetClientList(void) +{ + // Write _NET_CLIENT_LIST - initial mapping order + // Write _NET_CLIENT_LIST_Stacking - bottom-to-top order +} + +void EWMH_SetActiveWindow(Window w) +{ + // Write _NET_ACTIVE_WINDOW + ReplaceProp(X.root, _NET_ACTIVE_WINDOW, XA_WINDOW, &w, 1, 32); +} + +char* EWMH_GetName(Window w) +{ + // Read _NET_WM_NAME + // else read WM_NAME + + Atom actual_type; + int format; + unsigned long n, extra; + char* name = NULL; + XGetWindowProperty( + X.disp, w, _NET_WM_NAME, 0, -1, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **)&name); + if (!name) + { + XGetWindowProperty( + X.disp, w, XA_WM_NAME, 0, -1, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **)&name); + } + return name; +} + +int EWMH_GetWindowTypeFlags(Window w) +{ + // Read _NET_WM_WINDOW_TYPE + return ReadFlagHint(w, _NET_WM_WINDOW_TYPE, WindowTypes, nelem(WindowTypes)); +} + +int EWMH_GetWindowStateFlags(Window w) +{ + // Read _NET_WM_STATE + return ReadFlagHint(w, _NET_WM_STATE, WindowStates, nelem(WindowStates)); +} + +void EWMH_SetWindowStateFlags(Window w, int flags) +{ + // Write _NET_WM_STATE + WriteFlagHint(w, _NET_WM_STATE, WindowStates, nelem(WindowStates), flags); +} + +//void EWMH_GetWindowStrut(Strut* strut) +//{ +// // Read _NET_WM_STRUT_PARTIAL +// // Else read _NET_WM_STRUT +//} + +int EWMH_GetWindowPid(Window w) +{ + // Read _NET_WM_PID + (void)w; + return 0; +} + +void EWMH_SetWindowFrameExtents(Window w, int left, int right, int top, int bottom) +{ + // Write _NET_FRAME_EXTENTS + (void)w, (void)left, (void)right, (void)top, (void)bottom; +} diff --git a/monitors.c b/monitors.c index 478b136..4bdda8d 100644 --- a/monitors.c +++ b/monitors.c @@ -1,6 +1,6 @@ #include "anvil.h" -int GetActiveMonitor(void) +int Monitors_GetActiveMonitor(void) { int monitor = 0; Mouse_GetLocation(&PtrX, &PtrY); @@ -59,7 +59,7 @@ void Monitors_SetWorkspace(int ws_id) printf("WORKSPACE %d\n", ws_id); XGrabServer(X.disp); - int mon_id = GetActiveMonitor(); + int mon_id = Monitors_GetActiveMonitor(); int other_mon_id = Workspaces[ws_id].monitor; printf("MONITORS %d %d\n", mon_id, other_mon_id); if (mon_id != other_mon_id) -- 2.51.0