diff --git a/src/alttab.c b/src/alttab.c index 504a769..902097e 100644 --- a/src/alttab.c +++ b/src/alttab.c @@ -95,10 +95,6 @@ static int use_args_and_xrm(int *argc, char **argv) char *rm; char *empty = ""; int uo; - Atom nwm_prop, atype; - unsigned char *nwm; - int form; - unsigned long remain, len; XrmOptionDescRec xrmTable[] = { {"-w", "*windowmanager", XrmoptionSepArg, NULL}, {"-d", "*desktops", XrmoptionSepArg, NULL}, @@ -169,43 +165,20 @@ static int use_args_and_xrm(int *argc, char **argv) switch (xresource_load_int(&db, XRMAPPNAME, "windowmanager", &wmindex)) { case 1: - if (wmindex >= WM_MIN && wmindex <= WM_MAX) { - g.option_wm = wmindex; - goto wmDone; - } else { + if (wmindex < WM_MIN || wmindex > WM_MAX) { die(inv, "windowmanager argument range"); } break; case 0: msg(0, "no WM index or unknown, guessing\n"); + wmindex = WM_GUESS; break; case -1: die(inv, "windowmanager argument"); break; } -// EWMH? - if (ewmh_detectFeatures(&(g.ewmh))) { - msg(0, "EWMH-compatible WM detected: %s\n", g.ewmh.wmname); - g.option_wm = WM_EWMH; - goto wmDone; - } -// ratpoison? - nwm_prop = XInternAtom(dpy, "_NET_WM_NAME", false); - if (XGetWindowProperty(dpy, root, nwm_prop, 0, MAXNAMESZ, false, - AnyPropertyType, &atype, &form, &len, &remain, - &nwm) == Success && nwm) { - msg(0, "_NET_WM_NAME root property present: %s\n", nwm); - if (strstr((char *)nwm, "ratpoison") != NULL) { - g.option_wm = WM_RATPOISON; - XFree(nwm); - goto wmDone; - } - XFree(nwm); - } - msg(0, "unknown WM, using WM_TWM\n"); - g.option_wm = WM_TWM; - wmDone: - msg(0, "WM: %d\n", g.option_wm); + + initWin(wmindex); switch (xresource_load_int(&db, XRMAPPNAME, "desktops", &dsindex)) { case 1: @@ -430,12 +403,6 @@ static int use_args_and_xrm(int *argc, char **argv) g.option_font = DEFFONT + 4; } -// max recursion for searching windows -// -1 is "everything" -// in raw X this returns too much windows, "1" is probably sufficient -// no need for an option - g.option_max_reclevel = (g.option_wm == WM_NO) ? 1 : -1; - return 1; } diff --git a/src/alttab.h b/src/alttab.h index a09c821..06139a4 100644 --- a/src/alttab.h +++ b/src/alttab.h @@ -58,6 +58,14 @@ along with alttab. If not, see . #define DEFPREVKEYKS XK_VoidSymbol #define DEFNEXTKEYKS XK_VoidSymbol +#define WM_MIN 0 +#define WM_NO 0 +#define WM_EWMH 1 +#define WM_RATPOISON 2 +#define WM_TWM 3 +#define WM_MAX 3 +#define WM_GUESS -1 + #include "icon.h" #ifndef COMTYPES @@ -107,6 +115,22 @@ typedef struct PermanentWindowInfo { struct PermanentWindowInfo *next, *prev; } PermanentWindowInfo; +struct WmOps { + bool (*probe)(void); + int (*startup)(void); + int (*winlist)(void); + int (*setFocus)(int idx); + Window (*getActiveWindow)(void); + bool (*skipWindowInTaskbar)(Window w); + bool (*skipFocusChangeEvent)(void); + long (*eventMask)(Window w); +}; + +extern struct WmOps WmNoOps; +extern struct WmOps WmEwmhOps; +extern struct WmOps WmRatpoisonOps; +extern struct WmOps WmTwmOps; + /* typedef struct SwitchMoment { Window prev; @@ -126,14 +150,6 @@ typedef struct { * unlike g.winlist, survives uiHide */ PermanentWindowInfo *sortlist; // option_* are initialized from command line arguments or X resources or defaults - int option_max_reclevel; // max reclevel. -1 is "everything" -#define WM_MIN 0 -#define WM_NO 0 -#define WM_EWMH 1 -#define WM_RATPOISON 2 -#define WM_TWM 3 -#define WM_MAX 3 - int option_wm; #define DESK_MIN 0 #define DESK_CURRENT 0 #define DESK_ALL 1 @@ -200,6 +216,7 @@ Window getUiwin(); void shutdownGUI(void); // windows +void initWin(int wmindex); int startupWintasks(); int addIconFromProperty(WindowInfo * wi); int addIconFromHints(WindowInfo * wi); @@ -209,11 +226,6 @@ int addWindowInfo(Window win, int reclevel, int wm_id, unsigned long desktop, int initWinlist(void); void freeWinlist(); int setFocus(int winNdx); -int rp_startupWintasks(); -int x_initWindowsInfoRecursive(Window win, int reclevel); -int rp_initWinlist(); -int x_setFocus(int wndx); -int rp_setFocus(int winNdx); int execAndReadStdout(char *exe, char *args[], char *buf, int bufsize); int pulloutWindowToTop(int winNdx); void winPropChangeEvent(XPropertyEvent e); @@ -221,18 +233,11 @@ void winDestroyEvent(XDestroyWindowEvent e); void winFocusChangeEvent(XFocusChangeEvent e); bool common_skipWindow(Window w, unsigned long current_desktop, unsigned long window_desktop); -void x_setCommonPropertiesForAnyWindow(Window win); void addToSortlist(Window w, bool to_head, bool move); void shutdownWin(void); /* EWHM */ -bool ewmh_detectFeatures(EwmhFeatures * e); -Window ewmh_getActiveWindow(); -int ewmh_initWinlist(); int ewmh_setFocus(int winNdx, Window fwin); // fwin used if non-zero -unsigned long ewmh_getCurrentDesktop(); -unsigned long ewmh_getDesktopOfWindow(Window w); -bool ewmh_skipWindowInTaskbar(Window w); /* RANDR */ bool randrAvailable(); diff --git a/src/ewmh.c b/src/ewmh.c index 6dffe13..4c036eb 100644 --- a/src/ewmh.c +++ b/src/ewmh.c @@ -36,6 +36,9 @@ extern int scr; extern Window root; // PRIVATE +static unsigned long ewmh_getCurrentDesktop(); +static unsigned long ewmh_getDesktopOfWindow(Window w); +static bool ewmh_skipWindowInTaskbar(Window w); // // returns ptr to EWMH client list and client_list_size @@ -116,13 +119,11 @@ static int ewmh_switch_window(unsigned long window) return ewmh_send_wm_evt(window, "_NET_ACTIVE_WINDOW", edata); } -// PUBLIC - // // initialize EwmhFeatures // return true if usable at all // -bool ewmh_detectFeatures(EwmhFeatures * e) +static bool ewmh_detectFeatures(EwmhFeatures * e) { Window *chld_win; char *r; @@ -178,7 +179,7 @@ bool ewmh_detectFeatures(EwmhFeatures * e) // // active window or 0 // -Window ewmh_getActiveWindow() +static Window ewmh_getActiveWindow() { Window w = (Window) 0; char *awp; @@ -196,7 +197,7 @@ Window ewmh_getActiveWindow() // initialize winlist, correcting sortlist // return 1 if ok // -int ewmh_initWinlist() +static int ewmh_initWinlist() { Window *client_list; unsigned long client_list_size; @@ -254,28 +255,6 @@ int ewmh_initWinlist() return 1; } -// -// focus window in EWMH WM -// fwin used if non-zero, winNdx otherwise -// -int ewmh_setFocus(int winNdx, Window fwin) -{ - Window win = (fwin != 0) ? fwin : g.winlist[winNdx].id; - msg(1, "ewmh_setFocus win 0x%lx\n", win); - if (fwin == 0 && g.option_desktop != DESK_CURRENT) { - unsigned long wdesk = g.winlist[winNdx].desktop; - unsigned long cdesk = ewmh_getCurrentDesktop(); - msg(1, "ewmh_setFocus fwin 0x%lx opt %d wdesk %lu cdesk %lu\n", - fwin, g.option_desktop, wdesk, cdesk); - if (cdesk != wdesk && wdesk != DESKTOP_UNKNOWN) { - ewmh_switch_desktop(wdesk); - } - } - ewmh_switch_window(win); - XMapRaised(dpy, win); - return 1; -} - static unsigned long ewmh_getDesktopFromProp(Window w, char *prop1, char *prop2) { unsigned long *d; @@ -295,7 +274,7 @@ static unsigned long ewmh_getDesktopFromProp(Window w, char *prop1, char *prop2) // // get current desktop in EWMH WM // -unsigned long ewmh_getCurrentDesktop() +static unsigned long ewmh_getCurrentDesktop() { return ewmh_getDesktopFromProp(root, "_NET_CURRENT_DESKTOP", "_WIN_WORKSPACE"); } @@ -303,7 +282,7 @@ unsigned long ewmh_getCurrentDesktop() // // get desktop of window w in EWMH WM // -unsigned long ewmh_getDesktopOfWindow(Window w) +static unsigned long ewmh_getDesktopOfWindow(Window w) { return ewmh_getDesktopFromProp(w, "_NET_WM_DESKTOP", "_WIN_WORKSPACE"); } @@ -311,7 +290,7 @@ unsigned long ewmh_getDesktopOfWindow(Window w) // // does window have _NET_WM_STATE_SKIP_TASKBAR // -bool ewmh_skipWindowInTaskbar(Window w) +static bool ewmh_skipWindowInTaskbar(Window w) { Atom *state; long unsigned int state_propsize; @@ -338,3 +317,88 @@ bool ewmh_skipWindowInTaskbar(Window w) free(state); return ret; } + +static bool ewmhProbe(void) +{ + return ewmh_detectFeatures(&g.ewmh); +} + +static int ewmhStartup(void) +{ + long rootevmask = 0; + + // root: watching for _NET_ACTIVE_WINDOW + g.naw = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", true); + rootevmask |= PropertyChangeMask; + + // warning: this overwrites any previous value. + // note: x_setCommonPropertiesForAnyWindow does the similar thing + // for any window other than root and uiwin + XSelectInput(dpy, root, rootevmask); + + return 1; +} + +static int ewmhSetFocus(int winNdx) +{ + int r; + XWindowAttributes att; + + r = ewmh_setFocus(winNdx, 0); + // XSetInputFocus stuff. + // skippy-xd does it and notes that "order is important". + // fixes #28. + // it must be protected by testing IsViewable in the same way + // as in x.c, or BadMatch happens after switching desktops. + XGetWindowAttributes(dpy, g.winlist[winNdx].id, &att); + if (att.map_state == IsViewable) + XSetInputFocus(dpy, g.winlist[winNdx].id, RevertToParent, + CurrentTime); + return r; +} + +static bool ewmhSkipFocusChangeEvent(void) +{ + return true; +} + +static long ewmhEventMask(Window w) +{ + msg(0, "using direct focus tracking for 0x%lx\n", w); + return FocusChangeMask; +} + +// PUBLIC + +// +// focus window in EWMH WM +// fwin used if non-zero, winNdx otherwise +// +int ewmh_setFocus(int winNdx, Window fwin) +{ + Window win = (fwin != 0) ? fwin : g.winlist[winNdx].id; + msg(1, "ewmh_setFocus win 0x%lx\n", win); + if (fwin == 0 && g.option_desktop != DESK_CURRENT) { + unsigned long wdesk = g.winlist[winNdx].desktop; + unsigned long cdesk = ewmh_getCurrentDesktop(); + msg(1, "ewmh_setFocus fwin 0x%lx opt %d wdesk %lu cdesk %lu\n", + fwin, g.option_desktop, wdesk, cdesk); + if (cdesk != wdesk && wdesk != DESKTOP_UNKNOWN) { + ewmh_switch_desktop(wdesk); + } + } + ewmh_switch_window(win); + XMapRaised(dpy, win); + return 1; +} + +struct WmOps WmEwmhOps = { + .probe = ewmhProbe, + .startup = ewmhStartup, + .winlist = ewmh_initWinlist, + .setFocus = ewmhSetFocus, + .getActiveWindow = ewmh_getActiveWindow, + .skipWindowInTaskbar = ewmh_skipWindowInTaskbar, + .skipFocusChangeEvent = ewmhSkipFocusChangeEvent, + .eventMask = ewmhEventMask, +}; diff --git a/src/rp.c b/src/rp.c index 1a0cfa9..f7ebc52 100644 --- a/src/rp.c +++ b/src/rp.c @@ -30,6 +30,8 @@ along with alttab. If not, see . #include "alttab.h" #include "util.h" extern Globals g; +extern Display *dpy; +extern Window root; // PRIVATE @@ -99,12 +101,10 @@ static int rp_add_windows_in_group(int current_group, int window_group) return 1; } -// PUBLIC - // // early initialization in ratpoison // -int rp_startupWintasks() +static int rp_startupWintasks() { // search for ratpoison executable for later execv @@ -158,7 +158,7 @@ int rp_startupWintasks() // // initialize winlist/update sortlist from ratpoison output // -int rp_initWinlist() +static int rp_initWinlist() { #define fallback { msg(-1, "using current rp group\n") ; \ return rp_add_windows_in_group(DESKTOP_UNKNOWN, DESKTOP_UNKNOWN); } @@ -217,7 +217,7 @@ int rp_initWinlist() // // focus window in ratpoison // -int rp_setFocus(int winNdx) +static int rp_setFocus(int winNdx) { char selarg[64]; char *args[] = { "ratpoison", "-c", selarg, NULL }; @@ -236,3 +236,49 @@ int rp_setFocus(int winNdx) return 1; } + +static bool ratpoisonProbe(void) +{ + unsigned long remain, len; + Atom nwm_prop, atype; + int form; + unsigned char *nwm; + bool ret = false; + + nwm_prop = XInternAtom(dpy, "_NET_WM_NAME", false); + if (!XGetWindowProperty(dpy, root, nwm_prop, 0, MAXNAMESZ, false, + AnyPropertyType, &atype, &form, &len, &remain, + &nwm) == Success && nwm) + return false; + + msg(0, "_NET_WM_NAME root property present: %s\n", nwm); + if (strstr((char *)nwm, "ratpoison") != NULL) + ret = true; + + XFree(nwm); + return ret; +} + +static int ratpoisonStartup(void) +{ + return rp_startupWintasks(); +} + +static int ratpoisonWinlist(void) +{ + return rp_initWinlist(); +} + +static int ratpoisonSetFocus(int idx) +{ + return rp_setFocus(idx); +} + +// PUBLIC + +struct WmOps WmRatpoisonOps = { + .probe = ratpoisonProbe, + .startup = ratpoisonStartup, + .winlist = ratpoisonWinlist, + .setFocus = ratpoisonSetFocus, +}; diff --git a/src/win.c b/src/win.c index 8f35bfa..4afb92c 100644 --- a/src/win.c +++ b/src/win.c @@ -38,6 +38,69 @@ extern Window root; // PRIVATE +static struct WmOps *WmOpsVariants[] = { + [WM_NO] = &WmNoOps, + [WM_EWMH] = &WmEwmhOps, + [WM_RATPOISON] = &WmRatpoisonOps, + [WM_TWM] = &WmTwmOps, +}; + +static struct WmOps *WmOps; + +static inline bool wmProbe(int wm) +{ + return (WmOpsVariants[wm]->probe != NULL) && (WmOpsVariants[wm]->probe()); +} + +static inline int wmStartup(void) +{ + if (WmOps->startup == NULL) + return 1; + return WmOps->startup(); +} + +static inline int wmInitWinlist(void) +{ + if (WmOps->winlist == NULL) + return 0; + return WmOps->winlist(); +} + +static inline int wmSetFocus(int idx) +{ + if (WmOps->setFocus == NULL) + return 0; + return WmOps->setFocus(idx); +} + +static inline Window wmGetActiveWindow(void) +{ + if (WmOps->getActiveWindow == NULL) + return 0; + return WmOps->getActiveWindow(); +} + +static inline bool wmSkipWindowInTaskbar(Window w) +{ + if (WmOps->skipWindowInTaskbar == NULL) + return false; + return WmOps->skipWindowInTaskbar(w); +} + +static inline bool wmSkipFocusChangeEvent(void) +{ + if (WmOps->skipFocusChangeEvent == NULL) + return false; + return WmOps->skipFocusChangeEvent(); +} + +static inline long wmEventMask(Window w) +{ + if (WmOps->eventMask == NULL) + return 0; + return WmOps->eventMask(w); +} + // // helper for windows' qsort // CAUSES O(log(N)) OR EVEN WORSE! reintroduce winlist[]->order instead? @@ -99,6 +162,26 @@ static void print_winlist() } } +// +// this is where alttab is supposed to set properties or +// register interest in event for ANY foreign window encountered. +// warning: this is called only on addition to sortlist. +// +static void winSetCommonPropertiesForAnyWindow(Window win) +{ + long evmask = 0; + // root and our window are treated elsewhere + if (win == root || win == getUiwin()) + return; + // for delete notification + evmask |= StructureNotifyMask; + // for focusIn notification + evmask |= wmEventMask(win); + // warning: this overwrites previous value + if (evmask != 0) + XSelectInput(dpy, win, evmask); +} + // PUBLIC // @@ -135,47 +218,53 @@ void addToSortlist(Window w, bool to_head, bool move) if (add && !was) { // new window // register interest in events - x_setCommonPropertiesForAnyWindow(w); + winSetCommonPropertiesForAnyWindow(w); } } +// +// wmindex is the already validated option +void initWin(int wmindex) +{ + int wm; + + if (wmindex != WM_GUESS) { + wm = wmindex; + goto out; + } + + if (wmProbe(WM_EWMH)) { + msg(0, "EWMH-compatible WM detected: %s\n", g.ewmh.wmname); + wm = WM_EWMH; + goto out; + } + + if (wmProbe(WM_RATPOISON)) { + wm = WM_RATPOISON; + goto out; + } + + msg(0, "unknown WM, using WM_TWM\n"); + wm = WM_TWM; + +out: + msg(0, "WM: %d\n", wm); + WmOps = WmOpsVariants[wm]; +} + // // early initialization // once per execution // int startupWintasks() { - long rootevmask = 0; - g.sortlist = NULL; // utlist head must be initialized to NULL g.ic = NULL; // uthash too if (g.option_iconSrc != ISRC_RAM) { initIconHash(&(g.ic)); } - // root: watching for _NET_ACTIVE_WINDOW - if (g.option_wm == WM_EWMH) { - g.naw = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", true); - rootevmask |= PropertyChangeMask; - } - // warning: this overwrites any previous value. - // note: x_setCommonPropertiesForAnyWindow does the similar thing - // for any window other than root and uiwin - if (rootevmask != 0) { - XSelectInput(dpy, root, rootevmask); - } - switch (g.option_wm) { - case WM_NO: - return 1; - case WM_RATPOISON: - return rp_startupWintasks(); - case WM_EWMH: - return 1; - case WM_TWM: - return 1; - default: - return 0; - } + return wmStartup(); } // @@ -508,23 +597,8 @@ int initWinlist(void) msg(1, "before initWinlist\n"); print_sortlist(); } - switch (g.option_wm) { - case WM_NO: - r = x_initWindowsInfoRecursive(root, 0); // note: direction/current window index aren't used - break; - case WM_RATPOISON: - r = rp_initWinlist(); - break; - case WM_EWMH: - r = ewmh_initWinlist(); - break; - case WM_TWM: - r = x_initWindowsInfoRecursive(root, 0); - break; - default: - r = 0; - break; - } + + r = wmInitWinlist(); if (!r) __initWinlist(); @@ -571,34 +645,8 @@ void freeWinlist() int setFocus(int winNdx) { int r; - switch (g.option_wm) { - case WM_NO: - r = ewmh_setFocus(winNdx, 0); // for WM which isn't identified as EWMH compatible but accepts setting focus (dwm) - x_setFocus(winNdx); - break; - case WM_RATPOISON: - r = rp_setFocus(winNdx); - break; - case WM_EWMH: - r = ewmh_setFocus(winNdx, 0); - // XSetInputFocus stuff. - // skippy-xd does it and notes that "order is important". - // fixes #28. - // it must be protected by testing IsViewable in the same way - // as in x.c, or BadMatch happens after switching desktops. - XWindowAttributes att; - XGetWindowAttributes(dpy, g.winlist[winNdx].id, &att); - if (att.map_state == IsViewable) - XSetInputFocus(dpy, g.winlist[winNdx].id, RevertToParent, - CurrentTime); - break; - case WM_TWM: - r = ewmh_setFocus(winNdx, 0); - x_setFocus(winNdx); - break; - default: - return 0; - } + + r = wmSetFocus(winNdx); // pull to head addToSortlist(g.winlist[winNdx].id, true, true); return r; @@ -625,7 +673,7 @@ void winPropChangeEvent(XPropertyEvent e) if (e.atom != g.naw) return; // don't check for wm==EWMH, because _NET_ACTIVE_WINDOW changed for sure - aw = ewmh_getActiveWindow(); + aw = wmGetActiveWindow(); // can't get active window if (!aw) return; @@ -636,7 +684,7 @@ void winPropChangeEvent(XPropertyEvent e) if (g.sortlist != NULL && aw == g.sortlist->id) return; // is window hidden in WM? - if (ewmh_skipWindowInTaskbar(aw)) + if (wmSkipWindowInTaskbar(aw)) return; /* // the i3 sortlist bug is not here, see ewmh.c init_winlist instead @@ -745,7 +793,7 @@ void winFocusChangeEvent(XFocusChangeEvent e) // in non-EWMH only // probably should also maintain _NET_ACTIVE_WINDOW // support flag in EwmhFeatures - if (g.option_wm == WM_EWMH) + if (wmSkipFocusChangeEvent()) return; // focusIn only if (e.type != FocusIn) diff --git a/src/x.c b/src/x.c index e59c6e6..6e0fe66 100644 --- a/src/x.c +++ b/src/x.c @@ -33,6 +33,13 @@ extern Window root; // PRIVATE +// max recursion for searching windows +// -1 is "everything" +// in raw X this returns too much windows, "1" is probably sufficient +// no need for an option +static int max_reclevel; +static int wm; + // // get window group leader // to be used later. rewritten, not tested. @@ -57,13 +64,11 @@ Window x_get_leader(Window win) return leader; } -// PUBLIC - // // set winlist,maxNdx recursively using raw Xlib // first call should be (win=root, reclevel=0) // -int x_initWindowsInfoRecursive(Window win, int reclevel) +static int x_initWindowsInfoRecursive(Window win, int reclevel) { Window root, parent; @@ -88,24 +93,24 @@ int x_initWindowsInfoRecursive(Window win, int reclevel) // caveat: in rp, skips anything except of visible window // probably add an option for this in WMs too? wa.map_state = 0; - if (g.option_wm != WM_TWM) + if (wm != WM_TWM) XGetWindowAttributes(dpy, win, &wa); // in twm-like, add only windows with a name winname = NULL; - if (g.option_wm == WM_TWM) { + if (wm == WM_TWM) { winname = get_x_property(win, XA_STRING, "WM_NAME", NULL); } // insert detailed window data in window list - if ((g.option_wm == WM_TWM || wa.map_state == IsViewable) - && reclevel != 0 && (g.option_wm != WM_TWM || winname != NULL) -// && (g.option_wm != WM_TWM || leader == win) + if ((wm == WM_TWM || wa.map_state == IsViewable) + && reclevel != 0 && (wm != WM_TWM || winname != NULL) +// && (wm != WM_TWM || leader == win) && !common_skipWindow(win, DESKTOP_UNKNOWN, DESKTOP_UNKNOWN) ) { addWindowInfo(win, reclevel, 0, DESKTOP_UNKNOWN, winname); } // skip children if max recursion level reached - if (g.option_max_reclevel != -1 && reclevel >= g.option_max_reclevel) + if (max_reclevel != -1 && reclevel >= max_reclevel) return 1; // recursion @@ -126,7 +131,7 @@ int x_initWindowsInfoRecursive(Window win, int reclevel) // // set window focus in raw X // -int x_setFocus(int wndx) +static int x_setFocus(int wndx) { Window w = g.winlist[wndx].id; @@ -149,25 +154,47 @@ int x_setFocus(int wndx) return 1; } -// -// this is where alttab is supposed to set properties or -// register interest in event for ANY foreign window encountered. -// warning: this is called only on addition to sortlist. -// -void x_setCommonPropertiesForAnyWindow(Window win) +static int xSetFocus(int idx) { - long evmask = 0; - // root and our window are treated elsewhere - if (win == root || win == getUiwin()) - return; - // for delete notification - evmask |= StructureNotifyMask; - // for focusIn notification - if (g.option_wm != WM_EWMH) { - msg(0, "using direct focus tracking for 0x%lx\n", win); - evmask |= FocusChangeMask; - } - // warning: this overwrites previous value - if (evmask != 0) - XSelectInput(dpy, win, evmask); + int r; + + // for WM which isn't identified as EWMH compatible + // but accepts setting focus (dwm) + r = ewmh_setFocus(idx, 0); + x_setFocus(idx); + + return r; } + +static int xStartup(void) +{ + wm = WM_NO; + max_reclevel = 1; + return 1; +} + +static int twmStartup(void) +{ + wm = WM_TWM; + max_reclevel = -1; + return 1; +} + +static int xWinlist(void) +{ + return x_initWindowsInfoRecursive(root, 0); +} + +// PUBLIC + +struct WmOps WmNoOps = { + .startup = xStartup, + .winlist = xWinlist, + .setFocus = xSetFocus, +}; + +struct WmOps WmTwmOps = { + .startup = twmStartup, + .winlist = xWinlist, + .setFocus = xSetFocus, +};