X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=83b31a0ebc46c4995f6b3105f52ee47c0c3c38e6;hb=80b6156fc1d5c45c65f9c7987acaaf53846b2984;hp=f4b0fa59b0887cd25f6c4443e810ac862cb9d7ab;hpb=db56f5244f02caf93455c69375bd14373011bc58;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index f4b0fa5..83b31a0 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -186,7 +186,7 @@ static const char *buildstr = SPECTRWM_VERSION; #define SWM_D_BAR 0x4000 #define SWM_D_INIT 0x8000 -u_int32_t swm_debug = 0 +uint32_t swm_debug = 0 | SWM_D_MISC | SWM_D_EVENT | SWM_D_WS @@ -415,6 +415,7 @@ int disable_border = 0; int border_width = 1; int region_padding = 0; int tile_gap = 0; +int java_workaround = 1; int verbose_layout = 0; time_t time_started; pid_t bar_pid; @@ -466,7 +467,7 @@ struct ws_win { struct swm_geometry g; /* current geometry */ struct swm_geometry g_float; /* region coordinates */ int g_floatvalid; /* g_float geometry validity */ - int32_t mapped; + int mapped; int bordered; uint32_t ewmh_flags; int font_size_boundary[SWM_MAX_FONT_STEPS]; @@ -507,7 +508,7 @@ void fancy_stacker(struct workspace *); struct layout { void (*l_stack)(struct workspace *, struct swm_geometry *); void (*l_config)(struct workspace *, int); - u_int32_t flags; + uint32_t flags; #define SWM_L_FOCUSPREV (1<<0) #define SWM_L_MAPONFOCUS (1<<1) void (*l_string)(struct workspace *); @@ -543,7 +544,7 @@ struct workspace { struct ws_win_list winlist; /* list of windows in ws */ struct ws_win_list unmanagedlist; /* list of dead windows in ws */ struct ws_win_stack stack; /* stacking order */ - int32_t state; /* mapping state */ + int state; /* mapping state */ char stacker[10]; /* display stacker and layout */ /* stacker state */ @@ -640,6 +641,8 @@ union arg { #define SWM_ARG_ID_MOVEDOWN (101) #define SWM_ARG_ID_MOVELEFT (102) #define SWM_ARG_ID_MOVERIGHT (103) +#define SWM_ARG_ID_RAISE (105) +#define SWM_ARG_ID_LOWER (106) #define SWM_ARG_ID_BAR_TOGGLE (110) #define SWM_ARG_ID_BAR_TOGGLE_WS (111) char **argv; @@ -676,8 +679,12 @@ enum { _NET_CLIENT_LIST, _NET_CLOSE_WINDOW, _NET_CURRENT_DESKTOP, + _NET_DESKTOP_GEOMETRY, _NET_DESKTOP_NAMES, + _NET_DESKTOP_VIEWPORT, _NET_MOVERESIZE_WINDOW, + _NET_NUMBER_OF_DESKTOPS, + _NET_RESTACK_WINDOW, _NET_WM_ACTION_ABOVE, _NET_WM_ACTION_CLOSE, _NET_WM_ACTION_FULLSCREEN, @@ -687,7 +694,6 @@ enum { _NET_WM_DESKTOP, _NET_WM_FULL_PLACEMENT, _NET_WM_NAME, - _NET_NUMBER_OF_DESKTOPS, _NET_WM_STATE, _NET_WM_STATE_ABOVE, _NET_WM_STATE_FULLSCREEN, @@ -716,8 +722,12 @@ struct ewmh_hint { {"_NET_CLIENT_LIST", XCB_ATOM_NONE}, {"_NET_CLOSE_WINDOW", XCB_ATOM_NONE}, {"_NET_CURRENT_DESKTOP", XCB_ATOM_NONE}, + {"_NET_DESKTOP_GEOMETRY", XCB_ATOM_NONE}, {"_NET_DESKTOP_NAMES", XCB_ATOM_NONE}, + {"_NET_DESKTOP_VIEWPORT", XCB_ATOM_NONE}, {"_NET_MOVERESIZE_WINDOW", XCB_ATOM_NONE}, + {"_NET_NUMBER_OF_DESKTOPS", XCB_ATOM_NONE}, + {"_NET_RESTACK_WINDOW", XCB_ATOM_NONE}, {"_NET_WM_ACTION_ABOVE", XCB_ATOM_NONE}, {"_NET_WM_ACTION_CLOSE", XCB_ATOM_NONE}, {"_NET_WM_ACTION_FULLSCREEN", XCB_ATOM_NONE}, @@ -727,7 +737,6 @@ struct ewmh_hint { {"_NET_WM_DESKTOP", XCB_ATOM_NONE}, {"_NET_WM_FULL_PLACEMENT", XCB_ATOM_NONE}, {"_NET_WM_NAME", XCB_ATOM_NONE}, - {"_NET_NUMBER_OF_DESKTOPS", XCB_ATOM_NONE}, {"_NET_WM_STATE", XCB_ATOM_NONE}, {"_NET_WM_STATE_ABOVE", XCB_ATOM_NONE}, {"_NET_WM_STATE_FULLSCREEN", XCB_ATOM_NONE}, @@ -979,6 +988,7 @@ void ewmh_update_actions(struct ws_win *); void ewmh_update_client_list(void); void ewmh_update_current_desktop(void); void ewmh_update_desktop_names(void); +void ewmh_update_desktops(void); void ewmh_change_wm_state(struct ws_win *, xcb_atom_t, long); void ewmh_update_wm_state(struct ws_win *); char *expand_tilde(const char *); @@ -1019,9 +1029,9 @@ char *get_stack_mode_name(uint8_t); #endif int32_t get_swm_ws(xcb_window_t); char *get_win_name(xcb_window_t); +uint8_t get_win_state(xcb_window_t); void get_wm_protocols(struct ws_win *); int get_ws_idx(xcb_window_t); -uint32_t getstate(xcb_window_t); void grabbuttons(struct ws_win *); void grabkeys(void); void grab_windows(void); @@ -1040,7 +1050,7 @@ void kill_refs(struct ws_win *); void leavenotify(xcb_leave_notify_event_t *); #endif void load_float_geom(struct ws_win *); -struct ws_win *manage_window(xcb_window_t, uint16_t); +struct ws_win *manage_window(xcb_window_t, int); void map_window(struct ws_win *); void mapnotify(xcb_map_notify_event_t *); void mappingnotify(xcb_mapping_notify_event_t *); @@ -1110,7 +1120,7 @@ void setup_quirks(void); void setup_screens(void); void setup_spawn(void); void set_child_transient(struct ws_win *, xcb_window_t *); -void set_win_state(struct ws_win *, uint16_t); +void set_win_state(struct ws_win *, uint8_t); void shutdown_cleanup(void); void sighdlr(int); void socket_setnonblock(int); @@ -1150,7 +1160,6 @@ void version(struct swm_region *, union arg *); void win_to_ws(struct ws_win *, int, int); pid_t window_get_pid(xcb_window_t); void wkill(struct swm_region *, union arg *); -void workaround(void); void update_ws_stack(struct workspace *); void xft_init(struct swm_region *); void _add_startup_exception(const char *, va_list); @@ -1362,27 +1371,51 @@ get_wm_protocols(struct ws_win *win) { void setup_ewmh(void) { + xcb_window_t root, win; int i, j, num_screens; - for (i = 0; i < LENGTH(ewmh); i++) ewmh[i].atom = get_atom_from_string(ewmh[i].name); num_screens = get_screen_count(); for (i = 0; i < num_screens; i++) { - /* Support check window will be created by workaround(). */ + root = screens[i].root; + + /* Set up _NET_SUPPORTING_WM_CHECK. */ + win = xcb_generate_id(conn); + xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, root, + 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, 0, NULL); + + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, + a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, + a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win); + + /* + * Impersonate LG3D non-reparenting WM, written by Sun, to + * workaround a Java GUI rendering issue. + */ + if (java_workaround) + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, + ewmh[_NET_WM_NAME].atom, a_utf8_string, + 8, strlen("LG3D"), "LG3D"); + else + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, + ewmh[_NET_WM_NAME].atom, a_utf8_string, + 8, strlen("spectrwm"), "spectrwm"); /* Report supported atoms */ - xcb_delete_property(conn, screens[i].root, a_net_supported); + xcb_delete_property(conn, root, a_net_supported); for (j = 0; j < LENGTH(ewmh); j++) - xcb_change_property(conn, XCB_PROP_MODE_APPEND, - screens[i].root, a_net_supported, XCB_ATOM_ATOM, - 32, 1, &ewmh[j].atom); + xcb_change_property(conn, XCB_PROP_MODE_APPEND, root, + a_net_supported, XCB_ATOM_ATOM, 32, 1, + &ewmh[j].atom); - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, - screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom, - XCB_ATOM_CARDINAL, 32, 1, &workspace_limit); } + + ewmh_update_desktops(); + ewmh_get_desktop_names(); } void @@ -1418,10 +1451,10 @@ teardown_ewmh(void) void ewmh_autoquirk(struct ws_win *win) { - uint32_t i, n; - xcb_atom_t *type; - xcb_get_property_cookie_t c; xcb_get_property_reply_t *r; + xcb_get_property_cookie_t c; + xcb_atom_t *type; + int i, n; c = xcb_get_property(conn, 0, win->id, ewmh[_NET_WM_WINDOW_TYPE].atom, XCB_ATOM_ATOM, 0, UINT32_MAX); @@ -1683,7 +1716,7 @@ ewmh_get_wm_state(struct ws_win *win) void dumpwins(struct swm_region *r, union arg *args) { - struct ws_win *win; + struct ws_win *w; uint32_t state; xcb_get_window_attributes_cookie_t c; xcb_get_window_attributes_reply_t *wa; @@ -1697,33 +1730,40 @@ dumpwins(struct swm_region *r, union arg *args) } DPRINTF("=== managed window list ws %02d ===\n", r->ws->idx); - TAILQ_FOREACH(win, &r->ws->winlist, entry) { - state = getstate(win->id); - c = xcb_get_window_attributes(conn, win->id); + TAILQ_FOREACH(w, &r->ws->winlist, entry) { + state = get_win_state(w->id); + c = xcb_get_window_attributes(conn, w->id); wa = xcb_get_window_attributes_reply(conn, c, NULL); if (wa) { DPRINTF("win %#x, map_state: %d, state: %u, " - "transient: %#x\n", win->id, wa->map_state, - state, win->transient); + "transient: %#x\n", w->id, wa->map_state, + state, w->transient); free(wa); } else DPRINTF("win %#x, failed xcb_get_window_attributes\n", - win->id); + w->id); + } + + DPRINTF("=== stacking order (top down) === \n"); + TAILQ_FOREACH(w, &r->ws->stack, stack_entry) { + DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, " + "iconic: %s\n", w->id, YESNO(FULLSCREEN(w)), + YESNO(MAXIMIZED(w)), YESNO(ABOVE(w)), YESNO(ICONIC(w))); } DPRINTF("===== unmanaged window list =====\n"); - TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) { - state = getstate(win->id); - c = xcb_get_window_attributes(conn, win->id); + TAILQ_FOREACH(w, &r->ws->unmanagedlist, entry) { + state = get_win_state(w->id); + c = xcb_get_window_attributes(conn, w->id); wa = xcb_get_window_attributes_reply(conn, c, NULL); if (wa) { DPRINTF("win %#x, map_state: %d, state: %u, " - "transient: %#x\n", win->id, wa->map_state, - state, win->transient); + "transient: %#x\n", w->id, wa->map_state, + state, w->transient); free(wa); } else DPRINTF("win %#x, failed xcb_get_window_attributes\n", - win->id); + w->id); } DPRINTF("=================================\n"); @@ -2755,7 +2795,7 @@ bar_cleanup(struct swm_region *r) } void -set_win_state(struct ws_win *win, uint16_t state) +set_win_state(struct ws_win *win, uint8_t state) { uint16_t data[2] = { state, XCB_ATOM_NONE }; @@ -2769,12 +2809,12 @@ set_win_state(struct ws_win *win, uint16_t state) a_state, 32, 2, data); } -uint32_t -getstate(xcb_window_t w) +uint8_t +get_win_state(xcb_window_t w) { - uint32_t result = 0; - xcb_get_property_cookie_t c; xcb_get_property_reply_t *r; + xcb_get_property_cookie_t c; + uint32_t result = 0; c = xcb_get_property(conn, 0, w, a_state, a_state, 0L, 2L); r = xcb_get_property_reply(conn, c, NULL); @@ -2784,7 +2824,7 @@ getstate(xcb_window_t w) free(r); } - DNPRINTF(SWM_D_MISC, "getstate property: win %#x state %u\n", w, + DNPRINTF(SWM_D_MISC, "get_win_state property: win %#x state %u\n", w, result); return (result); } @@ -2965,6 +3005,9 @@ raise_window(struct ws_win *win) continue; if (ws->cur_layout == &layouts[SWM_MAX_STACK]) break; + if (TRANS(win) && (win->transient == target->transient || + win->transient == target->id)) + break; if (FULLSCREEN(win)) break; if (FULLSCREEN(target)) @@ -2986,6 +3029,17 @@ raise_window(struct ws_win *win) update_win_stacking(win); } +#ifdef SWM_DEBUG + if (swm_debug & SWM_D_STACK) { + DPRINTF("=== stacking order (top down) === \n"); + TAILQ_FOREACH(target, &r->ws->stack, stack_entry) { + DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, " + "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)), + YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)), + YESNO(ICONIC(target))); + } + } +#endif DNPRINTF(SWM_D_EVENT, "raise_window: done\n"); } @@ -3415,7 +3469,7 @@ unfocus_win(struct ws_win *win) } xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL, - &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel); + &win->s->c[SWM_S_COLOR_UNFOCUS].pixel); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none); @@ -3459,7 +3513,7 @@ focus_win(struct ws_win *win) /* Change border to unfocused color. */ xcb_change_window_attributes(conn, cfw->id, XCB_CW_BORDER_PIXEL, - &cfw->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel); + &cfw->s->c[SWM_S_COLOR_UNFOCUS].pixel); } else { unfocus_win(cfw); } @@ -3506,7 +3560,7 @@ focus_win(struct ws_win *win) } xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL, - &ws->r->s->c[SWM_S_COLOR_FOCUS].pixel); + &win->s->c[SWM_S_COLOR_FOCUS].pixel); if (ws->cur_layout->flags & SWM_L_MAPONFOCUS || ws->always_raise) { @@ -3605,13 +3659,14 @@ void set_region(struct swm_region *r) { struct swm_region *rf; + int vals[2]; if (r == NULL) return; rf = r->s->r_focus; /* Unfocus old region bar. */ - if (rf) { + if (rf != NULL) { if (rf == r) return; @@ -3620,6 +3675,16 @@ set_region(struct swm_region *r) &r->s->c[SWM_S_COLOR_BAR_BORDER_UNFOCUS].pixel); } + if (rf != NULL && rf != r && (X(rf) != X(r) || Y(rf) != Y(r) || + WIDTH(rf) != WIDTH(r) || HEIGHT(rf) != HEIGHT(r))) { + /* Set _NET_DESKTOP_GEOMETRY. */ + vals[0] = WIDTH(r); + vals[1] = HEIGHT(r); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, r->s->root, + ewmh[_NET_DESKTOP_GEOMETRY].atom, XCB_ATOM_CARDINAL, 32, 2, + &vals); + } + /* Set region bar border to focus_color. */ xcb_change_window_attributes(conn, r->bar->id, XCB_CW_BORDER_PIXEL, &r->s->c[SWM_S_COLOR_BAR_BORDER].pixel); @@ -3686,7 +3751,7 @@ switchws(struct swm_region *r, union arg *args) if ((win = old_ws->focus) != NULL) { xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL, - &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel); + &win->s->c[SWM_S_COLOR_UNFOCUS].pixel); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, @@ -3914,9 +3979,39 @@ swapwin(struct swm_region *r, union arg *args) args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); cur_focus = r->ws->focus; - if (cur_focus == NULL || ABOVE(cur_focus) || FULLSCREEN(cur_focus)) + if (cur_focus == NULL || FULLSCREEN(cur_focus)) return; + /* Adjust stacking in floating layer. */ + if (ABOVE(cur_focus)) { + switch (args->id) { + case SWM_ARG_ID_SWAPPREV: + target = TAILQ_PREV(cur_focus, ws_win_stack, + stack_entry); + if (target != NULL && FLOATING(target)) { + TAILQ_REMOVE(&cur_focus->ws->stack, cur_focus, + stack_entry); + TAILQ_INSERT_BEFORE(target, cur_focus, + stack_entry); + update_win_stacking(cur_focus); + focus_flush(); + } + break; + case SWM_ARG_ID_SWAPNEXT: + target = TAILQ_NEXT(cur_focus, stack_entry); + if (target != NULL && FLOATING(target)) { + TAILQ_REMOVE(&cur_focus->ws->stack, cur_focus, + stack_entry); + TAILQ_INSERT_AFTER(&cur_focus->ws->stack, + target, cur_focus, stack_entry); + update_win_stacking(cur_focus); + focus_flush(); + } + break; + } + goto out; + } + if (r->ws->cur_layout == &layouts[SWM_MAX_STACK]) return; @@ -3976,12 +4071,12 @@ swapwin(struct swm_region *r, union arg *args) } sort_windows(wl); - ewmh_update_client_list(); stack(); - focus_flush(); +out: + DNPRINTF(SWM_D_MOVE, "swapwin: done\n"); } struct ws_win * @@ -4826,7 +4921,10 @@ max_stack(struct workspace *ws, struct swm_geometry *g) else win = TAILQ_FIRST(&ws->winlist); - DNPRINTF(SWM_D_STACK, "max_stack: win: %#x\n", win->id); + DNPRINTF(SWM_D_STACK, "max_stack: focus_pending: %#x, focus: %#x, " + "focus_prev: %#x, first: %#x, win: %#x\n", WINID(ws->focus_pending), + WINID(ws->focus), WINID(ws->focus_prev), + WINID(TAILQ_FIRST(&ws->winlist)), win->id); /* Update window geometry. */ TAILQ_FOREACH(w, &ws->winlist, entry) { @@ -4928,6 +5026,7 @@ region_under(struct swm_screen *s, int x, int y) return (NULL); } +/* Transfer focused window to target workspace and focus. */ void send_to_ws(struct swm_region *r, union arg *args) { @@ -4941,7 +5040,7 @@ send_to_ws(struct swm_region *r, union arg *args) DNPRINTF(SWM_D_MOVE, "send_to_ws: win %#x, ws %d\n", win->id, wsid); - if (wsid >= workspace_limit) + if (wsid < 0 || wsid >= workspace_limit) return; if (win->ws->idx == wsid) @@ -4949,20 +5048,34 @@ send_to_ws(struct swm_region *r, union arg *args) win_to_ws(win, wsid, 1); + /* Set window to be focus on target ws. */ + if (focus_mode != SWM_FOCUS_FOLLOW) { + win->ws->focus = win; + win->ws->focus_pending = NULL; + } + + DNPRINTF(SWM_D_STACK, "send_to_ws: focus_pending: %#x, focus: %#x, " + "focus_prev: %#x, first: %#x, win: %#x\n", + WINID(r->ws->focus_pending), WINID(r->ws->focus), + WINID(r->ws->focus_prev), WINID(TAILQ_FIRST(&r->ws->winlist)), + win->id); + ewmh_apply_flags(win, win->ewmh_flags & ~EWMH_F_MAXIMIZED); ewmh_update_wm_state(win); /* Restack and set new focus. */ + if (FLOATING(win)) + load_float_geom(win); + stack(); if (focus_mode != SWM_FOCUS_FOLLOW) { - if (r->ws->focus_pending) { - focus_win(r->ws->focus_pending); - r->ws->focus_pending = NULL; + if (r->ws->focus != NULL) { + focus_win(r->ws->focus); } else { - xcb_set_input_focus(conn, - XCB_INPUT_FOCUS_PARENT, r->id, + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id, XCB_CURRENT_TIME); + bar_draw(); } } @@ -4975,7 +5088,7 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus) struct ws_win *parent; struct workspace *ws, *nws, *pws; - if (wsid >= workspace_limit) + if (wsid < 0 || wsid >= workspace_limit) return; if (win->ws->idx == wsid) @@ -4987,7 +5100,9 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus) DNPRINTF(SWM_D_MOVE, "win_to_ws: win %#x, ws %d -> %d\n", win->id, ws->idx, wsid); - if (focus_mode != SWM_FOCUS_FOLLOW) + /* Cleanup focus on source ws. */ + if (focus_mode != SWM_FOCUS_FOLLOW && + (ws->focus == win || ws->focus_pending == win)) ws->focus_pending = get_focus_prev(win); /* Move the parent if this is a transient window. */ @@ -5031,6 +5146,14 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus) if (unfocus) unfocus_win(win); + if (ws->focus_prev == win) + ws->focus_prev = NULL; + + if (focus_mode != SWM_FOCUS_FOLLOW && ws->focus_pending != NULL) { + ws->focus = ws->focus_pending; + ws->focus_pending = NULL; + } + /* Don't unmap if new ws is visible */ if (nws->r == NULL) unmap_window(win); @@ -5042,10 +5165,6 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus) TAILQ_INSERT_TAIL(&nws->stack, win, stack_entry); win->ws = nws; - /* Set focus on new ws. */ - unfocus_win(nws->focus); - nws->focus = win; - /* Update the window's workspace property: _NET_WM_DESKTOP */ DNPRINTF(SWM_D_PROP, "win_to_ws: set property: " "_NET_WM_DESKTOP: %d\n", wsid); @@ -5549,6 +5668,43 @@ ewmh_update_current_desktop(void) } void +ewmh_update_desktops(void) +{ + int num_screens, i, j; + uint32_t *vals; + + vals = calloc(sizeof(uint32_t), workspace_limit * 2); + if (vals == NULL) + err(1, "ewmh_update_desktops: calloc: failed to allocate " + "memory."); + + num_screens = get_screen_count(); + for (i = 0; i < num_screens; i++) { + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, + screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom, + XCB_ATOM_CARDINAL, 32, 1, &workspace_limit); + + for (j = 0; j < workspace_limit; ++j) { + if (screens[i].ws[j].r != NULL) { + vals[j * 2] = X(screens[i].ws[j].r); + vals[j * 2 + 1] = Y(screens[i].ws[j].r); + } else if (screens[i].ws[j].old_r != NULL) { + vals[j * 2] = X(screens[i].ws[j].old_r); + vals[j * 2 + 1] = Y(screens[i].ws[j].old_r); + } else { + vals[j * 2] = vals[j * 2 + 1] = 0; + } + } + + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, + screens[i].root, ewmh[_NET_DESKTOP_VIEWPORT].atom, + XCB_ATOM_CARDINAL, 32, workspace_limit * 2, vals); + } + + free(vals); +} + +void search_resp_search_workspace(const char *resp) { char *p, *q; @@ -5740,26 +5896,32 @@ maximize_toggle(struct swm_region *r, union arg *args) void floating_toggle(struct swm_region *r, union arg *args) { - struct ws_win *win = r->ws->focus; + struct ws_win *w = r->ws->focus; /* suppress unused warning since var is needed */ (void)args; - if (win == NULL) + if (w == NULL) return; - if (FULLSCREEN(win) || TRANS(win)) + DNPRINTF(SWM_D_MISC, "floating_toggle: win %#x\n", w->id); + + if (FULLSCREEN(w) || TRANS(w)) return; - ewmh_apply_flags(win, win->ewmh_flags ^ EWMH_F_ABOVE); - ewmh_update_wm_state(win); + if (w->ws->cur_layout == &layouts[SWM_MAX_STACK]) + return; + + ewmh_apply_flags(w, w->ewmh_flags ^ EWMH_F_ABOVE); + ewmh_update_wm_state(w); stack(); - if (win == win->ws->focus) - focus_win(win); + if (w == w->ws->focus) + focus_win(w); focus_flush(); + DNPRINTF(SWM_D_MISC, "floating_toggle: done\n"); } void @@ -6045,6 +6207,12 @@ resize(struct ws_win *win, union arg *args) xcb_flush(conn); } break; + case XCB_KEY_PRESS: + /* Ignore. */ + xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD, + ((xcb_key_press_event_t *)evt)->time); + xcb_flush(conn); + break; default: event_handle(evt); @@ -6095,9 +6263,18 @@ regionize(struct ws_win *win, int x, int y) r = region_under(win->s, X(win) + WIDTH(win) / 2, Y(win) + HEIGHT(win) / 2); - if (r && r != win->ws->r) { + if (r != NULL && r != win->ws->r) { + if (clear_maximized(r->ws) > 0) + stack(); + win_to_ws(win, r->ws->idx, 0); + + /* Set focus on new ws. */ + unfocus_win(r->ws->focus); + r->ws->focus = win; + set_region(r); + raise_window(win); } } @@ -6218,6 +6395,12 @@ move(struct ws_win *win, union arg *args) xcb_flush(conn); } break; + case XCB_KEY_PRESS: + /* Ignore. */ + xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD, + ((xcb_key_press_event_t *)evt)->time); + xcb_flush(conn); + break; default: event_handle(evt); @@ -6237,6 +6420,13 @@ move(struct ws_win *win, union arg *args) xcb_flush(conn); } store_float_geom(win); + + /* New region set to fullscreen layout. */ + if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) { + stack(); + focus_flush(); + } + out: free(qpr); xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); @@ -7607,7 +7797,8 @@ enum { SWM_S_WINDOW_CLASS_ENABLED, SWM_S_WINDOW_INSTANCE_ENABLED, SWM_S_WINDOW_NAME_ENABLED, - SWM_S_WORKSPACE_LIMIT + SWM_S_WORKSPACE_LIMIT, + SWM_S_WORKSPACE_NAME, }; int @@ -7615,7 +7806,7 @@ setconfvalue(const char *selector, const char *value, int flags) { struct workspace *ws; int i, ws_id, num_screens; - char *b, *str; + char *b, *str, s[1024]; switch (flags) { case SWM_S_BAR_ACTION: @@ -7827,11 +8018,32 @@ setconfvalue(const char *selector, const char *value, int flags) else if (workspace_limit < 1) workspace_limit = 1; + ewmh_update_desktops(); + break; + case SWM_S_WORKSPACE_NAME: + if (getenv("SWM_STARTED") != NULL) + return (0); + + bzero(s, sizeof s); + if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2) + errx(1, "invalid entry, should be 'ws[]:name'"); + ws_id--; + if (ws_id < 0 || ws_id >= workspace_limit) + errx(1, "setconfvalue: workspace_name: invalid " + "workspace %d.", ws_id + 1); + num_screens = get_screen_count(); - for (i = 0; i < num_screens; i++) { - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, - screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom, - XCB_ATOM_CARDINAL, 32, 1, &workspace_limit); + for (i = 0; i < num_screens; ++i) { + ws = (struct workspace *)&screens[i].ws; + + if (strlen(s) > 0) { + free(ws[ws_id].name); + if ((ws[ws_id].name = strdup(s)) == NULL) + err(1, "setconfvalue: workspace_name."); + + ewmh_update_desktop_names(); + ewmh_get_desktop_names(); + } } break; default: @@ -8096,6 +8308,7 @@ struct config_option configopt[] = { { "window_instance_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, { "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT }, + { "name", setconfvalue, SWM_S_WORKSPACE_NAME }, }; void @@ -8400,17 +8613,17 @@ get_ws_idx(xcb_window_t id) } struct ws_win * -manage_window(xcb_window_t id, uint16_t mapped) +manage_window(xcb_window_t id, int mapped) { - xcb_window_t trans = XCB_WINDOW_NONE; struct ws_win *win, *ww; - int ws_idx; - char *class, *instance, *name; struct swm_region *r; struct pid_e *p; struct quirk *qp; - uint32_t i, wa[2], new_flags; xcb_get_geometry_reply_t *gr; + xcb_window_t trans = XCB_WINDOW_NONE; + uint32_t i, wa[2], new_flags; + int ws_idx; + char *class, *instance, *name; if ((win = find_window(id)) != NULL) { DNPRINTF(SWM_D_MISC, "manage_window: win %#x already " @@ -8966,14 +9179,18 @@ configurerequest(xcb_configure_request_event_t *e) win->g_floatvalid = 1; - if (ABOVE(win) && r && !MAXIMIZED(win) && (TRANS(win) || - win->ws->cur_layout != &layouts[SWM_MAX_STACK])) { + if (!MAXIMIZED(win) && !FULLSCREEN(win) && + (TRANS(win) || (ABOVE(win) && + win->ws->cur_layout != &layouts[SWM_MAX_STACK]))) { WIDTH(win) = win->g_float.w; HEIGHT(win) = win->g_float.h; - if (r) { + if (r != NULL) { update_floater(win); focus_flush(); + } else { + config_win(win, e); + xcb_flush(conn); } } else { config_win(win, e); @@ -9475,6 +9692,7 @@ clientmessage(xcb_client_message_event_t *e) struct ws_win *win; struct swm_region *r = NULL; union arg a; + uint32_t val[2]; int num_screens, i; xcb_map_request_event_t mre; #ifdef SWM_DEBUG @@ -9542,12 +9760,18 @@ clientmessage(xcb_client_message_event_t *e) HEIGHT(win) = e->data.data32[4]; update_window(win); - } - else { - /* TODO: Change stack sizes */ - /* notify no change was made. */ + } else { + /* Notify no change was made. */ config_win(win, NULL); + /* TODO: Change stack sizes */ } + } else if (e->type == ewmh[_NET_RESTACK_WINDOW].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_RESTACK_WINDOW\n"); + val[0] = e->data.data32[1]; /* Sibling window. */ + val[1] = e->data.data32[2]; /* Stack mode detail. */ + + xcb_configure_window(conn, win->id, XCB_CONFIG_WINDOW_SIBLING | + XCB_CONFIG_WINDOW_STACK_MODE, val); } else if (e->type == ewmh[_NET_WM_STATE].atom) { DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE\n"); ewmh_change_wm_state(win, e->data.data32[1], e->data.data32[0]); @@ -9557,6 +9781,19 @@ clientmessage(xcb_client_message_event_t *e) ewmh_update_wm_state(win); stack(); + } else if (e->type == ewmh[_NET_WM_DESKTOP].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_DESKTOP\n"); + r = win->ws->r; + + win_to_ws(win, e->data.data32[0], 1); + + /* Restack if either the source or destination ws is mapped. */ + if (r != NULL || win->ws->r != NULL) { + if (FLOATING(win)) + load_float_geom(win); + + stack(); + } } focus_flush(); @@ -9924,6 +10161,11 @@ grab_windows(void) "skip %#x; region input window.\n", wins[j]); break; + } else if (r->bar->id == wins[j]) { + DNPRINTF(SWM_D_INIT, "grab_windows: " + "skip %#x; region bar.\n", + wins[j]); + break; } } @@ -9954,7 +10196,7 @@ grab_windows(void) continue; } - state = getstate(wins[j]); + state = get_win_state(wins[j]); manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN; mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE; if (mapped || manage) @@ -9979,7 +10221,7 @@ grab_windows(void) continue; } - state = getstate(wins[j]); + state = get_win_state(wins[j]); manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN; mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE; pc = xcb_icccm_get_wm_transient_for(conn, wins[j]); @@ -10114,33 +10356,6 @@ setup_globals(void) } void -workaround(void) -{ - int i, num_screens; - xcb_window_t root, win; - - /* work around sun jdk bugs, code from wmname */ - - num_screens = get_screen_count(); - for (i = 0; i < num_screens; i++) { - root = screens[i].root; - - win = xcb_generate_id(conn); - xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, root, - 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, - XCB_COPY_FROM_PARENT, 0, NULL); - - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, - a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win); - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, - a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win); - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, - ewmh[_NET_WM_NAME].atom, a_utf8_string, 8, strlen("LG3D"), - "LG3D"); - } -} - -void shutdown_cleanup(void) { int i, num_screens; @@ -10370,11 +10585,6 @@ noconfig: validate_spawns(); - /* 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); @@ -10384,6 +10594,9 @@ noconfig: TAILQ_FOREACH(r, &screens[i].rl, entry) bar_setup(r); + /* Manage existing windows. */ + grab_windows(); + grabkeys(); stack(); bar_draw();