X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=bc3e1fd4f76ac2885f01ea4fcd8b4fc94c09c83a;hb=3088ae3cd65be8b9a35ec1ff960e6221161be5dc;hp=4179ce372b49896fa335c5feb3893045e3602ab2;hpb=a10363decbac9b04827124411deb9f28458c25a0;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 4179ce3..bc3e1fd 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -173,6 +173,9 @@ u_int32_t swm_debug = 0 #define Y(r) (r)->g.y #define WIDTH(r) (r)->g.w #define HEIGHT(r) (r)->g.h +#define BORDER(w) (w->bordered ? border_width : 0) +#define MAX_X(r) ((r)->g.x + (r)->g.w) +#define MAX_Y(r) ((r)->g.y + (r)->g.h) #define SH_MIN(w) (w)->sh_mask & PMinSize #define SH_MIN_W(w) (w)->sh.min_width #define SH_MIN_H(w) (w)->sh.min_height @@ -312,7 +315,6 @@ pid_t bar_pid; XFontSet bar_fs; XFontSetExtents *bar_fs_extents; char *bar_fonts; -char *spawn_term[] = { NULL, NULL }; /* XXX fully dynamic */ struct passwd *pwd; #define SWM_MENU_FN (2) @@ -332,6 +334,12 @@ struct swm_geometry { struct swm_screen; struct workspace; +struct swm_bar { + Window id; + Pixmap buffer; + struct swm_geometry g; +}; + /* virtual "screens" */ struct swm_region { TAILQ_ENTRY(swm_region) entry; @@ -339,7 +347,7 @@ struct swm_region { struct workspace *ws; /* current workspace on this region */ struct workspace *ws_prior; /* prior workspace on this region */ struct swm_screen *s; /* screen idx */ - Window bar_window; + struct swm_bar *bar; }; TAILQ_HEAD(swm_region_list, swm_region); @@ -349,13 +357,13 @@ struct ws_win { Window transient; struct ws_win *child_trans; /* transient child window */ struct swm_geometry g; /* current geometry */ - struct swm_geometry g_float; /* geometry when floating */ - struct swm_geometry rg_float; /* region geom when floating */ + struct swm_geometry g_float; /* region coordinates */ int g_floatvalid; /* g_float geometry validity */ int floatmaxed; /* whether maxed by max_stack */ int floating; int manual; int iconic; + int bordered; unsigned int ewmh_flags; int font_size_boundary[SWM_MAX_FONT_STEPS]; int font_steps; @@ -453,8 +461,14 @@ struct workspace { } l_state; }; -enum { SWM_S_COLOR_BAR, SWM_S_COLOR_BAR_BORDER, SWM_S_COLOR_BAR_FONT, - SWM_S_COLOR_FOCUS, SWM_S_COLOR_UNFOCUS, SWM_S_COLOR_MAX }; +enum { + SWM_S_COLOR_BAR, + SWM_S_COLOR_BAR_BORDER, + SWM_S_COLOR_BAR_FONT, + SWM_S_COLOR_FOCUS, + SWM_S_COLOR_UNFOCUS, + SWM_S_COLOR_MAX +}; /* physical screen mapping */ #define SWM_WS_MAX (22) /* hard limit */ @@ -543,17 +557,33 @@ struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks); * 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 }; +enum { + _NET_ACTIVE_WINDOW, + _NET_CLOSE_WINDOW, + _NET_MOVERESIZE_WINDOW, + _NET_WM_ACTION_CLOSE, + _NET_WM_ACTION_FULLSCREEN, + _NET_WM_ACTION_MOVE, + _NET_WM_ACTION_RESIZE, + _NET_WM_ALLOWED_ACTIONS, + _NET_WM_STATE, + _NET_WM_STATE_ABOVE, + _NET_WM_STATE_FULLSCREEN, + _NET_WM_STATE_HIDDEN, + _NET_WM_STATE_MAXIMIZED_HORZ, + _NET_WM_STATE_MAXIMIZED_VERT, + _NET_WM_STATE_SKIP_PAGER, + _NET_WM_STATE_SKIP_TASKBAR, + _NET_WM_WINDOW_TYPE, + _NET_WM_WINDOW_TYPE_DIALOG, + _NET_WM_WINDOW_TYPE_DOCK, + _NET_WM_WINDOW_TYPE_NORMAL, + _NET_WM_WINDOW_TYPE_SPLASH, + _NET_WM_WINDOW_TYPE_TOOLBAR, + _NET_WM_WINDOW_TYPE_UTILITY, + _SWM_WM_STATE_MANUAL, + SWM_EWMH_HINT_MAX +}; struct ewmh_hint { char *name; @@ -561,33 +591,35 @@ struct ewmh_hint { } 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_MOVERESIZE_WINDOW", None}, + {"_NET_WM_ACTION_CLOSE", None}, + {"_NET_WM_ACTION_FULLSCREEN", None}, + {"_NET_WM_ACTION_MOVE", None}, + {"_NET_WM_ACTION_RESIZE", None}, + {"_NET_WM_ALLOWED_ACTIONS", None}, {"_NET_WM_STATE", None}, + {"_NET_WM_STATE_ABOVE", None}, + {"_NET_WM_STATE_FULLSCREEN", None}, + {"_NET_WM_STATE_HIDDEN", 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}, + {"_NET_WM_STATE_SKIP_TASKBAR", None}, + {"_NET_WM_WINDOW_TYPE", None}, + {"_NET_WM_WINDOW_TYPE_DIALOG", None}, + {"_NET_WM_WINDOW_TYPE_DOCK", None}, + {"_NET_WM_WINDOW_TYPE_NORMAL", None}, + {"_NET_WM_WINDOW_TYPE_SPLASH", None}, + {"_NET_WM_WINDOW_TYPE_TOOLBAR", None}, + {"_NET_WM_WINDOW_TYPE_UTILITY", 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 *, struct swm_region *); int floating_toggle_win(struct ws_win *); +void constrain_window(struct ws_win *, struct swm_region *, int); +void update_window(struct ws_win *); void spawn_select(struct swm_region *, union arg *, char *, int *); unsigned char *get_win_name(Window); @@ -759,8 +791,6 @@ ewmh_autoquirk(struct ws_win *win) int ewmh_set_win_fullscreen(struct ws_win *win, int fs) { - struct swm_geometry rg; - if (!win->ws->r) return (0); @@ -770,19 +800,18 @@ ewmh_set_win_fullscreen(struct ws_win *win, int fs) DNPRINTF(SWM_D_MISC, "ewmh_set_win_fullscreen: window: 0x%lx, " "fullscreen %s\n", win->id, YESNO(fs)); - rg = win->ws->r->g; - if (fs) { - store_float_geom(win, win->ws->r); + if (!win->g_floatvalid) + store_float_geom(win, win->ws->r); - win->g = rg; + win->g = win->ws->r->g; + win->bordered = 0; } else { if (win->g_floatvalid) { /* refloat at last floating relative position */ - X(win) = win->g_float.x - win->rg_float.x + rg.x; - Y(win) = win->g_float.y - win->rg_float.y + rg.y; - WIDTH(win) = win->g_float.w; - HEIGHT(win) = win->g_float.h; + win->g = win->g_float; + X(win) += X(win->ws->r); + Y(win) += Y(win->ws->r); } } @@ -1304,14 +1333,12 @@ socket_setnonblock(int fd) } void -bar_print(struct swm_region *r, char *s) +bar_print(struct swm_region *r, const char *s) { int x = 0; size_t len; XRectangle ibox, lbox; - XClearWindow(display, r->bar_window); - len = strlen(s); XmbTextExtents(bar_fs, s, len, &ibox, &lbox); @@ -1330,9 +1357,21 @@ bar_print(struct swm_region *r, char *s) if (x < SWM_BAR_OFFSET) x = SWM_BAR_OFFSET; - DRAWSTRING(display, r->bar_window, bar_fs, r->s->bar_gc, + /* clear back buffer */ + XSetForeground(display, r->s->bar_gc, r->s->c[SWM_S_COLOR_BAR].color); + XFillRectangle(display, r->bar->buffer, r->s->bar_gc, 0, 0, + WIDTH(r->bar), HEIGHT(r->bar)); + + /* draw back buffer */ + XSetForeground(display, r->s->bar_gc, + r->s->c[SWM_S_COLOR_BAR_FONT].color); + DRAWSTRING(display, r->bar->buffer, bar_fs, r->s->bar_gc, x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 - lbox.y, s, len); + + /* blt */ + XCopyArea(display, r->bar->buffer, r->bar->id, r->s->bar_gc, 0, 0, + WIDTH(r->bar), HEIGHT(r->bar), 0, 0); } void @@ -1369,6 +1408,26 @@ bar_title_name(char *s, size_t sz, struct swm_region *r) } void +bar_class_title_name(char *s, size_t sz, struct swm_region *r) +{ + if (r == NULL || r->ws == NULL || r->ws->focus == NULL) + return; + + bar_class_name(s, sz, r); + strlcat(s, ":", sz); + bar_title_name(s, sz, r); +} + +void +bar_window_float(char *s, size_t sz, struct swm_region *r) +{ + if (r == NULL || r ->ws == NULL || r->ws->focus == NULL) + return; + if (r->ws->focus->floating) + strlcat(s, "(f)", sz); +} + +void bar_window_name(char *s, size_t sz, struct swm_region *r) { unsigned char *title; @@ -1378,10 +1437,7 @@ bar_window_name(char *s, size_t sz, struct swm_region *r) if ((title = get_win_name(r->ws->focus->id)) == NULL) return; - if (r->ws->focus->floating) - strlcat(s, "(f) ", sz); strlcat(s, (char *)title, sz); - XFree(title); } @@ -1429,7 +1485,7 @@ bar_workspace_name(char *s, size_t sz, struct swm_region *r) /* build the default bar format according to the defined enabled options */ void -bar_fmt(char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz) +bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz) { /* if format provided, just copy the buffers */ if (bar_format != NULL) { @@ -1448,32 +1504,48 @@ bar_fmt(char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz) /* only show the workspace name if there's actually one */ if (r != NULL && r->ws != NULL && r->ws->name != NULL) strlcat(fmtnew, "<+D>", sz); - strlcat(fmtnew, " ", sz); + strlcat(fmtnew, "+3<", sz); if (clock_enabled) { strlcat(fmtnew, fmtexp, sz); - strlcat(fmtnew, " ", sz); + strlcat(fmtnew, "+4<", sz); } /* bar_urgent already adds the space before the last asterisk */ if (urgent_enabled) - strlcat(fmtnew, "* +U* ", sz); + strlcat(fmtnew, "* +U*+4<", sz); - if (title_class_enabled) + if (title_class_enabled) { strlcat(fmtnew, "+C", sz); - if (title_name_enabled) { - /* add a colon if showing the class and something is focused */ - if (title_class_enabled && r != NULL && r->ws != NULL && - r->ws->focus != NULL) - strlcat(fmtnew, ":", sz); - strlcat(fmtnew, "+T ", sz); + if (title_name_enabled == 0) + strlcat(fmtnew, "+4<", sz); } - if (window_name_enabled) - strlcat(fmtnew, "+64W ", sz); + /* checks needed by the colon and floating strlcat(3) calls below */ + if (r != NULL && r->ws != NULL && r->ws->focus != NULL) { + if (title_name_enabled) { + if (title_class_enabled) + strlcat(fmtnew, ":", sz); + strlcat(fmtnew, "+T+4<", sz); + } + if (window_name_enabled) { + if (r->ws->focus->floating) + strlcat(fmtnew, "+F ", sz); + strlcat(fmtnew, "+64W ", sz); + } + } /* finally add the action script output and the version */ - strlcat(fmtnew, " +A +V", sz); + strlcat(fmtnew, "+4<+A+4<+V", sz); +} + +void +bar_replace_pad(char *tmp, int *limit, size_t sz) +{ + /* special case; no limit given, pad one space, instead */ + if (*limit == sz - 1) + *limit = 1; + snprintf(tmp, sz, "%*s", *limit, " "); } /* replaces the bar format character sequences (like in tmux(1)) */ @@ -1482,35 +1554,30 @@ bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep, size_t sz) { char *ptr; - char num[8], tmp[SWM_BAR_MAX]; - int limit; - size_t len, numoff = 0; + char tmp[SWM_BAR_MAX]; + int limit, size; + size_t len; /* reset strlcat(3) buffer */ *tmp = '\0'; /* get number, if any */ fmt++; - while (*fmt != '\0' && isdigit((unsigned char) *fmt)) { - if (numoff >= sizeof num - 1) - break; - num[numoff++] = *fmt++; - } - num[numoff] = '\0'; - - if ((limit = strtonum(num, 1, sizeof tmp - 1, NULL)) == 0) + size = 0; + if (sscanf(fmt, "%d%n", &limit, &size) != 1) + limit = sizeof tmp - 1; + if (limit <= 0 || limit >= sizeof tmp) limit = sizeof tmp - 1; - /* if number is too big, skip to the first non-digit */ - if (numoff >= sizeof num - 1) { - while (*fmt != '\0' && isdigit((unsigned char) *fmt)) - fmt++; - } /* there is nothing to replace (ie EOL) */ + fmt += size; if (*fmt == '\0') return (fmt); switch (*fmt) { + case '<': + bar_replace_pad(tmp, &limit, sizeof tmp); + break; case 'A': snprintf(tmp, sizeof tmp, "%s", bar_ext); break; @@ -1520,12 +1587,18 @@ bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep, case 'D': bar_workspace_name(tmp, sizeof tmp, r); break; + case 'F': + bar_window_float(tmp, sizeof tmp, r); + break; case 'I': snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1); break; case 'N': snprintf(tmp, sizeof tmp, "%d", r->s->idx + 1); break; + case 'P': + bar_class_title_name(tmp, sizeof tmp, r); + break; case 'S': snprintf(tmp, sizeof tmp, "%s", r->ws->stacker); break; @@ -1631,6 +1704,8 @@ bar_fmt_print(void) for (i = 0; i < ScreenCount(display); i++) { TAILQ_FOREACH(r, &screens[i].rl, entry) { + if (r->bar == NULL) + continue; bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew); bar_replace(fmtnew, fmtrep, r, sizeof fmtrep); bar_print(r, fmtrep); @@ -1678,14 +1753,17 @@ bar_toggle(struct swm_region *r, union arg *args) DNPRINTF(SWM_D_BAR, "bar_toggle\n"); - if (bar_enabled) + if (bar_enabled) { for (i = 0; i < sc; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) - XUnmapWindow(display, tmpr->bar_window); - else + if (tmpr->bar) + XUnmapWindow(display, tmpr->bar->id); + } else { for (i = 0; i < sc; i++) TAILQ_FOREACH(tmpr, &screens[i].rl, entry) - XMapRaised(display, tmpr->bar_window); + if (tmpr->bar) + XMapRaised(display, tmpr->bar->id); + } bar_enabled = !bar_enabled; @@ -1733,11 +1811,13 @@ bar_refresh(void) bzero(&wa, sizeof wa); for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) { + if (r->bar == NULL) + continue; wa.border_pixel = screens[i].c[SWM_S_COLOR_BAR_BORDER].color; wa.background_pixel = screens[i].c[SWM_S_COLOR_BAR].color; - XChangeWindowAttributes(display, r->bar_window, + XChangeWindowAttributes(display, r->bar->id, CWBackPixel | CWBorderPixel, &wa); } bar_update(); @@ -1749,13 +1829,15 @@ bar_setup(struct swm_region *r) char *default_string; char **missing_charsets; int num_missing_charsets = 0; - int i, x, y; + int i; if (bar_fs) { XFreeFontSet(display, bar_fs); bar_fs = NULL; } + if ((r->bar = calloc(1, sizeof(struct swm_bar))) == NULL) + err(1, "bar_setup: calloc: failed to allocate memory."); DNPRINTF(SWM_D_BAR, "bar_setup: loading bar_fonts: %s\n", bar_fonts); @@ -1788,18 +1870,27 @@ bar_setup(struct swm_region *r) if (bar_height < 1) bar_height = 1; - x = X(r); - y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r); + X(r->bar) = X(r); + Y(r->bar) = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r); + WIDTH(r->bar) = WIDTH(r) - 2 * bar_border_width; + HEIGHT(r->bar) = bar_height - 2 * bar_border_width; - r->bar_window = XCreateSimpleWindow(display, - r->s->root, x, y, WIDTH(r) - 2 * bar_border_width, - bar_height - 2 * bar_border_width, + r->bar->id = XCreateSimpleWindow(display, + r->s->root, X(r->bar), Y(r->bar), WIDTH(r->bar), HEIGHT(r->bar), bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color, r->s->c[SWM_S_COLOR_BAR].color); - XSelectInput(display, r->bar_window, VisibilityChangeMask); + + r->bar->buffer = XCreatePixmap(display, r->bar->id, WIDTH(r->bar), + HEIGHT(r->bar), DefaultDepth(display, r->s->idx)); + + XSelectInput(display, r->bar->id, VisibilityChangeMask); + if (bar_enabled) - XMapRaised(display, r->bar_window); - DNPRINTF(SWM_D_BAR, "bar_setup: bar_window: 0x%lx\n", r->bar_window); + XMapRaised(display, r->bar->id); + + DNPRINTF(SWM_D_BAR, "bar_setup: window: 0x%lx, (x,y) w x h: (%d,%d) " + "%d x %d\n", WINID(r->bar), X(r->bar), Y(r->bar), WIDTH(r->bar), + HEIGHT(r->bar)); if (signal(SIGALRM, bar_signal) == SIG_ERR) err(1, "could not install bar_signal"); @@ -1807,6 +1898,17 @@ bar_setup(struct swm_region *r) } void +bar_cleanup(struct swm_region *r) +{ + if (r->bar == NULL) + return; + XDestroyWindow(display, r->bar->id); + XFreePixmap(display, r->bar->buffer); + free(r->bar); + r->bar = NULL; +} + +void drain_enter_notify(void) { int i = 0; @@ -1815,7 +1917,7 @@ drain_enter_notify(void) while (XCheckMaskEvent(display, EnterWindowMask, &cne)) i++; - DNPRINTF(SWM_D_MISC, "drain_enter_notify: drained: %d\n", i); + DNPRINTF(SWM_D_EVENT, "drain_enter_notify: drained: %d\n", i); } void @@ -1899,7 +2001,7 @@ config_win(struct ws_win *win, XConfigureRequestEvent *ev) ce.display = display; ce.event = win->id; ce.window = win->id; - ce.border_width = border_width; + ce.border_width = BORDER(win); ce.above = None; } else { /* normal */ @@ -1944,8 +2046,8 @@ config_win(struct ws_win *win, XConfigureRequestEvent *ev) } /* adjust x and y for requested border_width. */ - ce.x += border_width - ev->border_width; - ce.y += border_width - ev->border_width; + ce.x += BORDER(win) - ev->border_width; + ce.y += BORDER(win) - ev->border_width; ce.border_width = ev->border_width; ce.above = ev->above; } @@ -2071,16 +2173,20 @@ root_to_region(Window root) int i, x, y, wx, wy; unsigned int mask; + DNPRINTF(SWM_D_MISC, "root_to_region: window: 0x%lx\n", root); + for (i = 0; i < ScreenCount(display); i++) if (screens[i].root == root) break; if (XQueryPointer(display, screens[i].root, &rr, &cr, &x, &y, &wx, &wy, &mask) != False) { + DNPRINTF(SWM_D_MISC, "root_to_region: pointer: (%d,%d)\n", + x, y); /* choose a region based on pointer location */ TAILQ_FOREACH(r, &screens[i].rl, entry) - if (x >= X(r) && x <= X(r) + WIDTH(r) && - y >= Y(r) && y <= Y(r) + HEIGHT(r)) + if (X(r) <= x && x < MAX_X(r) && + Y(r) <= y && y < MAX_Y(r)) break; } @@ -2196,18 +2302,6 @@ spawn(int ws_idx, union arg *args, int close_fd) } void -spawnterm(struct swm_region *r, union arg *args) -{ - DNPRINTF(SWM_D_MISC, "spawnterm\n"); - - if (fork() == 0) { - if (term_width) - setenv("_SWM_XTERM_FONTADJ", "", 1); - spawn(r->ws->idx, args, 1); - } -} - -void kill_refs(struct ws_win *win) { int i, x; @@ -2928,46 +3022,65 @@ store_float_geom(struct ws_win *win, struct swm_region *r) { /* retain window geom and region geom */ win->g_float = win->g; - win->rg_float = r->g; + win->g_float.x -= X(r); + win->g_float.y -= Y(r); win->g_floatvalid = 1; + DNPRINTF(SWM_D_MISC, "store_float_geom: window: 0x%lx, g: (%d,%d)" + " %d x %d, g_float: (%d,%d) %d x %d\n", win->id, X(win), Y(win), + WIDTH(win), HEIGHT(win), win->g_float.x, win->g_float.y, + win->g_float.w, win->g_float.h); } void stack_floater(struct ws_win *win, struct swm_region *r) { - unsigned int mask; - XWindowChanges wc; - if (win == NULL) return; - bzero(&wc, sizeof wc); - mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight; + DNPRINTF(SWM_D_MISC, "stack_floater: window: 0x%lx\n", win->id); /* * to allow windows to change their size (e.g. mplayer fs) only retrieve * geom on ws switches or return from max mode */ - 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 - */ - X(win) = win->g_float.x - win->rg_float.x + X(r); - Y(win) = win->g_float.y - win->rg_float.y + Y(r); - WIDTH(win) = win->g_float.w; - HEIGHT(win) = win->g_float.h; - win->g_floatvalid = 0; + if (win->g_floatvalid && (win->floatmaxed || (r != r->ws->old_r && + !(win->ewmh_flags & EWMH_F_FULLSCREEN)))) { + /* refloat at last floating relative position */ + win->g = win->g_float; + X(win) += X(r); + Y(win) += Y(r); } win->floatmaxed = 0; - if ((win->quirks & SWM_Q_FULLSCREEN) && (WIDTH(win) >= WIDTH(r)) && - (HEIGHT(win) >= HEIGHT(r))) - wc.border_width = 0; - else - wc.border_width = border_width; + /* + * if set to fullscreen mode, configure window to maximum size. + */ + if (win->ewmh_flags & EWMH_F_FULLSCREEN) { + if (!win->g_floatvalid) + store_float_geom(win, win->ws->r); + + win->g = win->ws->r->g; + } + + /* + * remove border on fullscreen floater when in fullscreen mode or when + * the quirk is present. + */ + if ((win->ewmh_flags & EWMH_F_FULLSCREEN) || + ((win->quirks & SWM_Q_FULLSCREEN) && + (WIDTH(win) >= WIDTH(r)) && (HEIGHT(win) >= HEIGHT(r)))) { + if (win->bordered) { + win->bordered = 0; + X(win) += border_width; + Y(win) += border_width; + } + } else if (!win->bordered) { + win->bordered = 1; + X(win) -= border_width; + Y(win) -= border_width; + } + if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) { WIDTH(win) = (double)WIDTH(r) * dialog_ratio; HEIGHT(win) = (double)HEIGHT(r) * dialog_ratio; @@ -2978,39 +3091,14 @@ stack_floater(struct ws_win *win, struct swm_region *r) * floaters and transients are auto-centred unless moved * or resized */ - X(win) = X(r) + (WIDTH(r) - WIDTH(win)) / 2 - wc.border_width; - Y(win) = Y(r) + (HEIGHT(r) - HEIGHT(win)) / 2 - wc.border_width; - } - - /* win can be outside r if new r smaller than old r */ - /* Ensure top left corner inside r (move probs otherwise) */ - if (X(win) < X(r) - wc.border_width) - X(win) = X(r) - wc.border_width; - if (X(win) > X(r) + WIDTH(r) - 1) - X(win) = (WIDTH(win) > WIDTH(r)) ? X(r) : - (X(r) + WIDTH(r) - WIDTH(win) - 2 * wc.border_width); - if (Y(win) < Y(r) - wc.border_width) - Y(win) = Y(r) - wc.border_width; - if (Y(win) > Y(r) + HEIGHT(r) - 1) - Y(win) = (HEIGHT(win) > HEIGHT(r)) ? Y(r) : - (Y(r) + HEIGHT(r) - HEIGHT(win) - 2 * wc.border_width); - - wc.x = X(win); - wc.y = Y(win); - wc.width = WIDTH(win); - wc.height = HEIGHT(win); - - /* - * Retain floater and transient geometry for correct positioning - * when ws changes region - */ - if (!(win->ewmh_flags & EWMH_F_FULLSCREEN)) - store_float_geom(win, r); + X(win) = X(r) + (WIDTH(r) - WIDTH(win)) / 2 - BORDER(win); + Y(win) = Y(r) + (HEIGHT(r) - HEIGHT(win)) / 2 - BORDER(win); + } - DNPRINTF(SWM_D_MISC, "stack_floater: window: %lu, (x,y) w x h: (%d,%d) " - "%d x %d\n", win->id, wc.x, wc.y, wc.width, wc.height); + /* keep window within region bounds */ + constrain_window(win, r, 0); - XConfigureWindow(display, win->id, mask, &wc); + update_window(win); } /* @@ -3050,16 +3138,15 @@ adjust_font(struct ws_win *win) void 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, *fs_win = 0; + struct ws_win *win, *fs_win = NULL; 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; int split, colno, winno, mwin, msize, mscale; int remain, missing, v_slice, reconfigure; - unsigned int mask; + int bordered = 1; DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, " "flip: %s\n", ws->idx, YESNO(rot), YESNO(flip)); @@ -3185,37 +3272,41 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) else win_g.y += last_h + 2 * border_width; - bzero(&wc, sizeof wc); if (disable_border && bar_enabled == 0 && winno == 1){ - wc.border_width = 0; + bordered = 0; win_g.w += 2 * border_width; win_g.h += 2 * border_width; - } else - wc.border_width = border_width; - reconfigure = 0; + } else { + bordered = 1; + } if (rot) { if (X(win) != win_g.y || Y(win) != win_g.x || WIDTH(win) != win_g.h || HEIGHT(win) != win_g.w) { reconfigure = 1; - X(win) = wc.x = win_g.y; - Y(win) = wc.y = win_g.x; - WIDTH(win) = wc.width = win_g.h; - HEIGHT(win) = wc.height = win_g.w; + X(win) = win_g.y; + Y(win) = win_g.x; + WIDTH(win) = win_g.h; + HEIGHT(win) = win_g.w; } } else { if (X(win) != win_g.x || Y(win) != win_g.y || WIDTH(win) != win_g.w || HEIGHT(win) != win_g.h) { reconfigure = 1; - X(win) = wc.x = win_g.x; - Y(win) = wc.y = win_g.y; - WIDTH(win) = wc.width = win_g.w; - HEIGHT(win) = wc.height = win_g.h; + X(win) = win_g.x; + Y(win) = win_g.y; + WIDTH(win) = win_g.w; + HEIGHT(win) = win_g.h; } } + + if (bordered != win->bordered) { + reconfigure = 1; + win->bordered = bordered; + } + if (reconfigure) { adjust_font(win); - mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); + update_window(win); } if (XGetWindowAttributes(display, win->id, &wa)) @@ -3354,10 +3445,8 @@ horizontal_stack(struct workspace *ws, struct swm_geometry *g) void max_stack(struct workspace *ws, struct swm_geometry *g) { - XWindowChanges wc; struct swm_geometry gg = *g; struct ws_win *win, *wintrans = NULL, *parent = NULL; - unsigned int mask; int winno; DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx); @@ -3388,21 +3477,16 @@ max_stack(struct workspace *ws, struct swm_geometry *g) /* only reconfigure if necessary */ if (X(win) != gg.x || Y(win) != gg.y || WIDTH(win) != gg.w || HEIGHT(win) != gg.h) { - bzero(&wc, sizeof wc); - X(win) = wc.x = gg.x; - Y(win) = wc.y = gg.y; + win->g = gg; if (bar_enabled){ - wc.border_width = border_width; - WIDTH(win) = wc.width = gg.w; - HEIGHT(win) = wc.height = gg.h; + win->bordered = 1; } else { - wc.border_width = 0; - WIDTH(win) = wc.width = gg.w + 2 * border_width; - HEIGHT(win) = wc.height = gg.h + - 2 * border_width; + win->bordered = 0; + WIDTH(win) += 2 * border_width; + HEIGHT(win) += 2 * border_width; } - mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); + + update_window(win); } /* unmap only if we don't have multi screen */ if (win != ws->focus) @@ -3943,8 +4027,8 @@ floating_toggle_win(struct ws_win *win) } else { if (win->g_floatvalid) { /* refloat at last floating relative position */ - X(win) = win->g_float.x - win->rg_float.x + X(r); - Y(win) = win->g_float.y - win->rg_float.y + Y(r); + X(win) = win->g_float.x + X(r); + Y(win) = win->g_float.y + Y(r); WIDTH(win) = win->g_float.w; HEIGHT(win) = win->g_float.h; } @@ -3981,38 +4065,40 @@ floating_toggle(struct swm_region *r, union arg *args) void constrain_window(struct ws_win *win, struct swm_region *r, int resizable) { - if (X(win) + WIDTH(win) > X(r) + WIDTH(r) - border_width) { + if (MAX_X(win) + BORDER(win) > MAX_X(r)) { if (resizable) - WIDTH(win) = X(r) + WIDTH(r) - X(win) - border_width; + WIDTH(win) = MAX_X(r) - X(win) - BORDER(win); else - X(win) = X(r) + WIDTH(r) - WIDTH(win) - border_width; + X(win) = MAX_X(r)- WIDTH(win) - BORDER(win); } - if (X(win) < X(r) - border_width) { + if (X(win) + BORDER(win) < X(r)) { if (resizable) - WIDTH(win) -= X(r) - X(win) - border_width; + WIDTH(win) -= X(r) - X(win) - BORDER(win); - X(win) = X(r) - border_width; + X(win) = X(r) - BORDER(win); } - if (Y(win) + HEIGHT(win) > Y(r) + HEIGHT(r) - border_width) { + if (MAX_Y(win) + BORDER(win) > MAX_Y(r)) { if (resizable) - HEIGHT(win) = Y(r) + HEIGHT(r) - Y(win) - border_width; + HEIGHT(win) = MAX_Y(r) - Y(win) - BORDER(win); else - Y(win) = Y(r) + HEIGHT(r) - HEIGHT(win) - border_width; + Y(win) = MAX_Y(r) - HEIGHT(win) - BORDER(win); } - if (Y(win) < Y(r) - border_width) { + if (Y(win) + BORDER(win) < Y(r)) { if (resizable) - HEIGHT(win) -= Y(r) - Y(win) - border_width; + HEIGHT(win) -= Y(r) - Y(win) - BORDER(win); - Y(win) = Y(r) - border_width; + Y(win) = Y(r) - BORDER(win); } - if (WIDTH(win) < 1) - WIDTH(win) = 1; - if (HEIGHT(win) < 1) - HEIGHT(win) = 1; + if (resizable) { + if (WIDTH(win) < 1) + WIDTH(win) = 1; + if (HEIGHT(win) < 1) + HEIGHT(win) = 1; + } } void @@ -4023,14 +4109,16 @@ update_window(struct ws_win *win) bzero(&wc, sizeof wc); mask = CWBorderWidth | CWWidth | CWHeight | CWX | CWY; - wc.border_width = border_width; + + wc.border_width = BORDER(win); wc.x = X(win); wc.y = Y(win); wc.width = WIDTH(win); wc.height = HEIGHT(win); - DNPRINTF(SWM_D_MISC, "update_window: window: 0x%lx, (x,y) w x h: " - "(%d,%d) %d x %d\n", win->id, wc.x, wc.y, wc.width, wc.height); + DNPRINTF(SWM_D_EVENT, "update_window: window: 0x%lx, (x,y) w x h: " + "(%d,%d) %d x %d, bordered: %s\n", win->id, wc.x, wc.y, wc.width, + wc.height, YESNO(win->bordered)); XConfigureWindow(display, win->id, mask, &wc); } @@ -4057,6 +4145,9 @@ resize(struct ws_win *win, union arg *args) return; r = win->ws->r; + if (win->ewmh_flags & EWMH_F_FULLSCREEN) + return; + DNPRINTF(SWM_D_MOUSE, "resize: window: 0x%lx, floating: %s, " "transient: 0x%lx\n", win->id, YESNO(win->floating), win->transient); @@ -4240,6 +4331,9 @@ move(struct ws_win *win, union arg *args) return; r = win->ws->r; + if (win->ewmh_flags & EWMH_F_FULLSCREEN) + return; + DNPRINTF(SWM_D_MOUSE, "move: window: 0x%lx, floating: %s, transient: " "0x%lx\n", win->id, YESNO(win->floating), win->transient); @@ -4249,7 +4343,7 @@ move(struct ws_win *win, union arg *args) win->manual = 1; if (win->floating == 0 && !win->transient) { - store_float_geom(win,r); + store_float_geom(win, r); ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, _NET_WM_STATE_ADD); } @@ -4323,7 +4417,7 @@ move(struct ws_win *win, union arg *args) XSync(display, False); update_window(win); } - store_float_geom(win,r); + store_float_geom(win, r); XUngrabPointer(display, CurrentTime); /* drain events */ @@ -4363,8 +4457,6 @@ enum keyfuncid { kf_focus_prev, kf_swap_next, kf_swap_prev, - kf_spawn_term, - kf_spawn_menu, kf_quit, kf_restart, kf_focus_main, @@ -4422,12 +4514,8 @@ enum keyfuncid { kf_bar_toggle, kf_wind_kill, kf_wind_del, - kf_screenshot_all, - kf_screenshot_wind, kf_float_toggle, kf_version, - kf_spawn_lock, - kf_spawn_initscr, kf_spawn_custom, kf_iconify, kf_uniconify, @@ -4454,11 +4542,6 @@ dummykeyfunc(struct swm_region *r, union arg *args) { }; -void -legacyfunc(struct swm_region *r, union arg *args) -{ -}; - struct keyfunc { char name[SWM_FUNCNAME_LEN]; void (*func)(struct swm_region *r, union arg *); @@ -4479,8 +4562,6 @@ struct keyfunc { { "focus_prev", focus, {.id = SWM_ARG_ID_FOCUSPREV} }, { "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, { "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, - { "spawn_term", spawnterm, {.argv = spawn_term} }, - { "spawn_menu", legacyfunc, {0} }, { "quit", quit, {0} }, { "restart", restart, {0} }, { "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, @@ -4538,12 +4619,8 @@ struct keyfunc { { "bar_toggle", bar_toggle, {0} }, { "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} }, { "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} }, - { "screenshot_all", legacyfunc, {0} }, - { "screenshot_wind", legacyfunc, {0} }, { "float_toggle", floating_toggle,{0} }, { "version", version, {0} }, - { "spawn_lock", legacyfunc, {0} }, - { "spawn_initscr", legacyfunc, {0} }, { "spawn_custom", dummykeyfunc, {0} }, { "iconify", iconify, {0} }, { "uniconify", uniconify, {0} }, @@ -4588,7 +4665,7 @@ key_cmp(struct key *kp1, struct key *kp2) return (0); } -RB_GENERATE_STATIC(key_tree, key, entry, key_cmp); +RB_GENERATE(key_tree, key, entry, key_cmp); struct key_tree keys; /* mouse */ @@ -4878,6 +4955,7 @@ void setup_spawn(void) { setconfspawn("term", "xterm", 0); + setconfspawn("spawn_term", "xterm", 0); setconfspawn("screenshot_all", "screenshot.sh full", 0); setconfspawn("screenshot_wind", "screenshot.sh window", 0); setconfspawn("lock", "xlock", 0); @@ -5113,7 +5191,7 @@ setup_keys(void) setkeybinding(MODKEY, XK_k, kf_focus_prev, NULL); 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|ShiftMask, XK_Return, kf_spawn_custom,"term"); setkeybinding(MODKEY, XK_p, kf_spawn_custom,"menu"); setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit, NULL); setkeybinding(MODKEY, XK_q, kf_restart, NULL); @@ -5461,18 +5539,39 @@ setup_quirks(void) #define SWM_CONF_FILE "spectrwm.conf" #define SWM_CONF_FILE_OLD "scrotwm.conf" -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_WORKSPACE_LIMIT, - 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_URGENT_ENABLED, SWM_S_FOCUS_MODE, SWM_S_FOCUS_CLOSE, - SWM_S_FOCUS_CLOSE_WRAP, SWM_S_FOCUS_DEFAULT, SWM_S_SPAWN_ORDER, - 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_VERBOSE_LAYOUT, SWM_S_BAR_JUSTIFY, - SWM_S_BAR_FORMAT - }; +enum { + SWM_S_BAR_ACTION, + SWM_S_BAR_AT_BOTTOM, + SWM_S_BAR_BORDER_WIDTH, + SWM_S_BAR_DELAY, + SWM_S_BAR_ENABLED, + SWM_S_BAR_FONT, + SWM_S_BAR_FORMAT, + SWM_S_BAR_JUSTIFY, + SWM_S_BORDER_WIDTH, + SWM_S_CLOCK_ENABLED, + SWM_S_CLOCK_FORMAT, + SWM_S_CYCLE_EMPTY, + SWM_S_CYCLE_VISIBLE, + SWM_S_DIALOG_RATIO, + SWM_S_DISABLE_BORDER, + SWM_S_FOCUS_CLOSE, + SWM_S_FOCUS_CLOSE_WRAP, + SWM_S_FOCUS_DEFAULT, + SWM_S_FOCUS_MODE, + SWM_S_SPAWN_ORDER, + SWM_S_SPAWN_TERM, + SWM_S_SS_APP, + SWM_S_SS_ENABLED, + SWM_S_STACK_ENABLED, + SWM_S_TERM_WIDTH, + SWM_S_TITLE_CLASS_ENABLED, + SWM_S_TITLE_NAME_ENABLED, + SWM_S_URGENT_ENABLED, + SWM_S_VERBOSE_LAYOUT, + SWM_S_WINDOW_NAME_ENABLED, + SWM_S_WORKSPACE_LIMIT +}; int setconfvalue(char *selector, char *value, int flags) @@ -5481,17 +5580,37 @@ setconfvalue(char *selector, char *value, int flags) char *b; switch (flags) { + case SWM_S_BAR_ACTION: + free(bar_argv[0]); + if ((bar_argv[0] = strdup(value)) == NULL) + err(1, "setconfvalue: bar_action"); + break; + case SWM_S_BAR_AT_BOTTOM: + bar_at_bottom = atoi(value); + break; + case SWM_S_BAR_BORDER_WIDTH: + bar_border_width = atoi(value); + if (bar_border_width < 0) + bar_border_width = 0; + break; case SWM_S_BAR_DELAY: bar_delay = atoi(value); break; case SWM_S_BAR_ENABLED: bar_enabled = atoi(value); break; - case SWM_S_BAR_BORDER_WIDTH: - bar_border_width = atoi(value); + case SWM_S_BAR_FONT: + b = bar_fonts; + if (asprintf(&bar_fonts, "%s,%s", value, bar_fonts) == -1) + err(1, "setconfvalue: asprintf: failed to allocate " + "memory for bar_fonts."); + + free(b); break; - case SWM_S_BAR_AT_BOTTOM: - bar_at_bottom = atoi(value); + case SWM_S_BAR_FORMAT: + free(bar_format); + if ((bar_format = strdup(value)) == NULL) + err(1, "setconfvalue: bar_format"); break; case SWM_S_BAR_JUSTIFY: if (!strcmp(value, "left")) @@ -5503,13 +5622,10 @@ setconfvalue(char *selector, char *value, int flags) else errx(1, "invalid bar_justify"); break; - case SWM_S_BAR_FORMAT: - free(bar_format); - if ((bar_format = strdup(value)) == NULL) - err(1, "setconfvalue: bar_format"); - break; - case SWM_S_STACK_ENABLED: - stack_enabled = atoi(value); + case SWM_S_BORDER_WIDTH: + border_width = atoi(value); + if (border_width < 0) + border_width = 0; break; case SWM_S_CLOCK_ENABLED: clock_enabled = atoi(value); @@ -5527,40 +5643,13 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_CYCLE_VISIBLE: cycle_visible = atoi(value); break; - case SWM_S_WORKSPACE_LIMIT: - workspace_limit = atoi(value); - if (workspace_limit > SWM_WS_MAX) - workspace_limit = SWM_WS_MAX; - else if (workspace_limit < 1) - workspace_limit = 1; - break; - case SWM_S_SS_ENABLED: - ss_enabled = atoi(value); - break; - case SWM_S_TERM_WIDTH: - term_width = atoi(value); - break; - 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; - case SWM_S_URGENT_ENABLED: - urgent_enabled = atoi(value); + case SWM_S_DIALOG_RATIO: + dialog_ratio = atof(value); + if (dialog_ratio > 1.0 || dialog_ratio <= .3) + dialog_ratio = .6; break; - case SWM_S_FOCUS_MODE: - if (!strcmp(value, "default")) - focus_mode = SWM_FOCUS_DEFAULT; - else if (!strcmp(value, "follow_cursor")) - focus_mode = SWM_FOCUS_FOLLOW; - else if (!strcmp(value, "synergy")) - focus_mode = SWM_FOCUS_SYNERGY; - else - errx(1, "focus_mode"); + case SWM_S_DISABLE_BORDER: + disable_border = atoi(value); break; case SWM_S_FOCUS_CLOSE: if (!strcmp(value, "first")) @@ -5585,6 +5674,16 @@ setconfvalue(char *selector, char *value, int flags) else errx(1, "focus_default"); break; + case SWM_S_FOCUS_MODE: + if (!strcmp(value, "default")) + focus_mode = SWM_FOCUS_DEFAULT; + else if (!strcmp(value, "follow_cursor")) + focus_mode = SWM_FOCUS_FOLLOW; + else if (!strcmp(value, "synergy")) + focus_mode = SWM_FOCUS_SYNERGY; + else + errx(1, "focus_mode"); + break; case SWM_S_SPAWN_ORDER: if (!strcmp(value, "first")) spawn_position = SWM_STACK_BOTTOM; @@ -5597,36 +5696,31 @@ setconfvalue(char *selector, char *value, int flags) else errx(1, "spawn_position"); break; - case SWM_S_DISABLE_BORDER: - disable_border = atoi(value); + case SWM_S_SPAWN_TERM: + setconfspawn("term", value, 0); + setconfspawn("spawn_term", value, 0); break; - case SWM_S_BORDER_WIDTH: - border_width = atoi(value); + case SWM_S_SS_APP: break; - case SWM_S_BAR_FONT: - b = bar_fonts; - if (asprintf(&bar_fonts, "%s,%s", value, bar_fonts) == -1) - err(1, "setconfvalue: asprintf: failed to allocate " - "memory for bar_fonts."); - - free(b); + case SWM_S_SS_ENABLED: + ss_enabled = atoi(value); break; - case SWM_S_BAR_ACTION: - free(bar_argv[0]); - if ((bar_argv[0] = strdup(value)) == NULL) - err(1, "setconfvalue: bar_action"); + case SWM_S_STACK_ENABLED: + stack_enabled = atoi(value); break; - case SWM_S_SPAWN_TERM: - free(spawn_term[0]); - if ((spawn_term[0] = strdup(value)) == NULL) - err(1, "setconfvalue: spawn_term"); + case SWM_S_TERM_WIDTH: + term_width = atoi(value); + if (term_width < 0) + term_width = 0; break; - case SWM_S_SS_APP: + case SWM_S_TITLE_CLASS_ENABLED: + title_class_enabled = atoi(value); break; - case SWM_S_DIALOG_RATIO: - dialog_ratio = atof(value); - if (dialog_ratio > 1.0 || dialog_ratio <= .3) - dialog_ratio = .6; + 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_VERBOSE_LAYOUT: verbose_layout = atoi(value); @@ -5637,6 +5731,16 @@ setconfvalue(char *selector, char *value, int flags) layouts[i].l_string = plain_stacker; } break; + case SWM_S_WINDOW_NAME_ENABLED: + window_name_enabled = atoi(value); + break; + case SWM_S_WORKSPACE_LIMIT: + workspace_limit = atoi(value); + if (workspace_limit > SWM_WS_MAX) + workspace_limit = SWM_WS_MAX; + else if (workspace_limit < 1) + workspace_limit = 1; + break; default: return (1); } @@ -5741,7 +5845,7 @@ setautorun(char *selector, char *value, int flags) int setlayout(char *selector, char *value, int flags) { - int ws_id, i, x, mg, ma, si, raise; + int ws_id, i, x, mg, ma, si, raise, f = 0; int st = SWM_V_STACK; char s[1024]; struct workspace *ws; @@ -5761,9 +5865,15 @@ setlayout(char *selector, char *value, int flags) if (!strcasecmp(s, "vertical")) st = SWM_V_STACK; - else if (!strcasecmp(s, "horizontal")) + else if (!strcasecmp(s, "vertical_flip")) { + st = SWM_V_STACK; + f = 1; + } else if (!strcasecmp(s, "horizontal")) + st = SWM_H_STACK; + else if (!strcasecmp(s, "horizontal_flip")) { st = SWM_H_STACK; - else if (!strcasecmp(s, "fullscreen")) + f = 1; + } else if (!strcasecmp(s, "fullscreen")) st = SWM_MAX_STACK; else errx(1, "invalid layout entry, should be 'ws[]:" @@ -5799,6 +5909,12 @@ setlayout(char *selector, char *value, int flags) SWM_ARG_ID_STACKDEC); stack(); } + /* Apply flip */ + if (f) { + ws[ws_id].cur_layout->l_config(&ws[ws_id], + SWM_ARG_ID_FLIPLAYOUT); + stack(); + } } return (0); @@ -6076,9 +6192,7 @@ manage_window(Window id) Atom *prot = NULL, *pp; unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL; struct swm_region *r; - long mask = 0; const char *errstr; - XWindowChanges wc; struct pid_e *p; struct quirk *qp; @@ -6120,6 +6234,7 @@ manage_window(Window id) "new window"); win->id = id; + win->bordered = 0; /* see if we need to override the workspace */ p = find_pid(window_get_pid(id)); @@ -6202,14 +6317,22 @@ manage_window(Window id) else TAILQ_INSERT_TAIL(&ws->winlist, win, entry); + /* ignore window border if there is one. */ WIDTH(win) = win->wa.width; HEIGHT(win) = win->wa.height; - X(win) = win->wa.x; - Y(win) = win->wa.y; + X(win) = win->wa.x + win->wa.border_width; + Y(win) = win->wa.y + win->wa.border_width; + win->bordered = 0; win->g_floatvalid = 0; win->floatmaxed = 0; win->ewmh_flags = 0; + DNPRINTF(SWM_D_MISC, "manage_window: window: 0x%lx, (x,y) w x h: " + "(%d,%d) %d x %d, ws: %d\n", win->id, X(win), Y(win), WIDTH(win), + HEIGHT(win), ws->idx); + + constrain_window(win, r, 0); + /* Set window properties so we can remember this after reincarnation */ if (ws_idx_atom && prop == NULL && snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < @@ -6252,16 +6375,10 @@ manage_window(Window id) /* alter window position if quirky */ if (win->quirks & SWM_Q_ANYWHERE) { win->manual = 1; /* don't center the quirky windows */ - bzero(&wc, sizeof wc); - mask = 0; - if (bar_enabled && Y(win) < bar_height) { - Y(win) = wc.y = bar_height; - mask |= CWY; - } - if (WIDTH(win) + X(win) > WIDTH(r)) { - X(win) = wc.x = WIDTH(r) - WIDTH(win) - 2; - mask |= CWX; - } + if (bar_enabled && Y(win) < bar_height) + Y(win) = bar_height; + if (WIDTH(win) + X(win) > WIDTH(r)) + X(win) = WIDTH(r) - WIDTH(win) - 2; border_me = 1; } @@ -6279,10 +6396,10 @@ manage_window(Window id) /* border me */ if (border_me) { - bzero(&wc, sizeof wc); - wc.border_width = border_width; - mask |= CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); + win->bordered = 1; + X(win) -= border_width; + Y(win) -= border_width; + update_window(win); } XSelectInput(display, id, EnterWindowMask | FocusChangeMask | @@ -6448,9 +6565,6 @@ configurerequest(XEvent *e) if ((win = find_unmanaged_window(ev->window)) == NULL) new = 1; - DNPRINTF(SWM_D_EVENT, "configurerequest: window: 0x%lx, new: %s\n", - ev->window, YESNO(new)); - if (new) { bzero(&wc, sizeof wc); wc.x = ev->x; @@ -6460,9 +6574,31 @@ configurerequest(XEvent *e) wc.border_width = ev->border_width; wc.sibling = ev->above; wc.stack_mode = ev->detail; + + DNPRINTF(SWM_D_EVENT, "configurerequest: new window: 0x%lx, " + "new: %s, (x,y) w x h: (%d,%d) %d x %d\n", ev->window, + YESNO(new), wc.x, wc.y, wc.width, wc.height); + XConfigureWindow(display, ev->window, ev->value_mask, &wc); - } else + } else if ((!win->manual || win->quirks & SWM_Q_ANYWHERE) && + !(win->sh_mask & EWMH_F_FULLSCREEN)) { + win->g_float.x = ev->x - X(win->ws->r); + win->g_float.y = ev->y - Y(win->ws->r); + win->g_float.w = ev->width; + win->g_float.h = ev->height; + win->g_floatvalid = 1; + + if (win->floating) { + win->g = win->g_float; + win->g.x += X(win->ws->r); + win->g.y += Y(win->ws->r); + update_window(win); + } else { + config_win(win, ev); + } + } else { config_win(win, ev); + } } void @@ -6826,7 +6962,7 @@ visibilitynotify(XEvent *e) if (e->xvisibility.state == VisibilityUnobscured) for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) - if (e->xvisibility.window == r->bar_window) + if (e->xvisibility.window == WINID(r->bar)) bar_update(); } @@ -6942,7 +7078,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h) if (r->ws->r != NULL) r->ws->old_r = r->ws->r; r->ws->r = NULL; - XDestroyWindow(display, r->bar_window); + bar_cleanup(r); TAILQ_REMOVE(&s->rl, r, entry); TAILQ_INSERT_TAIL(&s->orl, r, entry); } @@ -7013,7 +7149,7 @@ scan_xrandr(int i) /* remove any old regions */ while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) { r->ws->old_r = r->ws->r = NULL; - XDestroyWindow(display, r->bar_window); + bar_cleanup(r); TAILQ_REMOVE(&screens[i].rl, r, entry); TAILQ_INSERT_TAIL(&screens[i].orl, r, entry); } @@ -7164,12 +7300,10 @@ setup_screens(void) setscreencolor("black", i + 1, SWM_S_COLOR_BAR); setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT); - /* create graphics context on screen with default font color */ - screens[i].bar_gc = XCreateGC(display, screens[i].root, 0, - &gcv); - - XSetForeground(display, screens[i].bar_gc, - screens[i].c[SWM_S_COLOR_BAR_FONT].color); + /* create graphics context on screen */ + gcv.graphics_exposures = 0; + screens[i].bar_gc = XCreateGC(display, screens[i].root, + GCGraphicsExposures, &gcv); /* set default cursor */ XDefineCursor(display, screens[i].root, @@ -7209,9 +7343,6 @@ setup_globals(void) if ((bar_fonts = strdup(SWM_BAR_FONTS)) == NULL) err(1, "setup_globals: strdup: failed to allocate memory."); - if ((spawn_term[0] = strdup("xterm")) == NULL) - err(1, "setup_globals: strdup: failed to allocate memory."); - if ((clock_format = strdup("%a %b %d %R %Z %Y")) == NULL) err(1, "setup_globals: strdup: failed to allocate memory."); } @@ -7342,11 +7473,9 @@ main(int argc, char *argv[]) } noconfig: - /* load conf (if any) and refresh font color in bar graphics contexts */ - if (cfile && conf_load(cfile, SWM_CONF_DEFAULT) == 0) - for (i = 0; i < ScreenCount(display); ++i) - XSetForeground(display, screens[i].bar_gc, - screens[i].c[SWM_S_COLOR_BAR_FONT].color); + /* load conf (if any) */ + if (cfile) + conf_load(cfile, SWM_CONF_DEFAULT); setup_ewmh(); /* set some values to work around bad programs */