add find_or_start
This commit is contained in:
@@ -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.
|
||||
|
||||
70
cerberus.c
70
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,
|
||||
|
||||
@@ -38,6 +38,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#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 {
|
||||
|
||||
5
config.h
5
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" },
|
||||
};
|
||||
|
||||
3
proto.h
3
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);
|
||||
|
||||
Reference in New Issue
Block a user