From 008f4e35931b789ddb09740666d8e6a3d2c4a631 Mon Sep 17 00:00:00 2001 From: seanpringle Date: Fri, 31 Aug 2012 14:44:51 +1000 Subject: [PATCH] add find_or_start --- README.md | 2 +- cerberus.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++--- cerberus.h | 5 +++- config.h | 5 ++++ proto.h | 3 +++ 5 files changed, 80 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c79595f..ca6d2f8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ cerberus * Designed for wide screens. * Static tiling; you get just three fixed asymmetric tiles and windows never move automatically. * Bare minimum EWMH to support panels and [simpleswitcher](https://github.com/seanpringle/simpleswitcher) -* A few keyboard controls for moving, focusing, cycling, closing. +* A few keyboard controls for moving, focusing, cycling, closing, and finding windows. * Transient windows and dialogs are centered on parent, not tiled. * Splash screens and notification popups are displayed as requested, not tiled. * config.h for customization of borders and keys. diff --git a/cerberus.c b/cerberus.c index 1e26af1..be99322 100644 --- a/cerberus.c +++ b/cerberus.c @@ -30,6 +30,32 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "proto.h" #include "config.h" +void catch_exit(int sig) +{ + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +int execsh(char *cmd) +{ + // use sh for args parsing + return execlp("/bin/sh", "sh", "-c", cmd, NULL); +} + +// execute sub-process +pid_t exec_cmd(char *cmd) +{ + if (!cmd || !cmd[0]) return -1; + signal(SIGCHLD, catch_exit); + pid_t pid = fork(); + if (!pid) + { + setsid(); + execsh(cmd); + exit(EXIT_FAILURE); + } + return pid; +} + // X error handler int oops(Display *d, XErrorEvent *ee) { @@ -477,6 +503,36 @@ void client_active(client *c) ewmh_active_window(c->window); } +// real simple switcher/launcher +void find_or_start(char *class) +{ + int i; stack all; + memset(&all, 0, sizeof(stack)); + windows_visible(&all); + client *found = NULL; + + for (i = 0; !found && i < all.depth; i++) + { + XClassHint chint; + client *c = all.clients[i]; + if (c && c->manage && XGetClassHint(display, c->window, &chint)) + { + if (!strcasecmp(chint.res_class, class) || !strcasecmp(chint.res_name, class)) + found = c; + + XFree(chint.res_class); + XFree(chint.res_name); + } + } + if (found) + { + client_raise(found); + client_active(found); + return; + } + exec_cmd(class); +} + // client events we care about void window_listen(Window win) { @@ -606,15 +662,16 @@ void key_press(XKeyEvent *e) latest = e->time; client *c = window_client(current); - short act = ACTION_NONE; + short act = ACTION_NONE; void *data = NULL; KeySym key = XkbKeycodeToKeysym(display, e->keycode, 0, 0); unsigned int state = e->state & ~(LockMask|NumlockMask); for (i = 0; i < sizeof(keys)/sizeof(binding); i++) { - if (keys[i].key == key && keys[i].mod == state) + if (keys[i].key == key && (keys[i].mod == AnyModifier || keys[i].mod == state)) { - act = keys[i].act; + act = keys[i].act; + data = keys[i].data; break; } } @@ -656,6 +713,9 @@ void key_press(XKeyEvent *e) case ACTION_FOCUS_SPOT3: spot_active(SPOT3, None); break; + case ACTION_FIND_OR_START: + find_or_start(data); + break; } client_free(c); ewmh_client_list(); @@ -713,6 +773,7 @@ void focus_change(XFocusChangeEvent *e) int main(int argc, char *argv[]) { int i, j; + signal(SIGCHLD, catch_exit); if(!(display = XOpenDisplay(0))) return 1; @@ -738,6 +799,9 @@ int main(int argc, char *argv[]) { XGrabKey(display, XKeysymToKeycode(display, keys[i].key), keys[i].mod, root, True, GrabModeAsync, GrabModeAsync); + + if (keys[i].mod == AnyModifier) continue; + XGrabKey(display, XKeysymToKeycode(display, keys[i].key), keys[i].mod|LockMask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(display, XKeysymToKeycode(display, keys[i].key), keys[i].mod|NumlockMask, root, diff --git a/cerberus.h b/cerberus.h index 99b4ac9..d6687f6 100644 --- a/cerberus.h +++ b/cerberus.h @@ -38,6 +38,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include +#include #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -118,7 +120,7 @@ enum { ACTION_CYCLE, ACTION_CLOSE, ACTION_OTHER, - ACTION_STATE, + ACTION_FIND_OR_START, ACTIONS }; @@ -126,6 +128,7 @@ typedef struct { unsigned int mod; KeySym key; short act; + void *data; } binding; enum { diff --git a/config.h b/config.h index ccc1cb0..7663989 100644 --- a/config.h +++ b/config.h @@ -39,4 +39,9 @@ binding keys[] = { // gracefully close the current window { .mod = Mod4Mask, .key = XK_Escape, .act = ACTION_CLOSE }, + + // find or start apps by WM_CLASS (case insensitive) + { .mod = AnyModifier, .key = XK_F1, .act = ACTION_FIND_OR_START, .data = "urxvt" }, + { .mod = AnyModifier, .key = XK_F2, .act = ACTION_FIND_OR_START, .data = "kate" }, + { .mod = AnyModifier, .key = XK_F3, .act = ACTION_FIND_OR_START, .data = "chromium" }, }; diff --git a/proto.h b/proto.h index 4a1bd7d..71172e4 100644 --- a/proto.h +++ b/proto.h @@ -1,3 +1,5 @@ +void catch_exit(int sig); +int execsh(char *cmd); int oops(Display *d, XErrorEvent *ee); unsigned int color_get(const char *name); int window_get_prop(Window w, Atom prop, Atom *type, int *items, void *buffer, int bytes); @@ -22,6 +24,7 @@ void client_stack(client *c, stack *all, stack *raise); void client_raise(client *c); void client_lower(client *c); void client_active(client *c); +void find_or_start(char *class); void window_listen(Window win); void client_review(client *c); void create_notify(XCreateWindowEvent *e);