X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=01cbd3825c686fc70de96af660453870ed2d806b;hb=8027864cf5decd4ca9f26c92bc741c3db45cec45;hp=9dadbee842f7fad0450135225ebc2d4001856360;hpb=5cd855abc35e620a2bfaa4a6dac9787bcaa411aa;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 9dadbee..01cbd38 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -52,7 +52,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.9.25" +#define SWM_VERSION "0.9.29" #include #include @@ -66,6 +66,7 @@ static const char *cvstag = "$scrotwm$"; #include #include #include +#include #include #include @@ -197,6 +198,8 @@ int bar_version = 0; sig_atomic_t bar_alarm = 0; int bar_delay = 30; int bar_enabled = 1; +int bar_border_width = 1; +int bar_at_bottom = 0; int bar_extra = 1; int bar_extra_running = 0; int bar_verbose = 1; @@ -206,8 +209,10 @@ int clock_enabled = 1; char *clock_format = NULL; int title_name_enabled = 0; int title_class_enabled = 0; +int window_name_enabled = 0; int focus_mode = SWM_FOCUS_DEFAULT; int disable_border = 0; +int border_width = 1; pid_t bar_pid; GC bar_gc; XGCValues bar_gcv; @@ -256,6 +261,7 @@ struct ws_win { int floatmaxed; /* flag: floater was maxed in max_stack */ int floating; int manual; + unsigned int ewmh_flags; int font_size_boundary[SWM_MAX_FONT_STEPS]; int font_steps; int last_inc; @@ -401,6 +407,335 @@ struct quirk { int quirks_size = 0, quirks_length = 0; struct quirk *quirks = NULL; +/* + * Supported EWMH hints should be added to + * both the enum and the ewmh array + */ +enum { _NET_ACTIVE_WINDOW, _NET_MOVERESIZE_WINDOW, _NET_CLOSE_WINDOW, + _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DOCK, + _NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_UTILITY, + _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_DIALOG, + _NET_WM_WINDOW_TYPE_NORMAL, _NET_WM_STATE, + _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT, + _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_SKIP_PAGER, + _NET_WM_STATE_HIDDEN, _NET_WM_STATE_ABOVE, _SWM_WM_STATE_MANUAL, + _NET_WM_STATE_FULLSCREEN, _NET_WM_ALLOWED_ACTIONS, _NET_WM_ACTION_MOVE, + _NET_WM_ACTION_RESIZE, _NET_WM_ACTION_FULLSCREEN, _NET_WM_ACTION_CLOSE, + SWM_EWMH_HINT_MAX }; + +struct ewmh_hint { + char *name; + Atom atom; +} ewmh[SWM_EWMH_HINT_MAX] = { + /* must be in same order as in the enum */ + {"_NET_ACTIVE_WINDOW", None}, + {"_NET_MOVERESIZE_WINDOW", None}, + {"_NET_CLOSE_WINDOW", None}, + {"_NET_WM_WINDOW_TYPE", None}, + {"_NET_WM_WINDOW_TYPE_DOCK", None}, + {"_NET_WM_WINDOW_TYPE_TOOLBAR", None}, + {"_NET_WM_WINDOW_TYPE_UTILITY", None}, + {"_NET_WM_WINDOW_TYPE_SPLASH", None}, + {"_NET_WM_WINDOW_TYPE_DIALOG", None}, + {"_NET_WM_WINDOW_TYPE_NORMAL", None}, + {"_NET_WM_STATE", None}, + {"_NET_WM_STATE_MAXIMIZED_HORZ", None}, + {"_NET_WM_STATE_MAXIMIZED_VERT", None}, + {"_NET_WM_STATE_SKIP_TASKBAR", None}, + {"_NET_WM_STATE_SKIP_PAGER", None}, + {"_NET_WM_STATE_HIDDEN", None}, + {"_NET_WM_STATE_ABOVE", None}, + {"_SWM_WM_STATE_MANUAL", None}, + {"_NET_WM_STATE_FULLSCREEN", None}, + {"_NET_WM_ALLOWED_ACTIONS", None}, + {"_NET_WM_ACTION_MOVE", None}, + {"_NET_WM_ACTION_RESIZE", None}, + {"_NET_WM_ACTION_FULLSCREEN", None}, + {"_NET_WM_ACTION_CLOSE", None}, +}; + +void store_float_geom(struct ws_win *win, struct swm_region *r); +int floating_toggle_win(struct ws_win *win); + +int +get_property(Window id, Atom atom, long count, Atom type, + unsigned long *n, unsigned char **data) +{ + int format, status; + unsigned long tmp, extra; + unsigned long *nitems; + Atom real; + + nitems = n != NULL ? n : &tmp; + status = XGetWindowProperty(display, id, atom, 0L, count, False, type, + &real, &format, nitems, &extra, data); + + if (status != Success) + return False; + if (real != type) + return False; + + return True; +} + +void +setup_ewmh(void) +{ + int i,j; + Atom sup_list; + + sup_list = XInternAtom(display, "_NET_SUPPORTED", False); + + for (i = 0; i < LENGTH(ewmh); i++) + ewmh[i].atom = XInternAtom(display, ewmh[i].name, False); + + for (i = 0; i < ScreenCount(display); i++) { + /* Support check window will be created by workaround(). */ + + /* Report supported atoms */ + XDeleteProperty(display, screens[i].root, sup_list); + for (j = 0; j < LENGTH(ewmh); j++) + XChangeProperty(display, screens[i].root, sup_list, XA_ATOM, 32, + PropModeAppend, (unsigned char *)&ewmh[j].atom,1); + } +} + +void +teardown_ewmh(void) +{ + int i, success; + unsigned char *data = NULL; + unsigned long n; + Atom sup_check, sup_list; + Window id; + + sup_check = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); + sup_list = XInternAtom(display, "_NET_SUPPORTED", False); + + for (i = 0; i < ScreenCount(display); i++) { + /* Get the support check window and destroy it */ + success = get_property(screens[i].root, sup_check, 1, XA_WINDOW, + &n, &data); + + if (success) { + id = data[0]; + XDestroyWindow(display, id); + XDeleteProperty(display, screens[i].root, sup_check); + XDeleteProperty(display, screens[i].root, sup_list); + } + + XFree(data); + } +} + +void +ewmh_autoquirk(struct ws_win *win) +{ + int success, i; + unsigned long *data = NULL; + unsigned long n; + Atom type; + + success = get_property(win->id, ewmh[_NET_WM_WINDOW_TYPE].atom, (~0L), + XA_ATOM, &n, (unsigned char **)&data); + + if (!success) { + XFree(data); + return; + } + + for (i = 0; i < n; i++) { + type = data[i]; + if (type == ewmh[_NET_WM_WINDOW_TYPE_NORMAL].atom) + break; + if (type == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom || + type == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom || + type == ewmh[_NET_WM_WINDOW_TYPE_UTILITY].atom) { + win->floating = 1; + win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE; + break; + } + if (type == ewmh[_NET_WM_WINDOW_TYPE_SPLASH].atom || + type == ewmh[_NET_WM_WINDOW_TYPE_DIALOG].atom) { + win->floating = 1; + win->quirks = SWM_Q_FLOAT; + break; + } + } + + XFree(data); +} + +#define SWM_EWMH_ACTION_COUNT_MAX (6) +#define EWMH_F_FULLSCREEN (1<<0) +#define EWMH_F_ABOVE (1<<1) +#define EWMH_F_HIDDEN (1<<2) +#define EWMH_F_SKIP_PAGER (1<<3) +#define EWMH_F_SKIP_TASKBAR (1<<4) +#define SWM_F_MANUAL (1<<5) + +int +ewmh_set_win_fullscreen(struct ws_win *win, int fs) +{ + struct swm_geometry rg; + + if (!win->ws->r) + return 0; + + if (!win->floating) + return 0; + + DNPRINTF(SWM_D_MISC, "ewmh_set_win_fullscreen: win 0x%lx fs: %d\n", + win->id, fs); + + rg = win->ws->r->g; + + if (fs) { + store_float_geom(win, win->ws->r); + + win->g.x = rg.x; + win->g.y = rg.y; + win->g.w = rg.w; + win->g.h = rg.h; + } else { + if (win->g_floatvalid) { + /* refloat at last floating relative position */ + win->g.x = win->g_float.x - win->rg_float.x + rg.x; + win->g.y = win->g_float.y - win->rg_float.y + rg.y; + win->g.w = win->g_float.w; + win->g.h = win->g_float.h; + } + } + + return 1; +} + +void +ewmh_update_actions(struct ws_win *win) +{ + Atom actions[SWM_EWMH_ACTION_COUNT_MAX]; + int n = 0; + + if (win == NULL) + return; + + actions[n++] = ewmh[_NET_WM_ACTION_CLOSE].atom; + + if (win->floating) { + actions[n++] = ewmh[_NET_WM_ACTION_MOVE].atom; + actions[n++] = ewmh[_NET_WM_ACTION_RESIZE].atom; + } + + XChangeProperty(display, win->id, ewmh[_NET_WM_ALLOWED_ACTIONS].atom, + XA_ATOM, 32, PropModeReplace, (unsigned char *)actions, n); +} + +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + +void +ewmh_update_win_state(struct ws_win *win, long state, long action) +{ + unsigned int mask = 0; + unsigned int changed = 0; + unsigned int orig_flags; + + if (win == NULL) + return; + + if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) + mask = EWMH_F_FULLSCREEN; + if (state == ewmh[_NET_WM_STATE_ABOVE].atom) + mask = EWMH_F_ABOVE; + if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) + mask = SWM_F_MANUAL; + if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom) + mask = EWMH_F_SKIP_PAGER; + if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom) + mask = EWMH_F_SKIP_TASKBAR; + + + orig_flags = win->ewmh_flags; + + switch (action) { + case _NET_WM_STATE_REMOVE: + win->ewmh_flags &= ~mask; + break; + case _NET_WM_STATE_ADD: + win->ewmh_flags |= mask; + break; + case _NET_WM_STATE_TOGGLE: + win->ewmh_flags ^= mask; + break; + } + + changed = (win->ewmh_flags & mask) ^ (orig_flags & mask) ? 1 : 0; + + if (state == ewmh[_NET_WM_STATE_ABOVE].atom) + if (changed) + if (!floating_toggle_win(win)) + win->ewmh_flags = orig_flags; /* revert */ + if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) + if (changed) + win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0; + if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) + if (changed) + if (!ewmh_set_win_fullscreen(win, win->ewmh_flags & EWMH_F_FULLSCREEN)) + win->ewmh_flags = orig_flags; /* revert */ + + XDeleteProperty(display, win->id, ewmh[_NET_WM_STATE].atom); + + if (win->ewmh_flags & EWMH_F_FULLSCREEN) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_FULLSCREEN].atom, 1); + if (win->ewmh_flags & EWMH_F_SKIP_PAGER) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_PAGER].atom, 1); + if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom, 1); + if (win->ewmh_flags & EWMH_F_ABOVE) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_ABOVE].atom, 1); + if (win->ewmh_flags & SWM_F_MANUAL) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_SWM_WM_STATE_MANUAL].atom, 1); +} + +void +ewmh_get_win_state(struct ws_win *win) +{ + int success, i; + unsigned long n; + Atom *states; + + if (win == NULL) + return; + + win->ewmh_flags = 0; + if (win->floating) + win->ewmh_flags |= EWMH_F_ABOVE; + if (win->manual) + win->ewmh_flags |= SWM_F_MANUAL; + + success = get_property(win->id, ewmh[_NET_WM_STATE].atom, (~0L), XA_ATOM, + &n, (unsigned char **)&states); + + if (!success) + return; + + for (i = 0; i < n; i++) + ewmh_update_win_state(win, states[i], _NET_WM_STATE_ADD); + + XFree(states); +} + /* events */ #ifdef SWM_DEBUG void @@ -577,6 +912,7 @@ void maprequest(XEvent *); void propertynotify(XEvent *); void unmapnotify(XEvent *); void visibilitynotify(XEvent *); +void clientmessage(XEvent *); void (*handler[LASTEvent])(XEvent *) = { [Expose] = expose, @@ -594,6 +930,7 @@ void (*handler[LASTEvent])(XEvent *) = { [PropertyNotify] = propertynotify, [UnmapNotify] = unmapnotify, [VisibilityNotify] = visibilitynotify, + [ClientMessage] = clientmessage, }; void @@ -706,10 +1043,12 @@ custom_region(char *val) if (x < 0 || x > DisplayWidth(display, sidx) || y < 0 || y > DisplayHeight(display, sidx) || w + x > DisplayWidth(display, sidx) || - h + y > DisplayHeight(display, sidx)) - errx(1, "region %ux%u+%u+%u not within screen boundaries " + h + y > DisplayHeight(display, sidx)) { + fprintf(stderr, "ignoring region %ux%u+%u+%u - not within screen boundaries " "(%ux%u)\n", w, h, x, y, DisplayWidth(display, sidx), DisplayHeight(display, sidx)); + return; + } new_region(&screens[sidx], x, y, w, h); } @@ -780,6 +1119,23 @@ out: } void +bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus) +{ + char *title; + + if (window_name_enabled && cur_focus != NULL) { + XFetchName(display, cur_focus->id, &title); + if (title) { + if (cur_focus->floating) + strlcat(s, "(f) ", sz); + strlcat(s, title, sz); + strlcat(s, " ", sz); + XFree(title); + } + } +} + +void bar_update(void) { time_t tmt; @@ -823,8 +1179,10 @@ bar_update(void) x = 1; TAILQ_FOREACH(r, &screens[i].rl, entry) { strlcpy(cn, "", sizeof cn); - if (r && r->ws) + if (r && r->ws) { 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; @@ -920,7 +1278,7 @@ bar_refresh(void) void bar_setup(struct swm_region *r) { - int i; + int i, x, y; if (bar_fs) { XFreeFont(display, bar_fs); @@ -939,11 +1297,13 @@ bar_setup(struct swm_region *r) if (bar_fs == NULL) errx(1, "couldn't create font structure"); - bar_height = bar_fs->ascent + bar_fs->descent + 3; + bar_height = bar_fs->ascent + bar_fs->descent + 1 + 2 * bar_border_width; + x = X(r); + y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r); r->bar_window = XCreateSimpleWindow(display, - r->s->root, X(r), Y(r), WIDTH(r) - 2, bar_height - 2, - 1, r->s->c[SWM_S_COLOR_BAR_BORDER].color, + r->s->root, x, y, WIDTH(r) - 2 * bar_border_width, bar_height - 2 * bar_border_width, + bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color, r->s->c[SWM_S_COLOR_BAR].color); bar_gc = XCreateGC(display, r->bar_window, 0, &bar_gcv); XSetFont(display, bar_gc, bar_fs->fid); @@ -974,15 +1334,11 @@ set_win_state(struct ws_win *win, long state) long getstate(Window w) { - int format, status; long result = -1; unsigned char *p = NULL; - unsigned long n, extra; - Atom real; + unsigned long n; - status = XGetWindowProperty(display, w, astate, 0L, 2L, False, astate, - &real, &format, &n, &extra, (unsigned char **)&p); - if (status != Success) + if (!get_property(w, astate, 2L, astate, &n, &p)) return (-1); if (n != 0) result = *((long *)p); @@ -1037,7 +1393,7 @@ configreq_win(struct ws_win *win) cr.y = win->g.y; cr.width = win->g.w; cr.height = win->g.h; - cr.border_width = 1; + cr.border_width = border_width; XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&cr); } @@ -1061,7 +1417,7 @@ config_win(struct ws_win *win) ce.y = win->g.y; ce.width = win->g.w; ce.height = win->g.h; - ce.border_width = 1; /* XXX store this! */ + ce.border_width = border_width; /* XXX store this! */ ce.above = None; ce.override_redirect = False; XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&ce); @@ -1105,9 +1461,8 @@ unmap_window(struct ws_win *win) set_win_state(win, IconicState); XUnmapWindow(display, win->id); - if (win->ws->r) - XSetWindowBorder(display, win->id, - win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); + XSetWindowBorder(display, win->id, + win->s->c[SWM_S_COLOR_UNFOCUS].color); } void @@ -1220,7 +1575,8 @@ find_window(Window id) { struct ws_win *win; Window wrr, wpr, *wcr = NULL; - int i, j, nc; + int i, j; + unsigned int nc; for (i = 0; i < ScreenCount(display); i++) for (j = 0; j < SWM_WS_MAX; j++) @@ -1251,39 +1607,56 @@ find_window(Window id) void spawn(struct swm_region *r, union arg *args) { - char *ret; - int si; + int fd; + char *ret = NULL; DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]); - /* - * The double-fork construct avoids zombie processes and keeps the code - * clean from stupid signal handlers. - */ + if (fork() == 0) { - if (fork() == 0) { - if (display) - close(ConnectionNumber(display)); - setenv("LD_PRELOAD", SWM_LIB, 1); - if (asprintf(&ret, "%d", r->ws->idx)) { - setenv("_SWM_WS", ret, 1); - free(ret); - } - if (asprintf(&ret, "%d", getpid())) { - setenv("_SWM_PID", ret, 1); - free(ret); - } - setsid(); - /* kill stdin, mplayer, ssh-add etc. need that */ - si = open("/dev/null", O_RDONLY, 0); - if (si == -1) - err(1, "open /dev/null"); - if (dup2(si, 0) == -1) - err(1, "dup2 /dev/null"); - execvp(args->argv[0], args->argv); - fprintf(stderr, "execvp failed\n"); - perror(" failed"); + if (display) + close(ConnectionNumber(display)); + + setenv("LD_PRELOAD", SWM_LIB, 1); + + if (asprintf(&ret, "%d", r->ws->idx) == -1) { + perror("_SWM_WS"); + _exit(1); + } + setenv("_SWM_WS", ret, 1); + free(ret); + ret = NULL; + + if (asprintf(&ret, "%d", getpid()) == -1) { + perror("_SWM_PID"); + _exit(1); + } + setenv("_SWM_PID", ret, 1); + free(ret); + ret = NULL; + + if (setsid() == -1) { + perror("setsid"); + _exit(1); } - exit(0); + + /* + * close stdin and stdout to prevent interaction between apps + * and the baraction script + * leave stderr open to record errors + */ + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) { + perror("open"); + _exit(1); + } + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + if (fd > 2) + close(fd); + + execvp(args->argv[0], args->argv); + + perror("execvp"); + _exit(1); } } @@ -1362,6 +1735,7 @@ void unfocus_win(struct ws_win *win) { XEvent cne; + Window none = None; DNPRINTF(SWM_D_FOCUS, "unfocus_win: id: %lu\n", WINID(win)); @@ -1371,7 +1745,7 @@ unfocus_win(struct ws_win *win) return; if (validate_ws(win->ws)) - abort(); + return; /* XXX this gets hit with thunderbird, needs fixing */ if (win->ws->r == NULL) return; @@ -1403,6 +1777,9 @@ unfocus_win(struct ws_win *win) XSetWindowBorder(display, win->id, win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); + XChangeProperty(display, win->s->root, + ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&none,1); } void @@ -1436,7 +1813,8 @@ focus_win(struct ws_win *win) return; if (validate_ws(win->ws)) - abort(); + return; /* XXX this gets hit with thunderbird, needs fixing */ + if (validate_win(win)) { kill_refs(win); return; @@ -1466,7 +1844,14 @@ focus_win(struct ws_win *win) win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS) XMapRaised(display, win->id); + + XChangeProperty(display, win->s->root, + ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&win->id,1); } + + if (window_name_enabled) + bar_update(); } void @@ -1562,14 +1947,14 @@ void priorws(struct swm_region *r, union arg *args) { union arg a; - + DNPRINTF(SWM_D_WS, "priorws id %d " "in screen[%d]:%dx%d+%d+%d ws %d\n", args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); - + if (r->ws_prior == NULL) return; - + a.id = r->ws_prior->idx; switchws(r, &a); } @@ -1722,10 +2107,10 @@ focus_prev(struct ws_win *win) /* if in max_stack try harder */ if (ws->cur_layout->flags & SWM_L_FOCUSPREV) { - if (cur_focus != ws->focus_prev) - winfocus = ws->focus_prev; - else if (cur_focus != ws->focus) - winfocus = ws->focus; + if (cur_focus != ws->focus_prev) + winfocus = ws->focus_prev; + else if (cur_focus != ws->focus) + winfocus = ws->focus; else winfocus = TAILQ_PREV(win, ws_win_list, entry); if (winfocus) @@ -1779,7 +2164,7 @@ focus(struct swm_region *r, union arg *args) winlostfocus = cur_focus; switch (args->id) { - case SWM_ARG_ID_FOCUSPREV: + case SWM_ARG_ID_FOCUSPREV: winfocus = TAILQ_PREV(cur_focus, ws_win_list, entry); if (winfocus == NULL) winfocus = TAILQ_LAST(wl, ws_win_list); @@ -1859,10 +2244,11 @@ stack(void) { /* start with screen geometry, adjust for bar */ g = r->g; - g.w -= 2; - g.h -= 2; + g.w -= 2 * border_width; + g.h -= 2 * border_width; if (bar_enabled) { - g.y += bar_height; + if (!bar_at_bottom) + g.y += bar_height; g.h -= bar_height; } r->ws->cur_layout->l_stack(r->ws, &g); @@ -1906,7 +2292,8 @@ stack_floater(struct ws_win *win, struct swm_region *r) * geom on ws switches or return from max mode */ - if (win->floatmaxed || (r != r->ws->old_r && win->g_floatvalid) ) { + if (win->floatmaxed || (r != r->ws->old_r && win->g_floatvalid + && !(win->ewmh_flags & EWMH_F_FULLSCREEN))) { /* * use stored g and rg to set relative position and size * as in old region or before max stack mode @@ -1924,7 +2311,7 @@ stack_floater(struct ws_win *win, struct swm_region *r) (win->g.h >= HEIGHT(r))) wc.border_width = 0; else - wc.border_width = 1; + wc.border_width = border_width; if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) { win->g.w = (double)WIDTH(r) * dialog_ratio; win->g.h = (double)HEIGHT(r) * dialog_ratio; @@ -1935,22 +2322,22 @@ stack_floater(struct ws_win *win, struct swm_region *r) * floaters and transients are auto-centred unless moved * or resized */ - win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2; - win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2; + win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2 - border_width; + win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2 - border_width; } /* win can be outside r if new r smaller than old r */ /* Ensure top left corner inside r (move probs otherwise) */ - if (win->g.x < r->g.x ) - win->g.x = r->g.x; + if (win->g.x < r->g.x - border_width) + win->g.x = r->g.x - border_width; if (win->g.x > r->g.x + r->g.w - 1) win->g.x = (win->g.w > r->g.w) ? r->g.x : - (r->g.x + r->g.w - win->g.w - 2); - if (win->g.y < r->g.y ) - win->g.y = r->g.y; + (r->g.x + r->g.w - win->g.w - 2 * border_width); + if (win->g.y < r->g.y - border_width) + win->g.y = r->g.y - border_width; if (win->g.y > r->g.y + r->g.h - 1) win->g.y = (win->g.h > r->g.h) ? r->g.y : - (r->g.y + r->g.h - win->g.h - 2); + (r->g.y + r->g.h - win->g.h - 2 * border_width); wc.x = win->g.x; wc.y = win->g.y; @@ -1961,7 +2348,8 @@ stack_floater(struct ws_win *win, struct swm_region *r) * Retain floater and transient geometry for correct positioning * when ws changes region */ - store_float_geom(win, r); + if (!(win->ewmh_flags & EWMH_F_FULLSCREEN)) + store_float_geom(win, r); DNPRINTF(SWM_D_MISC, "stack_floater: win %lu x %d y %d w %d h %d\n", win->id, wc.x, wc.y, wc.width, wc.height); @@ -2010,7 +2398,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) XWindowChanges wc; XWindowAttributes wa; struct swm_geometry win_g, r_g = *g; - struct ws_win *win; + struct ws_win *win, *fs_win = 0; int i, j, s, stacks; int w_inc = 1, h_inc, w_base = 1, h_base; int hrh, extra = 0, h_slice, last_h = 0; @@ -2075,11 +2463,11 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) } else { msize = -2; colno = split = winno / stacks; - win_g.w = ((r_g.w - (stacks * 2) + 2) / stacks); + win_g.w = ((r_g.w - (stacks * 2 * border_width) + 2 * border_width) / stacks); } hrh = r_g.h / colno; extra = r_g.h - (colno * hrh); - win_g.h = hrh - 2; + win_g.h = hrh - 2 * border_width; /* stack all the tiled windows */ i = j = 0, s = stacks; @@ -2087,6 +2475,11 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) if (win->transient != 0 || win->floating != 0) continue; + if (win->ewmh_flags & EWMH_F_FULLSCREEN) { + fs_win = win; + continue; + } + if (split && i == split) { colno = (winno - mwin) / stacks; if (s <= (winno - mwin) % stacks) @@ -2097,15 +2490,15 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) if (flip) win_g.x = r_g.x; else - win_g.x += win_g.w + 2; - win_g.w = (r_g.w - msize - (stacks * 2)) / stacks; + win_g.x += win_g.w + 2 * border_width; + win_g.w = (r_g.w - msize - (stacks * 2 * border_width)) / stacks; if (s == 1) - win_g.w += (r_g.w - msize - (stacks * 2)) % + win_g.w += (r_g.w - msize - (stacks * 2 * border_width)) % stacks; s--; j = 0; } - win_g.h = hrh - 2; + win_g.h = hrh - 2 * border_width; if (rot) { h_inc = win->sh.width_inc; h_base = win->sh.base_width; @@ -2132,15 +2525,15 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) if (j == 0) win_g.y = r_g.y; else - win_g.y += last_h + 2; + win_g.y += last_h + 2 * border_width; bzero(&wc, sizeof wc); if (disable_border && bar_enabled == 0 && winno == 1){ wc.border_width = 0; - win_g.w += 2; - win_g.h += 2; + win_g.w += 2 * border_width; + win_g.h += 2 * border_width; } else - wc.border_width = 1; + wc.border_width = border_width; reconfigure = 0; if (rot) { if (win->g.x != win_g.y || win->g.y != win_g.x || @@ -2183,9 +2576,19 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) if (win->transient == 0 && win->floating == 0) continue; + if (win->ewmh_flags & EWMH_F_FULLSCREEN) { + fs_win = win; + continue; + } + stack_floater(win, ws->r); XMapRaised(display, win->id); } + + if (fs_win) { + stack_floater(fs_win, ws->r); + XMapRaised(display, fs_win->id); + } } void @@ -2324,13 +2727,13 @@ max_stack(struct workspace *ws, struct swm_geometry *g) win->g.x = wc.x = gg.x; win->g.y = wc.y = gg.y; if (bar_enabled){ - wc.border_width = 1; + wc.border_width = border_width; win->g.w = wc.width = gg.w; win->g.h = wc.height = gg.h; } else { wc.border_width = 0; - win->g.w = wc.width = gg.w + 2; - win->g.h = wc.height = gg.h + 2; + win->g.w = wc.width = gg.w + 2 * border_width; + win->g.h = wc.height = gg.h + 2 * border_width; } mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); @@ -2391,6 +2794,7 @@ send_to_ws(struct swm_region *r, union arg *args) XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, PropModeReplace, ws_idx_str, SWM_PROPLEN); } + stack(); } @@ -2399,7 +2803,7 @@ wkill(struct swm_region *r, union arg *args) { DNPRINTF(SWM_D_MISC, "wkill %d\n", args->id); - if(r->ws->focus == NULL) + if (r->ws->focus == NULL) return; if (args->id == SWM_ARG_ID_KILLWINDOW) @@ -2409,18 +2813,23 @@ wkill(struct swm_region *r, union arg *args) client_msg(r->ws->focus, adelete); } -void -floating_toggle(struct swm_region *r, union arg *args) + +int +floating_toggle_win(struct ws_win *win) { - struct ws_win *win = r->ws->focus; - union arg a; + struct swm_region *r; if (win == NULL) - return; + return 0; + + if (!win->ws->r) + return 0; + + r = win->ws->r; /* reject floating toggles in max stack mode */ - if (r->ws->cur_layout == &layouts[SWM_MAX_STACK]) - return; + if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) + return 0; if (win->floating) { if (!win->floatmaxed) { @@ -2430,18 +2839,38 @@ floating_toggle(struct swm_region *r, union arg *args) win->floating = 0; } else { if (win->g_floatvalid) { - /* refloat at last floating relative position */ - win->g.x = win->g_float.x - win->rg_float.x + r->g.x; - win->g.y = win->g_float.y - win->rg_float.y + r->g.y; - win->g.w = win->g_float.w; - win->g.h = win->g_float.h; - } + /* refloat at last floating relative position */ + win->g.x = win->g_float.x - win->rg_float.x + r->g.x; + win->g.y = win->g_float.y - win->rg_float.y + r->g.y; + win->g.w = win->g_float.w; + win->g.h = win->g_float.h; + } win->floating = 1; } + ewmh_update_actions(win); + + return 1; +} + +void +floating_toggle(struct swm_region *r, union arg *args) +{ + struct ws_win *win = r->ws->focus; + union arg a; + + if (win == NULL) + return; + + ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, + _NET_WM_STATE_TOGGLE); + stack(); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(win->ws->r, &a); + + if (win == win->ws->focus) { + a.id = SWM_ARG_ID_FOCUSCUR; + focus(win->ws->r, &a); + } } void @@ -2454,12 +2883,12 @@ resize_window(struct ws_win *win, int center) r = root_to_region(win->wa.root); bzero(&wc, sizeof wc); mask = CWBorderWidth | CWWidth | CWHeight; - wc.border_width = 1; + wc.border_width = border_width; wc.width = win->g.w; wc.height = win->g.h; if (center == SWM_ARG_ID_CENTER) { - wc.x = (WIDTH(r) - win->g.w) / 2; - wc.y = (HEIGHT(r) - win->g.h) / 2; + wc.x = (WIDTH(r) - win->g.w) / 2 - border_width; + wc.y = (HEIGHT(r) - win->g.h) / 2 - border_width; mask |= CWX | CWY; } @@ -2491,6 +2920,8 @@ resize(struct ws_win *win, union arg *args) return; win->manual = 1; + ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom, + _NET_WM_STATE_ADD); /* raise the window = move to last in window list */ a.id = SWM_ARG_ID_MOVELAST; swapwin(r, &a); @@ -2502,14 +2933,14 @@ resize(struct ws_win *win, union arg *args) /* place pointer at bottom left corner or nearest point inside r */ if ( win->g.x + win->g.w < r->g.x + r->g.w - 1) - relx = win->g.w; + relx = win->g.w - 1; else - relx = r->g.x + r->g.w - win->g.x - 2; + relx = r->g.x + r->g.w - win->g.x - 1; if ( win->g.y + win->g.h < r->g.y + r->g.h - 1) - rely = win->g.h; + rely = win->g.h - 1; else - rely = r->g.y + r->g.h - win->g.y - 2; + rely = r->g.y + r->g.h - win->g.y - 1; XWarpPointer(display, None, win->id, 0, 0, 0, 0, relx, rely); do { @@ -2533,11 +2964,11 @@ resize(struct ws_win *win, union arg *args) ev.xmotion.x = 1; if (ev.xmotion.y <= 1) ev.xmotion.y = 1; - win->g.w = ev.xmotion.x; - win->g.h = ev.xmotion.y; + win->g.w = ev.xmotion.x + 1; + win->g.h = ev.xmotion.y + 1; - /* not free, don't sync more than 60 times / second */ - if ((ev.xmotion.time - time) > (1000 / 60) ) { + /* not free, don't sync more than 120 times / second */ + if ((ev.xmotion.time - time) > (1000 / 120) ) { time = ev.xmotion.time; XSync(display, False); resize_window(win, args->id); @@ -2597,7 +3028,11 @@ move(struct ws_win *win, union arg *args) win->manual = 1; if (win->floating == 0 && !win->transient) { win->floating = 1; + ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, + _NET_WM_STATE_ADD); } + ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom, + _NET_WM_STATE_ADD); /* raise the window = move to last in window list */ a.id = SWM_ARG_ID_MOVELAST; @@ -2607,7 +3042,7 @@ move(struct ws_win *win, union arg *args) if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess) return; - XWarpPointer(display, None, win->id, 0, 0, 0, 0, -1, -1); + XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0); do { XMaskEvent(display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); @@ -2625,11 +3060,11 @@ move(struct ws_win *win, union arg *args) ev.xmotion.y_root > r->g.y + r->g.h - 1) continue; - win->g.x = ev.xmotion.x_root; - win->g.y = ev.xmotion.y_root; + win->g.x = ev.xmotion.x_root - border_width; + win->g.y = ev.xmotion.y_root - border_width; - /* not free, don't sync more than 60 times / second */ - if ((ev.xmotion.time - time) > (1000 / 60) ) { + /* not free, don't sync more than 120 times / second */ + if ((ev.xmotion.time - time) > (1000 / 120) ) { time = ev.xmotion.time; XSync(display, False); move_window(win); @@ -3360,7 +3795,7 @@ grabbuttons(struct ws_win *win, int focused) updatenumlockmask(); XUngrabButton(display, AnyButton, AnyModifier, win->id); - if(focused) { + if (focused) { for (i = 0; i < LENGTH(buttons); i++) if (buttons[i].action == client_click) for (j = 0; j < LENGTH(modifiers); j++) @@ -3532,12 +3967,13 @@ setup_quirks(void) /* conf file stuff */ #define SWM_CONF_FILE "scrotwm.conf" -enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_STACK_ENABLED, +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_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BAR_FONT, - SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO + SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_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 }; int @@ -3550,6 +3986,12 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_BAR_ENABLED: bar_enabled = atoi(value); break; + case SWM_S_BAR_BORDER_WIDTH: + bar_border_width = atoi(value); + break; + case SWM_S_BAR_AT_BOTTOM: + bar_at_bottom = atoi(value); + break; case SWM_S_STACK_ENABLED: stack_enabled = atoi(value); break; @@ -3578,6 +4020,9 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_TITLE_CLASS_ENABLED: title_class_enabled = atoi(value); break; + case SWM_S_WINDOW_NAME_ENABLED: + window_name_enabled = atoi(value); + break; case SWM_S_TITLE_NAME_ENABLED: title_name_enabled = atoi(value); break; @@ -3594,6 +4039,9 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_DISABLE_BORDER: disable_border = atoi(value); break; + case SWM_S_BORDER_WIDTH: + border_width = atoi(value); + break; case SWM_S_BAR_FONT: free(bar_fonts[0]); if ((bar_fonts[0] = strdup(value)) == NULL) @@ -3660,7 +4108,9 @@ struct config_option { }; 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_color", setconfcolor, SWM_S_COLOR_BAR }, { "bar_font_color", setconfcolor, SWM_S_COLOR_BAR_FONT }, { "bar_font", setconfvalue, SWM_S_BAR_FONT }, @@ -3682,11 +4132,13 @@ struct config_option configopt[] = { { "spawn_term", setconfvalue, SWM_S_SPAWN_TERM }, { "screenshot_enabled", setconfvalue, SWM_S_SS_ENABLED }, { "screenshot_app", setconfvalue, SWM_S_SS_APP }, + { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_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 }, }; @@ -3823,6 +4275,7 @@ manage_window(Window id) TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); if (win->transient) set_child_transient(win); + ewmh_update_actions(win); return (win); } @@ -3843,6 +4296,7 @@ manage_window(Window id) DNPRINTF(SWM_D_MISC, "manage_window: win %lu transient %lu\n", win->id, win->transient); } + /* get supported protocols */ if (XGetWMProtocols(display, id, &prot, &n)) { for (i = 0, pp = prot; i < n; i++, pp++) { @@ -3897,6 +4351,7 @@ manage_window(Window id) win->g.y = win->wa.y; win->g_floatvalid = 0; win->floatmaxed = 0; + win->ewmh_flags = 0; /* Set window properties so we can remember this after reincarnation */ if (ws_idx_atom && prop == NULL && @@ -3906,7 +4361,10 @@ manage_window(Window id) XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, PropModeReplace, ws_idx_str, SWM_PROPLEN); } - XFree(prop); + if (prop) + XFree(prop); + + ewmh_autoquirk(win); if (XGetClassHint(display, win->id, &win->ch)) { DNPRINTF(SWM_D_CLASS, "class: %s name: %s\n", @@ -3937,7 +4395,7 @@ manage_window(Window id) win->manual = 1; /* don't center the quirky windows */ bzero(&wc, sizeof wc); mask = 0; - if (win->g.y < bar_height) { + if (bar_enabled && win->g.y < bar_height) { win->g.y = wc.y = bar_height; mask |= CWY; } @@ -3956,10 +4414,14 @@ manage_window(Window id) fake_keypress(win, XK_KP_Add, ShiftMask); } + ewmh_get_win_state(win); + ewmh_update_actions(win); + ewmh_update_win_state(win, None, _NET_WM_STATE_REMOVE); + /* border me */ if (border_me) { bzero(&wc, sizeof wc); - wc.border_width = 1; + wc.border_width = border_width; mask = CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); configreq_win(win); @@ -4019,7 +4481,9 @@ unmanage_window(struct ws_win *win) parent->child_trans = NULL; } - /* work around for mplayer going full screen */ + /* focus on root just in case */ + XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime); + if (!win->floating) focus_prev(win); @@ -4044,9 +4508,17 @@ focus_magic(struct ws_win *win, int do_trans) if (win->child_trans->take_focus) client_msg(win, takefocus); } else { - focus_win(win->child_trans); - if (win->child_trans->take_focus) - client_msg(win->child_trans, takefocus); + /* make sure transient hasn't dissapeared */ + if (validate_win(win->child_trans) == 0) { + focus_win(win->child_trans); + if (win->child_trans->take_focus) + client_msg(win->child_trans, takefocus); + } else { + win->child_trans = NULL; + focus_win(win); + if (win->take_focus) + client_msg(win, takefocus); + } } } else { /* regular focus */ @@ -4438,6 +4910,8 @@ propertynotify(XEvent *e) XMoveResizeWindow(display, win->id, win->g.x, win->g.y, win->g.w, win->g.h); #endif + if (window_name_enabled) + bar_update(); break; default: break; @@ -4477,6 +4951,59 @@ visibilitynotify(XEvent *e) bar_update(); } +void +clientmessage(XEvent *e) +{ + XClientMessageEvent *ev; + struct ws_win *win; + + ev = &e->xclient; + + win = find_window(ev->window); + if (win == NULL) + return; + + DNPRINTF(SWM_D_EVENT, "clientmessage: window: 0x%lx type: %ld \n", + ev->window, ev->message_type); + + if (ev->message_type == ewmh[_NET_ACTIVE_WINDOW].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW \n"); + focus_win(win); + } + if (ev->message_type == ewmh[_NET_CLOSE_WINDOW].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW \n"); + if (win->can_delete) + client_msg(win, adelete); + else + XKillClient(display, win->id); + } + if (ev->message_type == ewmh[_NET_MOVERESIZE_WINDOW].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_MOVERESIZE_WINDOW \n"); + if (win->floating) { + if (ev->data.l[0] & (1<<8)) /* x */ + win->g.x = ev->data.l[1]; + if (ev->data.l[0] & (1<<9)) /* y */ + win->g.y = ev->data.l[2]; + if (ev->data.l[0] & (1<<10)) /* width */ + win->g.w = ev->data.l[3]; + if (ev->data.l[0] & (1<<11)) /* height */ + win->g.h = ev->data.l[4]; + } + else { + /* TODO: Change stack sizes */ + } + config_win(win); + } + if (ev->message_type == ewmh[_NET_WM_STATE].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE \n"); + ewmh_update_win_state(win, ev->data.l[1], ev->data.l[0]); + if (ev->data.l[2]) + ewmh_update_win_state(win, ev->data.l[2], ev->data.l[0]); + + stack(); + } +} + int xerror_start(Display *d, XErrorEvent *ee) { @@ -4671,16 +5198,57 @@ screenchange(XEvent *e) { } void -setup_screens(void) +grab_windows(void) { Window d1, d2, *wins = NULL; XWindowAttributes wa; unsigned int no; - int i, j, k; + int i, j; + long state, manage; + + for (i = 0; i < ScreenCount(display); i++) { + if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no)) + continue; + + /* attach windows to a region */ + /* normal windows */ + for (j = 0; j < no; j++) { + if (!XGetWindowAttributes(display, wins[j], &wa) || + wa.override_redirect || + XGetTransientForHint(display, wins[j], &d1)) + continue; + + state = getstate(wins[j]); + manage = state == IconicState; + if (wa.map_state == IsViewable || manage) + manage_window(wins[j]); + } + /* transient windows */ + for (j = 0; j < no; j++) { + if (!XGetWindowAttributes(display, wins[j], &wa) || + wa.override_redirect) + continue; + + state = getstate(wins[j]); + manage = state == IconicState; + if (XGetTransientForHint(display, wins[j], &d1) && + manage) + manage_window(wins[j]); + } + if (wins) { + XFree(wins); + wins = NULL; + } + } +} + +void +setup_screens(void) +{ + int i, j, k; int errorbase, major, minor; struct workspace *ws; int ws_idx_atom; - long state, manage; if ((screens = calloc(ScreenCount(display), sizeof(struct swm_screen))) == NULL) @@ -4731,45 +5299,12 @@ setup_screens(void) SWM_ARG_ID_STACKINIT); ws->cur_layout = &layouts[0]; } - /* grab existing windows (before we build the bars)*/ - if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no)) - continue; scan_xrandr(i); if (xrandr_support) XRRSelectInput(display, screens[i].root, RRScreenChangeNotifyMask); - - /* attach windows to a region */ - /* normal windows */ - for (j = 0; j < no; j++) { - if (!XGetWindowAttributes(display, wins[j], &wa) || - wa.override_redirect || - XGetTransientForHint(display, wins[j], &d1)) - continue; - - state = getstate(wins[j]); - manage = state == IconicState; - if (wa.map_state == IsViewable || manage) - manage_window(wins[j]); - } - /* transient windows */ - for (j = 0; j < no; j++) { - if (!XGetWindowAttributes(display, wins[j], &wa) || - wa.override_redirect) - continue; - - state = getstate(wins[j]); - manage = state == IconicState; - if (XGetTransientForHint(display, wins[j], &d1) && - manage) - manage_window(wins[j]); - } - if (wins) { - XFree(wins); - wins = NULL; - } } } @@ -4796,7 +5331,7 @@ workaround(void) { int i; Atom netwmcheck, netwmname, utf8_string; - Window root; + Window root, win; /* work around sun jdk bugs, code from wmname */ netwmcheck = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); @@ -4804,10 +5339,16 @@ workaround(void) utf8_string = XInternAtom(display, "UTF8_STRING", False); for (i = 0; i < ScreenCount(display); i++) { root = screens[i].root; + win = XCreateSimpleWindow(display,root, 0, 0, 1, 1, 0, + screens[i].c[SWM_S_COLOR_UNFOCUS].color, + screens[i].c[SWM_S_COLOR_UNFOCUS].color); + XChangeProperty(display, root, netwmcheck, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&root, 1); - XChangeProperty(display, root, netwmname, utf8_string, 8, - PropModeReplace, "LG3D", strlen("LG3D")); + PropModeReplace, (unsigned char *)&win,1); + XChangeProperty(display, win, netwmcheck, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&win,1); + XChangeProperty(display, win, netwmname, utf8_string, 8, + PropModeReplace, (unsigned char*)"LG3D", strlen("LG3D")); } } @@ -4868,6 +5409,7 @@ main(int argc, char *argv[]) setup_quirks(); setup_spawn(); + /* load config */ snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE); if (stat(conf, &sb) != -1) { if (S_ISREG(sb.st_mode)) @@ -4882,6 +5424,13 @@ main(int argc, char *argv[]) if (cfile) conf_load(cfile); + setup_ewmh(); + /* set some values to work around bad programs */ + workaround(); + + /* grab existing windows (before we build the bars) */ + grab_windows(); + /* setup all bars */ for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) { @@ -4890,9 +5439,6 @@ main(int argc, char *argv[]) bar_setup(r); } - /* set some values to work around bad programs */ - workaround(); - unfocus_all(); grabkeys(); @@ -4963,6 +5509,7 @@ main(int argc, char *argv[]) } } done: + teardown_ewmh(); bar_extra_stop(); XFreeGC(display, bar_gc); XCloseDisplay(display);