From 20d714fac6b60c6c2b02c628465a7c4489055cfc Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Thu, 12 Mar 2020 16:22:46 -0400 Subject: [PATCH] added keyboard shortcuts to switch workspaces and send windows to a workspace --- anvil.c | 3 +- anvil.h | 21 +++++++++++ client.c | 14 +++++++ keys.c | 69 +++++++++++++++++++++++++++++++++++ mons.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 200 insertions(+), 16 deletions(-) create mode 100644 keys.c diff --git a/anvil.c b/anvil.c index d700467..0540e1e 100644 --- a/anvil.c +++ b/anvil.c @@ -165,7 +165,7 @@ static void xexpose(XEvent* e) static void xkeypress(XEvent* e) { - (void)e; + keys_run(&(e->xkey)); } int main(void) @@ -184,6 +184,7 @@ int main(void) check_for_wm(); mons_init(); client_initall(); + keys_init(); /* setup event handlers */ X.eventfns[ButtonPress] = xbtnpress; diff --git a/anvil.h b/anvil.h index 342ad9c..6812b11 100644 --- a/anvil.h +++ b/anvil.h @@ -1,9 +1,12 @@ #include #include +#include +#include #include #include #include #include +#include #define min(a,b) (a < b ? a : b) #define max(a,b) (a > b ? a : b) @@ -52,12 +55,27 @@ typedef struct Location { Client* client; } Location; +typedef union { + int i; +} Arg; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(Arg* arg); + Arg arg; +} Key; + #define BORDER_WIDTH 5 #define TITLE_HEIGHT 10 /* anvil.c */ extern XConf X; +/* keys.c */ +void keys_init(void); +void keys_run(XKeyEvent* ev); + /* mons.c */ extern Monitor* Monitors; void mons_init(void); @@ -65,6 +83,8 @@ void mons_addclient(Client* c); void mons_delclient(Client* c); int mons_find(Window win, Location* loc); void mons_place(Client* c); +void mons_wspace(int i); +void mons_towspace(Client* c, int i); /* client.c */ extern Client* Focused; @@ -78,6 +98,7 @@ void client_move(Client* c, int xdiff, int ydiff); void client_resize(Client* c, int xdiff, int ydiff); void client_close(Client* c); void client_focus(Client* c); +void client_show(Client* c, int show); /* error.c */ extern int (*error_default)(Display* disp, XErrorEvent* ev); diff --git a/client.c b/client.c index e961417..09bfc14 100644 --- a/client.c +++ b/client.c @@ -151,4 +151,18 @@ void client_focus(Client* c) client_draw(prev); } XSync(X.disp, False); +} + +void client_show(Client* c, int show) +{ + if (show) + { + XMapWindow(X.disp, c->frame); + XMapWindow(X.disp, c->win); + } + else + { + XUnmapWindow(X.disp, c->frame); + XUnmapWindow(X.disp, c->win); + } } \ No newline at end of file diff --git a/keys.c b/keys.c new file mode 100644 index 0000000..4a1c5f0 --- /dev/null +++ b/keys.c @@ -0,0 +1,69 @@ +#include "anvil.h" + +static void set_workspace(Arg* arg) +{ + mons_wspace(arg->i); +} + +static void to_workspace(Arg* arg) +{ + mons_towspace(Focused, arg->i); +} + +#define MODKEY Mod4Mask + +static Key keys[] = { + { MODKEY, XK_1, set_workspace, {.i = 0 } }, + { MODKEY, XK_2, set_workspace, {.i = 1 } }, + { MODKEY, XK_3, set_workspace, {.i = 2 } }, + { MODKEY, XK_4, set_workspace, {.i = 3 } }, + { MODKEY, XK_5, set_workspace, {.i = 4 } }, + { MODKEY, XK_6, set_workspace, {.i = 5 } }, + { MODKEY, XK_7, set_workspace, {.i = 6 } }, + { MODKEY, XK_8, set_workspace, {.i = 7 } }, + { MODKEY, XK_9, set_workspace, {.i = 8 } }, + { MODKEY, XK_0, set_workspace, {.i = 9 } }, + + { MODKEY|ShiftMask, XK_1, to_workspace, {.i = 0 } }, + { MODKEY|ShiftMask, XK_2, to_workspace, {.i = 1 } }, + { MODKEY|ShiftMask, XK_3, to_workspace, {.i = 2 } }, + { MODKEY|ShiftMask, XK_4, to_workspace, {.i = 3 } }, + { MODKEY|ShiftMask, XK_5, to_workspace, {.i = 4 } }, + { MODKEY|ShiftMask, XK_6, to_workspace, {.i = 5 } }, + { MODKEY|ShiftMask, XK_7, to_workspace, {.i = 6 } }, + { MODKEY|ShiftMask, XK_8, to_workspace, {.i = 7 } }, + { MODKEY|ShiftMask, XK_9, to_workspace, {.i = 8 } }, + { MODKEY|ShiftMask, XK_0, to_workspace, {.i = 9 } }, +}; + +void keys_init(void) +{ + KeyCode code; + for (unsigned int i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) + { + if ((code = XKeysymToKeycode(X.disp, keys[i].keysym))) + { + XGrabKey(X.disp, code, keys[i].mod, X.root, True, GrabModeAsync, GrabModeAsync); + } + } +} + +void keys_run(XKeyEvent* ev) +{ + KeySym keysym = XkbKeycodeToKeysym(X.disp, ev->keycode, 0, 0); + for (unsigned int i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) + { + printf("%d: (%d == %d) && (%d == %d)\n", + (int)i, + (int)keysym, + (int)keys[i].keysym, + (int)keys[i].mod, + (int)ev->state + ); + if (keysym == keys[i].keysym && keys[i].mod == ev->state && keys[i].func) + { + keys[i].func(&(keys[i].arg)); + break; + } + } +} diff --git a/mons.c b/mons.c index ed6cebd..ff62381 100644 --- a/mons.c +++ b/mons.c @@ -1,6 +1,11 @@ #include "anvil.h" #include +static Monitor* pickmon(void); +static Workspace* pickws(Monitor* mon, int wsid); +static Client* delclient(Client* list, Client* dead); +static void client_visibility(Workspace* wspace, int show); + Monitor* Monitors = NULL; void mons_init(void) @@ -11,7 +16,12 @@ void mons_init(void) for (int i = 0; i < nmons; i++) { Monitor* m = ecalloc(1, sizeof(Monitor)); - m->wspaces = ecalloc(1, sizeof(Workspace)); + for (int i = 0; i < 10; i++) + { + Workspace* wspace = ecalloc(1, sizeof(Workspace)); + wspace->next = m->wspaces; + m->wspaces = wspace; + } m->cspace = m->wspaces; m->x = mons[i].x_org; m->y = mons[i].y_org; @@ -35,19 +45,6 @@ void mons_addclient(Client* c) mons_place(c); } -Client* delclient(Client* list, Client* dead) -{ - if (list == dead) - { - list = list->next; - } - else - { - list->next = delclient(list->next, dead); - } - return list; -} - void mons_delclient(Client* c) { Location loc = {0}; @@ -117,4 +114,86 @@ void mons_place(Client* c) closest->cspace->floating = c; } } -} \ No newline at end of file +} + +void mons_wspace(int wsid) +{ + Monitor* mon = pickmon(); + Workspace* wspace = pickws(mon, wsid); + if (mon->cspace != wspace) + { + client_visibility(mon->cspace, 0); + client_visibility(wspace, 1); + mon->cspace = wspace; + } +} + +void mons_towspace(Client* c, int wsid) +{ + Location loc; + printf("%p to %d\n", c, wsid); + if (mons_find(c->win, &loc)) + { + Workspace* wspace = pickws(loc.monitor, wsid); + if (wspace != loc.workspace) + { + client_show(c, 0); + loc.workspace->floating = delclient(loc.workspace->floating, c); + c->next = wspace->floating; + wspace->floating = c; + } + } +} + +static Monitor* pickmon(void) +{ + Window root = 0, child = 0; + int ptrx = 0, ptry = 0, winx = 0, winy = 0, mask = 0; + XQueryPointer(X.disp, X.root, &root, &child, &ptrx, &ptry, &winx, &winy, (unsigned int*)&mask); + Monitor* mon = Monitors; + for (; mon; mon = mon->next) + { + if ((mon->x <= ptrx && ptrx < mon->x+mon->w) && (mon->y <= ptry && ptry < mon->y+mon->h)) + { + break; + } + } + assert(mon); + return mon; +} + +static Workspace* pickws(Monitor* mon, int wsid) +{ + Workspace* wspace = mon->wspaces; + int i = 0; + for (; wspace; wspace = wspace->next, i++) + { + if (i == wsid) + { + break; + } + } + return wspace; +} + +static Client* delclient(Client* list, Client* dead) +{ + if (list == dead) + { + list = list->next; + } + else + { + list->next = delclient(list->next, dead); + } + return list; +} + +static void client_visibility(Workspace* wspace, int show) +{ + for (Client* client = wspace->floating; client; client = client->next) + { + client_show(client, show); + } + XSync(X.disp, False); +} -- 2.52.0