X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=55bf753bd425679fcbb7d944b486bec2f3da98ae;hb=163f135835a874fde60008254cea4a1f753ddc64;hp=b96e6f47d5cc43f8be28d27b5c36e0925adfe671;hpb=e126add24b56470c8dc0cd7d0ee0dd71de22fb9a;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index b96e6f4..55bf753 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -4,6 +4,7 @@ * Copyright (c) 2009-2010-2011 Ryan McBride * Copyright (c) 2009 Darrin Chandler * Copyright (c) 2009 Pierre-Yves Ritschard + * Copyright (c) 2010 Tuukka Kataja * Copyright (c) 2011 Jason L. Wright * * Permission to use, copy, modify, and distribute this software for any @@ -54,7 +55,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.9.30" +#define SWM_VERSION "0.9.34" #include #include @@ -86,6 +87,7 @@ static const char *cvstag = #include #include #include +#include #ifdef __OSX__ #include @@ -219,6 +221,7 @@ int bar_verbose = 1; int bar_height = 0; int stack_enabled = 1; int clock_enabled = 1; +int urgent_enabled = 0; char *clock_format = NULL; int title_name_enabled = 0; int title_class_enabled = 0; @@ -226,6 +229,7 @@ int window_name_enabled = 0; int focus_mode = SWM_FOCUS_DEFAULT; int disable_border = 0; int border_width = 1; +int verbose_layout = 0; pid_t bar_pid; GC bar_gc; XGCValues bar_gcv; @@ -292,6 +296,15 @@ struct ws_win { }; TAILQ_HEAD(ws_win_list, ws_win); +/* pid goo */ +struct pid_e { + TAILQ_ENTRY(pid_e) entry; + long pid; + int ws; +}; +TAILQ_HEAD(pid_list, pid_e); +struct pid_list pidlist = TAILQ_HEAD_INITIALIZER(pidlist); + /* layout handlers */ void stack(void); void vertical_config(struct workspace *, int); @@ -299,6 +312,8 @@ void vertical_stack(struct workspace *, struct swm_geometry *); void horizontal_config(struct workspace *, int); void horizontal_stack(struct workspace *, struct swm_geometry *); void max_stack(struct workspace *, struct swm_geometry *); +void plain_stacker(struct workspace *); +void fancy_stacker(struct workspace *); struct ws_win *find_window(Window); @@ -313,18 +328,20 @@ struct layout { u_int32_t flags; #define SWM_L_FOCUSPREV (1<<0) #define SWM_L_MAPONFOCUS (1<<1) - char *name; + void (*l_string)(struct workspace *); } layouts[] = { /* stack, configure */ - { vertical_stack, vertical_config, 0, "[|]" }, - { horizontal_stack, horizontal_config, 0, "[-]" }, + { vertical_stack, vertical_config, 0, plain_stacker }, + { horizontal_stack, horizontal_config, 0, plain_stacker }, { max_stack, NULL, - SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV, "[ ]" }, + SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV, plain_stacker }, { NULL, NULL, 0, NULL }, }; -/* position of max_stack mode in the layouts array */ -#define SWM_MAX_STACK 2 +/* position of max_stack mode in the layouts array, index into layouts! */ +#define SWM_V_STACK (0) +#define SWM_H_STACK (1) +#define SWM_MAX_STACK (2) #define SWM_H_SLICE (32) #define SWM_V_SLICE (32) @@ -332,6 +349,7 @@ struct layout { /* define work spaces */ struct workspace { int idx; /* workspace index */ + int always_raise; /* raise windows on focus */ struct layout *cur_layout; /* current layout handlers */ struct ws_win *focus; /* may be NULL */ struct ws_win *focus_prev; /* may be NULL */ @@ -339,6 +357,7 @@ struct workspace { struct swm_region *old_r; /* may be NULL */ struct ws_win_list winlist; /* list of windows in ws */ struct ws_win_list unmanagedlist; /* list of dead windows in ws */ + char stacker[10]; /* display stacker and layout */ /* stacker state */ struct { @@ -401,6 +420,14 @@ union arg { #define SWM_ARG_ID_CENTER (71) #define SWM_ARG_ID_KILLWINDOW (80) #define SWM_ARG_ID_DELETEWINDOW (81) +#define SWM_ARG_ID_WIDTHGROW (90) +#define SWM_ARG_ID_WIDTHSHRINK (91) +#define SWM_ARG_ID_HEIGHTGROW (92) +#define SWM_ARG_ID_HEIGHTSHRINK (93) +#define SWM_ARG_ID_MOVEUP (100) +#define SWM_ARG_ID_MOVEDOWN (101) +#define SWM_ARG_ID_MOVELEFT (102) +#define SWM_ARG_ID_MOVERIGHT (103) char **argv; }; @@ -595,12 +622,11 @@ void ewmh_autoquirk(struct ws_win *win) { int success, i; - unsigned long *data = NULL; - unsigned long n; + unsigned long *data = NULL, n; Atom type; success = get_property(win->id, ewmh[_NET_WM_WINDOW_TYPE].atom, (~0L), - XA_ATOM, &n, (unsigned char **)&data); + XA_ATOM, &n, (void *)&data); if (!success) { XFree(data); @@ -789,7 +815,7 @@ ewmh_get_win_state(struct ws_win *win) win->ewmh_flags |= SWM_F_MANUAL; success = get_property(win->id, ewmh[_NET_WM_STATE].atom, - (~0L), XA_ATOM, &n, (unsigned char **)&states); + (~0L), XA_ATOM, &n, (void *)&states); if (!success) return; @@ -1047,6 +1073,24 @@ sighdlr(int sig) errno = saved_errno; } +struct pid_e * +find_pid(long pid) +{ + struct pid_e *p = NULL; + + DNPRINTF(SWM_D_MISC, "find_pid: %lu\n", pid); + + if (pid == 0) + return (NULL); + + TAILQ_FOREACH(p, &pidlist, entry) { + if (p->pid == pid) + return (p); + } + + return (NULL); +} + unsigned long name_to_color(char *colorname) { @@ -1093,6 +1137,28 @@ setscreencolor(char *val, int i, int c) } void +fancy_stacker(struct workspace *ws) +{ + strcpy(ws->stacker, "[ ]"); + if (ws->cur_layout->l_stack == vertical_stack) + snprintf(ws->stacker, sizeof ws->stacker, "[%d|%d]", + ws->l_state.vertical_mwin, ws->l_state.vertical_stacks); + if (ws->cur_layout->l_stack == horizontal_stack) + snprintf(ws->stacker, sizeof ws->stacker, "[%d-%d]", + ws->l_state.horizontal_mwin, ws->l_state.horizontal_stacks); +} + +void +plain_stacker(struct workspace *ws) +{ + strcpy(ws->stacker, "[ ]"); + if (ws->cur_layout->l_stack == vertical_stack) + strcpy(ws->stacker, "[|]"); + if (ws->cur_layout->l_stack == horizontal_stack) + strcpy(ws->stacker, "[-]"); +} + +void custom_region(char *val) { unsigned int sidx, x, y, w, h; @@ -1108,8 +1174,8 @@ custom_region(char *val) if (w < 1 || h < 1) errx(1, "region %ux%u+%u+%u too small\n", w, h, x, y); - if (x < 0 || x > DisplayWidth(display, sidx) || - y < 0 || y > DisplayHeight(display, sidx) || + if (x > DisplayWidth(display, sidx) || + y > DisplayHeight(display, sidx) || w + x > DisplayWidth(display, sidx) || h + y > DisplayHeight(display, sidx)) { fprintf(stderr, "ignoring region %ux%u+%u+%u " @@ -1204,6 +1270,44 @@ bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus) } } +int urgent[SWM_WS_MAX]; +void +bar_urgent(char *s, ssize_t sz) +{ + XWMHints *wmh = NULL; + struct ws_win *win; + int i, j; + char b[8]; + + if (urgent_enabled == 0) + return; + + for (i = 0; i < SWM_WS_MAX; i++) + urgent[i] = 0; + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { + wmh = XGetWMHints(display, win->id); + if (wmh == NULL) + continue; + + if (wmh->flags & XUrgencyHint) + urgent[j] = 1; + XFree(wmh); + } + + strlcat(s, "* ", sz); + for (i = 0; i < SWM_WS_MAX; i++) { + if (urgent[i]) + snprintf(b, sizeof b, "%d ", i + 1); + else + snprintf(b, sizeof b, "- "); + strlcat(s, b, sz); + } + strlcat(s, "* ", sz); +} + void bar_update(void) { @@ -1216,7 +1320,6 @@ bar_update(void) char cn[SWM_BAR_MAX]; char loc[SWM_BAR_MAX]; char *b; - char *stack = ""; if (bar_enabled == 0) return; @@ -1249,15 +1352,13 @@ bar_update(void) TAILQ_FOREACH(r, &screens[i].rl, entry) { strlcpy(cn, "", sizeof cn); if (r && r->ws) { + bar_urgent(cn, sizeof cn); bar_class_name(cn, sizeof cn, r->ws->focus); bar_window_name(cn, sizeof cn, r->ws->focus); } - if (stack_enabled) - stack = r->ws->cur_layout->name; - snprintf(loc, sizeof loc, "%d:%d %s %s%s %s %s", - x++, r->ws->idx + 1, stack, s, cn, bar_ext, + x++, r->ws->idx + 1, r->ws->stacker, s, cn, bar_ext, bar_vertext); bar_print(r, loc); } @@ -1687,7 +1788,7 @@ find_window(Window id) } void -spawn(struct swm_region *r, union arg *args, int close_fd) +spawn(int ws_idx, union arg *args, int close_fd) { int fd; char *ret = NULL; @@ -1699,7 +1800,7 @@ spawn(struct swm_region *r, union arg *args, int close_fd) setenv("LD_PRELOAD", SWM_LIB, 1); - if (asprintf(&ret, "%d", r->ws->idx) == -1) { + if (asprintf(&ret, "%d", ws_idx) == -1) { perror("_SWM_WS"); _exit(1); } @@ -1747,10 +1848,11 @@ spawnterm(struct swm_region *r, union arg *args) { DNPRINTF(SWM_D_MISC, "spawnterm\n"); - if (term_width) - setenv("_SWM_XTERM_FONTADJ", "", 1); - if (fork() == 0) - spawn(r, args, 1); + if (fork() == 0) { + if (term_width) + setenv("_SWM_XTERM_FONTADJ", "", 1); + spawn(r->ws->idx, args, 1); + } } void @@ -1929,11 +2031,11 @@ focus_win(struct ws_win *win) if (win->java == 0) XSetInputFocus(display, win->id, RevertToParent, CurrentTime); - XMapRaised(display, win->id); grabbuttons(win, 1); XSetWindowBorder(display, win->id, win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); - if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS) + if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS || + win->ws->always_raise) XMapRaised(display, win->id); XChangeProperty(display, win->s->root, @@ -2380,8 +2482,9 @@ stack_config(struct swm_region *r, union arg *args) if (ws->cur_layout->l_config != NULL) ws->cur_layout->l_config(ws, args->id); - if (args->id != SWM_ARG_ID_STACKINIT); + if (args->id != SWM_ARG_ID_STACKINIT) stack(); + bar_update(); } void @@ -2408,6 +2511,7 @@ stack(void) { g.h -= bar_height; } r->ws->cur_layout->l_stack(r->ws, &g); + r->ws->cur_layout->l_string(r->ws); /* save r so we can track region changes */ r->ws->old_r = r; } @@ -2961,7 +3065,8 @@ send_to_ws(struct swm_region *r, union arg *args) /* Try to update the window's workspace property */ ws_idx_atom = XInternAtom(display, "_SWM_WS", False); if (ws_idx_atom && - snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) { + snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < + SWM_PROPLEN) { DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n", ws_idx_str); XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, @@ -2972,6 +3077,26 @@ send_to_ws(struct swm_region *r, union arg *args) } void +pressbutton(struct swm_region *r, union arg *args) +{ + XTestFakeButtonEvent(display, args->id, True, CurrentTime); + XTestFakeButtonEvent(display, args->id, False, CurrentTime); +} + +void +raise_toggle(struct swm_region *r, union arg *args) +{ + if (r && r->ws == NULL) + return; + + r->ws->always_raise = !r->ws->always_raise; + + /* bring floaters back to top */ + if (r->ws->always_raise == 0) + stack(); +} + +void iconify(struct swm_region *r, union arg *args) { union arg a; @@ -3022,7 +3147,7 @@ uniconify(struct swm_region *r, union arg *args) { struct ws_win *win; FILE *lfile; - char *name; + unsigned char *name; int count = 0; unsigned long len; @@ -3073,7 +3198,8 @@ search_do_resp(void) { ssize_t rbytes; struct ws_win *win; - char *name, *resp, *s; + unsigned char *name; + char *resp, *s; unsigned long len; DNPRINTF(SWM_D_MISC, "search_do_resp:\n"); @@ -3220,14 +3346,20 @@ resize_window(struct ws_win *win, int center) XConfigureWindow(display, win->id, mask, &wc); } +#define SWM_RESIZE_STEPS (50) + void resize(struct ws_win *win, union arg *args) { XEvent ev; Time time = 0; - struct swm_region *r = win->ws->r; + struct swm_region *r = NULL; int relx, rely; + int resize_step = 0; + if (win == NULL) + return; + r = win->ws->r; DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %lu\n", win->id, win->floating, win->transient); @@ -3244,6 +3376,33 @@ resize(struct ws_win *win, union arg *args) _NET_WM_STATE_ADD); stack(); + + switch (args->id) { + case SWM_ARG_ID_WIDTHSHRINK: + win->g.w -= SWM_RESIZE_STEPS; + resize_step = 1; + break; + case SWM_ARG_ID_WIDTHGROW: + win->g.w += SWM_RESIZE_STEPS; + resize_step = 1; + break; + case SWM_ARG_ID_HEIGHTSHRINK: + win->g.h -= SWM_RESIZE_STEPS; + resize_step = 1; + break; + case SWM_ARG_ID_HEIGHTGROW: + win->g.h += SWM_RESIZE_STEPS; + resize_step = 1; + break; + default: + break; + } + if (resize_step) { + resize_window(win, 0); + store_float_geom(win,r); + return; + } + if (focus_mode == SWM_FOCUS_DEFAULT) drain_enter_notify(); @@ -3311,6 +3470,20 @@ resize(struct ws_win *win, union arg *args) } void +resize_step(struct swm_region *r, union arg *args) +{ + struct ws_win *win = NULL; + + if (r && r->ws && r->ws->focus) + win = r->ws->focus; + else + return; + + resize(win, args); +} + + +void move_window(struct ws_win *win) { unsigned int mask; @@ -3330,12 +3503,19 @@ move_window(struct ws_win *win) XConfigureWindow(display, win->id, mask, &wc); } +#define SWM_MOVE_STEPS (50) + void move(struct ws_win *win, union arg *args) { XEvent ev; Time time = 0; - struct swm_region *r = win->ws->r; + int move_step = 0; + struct swm_region *r = NULL; + + if (win == NULL) + return; + r = win->ws->r; DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %lu\n", win->id, win->floating, win->transient); @@ -3354,6 +3534,34 @@ move(struct ws_win *win, union arg *args) stack(); + move_step = 0; + switch (args->id) { + case SWM_ARG_ID_MOVELEFT: + win->g.x -= (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + case SWM_ARG_ID_MOVERIGHT: + win->g.x += (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + case SWM_ARG_ID_MOVEUP: + win->g.y -= (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + case SWM_ARG_ID_MOVEDOWN: + win->g.y += (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + default: + break; + } + if (move_step) { + move_window(win); + store_float_geom(win,r); + return; + } + + if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess) return; @@ -3399,6 +3607,23 @@ move(struct ws_win *win, union arg *args) drain_enter_notify(); } +void +move_step(struct swm_region *r, union arg *args) +{ + struct ws_win *win = NULL; + + if (r && r->ws && r->ws->focus) + win = r->ws->focus; + else + return; + + if (!(win->transient != 0 || win->floating != 0)) + return; + + move(win, args); +} + + /* user/key callable function IDs */ enum keyfuncid { kf_cycle_layout, @@ -3456,6 +3681,16 @@ enum keyfuncid { kf_spawn_custom, kf_iconify, kf_uniconify, + kf_raise_toggle, + kf_button2, + kf_width_shrink, + kf_width_grow, + kf_height_shrink, + kf_height_grow, + kf_move_left, + kf_move_right, + kf_move_up, + kf_move_down, kf_dumpwins, /* MUST BE LAST */ kf_invalid }; @@ -3532,6 +3767,16 @@ struct keyfunc { { "spawn_custom", dummykeyfunc, {0} }, { "iconify", iconify, {0} }, { "uniconify", uniconify, {0} }, + { "raise_toggle", raise_toggle, {0} }, + { "button2", pressbutton, {2} }, + { "width_shrink", resize_step, {.id = SWM_ARG_ID_WIDTHSHRINK} }, + { "width_grow", resize_step, {.id = SWM_ARG_ID_WIDTHGROW} }, + { "height_shrink", resize_step, {.id = SWM_ARG_ID_HEIGHTSHRINK} }, + { "height_grow", resize_step, {.id = SWM_ARG_ID_HEIGHTGROW} }, + { "move_left", move_step, {.id = SWM_ARG_ID_MOVELEFT} }, + { "move_right", move_step, {.id = SWM_ARG_ID_MOVERIGHT} }, + { "move_up", move_step, {.id = SWM_ARG_ID_MOVEUP} }, + { "move_down", move_step, {.id = SWM_ARG_ID_MOVEDOWN} }, { "dumpwins", dumpwins, {0} }, /* MUST BE LAST */ { "invalid key func", NULL, {0} }, }; @@ -3678,7 +3923,7 @@ spawn_custom(struct swm_region *r, union arg *args, char *spawn_name) return; a.argv = real_args; if (fork() == 0) - spawn(r, &a, 1); + spawn(r->ws->idx, &a, 1); for (i = 0; i < spawn_argc; i++) free(real_args[i]); @@ -3714,7 +3959,7 @@ spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid) errx(1, "dup2"); close(select_list_pipe[1]); close(select_resp_pipe[0]); - spawn(r, &a, 0); + spawn(r->ws->idx, &a, 0); break; default: /* parent */ close(select_list_pipe[0]); @@ -3835,8 +4080,9 @@ setconfspawn(char *selector, char *value, int flags) cp += (long)strspn(cp, " \t"); if (strlen(word) > 0) { prog->argc++; - prog->argv = realloc(prog->argv, - prog->argc * sizeof(char *)); + if ((prog->argv = realloc(prog->argv, + prog->argc * sizeof(char *))) == NULL) + err(1, "setconfspawn: realloc"); if ((prog->argv[prog->argc - 1] = strdup(word)) == NULL) err(1, "setconfspawn: strdup"); } @@ -3983,7 +4229,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, keys_size = 4; DNPRINTF(SWM_D_KEY, "setkeybinding: init list %d\n", keys_size); keys = malloc((size_t)keys_size * sizeof(struct key)); - if (!keys) { + if (keys == NULL) { fprintf(stderr, "malloc failed\n"); perror(" failed"); quit(NULL, NULL); @@ -3992,7 +4238,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, keys_size *= 2; DNPRINTF(SWM_D_KEY, "setkeybinding: grow list %d\n", keys_size); keys = realloc(keys, (size_t)keys_size * sizeof(struct key)); - if (!keys) { + if (keys == NULL) { fprintf(stderr, "realloc failed\n"); perror(" failed"); quit(NULL, NULL); @@ -4008,7 +4254,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, keys[j].spawn_name = strdupsafe(spawn_name); } else { fprintf(stderr, "keys array problem?\n"); - if (!keys) { + if (keys == NULL) { fprintf(stderr, "keys array problem\n"); quit(NULL, NULL); } @@ -4080,7 +4326,7 @@ setup_keys(void) setkeybinding(MODKEY|ShiftMask, XK_j, kf_swap_next, NULL); setkeybinding(MODKEY|ShiftMask, XK_k, kf_swap_prev, NULL); setkeybinding(MODKEY|ShiftMask, XK_Return, kf_spawn_term, NULL); - setkeybinding(MODKEY, XK_p, kf_spawn_custom, "menu"); + setkeybinding(MODKEY, XK_p, kf_spawn_custom,"menu"); setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit, NULL); setkeybinding(MODKEY, XK_q, kf_restart, NULL); setkeybinding(MODKEY, XK_m, kf_focus_main, NULL); @@ -4114,14 +4360,24 @@ setup_keys(void) setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev, NULL); setkeybinding(MODKEY|ShiftMask, XK_x, kf_wind_kill, NULL); setkeybinding(MODKEY, XK_x, kf_wind_del, NULL); - setkeybinding(MODKEY, XK_s, kf_spawn_custom, "screenshot_all"); - setkeybinding(MODKEY|ShiftMask, XK_s, kf_spawn_custom, "screenshot_wind"); + setkeybinding(MODKEY, XK_s, kf_spawn_custom,"screenshot_all"); + setkeybinding(MODKEY|ShiftMask, XK_s, kf_spawn_custom,"screenshot_wind"); setkeybinding(MODKEY, XK_t, kf_float_toggle,NULL); setkeybinding(MODKEY|ShiftMask, XK_v, kf_version, NULL); - setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_custom, "lock"); - setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_custom, "initscr"); + setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_custom,"lock"); + setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_custom,"initscr"); setkeybinding(MODKEY, XK_w, kf_iconify, NULL); setkeybinding(MODKEY|ShiftMask, XK_w, kf_uniconify, NULL); + setkeybinding(MODKEY|ShiftMask, XK_r, kf_raise_toggle,NULL); + setkeybinding(MODKEY, XK_v, kf_button2, NULL); + setkeybinding(MODKEY, XK_equal, kf_width_grow, NULL); + setkeybinding(MODKEY, XK_minus, kf_width_shrink,NULL); + setkeybinding(MODKEY|ShiftMask, XK_equal, kf_height_grow, NULL); + setkeybinding(MODKEY|ShiftMask, XK_minus, kf_height_shrink,NULL); + setkeybinding(MODKEY, XK_bracketleft, kf_move_left, NULL); + setkeybinding(MODKEY, XK_bracketright,kf_move_right, NULL); + setkeybinding(MODKEY|ShiftMask, XK_bracketleft, kf_move_up, NULL); + setkeybinding(MODKEY|ShiftMask, XK_bracketright,kf_move_down, NULL); #ifdef SWM_DEBUG setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL); #endif @@ -4286,7 +4542,7 @@ setquirk(const char *class, const char *name, const int quirk) quirks_size = 4; DNPRINTF(SWM_D_QUIRK, "setquirk: init list %d\n", quirks_size); quirks = malloc((size_t)quirks_size * sizeof(struct quirk)); - if (!quirks) { + if (quirks == NULL) { fprintf(stderr, "setquirk: malloc failed\n"); perror(" failed"); quit(NULL, NULL); @@ -4296,7 +4552,7 @@ setquirk(const char *class, const char *name, const int quirk) DNPRINTF(SWM_D_QUIRK, "setquirk: grow list %d\n", quirks_size); quirks = realloc(quirks, (size_t)quirks_size * sizeof(struct quirk)); - if (!quirks) { + if (quirks == NULL) { fprintf(stderr, "setquirk: realloc failed\n"); perror(" failed"); quit(NULL, NULL); @@ -4310,7 +4566,7 @@ setquirk(const char *class, const char *name, const int quirk) quirks[j].quirk = quirk; } else { fprintf(stderr, "quirks array problem?\n"); - if (!quirks) { + if (quirks == NULL) { fprintf(stderr, "quirks array problem!\n"); quit(NULL, NULL); } @@ -4360,15 +4616,17 @@ enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH, SWM_S_STACK_ENABLED, SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT, SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED, SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED, - SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED, + SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED, SWM_S_URGENT_ENABLED, SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH, SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, - SWM_S_SS_APP, SWM_S_DIALOG_RATIO, SWM_S_BAR_AT_BOTTOM + SWM_S_SS_APP, SWM_S_DIALOG_RATIO, SWM_S_BAR_AT_BOTTOM, + SWM_S_VERBOSE_LAYOUT }; int setconfvalue(char *selector, char *value, int flags) { + int i; switch (flags) { case SWM_S_BAR_DELAY: bar_delay = atoi(value); @@ -4416,6 +4674,9 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_TITLE_NAME_ENABLED: title_name_enabled = atoi(value); break; + case SWM_S_URGENT_ENABLED: + urgent_enabled = atoi(value); + break; case SWM_S_FOCUS_MODE: if (!strcmp(value, "default")) focus_mode = SWM_FOCUS_DEFAULT; @@ -4454,6 +4715,15 @@ setconfvalue(char *selector, char *value, int flags) if (dialog_ratio > 1.0 || dialog_ratio <= .3) dialog_ratio = .6; break; + case SWM_S_VERBOSE_LAYOUT: + verbose_layout = atoi(value); + for (i = 0; layouts[i].l_stack != NULL; i++) { + if (verbose_layout) + layouts[i].l_string = fancy_stacker; + else + layouts[i].l_string = plain_stacker; + } + break; default: return (1); } @@ -4490,17 +4760,148 @@ setconfregion(char *selector, char *value, int flags) return (0); } +int +setautorun(char *selector, char *value, int flags) +{ + int ws_id; + char s[1024]; + char *ap, *sp = s; + union arg a; + int argc = 0; + long pid; + struct pid_e *p; + + if (getenv("SWM_STARTED")) + return (0); + + bzero(s, sizeof s); + if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2) + errx(1, "invalid autorun entry, should be 'ws[]:command'\n"); + ws_id--; + if (ws_id < 0 || ws_id >= SWM_WS_MAX) + errx(1, "autorun: invalid workspace %d\n", ws_id + 1); + + /* + * This is a little intricate + * + * If the pid already exists we simply reuse it because it means it was + * used before AND not claimed by manage_window. We get away with + * altering it in the parent after INSERT because this can not be a race + */ + a.argv = NULL; + while ((ap = strsep(&sp, " \t")) != NULL) { + if (*ap == '\0') + continue; + DNPRINTF(SWM_D_SPAWN, "setautorun: arg [%s]\n", ap); + argc++; + if ((a.argv = realloc(a.argv, argc * sizeof(char *))) == NULL) + err(1, "setautorun: realloc"); + a.argv[argc - 1] = ap; + } + + if ((a.argv = realloc(a.argv, (argc + 1) * sizeof(char *))) == NULL) + err(1, "setautorun: realloc"); + a.argv[argc] = NULL; + + if ((pid = fork()) == 0) { + spawn(ws_id, &a, 1); + /* NOTREACHED */ + _exit(1); + } + free(a.argv); + + /* parent */ + p = find_pid(pid); + if (p == NULL) { + p = calloc(1, sizeof *p); + if (p == NULL) + return (1); + TAILQ_INSERT_TAIL(&pidlist, p, entry); + } + + p->pid = pid; + p->ws = ws_id; + + return (0); +} + +int +setlayout(char *selector, char *value, int flags) +{ + int ws_id, i, x, mg, ma, si, raise; + int st = SWM_V_STACK; + char s[1024]; + struct workspace *ws; + + if (getenv("SWM_STARTED")) + return (0); + + bzero(s, sizeof s); + if (sscanf(value, "ws[%d]:%d:%d:%d:%d:%1023c", + &ws_id, &mg, &ma, &si, &raise, s) != 6) + errx(1, "invalid layout entry, should be 'ws[]:" + "::::" + "'\n"); + ws_id--; + if (ws_id < 0 || ws_id >= SWM_WS_MAX) + errx(1, "layout: invalid workspace %d\n", ws_id + 1); + + if (!strcasecmp(s, "vertical")) + st = SWM_V_STACK; + else if (!strcasecmp(s, "horizontal")) + st = SWM_H_STACK; + else if (!strcasecmp(s, "fullscreen")) + st = SWM_MAX_STACK; + else + errx(1, "invalid layout entry, should be 'ws[]:" + "::::" + "'\n"); + + for (i = 0; i < ScreenCount(display); i++) { + ws = (struct workspace *)&screens[i].ws; + ws[ws_id].cur_layout = &layouts[st]; + + ws[ws_id].always_raise = raise; + if (st == SWM_MAX_STACK) + continue; + + /* master grow */ + for (x = 0; x < abs(mg); x++) { + ws[ws_id].cur_layout->l_config(&ws[ws_id], + mg >= 0 ? SWM_ARG_ID_MASTERGROW : + SWM_ARG_ID_MASTERSHRINK); + stack(); + } + /* master add */ + for (x = 0; x < abs(ma); x++) { + ws[ws_id].cur_layout->l_config(&ws[ws_id], + ma >= 0 ? SWM_ARG_ID_MASTERADD : + SWM_ARG_ID_MASTERDEL); + stack(); + } + /* stack inc */ + for (x = 0; x < abs(si); x++) { + ws[ws_id].cur_layout->l_config(&ws[ws_id], + si >= 0 ? SWM_ARG_ID_STACKINC : + SWM_ARG_ID_STACKDEC); + stack(); + } + } + + return (0); +} + /* config options */ struct config_option { char *optname; - int (*func)(char*, char*, int); - int funcflags; + int (*func)(char*, char*, int); + int funcflags; }; struct config_option configopt[] = { { "bar_enabled", setconfvalue, SWM_S_BAR_ENABLED }, { "bar_at_bottom", setconfvalue, SWM_S_BAR_AT_BOTTOM }, { "bar_border", setconfcolor, SWM_S_COLOR_BAR_BORDER }, - { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH }, + { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH }, { "bar_color", setconfcolor, SWM_S_COLOR_BAR }, { "bar_font_color", setconfcolor, SWM_S_COLOR_BAR_FONT }, { "bar_font", setconfvalue, SWM_S_BAR_FONT }, @@ -4515,6 +4916,7 @@ struct config_option configopt[] = { { "cycle_empty", setconfvalue, SWM_S_CYCLE_EMPTY }, { "cycle_visible", setconfvalue, SWM_S_CYCLE_VISIBLE }, { "dialog_ratio", setconfvalue, SWM_S_DIALOG_RATIO }, + { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, { "modkey", setconfmodkey, 0 }, { "program", setconfspawn, 0 }, { "quirk", setconfquirk, 0 }, @@ -4523,12 +4925,15 @@ struct config_option configopt[] = { { "screenshot_enabled", setconfvalue, SWM_S_SS_ENABLED }, { "screenshot_app", setconfvalue, SWM_S_SS_APP }, { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, + { "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED }, { "term_width", setconfvalue, SWM_S_TERM_WIDTH }, { "title_class_enabled", setconfvalue, SWM_S_TITLE_CLASS_ENABLED }, { "title_name_enabled", setconfvalue, SWM_S_TITLE_NAME_ENABLED }, - { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, - { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER }, - { "border_width", setconfvalue, SWM_S_BORDER_WIDTH }, + { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, + { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER }, + { "border_width", setconfvalue, SWM_S_BORDER_WIDTH }, + { "autorun", setautorun, 0 }, + { "layout", setlayout, 0 }, }; @@ -4677,6 +5082,52 @@ set_child_transient(struct ws_win *win, Window *trans) XFree(wmh); } +long +window_get_pid(Window win) +{ + Atom actual_type_return; + int actual_format_return = 0; + unsigned long nitems_return = 0; + unsigned long bytes_after_return = 0; + long *pid = NULL; + long ret = 0; + const char *errstr; + unsigned char *prop = NULL; + + if (XGetWindowProperty(display, win, + XInternAtom(display, "_NET_WM_PID", False), 0, 1, False, + XA_CARDINAL, &actual_type_return, &actual_format_return, + &nitems_return, &bytes_after_return, + (unsigned char**)(void*)&pid) != Success) + goto tryharder; + if (actual_type_return != XA_CARDINAL) + goto tryharder; + if (pid == NULL) + goto tryharder; + + ret = *pid; + XFree(pid); + + return (ret); + +tryharder: + if (XGetWindowProperty(display, win, + XInternAtom(display, "_SWM_PID", False), 0, SWM_PROPLEN, False, + XA_STRING, &actual_type_return, &actual_format_return, + &nitems_return, &bytes_after_return, &prop) != Success) + return (0); + if (actual_type_return != XA_STRING) + return (0); + if (prop == NULL) + return (0); + + ret = strtonum((const char *)prop, 0, UINT_MAX, &errstr); + /* ignore error because strtonum returns 0 anyway */ + XFree(prop); + + return (ret); +} + struct ws_win * manage_window(Window id) { @@ -4692,6 +5143,7 @@ manage_window(Window id) long mask; const char *errstr; XWindowChanges wc; + struct pid_e *p; if ((win = find_window(id)) != NULL) return (win); /* already being managed */ @@ -4716,11 +5168,15 @@ manage_window(Window id) win->id = id; + /* see if we need to override the workspace */ + p = find_pid(window_get_pid(id)); + /* Get all the window data in one shot */ ws_idx_atom = XInternAtom(display, "_SWM_WS", False); - if (ws_idx_atom) + if (ws_idx_atom) { XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN, False, XA_STRING, &type, &format, &nitems, &bytes, &prop); + } XGetWindowAttributes(display, id, &win->wa); XGetWMNormalHints(display, id, &win->sh, &mask); win->hints = XGetWMHints(display, id); @@ -4752,9 +5208,14 @@ manage_window(Window id) * transient, * put it in the same workspace */ r = root_to_region(win->wa.root); - if (prop && win->transient == 0) { + if (p) { + ws = &r->s->ws[p->ws]; + TAILQ_REMOVE(&pidlist, p, entry); + free(p); + p = NULL; + } else if (prop && win->transient == 0) { DNPRINTF(SWM_D_PROP, "got property _SWM_WS=%s\n", prop); - ws_idx = strtonum(prop, 0, 9, &errstr); + ws_idx = strtonum((const char *)prop, 0, 9, &errstr); if (errstr) { DNPRINTF(SWM_D_EVENT, "window idx is %s: %s", errstr, prop); @@ -4795,7 +5256,8 @@ manage_window(Window id) /* Set window properties so we can remember this after reincarnation */ if (ws_idx_atom && prop == NULL && - snprintf(ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < SWM_PROPLEN) { + snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < + SWM_PROPLEN) { DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n", ws_idx_str); XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, @@ -5007,7 +5469,6 @@ buttonpress(XEvent *e) DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window); - action = root_click; if ((win = find_window(ev->window)) == NULL) return; @@ -5701,14 +6162,11 @@ setup_screens(void) int i, j, k; int errorbase, major, minor; struct workspace *ws; - int ws_idx_atom; if ((screens = calloc(ScreenCount(display), sizeof(struct swm_screen))) == NULL) errx(1, "calloc: screens"); - ws_idx_atom = XInternAtom(display, "_SWM_WS", False); - /* initial Xrandr setup */ xrandr_support = XRRQueryExtension(display, &xrandr_eventbase, &errorbase); @@ -5751,6 +6209,7 @@ setup_screens(void) layouts[k].l_config(ws, SWM_ARG_ID_STACKINIT); ws->cur_layout = &layouts[0]; + ws->cur_layout->l_string(ws); } scan_xrandr(i); @@ -5884,10 +6343,12 @@ main(int argc, char *argv[]) setup_ewmh(); /* set some values to work around bad programs */ workaround(); - /* grab existing windows (before we build the bars) */ grab_windows(); + if (getenv("SWM_STARTED") == NULL) + setenv("SWM_STARTED", "YES", 1); + /* setup all bars */ for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) {