From e0c13213c55ee63781d195357647b1eeaf3edda8 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 13 Feb 2022 19:57:24 -0800 Subject: [PATCH] [amiwm] add a new command action to rotate windows This adds a command to iterate over the set of windows. It's not like alt-tab in ye olde windows world where you'd alt tab once to switch between two windows, and then keep alt-tab'ing with alt down to go through the window list. For now it just literally iterates through those windows. This makes it a lot easier to work with a large number of open windows without having to constantly use the mouse. --- MODULES.md | 19 ++++++- frame.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++ kbdlexer.l | 2 + libami/libami.h | 2 + libami/mdscreen.c | 10 ++++ module.c | 17 +++++++ module.h | 2 + 7 files changed, 177 insertions(+), 2 deletions(-) diff --git a/MODULES.md b/MODULES.md index 76ad023..be5227f 100644 --- a/MODULES.md +++ b/MODULES.md @@ -35,11 +35,13 @@ image, but repeated. ## Keyboard module With the Keyboard module, you can bind window manager functions to keys -on the keyboard. The initstring should consist of keybindings on the -form +on the keyboard. The initstring should consist of one or more keybindings +on the form modifiers:where:func +Multiple keybindings are specified with spaces between them. + ### modifiers Modifiers is 0 or more of: @@ -47,6 +49,10 @@ Modifiers is 0 or more of: Mod1 Mod2 Mod3 Mod4 Mod5 Button1 Button2 Button3 Button4 Button5 +Modifiers are joined together using spaces. This can be confusing +as it looks like keybindings are specified with spaces between them +but the parser actually handles this. + The modifiers listed must be pressed together with the key to activate the binding. @@ -67,6 +73,8 @@ The function to perform when the key is pressed. Currently the following are defined: rotatescreens - Move the frontmost screen to the back +raisewindow - Rotate the bottom window to the top of the screen +lowerwindow - Rotate the top window to the bottom of the screen front - Move the window in which the key is pressed to the front back - Move the window in which the key is pressed to the back iconify - Iconify the window in which the key is pressed @@ -84,6 +92,13 @@ iconify respectively. The will only have effect inside windows and in window frames. (These are the only places that front/iconfy/back has effect anyway.) +An example with multiple modifiers in a single keybinding. + +Module "Keyboard" \ + Meta:all:rotatewindows\ + Meta:all:raisescreen\ + Control Meta:all:lowerscreen" + ## Filesystem module This is an april fools joke module, but at least it's a starting diff --git a/frame.c b/frame.c index 47b9786..cf4acfd 100644 --- a/frame.c +++ b/frame.c @@ -591,6 +591,133 @@ void raiselowerclient(Client *c, int place) } else XRaiseWindow(dpy, c->parent); } +extern void setfocus(Window); +extern Client *activeclient; + +/* + * Lower the top most client. + * + * Update focus if required. + */ +void +lowertopmostclient(Scrn *scr) +{ + Window r, p, *children; + unsigned int nchildren; + Client *c_top, *c_bot; + Window ws[2]; + + /* Query the list of windows under the active screen */ + if (XQueryTree(dpy, scr->back, &r, &p, &children, &nchildren) == 0) { + fprintf(stderr, "%s: couldn't fetch the window list\n", __func__); + return; + } + + /* + * Grab the top most client + */ + c_top = topmostmappedclient(children, nchildren); + if (c_top == NULL) { + fprintf(stderr, "%s: couldn't get the top most mapped client\n", __func__); + return; + } + + /* + * And the bottom most client. + */ + c_bot = bottommostmappedclient(children, nchildren); + if (c_bot == NULL) { + fprintf(stderr, "%s: couldn't get the bottom most mapped client\n", __func__); + return; + } + + /* + * If we're doing click-to-focus, mark the old top-most window + * as inactive; mark the new top-most window as active and has focus. + */ + if (prefs.focus == FOC_CLICKTOTYPE) { + c_top->active = False; + c_bot->active = True; + activeclient = c_bot; + redrawclient(c_bot); + redrawclient(c_top); + setfocus(c_bot->window); + } + + /* + * Push this to the bottom of the stack. + */ + ws[0]=c_bot->parent; + ws[1]=c_top->parent; + XRestackWindows(dpy, ws, 2); + + /* + * Free the children list. + */ + if (children) + XFree(children); +} + +/* + * Raise the bottom most client. + * + * Update focus if required. + */ +void +raisebottommostclient(Scrn *scr) +{ + Window r, p, *children; + unsigned int nchildren; + Client *c_top, *c_bot; + + /* Query the list of windows under the active screen */ + if (XQueryTree(dpy, scr->back, &r, &p, &children, &nchildren) == 0) { + fprintf(stderr, "%s: couldn't fetch the window list\n", __func__); + return; + } + + /* + * Grab the top most client + */ + c_top = topmostmappedclient(children, nchildren); + if (c_top == NULL) { + fprintf(stderr, "%s: couldn't get the top most mapped client\n", __func__); + return; + } + + /* + * And the bottom most client. + */ + c_bot = bottommostmappedclient(children, nchildren); + if (c_bot == NULL) { + fprintf(stderr, "%s: couldn't get the bottom most mapped client\n", __func__); + return; + } + + /* + * If we're doing click-to-focus, mark the old top-most window + * as inactive; mark the new top-most window as active and has focus. + */ + if (prefs.focus == FOC_CLICKTOTYPE) { + c_top->active = False; + c_bot->active = True; + activeclient = c_bot; + redrawclient(c_bot); + redrawclient(c_top); + setfocus(c_bot->window); + } + + /* Raise the selected window to the top */ + XRaiseWindow(dpy, c_bot->parent); + + /* + * Free the children list. + */ + if (children) + XFree(children); +} + + void gadgetunclicked(Client *c, XEvent *e) { extern void adjusticon(Icon *); diff --git a/kbdlexer.l b/kbdlexer.l index 79184f6..3149834 100644 --- a/kbdlexer.l +++ b/kbdlexer.l @@ -41,6 +41,8 @@ int parse_keyword(char *str, YYSTYPE *val) { "back", (mdfuncp)md_back }, { "front", (mdfuncp)md_front }, { "iconify", (mdfuncp)md_iconify }, + { "lowerwindow", (mdfuncp)md_rotate_window_lower }, + { "raisewindow", (mdfuncp)md_rotate_window_raise }, { "rotatescreens", (mdfuncp)k_rotscreens }, }; #define N_FUNC (sizeof(functab)/sizeof(functab[0])) diff --git a/libami/libami.h b/libami/libami.h index f02f74e..160dbea 100644 --- a/libami/libami.h +++ b/libami/libami.h @@ -368,6 +368,8 @@ extern int md_front(Window); extern int md_back(Window); extern int md_iconify(Window); extern int md_errormsg(Window, char *); +extern int md_rotate_window_raise(Window); +extern int md_rotate_window_lower(Window); /* eventdispatcher.c */ extern void cx_event_broker(int, unsigned long, int (*)(XEvent*)); diff --git a/libami/mdscreen.c b/libami/mdscreen.c index c7c1312..9599c99 100644 --- a/libami/mdscreen.c +++ b/libami/mdscreen.c @@ -22,6 +22,16 @@ int md_iconify(XID id) return md_command00(id, MCMD_ICONIFY); } +int md_rotate_window_raise(XID id) +{ + return md_command00(id, MCMD_ROTATE_WINDOW_RAISE); +} + +int md_rotate_window_lower(XID id) +{ + return md_command00(id, MCMD_ROTATE_WINDOW_LOWER); +} + int md_errormsg(Window id, char *str) { return md_command0(id, MCMD_ERRORMSG, str, strlen(str)); diff --git a/module.c b/module.c index e11e812..3b1bb7b 100644 --- a/module.c +++ b/module.c @@ -335,6 +335,9 @@ void mod_menuselect(struct module *m, int menu, int item, int subitem) menu, item, subitem, (int)m->pid); } +extern void lowertopmostclient(Scrn *scr); +extern void raisebottommostclient(Scrn *scr); + static void handle_module_cmd(struct module *m, char *data, int data_len) { extern Scrn *getscreen(Window); @@ -369,6 +372,20 @@ static void handle_module_cmd(struct module *m, char *data, int data_len) screentoback(); reply_module(m, NULL, 0); break; + case MCMD_ROTATE_WINDOW_RAISE: + /* Get the current screen */ + scr = getscreen(id); + /* raise away! */ + raisebottommostclient(scr); + reply_module(m, NULL, 0); + break; + case MCMD_ROTATE_WINDOW_LOWER: + /* Get the current screen */ + scr = getscreen(id); + /* lower away! */ + lowertopmostclient(scr); + reply_module(m, NULL, 0); + break; case MCMD_ADD_KEYGRAB: if(data_len>=sizeof(int[2])) { int res=create_keygrab(m, ((int*)data)[0], ((int*)data)[1]); diff --git a/module.h b/module.h index 0abdb39..9c891f1 100644 --- a/module.h +++ b/module.h @@ -14,6 +14,8 @@ #define MCMD_GETICONDIR 16 #define MCMD_GETICONPALETTE 17 #define MCMD_MANAGEMENU 18 +#define MCMD_ROTATE_WINDOW_RAISE 19 +#define MCMD_ROTATE_WINDOW_LOWER 20 struct mcmd_header { XID id;