X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/57bfbfcfaa04c4b29ecc8c3d18d8847d2294c9ea..4f61f954631d86255dab707a0b91b44b63fed06f:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index 40c5416..1542fe1 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -1,14 +1,15 @@ /* - * Copyright (c) 2009-2012 Marco Peereboom + * Copyright (c) 2009-2015 Marco Peereboom * Copyright (c) 2009-2011 Ryan McBride * Copyright (c) 2009 Darrin Chandler * Copyright (c) 2009 Pierre-Yves Ritschard * Copyright (c) 2010 Tuukka Kataja * Copyright (c) 2011 Jason L. Wright - * Copyright (c) 2011-2013 Reginald Kennedy + * Copyright (c) 2011-2015 Reginald Kennedy * Copyright (c) 2011-2012 Lawrence Teo * Copyright (c) 2011-2012 Tiago Cunha - * Copyright (c) 2012-2013 David Hill + * Copyright (c) 2012-2015 David Hill + * Copyright (c) 2014-2015 Yuri D'Elia * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -77,12 +78,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -114,9 +117,9 @@ static const char *buildstr = SPECTRWM_BUILDSTR; static const char *buildstr = SPECTRWM_VERSION; #endif -#if !defined(__CYGWIN__) /* cygwin chokes on xrandr stuff */ +#if !defined(__CYGWIN__) /* cygwin chokes on randr stuff */ # if RANDR_MAJOR < 1 -# error XRandR versions less than 1.0 are not supported +# error RandR versions less than 1.0 are not supported #endif # if RANDR_MAJOR >= 1 @@ -186,7 +189,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 @@ -316,9 +319,8 @@ volatile sig_atomic_t running = 1; volatile sig_atomic_t restart_wm = 0; xcb_timestamp_t last_event_time = 0; int outputs = 0; -int other_wm; -int xrandr_support; -int xrandr_eventbase; +bool randr_support; +int randr_eventbase; unsigned int numlockmask = 0; Display *display; @@ -326,11 +328,14 @@ xcb_connection_t *conn; xcb_key_symbols_t *syms; int boundary_width = 50; -int cycle_empty = 0; -int cycle_visible = 0; +bool cycle_empty = false; +bool cycle_visible = false; int term_width = 0; int font_adjusted = 0; unsigned int mod_key = MODKEY; +bool warp_focus = false; +bool warp_pointer = false; +bool workspace_clamp = false; /* dmenu search */ struct swm_region *search_r; @@ -389,42 +394,46 @@ int bar_pipe[2]; char bar_ext[SWM_BAR_MAX]; char bar_ext_buf[SWM_BAR_MAX]; char bar_vertext[SWM_BAR_MAX]; -int bar_version = 0; -int bar_enabled = 1; +bool bar_version = false; +bool bar_enabled = true; int bar_border_width = 1; -int bar_at_bottom = 0; -int bar_extra = 0; -int bar_verbose = 1; +bool bar_at_bottom = false; +bool bar_extra = false; int bar_height = 0; int bar_justify = SWM_BAR_JUSTIFY_LEFT; char *bar_format = NULL; -int stack_enabled = 1; -int clock_enabled = 1; -int iconic_enabled = 0; -int urgent_enabled = 0; +bool stack_enabled = true; +bool clock_enabled = true; +bool iconic_enabled = false; +bool maximize_hide_bar = false; +bool urgent_enabled = false; +bool urgent_collapse = false; char *clock_format = NULL; -int window_class_enabled = 0; -int window_instance_enabled = 0; -int window_name_enabled = 0; +bool window_class_enabled = false; +bool window_instance_enabled = false; +bool window_name_enabled = false; int focus_mode = SWM_FOCUS_DEFAULT; int focus_close = SWM_STACK_BELOW; -int focus_close_wrap = 1; +bool focus_close_wrap = true; int focus_default = SWM_STACK_TOP; int spawn_position = SWM_STACK_TOP; -int disable_border = 0; +bool disable_border = false; int border_width = 1; int region_padding = 0; int tile_gap = 0; -int java_workaround = 1; -int verbose_layout = 0; +bool java_workaround = true; +bool verbose_layout = false; +#ifdef SWM_DEBUG time_t time_started; +#endif pid_t bar_pid; XFontSet bar_fs; XFontSetExtents *bar_fs_extents; XftFont *bar_font; -int bar_font_legacy = 1; +bool bar_font_legacy = true; char *bar_fonts; XftColor bar_font_color; +XftColor search_font_color; struct passwd *pwd; char *startup_exception; unsigned int nr_exceptions = 0; @@ -466,17 +475,17 @@ struct ws_win { struct ws_win *focus_child; /* focus on child transient */ struct swm_geometry g; /* current geometry */ struct swm_geometry g_float; /* region coordinates */ - int g_floatvalid; /* g_float geometry validity */ - int32_t mapped; - int bordered; + bool g_floatvalid; /* g_float geometry validity */ + bool mapped; + bool bordered; uint32_t ewmh_flags; int font_size_boundary[SWM_MAX_FONT_STEPS]; int font_steps; int last_inc; - int can_delete; - int take_focus; - int java; - unsigned long quirks; + bool can_delete; + bool take_focus; + bool java; + uint32_t quirks; struct workspace *ws; /* always valid */ struct swm_screen *s; /* always valid, never changes */ xcb_size_hints_t sh; @@ -508,7 +517,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 *); @@ -533,8 +542,8 @@ struct layout { struct workspace { int idx; /* workspace index */ char *name; /* workspace name */ - int always_raise; /* raise windows on focus */ - int bar_enabled; /* bar visibility */ + bool always_raise; /* raise windows on focus */ + bool bar_enabled; /* bar visibility */ struct layout *cur_layout; /* current layout handlers */ struct ws_win *focus; /* may be NULL */ struct ws_win *focus_prev; /* may be NULL */ @@ -544,7 +553,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 */ @@ -552,11 +561,11 @@ struct workspace { int horizontal_msize; int horizontal_mwin; int horizontal_stacks; - int horizontal_flip; + bool horizontal_flip; int vertical_msize; int vertical_mwin; int vertical_stacks; - int vertical_flip; + bool vertical_flip; } l_state; }; @@ -572,7 +581,9 @@ enum { SWM_S_COLOR_BAR_BORDER_UNFOCUS, SWM_S_COLOR_BAR_FONT, SWM_S_COLOR_FOCUS, + SWM_S_COLOR_FOCUS_MAXIMIZED, SWM_S_COLOR_UNFOCUS, + SWM_S_COLOR_UNFOCUS_MAXIMIZED, SWM_S_COLOR_MAX }; @@ -592,6 +603,7 @@ struct swm_screen { struct { uint32_t pixel; char *name; + int manual; } c[SWM_S_COLOR_MAX]; xcb_gcontext_t bar_gc; @@ -617,6 +629,7 @@ union arg { #define SWM_ARG_ID_FLIPLAYOUT (24) #define SWM_ARG_ID_STACKRESET (30) #define SWM_ARG_ID_STACKINIT (31) +#define SWM_ARG_ID_STACKBALANCE (32) #define SWM_ARG_ID_CYCLEWS_UP (40) #define SWM_ARG_ID_CYCLEWS_DOWN (41) #define SWM_ARG_ID_CYCLERG_UP (42) @@ -641,8 +654,12 @@ 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) +#define SWM_ARG_ID_CYCLERG_MOVE_UP (112) +#define SWM_ARG_ID_CYCLERG_MOVE_DOWN (113) char **argv; }; @@ -655,7 +672,8 @@ struct quirk { regex_t regex_class; regex_t regex_instance; regex_t regex_name; - unsigned long quirk; + uint32_t quirk; + int ws; /* Initial workspace. */ #define SWM_Q_FLOAT (1<<0) /* float this window */ #define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */ #define SWM_Q_ANYWHERE (1<<2) /* don't position this window */ @@ -664,6 +682,10 @@ struct quirk { #define SWM_Q_FOCUSPREV (1<<5) /* focus on caller */ #define SWM_Q_NOFOCUSONMAP (1<<6) /* Don't focus on window when mapped. */ #define SWM_Q_FOCUSONMAP_SINGLE (1<<7) /* Only focus if single win of type. */ +#define SWM_Q_OBEYAPPFOCUSREQ (1<<8) /* Focus when applications ask. */ +#define SWM_Q_IGNOREPID (1<<9) /* Ignore PID when determining ws. */ +#define SWM_Q_IGNORESPAWNWS (1<<10) /* Ignore _SWM_WS when managing win. */ +#define SWM_Q_NOFOCUSCYCLE (1<<11) /* Remove from normal focus cycle. */ }; TAILQ_HEAD(quirk_list, quirk); struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks); @@ -867,6 +889,8 @@ enum keyfuncid { KF_RG_7, KF_RG_8, KF_RG_9, + KF_RG_MOVE_NEXT, + KF_RG_MOVE_PREV, KF_RG_NEXT, KF_RG_PREV, KF_SCREEN_NEXT, @@ -874,6 +898,7 @@ enum keyfuncid { KF_SEARCH_WIN, KF_SEARCH_WORKSPACE, KF_SPAWN_CUSTOM, + KF_STACK_BALANCE, KF_STACK_INC, KF_STACK_DEC, KF_STACK_RESET, @@ -954,6 +979,7 @@ void bar_window_name(char *, size_t, struct swm_region *); void bar_window_state(char *, size_t, struct swm_region *); void bar_workspace_name(char *, size_t, struct swm_region *); void buttonpress(xcb_button_press_event_t *); +void center_pointer(struct swm_region *); void check_conn(void); void clear_keys(void); int clear_maximized(struct workspace *); @@ -964,7 +990,7 @@ void configurenotify(xcb_configure_notify_event_t *); void configurerequest(xcb_configure_request_event_t *); void config_win(struct ws_win *, xcb_configure_request_event_t *); void constrain_window(struct ws_win *, struct swm_geometry *, int *); -int count_win(struct workspace *, int); +int count_win(struct workspace *, bool); void cursors_cleanup(void); void cursors_load(void); void custom_region(const char *); @@ -1023,18 +1049,20 @@ int get_region_index(struct swm_region *); xcb_screen_t *get_screen(int); int get_screen_count(void); #ifdef SWM_DEBUG +char *get_source_type_label(uint32_t); char *get_stack_mode_name(uint8_t); #endif int32_t get_swm_ws(xcb_window_t); +bool get_urgent(struct ws_win *); 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); +int get_ws_idx(struct ws_win *); void grabbuttons(struct ws_win *); void grabkeys(void); void grab_windows(void); void iconify(struct swm_region *, union arg *); -int isxlfd(char *); +bool isxlfd(char *); void keypress(xcb_key_press_event_t *); int key_cmp(struct key *, struct key *); void key_insert(unsigned int, KeySym, enum keyfuncid, const char *); @@ -1048,7 +1076,8 @@ 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); +void lower_window(struct ws_win *); +struct ws_win *manage_window(xcb_window_t, int, bool); void map_window(struct ws_win *); void mapnotify(xcb_map_notify_event_t *); void mappingnotify(xcb_mapping_notify_event_t *); @@ -1061,7 +1090,7 @@ uint32_t name_to_pixel(int, const char *); void name_workspace(struct swm_region *, union arg *); void new_region(struct swm_screen *, int, int, int, int); int parsekeys(const char *, unsigned int, unsigned int *, KeySym *); -int parsequirks(const char *, unsigned long *); +int parsequirks(const char *, uint32_t *, int *); int parse_rgb(const char *, uint16_t *, uint16_t *, uint16_t *); void pressbutton(struct swm_region *, union arg *); void priorws(struct swm_region *, union arg *); @@ -1070,10 +1099,11 @@ void print_win_geom(xcb_window_t); #endif void propertynotify(xcb_property_notify_event_t *); void quirk_free(struct quirk *); -void quirk_insert(const char *, const char *, const char *,unsigned long); +void clear_quirks(void); +void quirk_insert(const char *, const char *, const char *, uint32_t, int); void quirk_remove(struct quirk *); void quirk_replace(struct quirk *, const char *, const char *, const char *, - unsigned long); + uint32_t, int); void quit(struct swm_region *, union arg *); void raise_toggle(struct swm_region *, union arg *); void raise_window(struct ws_win *); @@ -1085,7 +1115,7 @@ void resize_step(struct swm_region *, union arg *); void restart(struct swm_region *, union arg *); struct swm_region *root_to_region(xcb_window_t, int); void screenchange(xcb_randr_screen_change_notify_event_t *); -void scan_xrandr(int); +void scan_randr(int); void search_do_resp(void); void search_resp_name_workspace(const char *, size_t); void search_resp_search_window(const char *); @@ -1108,7 +1138,7 @@ int setconfvalue(const char *, const char *, int); void setkeybinding(unsigned int, KeySym, enum keyfuncid, const char *); int setkeymapping(const char *, const char *, int); int setlayout(const char *, const char *, int); -void setquirk(const char *, const char *, const char *,unsigned long); +void setquirk(const char *, const char *, const char *, uint32_t, int); void setscreencolor(const char *, int, int); void setspawn(const char *, const char *, int); void setup_ewmh(void); @@ -1118,21 +1148,22 @@ 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); void sort_windows(struct ws_win_list *); -void spawn(int, union arg *, int); +void spawn(int, union arg *, bool); void spawn_custom(struct swm_region *, union arg *, const char *); int spawn_expand(struct swm_region *, union arg *, const char *, char ***); void spawn_insert(const char *, const char *, int); struct spawn_prog *spawn_find(const char *); void spawn_remove(struct spawn_prog *); +void clear_spawns(void); void spawn_replace(struct spawn_prog *, const char *, const char *, int); void spawn_select(struct swm_region *, union arg *, const char *, int *); void stack_config(struct swm_region *, union arg *); -void stack_master(struct workspace *, struct swm_geometry *, int, int); +void stack_master(struct workspace *, struct swm_geometry *, int, bool); void store_float_geom(struct ws_win *); char *strdupsafe(const char *); void swapwin(struct swm_region *, union arg *); @@ -1150,12 +1181,13 @@ void update_floater(struct ws_win *); void update_modkey(unsigned int); void update_win_stacking(struct ws_win *); void update_window(struct ws_win *); +void update_window_color(struct ws_win *); void update_wm_state(struct ws_win *win); void validate_spawns(void); int validate_win(struct ws_win *); int validate_ws(struct workspace *); void version(struct swm_region *, union arg *); -void win_to_ws(struct ws_win *, int, int); +void win_to_ws(struct ws_win *, int, bool); pid_t window_get_pid(xcb_window_t); void wkill(struct swm_region *, union arg *); void update_ws_stack(struct workspace *); @@ -1358,9 +1390,9 @@ get_wm_protocols(struct ws_win *win) { &wpr, NULL)) { for (i = 0; i < (int)wpr.atoms_len; i++) { if (wpr.atoms[i] == a_takefocus) - win->take_focus = 1; + win->take_focus = true; if (wpr.atoms[i] == a_delete) - win->can_delete = 1; + win->can_delete = true; } xcb_icccm_get_wm_protocols_reply_wipe(&wpr); } @@ -1449,10 +1481,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); @@ -1630,6 +1662,8 @@ ewmh_apply_flags(struct ws_win *win, uint32_t pending) ws->focus_pending = win; } } + + update_window_color(win); raise_window(win); } @@ -1714,7 +1748,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; @@ -1728,33 +1762,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"); @@ -1885,24 +1926,13 @@ name_to_pixel(int sidx, const char *colorname) void setscreencolor(const char *val, int i, int c) { - int num_screens; + if (i < 0 || i >= get_screen_count()) + return; - num_screens = get_screen_count(); - if (i > 0 && i <= num_screens) { - screens[i - 1].c[c].pixel = name_to_pixel(i - 1, val); - free(screens[i - 1].c[c].name); - if ((screens[i - 1].c[c].name = strdup(val)) == NULL) - err(1, "strdup"); - } else if (i == -1) { - for (i = 0; i < num_screens; i++) { - screens[i].c[c].pixel = name_to_pixel(0, val); - free(screens[i].c[c].name); - if ((screens[i].c[c].name = strdup(val)) == NULL) - err(1, "strdup"); - } - } else - errx(1, "invalid screen index: %d out of bounds (maximum %d)", - i, num_screens); + screens[i].c[c].pixel = name_to_pixel(i, val); + free(screens[i].c[c].name); + if ((screens[i].c[c].name = strdup(val)) == NULL) + err(1, "strdup"); } void @@ -2098,7 +2128,7 @@ bar_extra_stop(void) bar_pid = 0; } strlcpy(bar_ext, "", sizeof bar_ext); - bar_extra = 0; + bar_extra = false; } void @@ -2154,38 +2184,50 @@ bar_window_name(char *s, size_t sz, struct swm_region *r) free(title); } +bool +get_urgent(struct ws_win *win) +{ + xcb_icccm_wm_hints_t hints; + xcb_get_property_cookie_t c; + bool urgent = false; + + if (win) { + c = xcb_icccm_get_wm_hints(conn, win->id); + if (xcb_icccm_get_wm_hints_reply(conn, c, &hints, NULL)) + urgent = xcb_icccm_wm_hints_get_urgency(&hints); + } + + return urgent; +} + void bar_urgent(char *s, size_t sz) { struct ws_win *win; int i, j, num_screens; - int urgent[SWM_WS_MAX]; + bool urgent[SWM_WS_MAX]; char b[8]; - xcb_get_property_cookie_t c; - xcb_icccm_wm_hints_t hints; for (i = 0; i < workspace_limit; i++) - urgent[i] = 0; + urgent[i] = false; num_screens = get_screen_count(); for (i = 0; i < num_screens; i++) for (j = 0; j < workspace_limit; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { - c = xcb_icccm_get_wm_hints(conn, win->id); - if (xcb_icccm_get_wm_hints_reply(conn, c, - &hints, NULL) == 0) - continue; - if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) - urgent[j] = 1; - } + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + if (get_urgent(win)) + urgent[j] = true; for (i = 0; i < workspace_limit; i++) { - if (urgent[i]) + if (urgent[i]) { snprintf(b, sizeof b, "%d ", i + 1); - else - snprintf(b, sizeof b, "- "); - strlcat(s, b, sz); + strlcat(s, b, sz); + } else if (!urgent_collapse) { + strlcat(s, "- ", sz); + } } + if(urgent_collapse && s[0]) + s[strlen(s) - 1] = 0; } void @@ -2476,7 +2518,7 @@ bar_extra_update(void) { size_t len; char b[SWM_BAR_MAX]; - int changed = 0; + bool changed = false; if (!bar_extra) return changed; @@ -2498,7 +2540,7 @@ bar_extra_update(void) /* Append new output to bar. */ strlcat(bar_ext, b, sizeof(bar_ext)); - changed = 1; + changed = true; } else { /* Buffer output. */ strlcat(bar_ext_buf, b, sizeof(bar_ext_buf)); @@ -2509,7 +2551,7 @@ bar_extra_update(void) if (errno != EAGAIN) { warn("bar_action failed"); bar_extra_stop(); - changed = 1; + changed = true; } return changed; @@ -2533,7 +2575,7 @@ bar_toggle(struct swm_region *r, union arg *args) if (bar_enabled) r->ws->bar_enabled = !r->ws->bar_enabled; else - bar_enabled = r->ws->bar_enabled = 1; + bar_enabled = r->ws->bar_enabled = true; break; case SWM_ARG_ID_BAR_TOGGLE: bar_enabled = !bar_enabled; @@ -2565,7 +2607,7 @@ bar_extra_setup(void) /* do this here because the conf file is in memory */ if (!bar_extra && bar_argv[0]) { /* launch external status app */ - bar_extra = 1; + bar_extra = true; if (pipe(bar_pipe) == -1) err(1, "pipe error"); socket_setnonblock(bar_pipe[0]); @@ -2606,7 +2648,7 @@ kill_bar_extra_atexit(void) kill(bar_pid, SIGTERM); } -int +bool isxlfd(char *s) { int count = 0; @@ -2709,6 +2751,12 @@ xft_init(struct swm_region *r) DefaultColormap(display, r->s->idx), &color, &bar_font_color)) warn("Xft error: unable to allocate color."); + PIXEL_TO_XRENDERCOLOR(r->s->c[SWM_S_COLOR_BAR].pixel, color); + + if (!XftColorAllocValue(display, DefaultVisual(display, r->s->idx), + DefaultColormap(display, r->s->idx), &color, &search_font_color)) + warn("Xft error: unable to allocate color."); + bar_height = bar_font->height + 2 * bar_border_width; if (bar_height < 1) @@ -2756,11 +2804,18 @@ bar_setup(struct swm_region *r) XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK, wa); + /* Stack bar window above region window to start. */ + wa[0] = r->id; + wa[1] = XCB_STACK_MODE_ABOVE; + + xcb_configure_window(conn, r->bar->id, XCB_CONFIG_WINDOW_SIBLING | + XCB_CONFIG_WINDOW_STACK_MODE, wa); + r->bar->buffer = xcb_generate_id(conn); xcb_create_pixmap(conn, screen->root_depth, r->bar->buffer, r->bar->id, WIDTH(r->bar), HEIGHT(r->bar)); - if (xrandr_support) + if (randr_support) xcb_randr_select_input(conn, r->bar->id, XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE); @@ -2786,7 +2841,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 }; @@ -2800,12 +2855,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); @@ -2815,7 +2870,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); } @@ -2950,7 +3005,7 @@ config_win(struct ws_win *win, xcb_configure_request_event_t *ev) } int -count_win(struct workspace *ws, int count_transient) +count_win(struct workspace *ws, bool count_transient) { struct ws_win *win; int count = 0; @@ -2978,14 +3033,74 @@ quit(struct swm_region *r, union arg *args) running = 0; } +void +lower_window(struct ws_win *win) +{ + struct ws_win *target = NULL; + struct workspace *ws; + + if (win == NULL) + return; + + ws = win->ws; + + DNPRINTF(SWM_D_EVENT, "lower_window: win %#x\n", win->id); + + TAILQ_FOREACH(target, &ws->stack, stack_entry) { + if (target == win || ICONIC(target)) + continue; + if (ws->cur_layout == &layouts[SWM_MAX_STACK]) + break; + if (TRANS(win)) { + if (win->transient == target->transient) + continue; + if (win->transient == target->id) + break; + } + if (FULLSCREEN(target)) + continue; + if (FULLSCREEN(win)) + break; + if (MAXIMIZED(target)) + continue; + if (MAXIMIZED(win)) + break; + if (ABOVE(target) || TRANS(target)) + continue; + if (ABOVE(win) || TRANS(win)) + break; + } + + /* Change stack position. */ + TAILQ_REMOVE(&ws->stack, win, stack_entry); + if (target) + TAILQ_INSERT_BEFORE(target, win, stack_entry); + else + TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry); + + update_win_stacking(win); + +#ifdef SWM_DEBUG + if (swm_debug & SWM_D_STACK) { + DPRINTF("=== stacking order (top down) === \n"); + TAILQ_FOREACH(target, &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, "lower_window: done\n"); +} + void raise_window(struct ws_win *win) { struct ws_win *target = NULL; - struct swm_region *r; struct workspace *ws; - if (win == NULL || (r = win->ws->r) == NULL) + if (win == NULL) return; ws = win->ws; @@ -2996,6 +3111,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)) @@ -3004,19 +3122,32 @@ raise_window(struct ws_win *win) break; if (MAXIMIZED(target)) continue; - if (ABOVE(win) || TRANS(win)) + if (ABOVE(win) || TRANS(win) || + (win->ws->focus == win && ws->always_raise)) break; if (!ABOVE(target) && !TRANS(target)) break; } - if (target != NULL) { - /* Change stack position. */ - TAILQ_REMOVE(&ws->stack, win, stack_entry); + TAILQ_REMOVE(&ws->stack, win, stack_entry); + if (target) TAILQ_INSERT_BEFORE(target, win, stack_entry); - update_win_stacking(win); - } + else + TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry); + + update_win_stacking(win); +#ifdef SWM_DEBUG + if (swm_debug & SWM_D_STACK) { + DPRINTF("=== stacking order (top down) === \n"); + TAILQ_FOREACH(target, &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"); } @@ -3031,10 +3162,14 @@ update_win_stacking(struct ws_win *win) return; sibling = TAILQ_NEXT(win, stack_entry); - if (sibling != NULL && FLOATING(win) == FLOATING(sibling)) + if (sibling != NULL && (FLOATING(win) == FLOATING(sibling) || + (win->ws->always_raise && win->ws->focus == win))) val[0] = sibling->id; + else if (FLOATING(win) || (win->ws->always_raise && + win->ws->focus == win)) + val[0] = r->bar->id; else - val[0] = FLOATING(win) ? r->bar->id : r->id; + val[0] = r->id; DNPRINTF(SWM_D_EVENT, "update_win_stacking: %#x, sibling %#x\n", win->id, val[0]); @@ -3059,7 +3194,7 @@ map_window(struct ws_win *win) xcb_map_window(conn, win->id); set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL); - win->mapped = 1; + win->mapped = true; } void @@ -3076,7 +3211,7 @@ unmap_window(struct ws_win *win) xcb_unmap_window(conn, win->id); set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC); - win->mapped = 0; + win->mapped = false; } void @@ -3169,6 +3304,26 @@ get_pointer_win(xcb_window_t root) return win; } +void +center_pointer(struct swm_region *r) +{ + struct ws_win *win; + + if (!warp_pointer || r == NULL) + return; + + win = r->ws->focus; + + DNPRINTF(SWM_D_EVENT, "center_pointer: win %#x.\n", WINID(win)); + + if (win && win->mapped) + xcb_warp_pointer(conn, XCB_NONE, win->id, 0, 0, 0, 0, + WIDTH(win) / 2, HEIGHT(win) / 2); + else + xcb_warp_pointer(conn, XCB_NONE, r->id, 0, 0, 0, 0, + WIDTH(r) / 2, HEIGHT(r) / 2); +} + struct swm_region * root_to_region(xcb_window_t root, int check) { @@ -3281,7 +3436,7 @@ find_window(xcb_window_t id) } void -spawn(int ws_idx, union arg *args, int close_fd) +spawn(int ws_idx, union arg *args, bool close_fd) { int fd; char *ret = NULL; @@ -3445,8 +3600,11 @@ unfocus_win(struct ws_win *win) win->ws->focus_prev = NULL; } - xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL, - &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel); + update_window_color(win); + + /* Raise window to "top unfocused position." */ + if (win->ws->always_raise) + raise_window(win); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none); @@ -3457,19 +3615,13 @@ unfocus_win(struct ws_win *win) void focus_win(struct ws_win *win) { - struct ws_win *cfw = NULL, *parent = NULL, *w; + struct ws_win *cfw = NULL, *parent = NULL, *w, *tmpw; struct workspace *ws; xcb_get_input_focus_reply_t *gifr; DNPRINTF(SWM_D_FOCUS, "focus_win: win %#x\n", WINID(win)); - if (win == NULL) - goto out; - - if (win->ws == NULL) - goto out; - - if (!win->mapped) + if (win == NULL || win->ws == NULL || !win->mapped) goto out; ws = win->ws; @@ -3490,7 +3642,9 @@ 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[(MAXIMIZED(cfw) ? + SWM_S_COLOR_UNFOCUS_MAXIMIZED : + SWM_S_COLOR_UNFOCUS)].pixel); } else { unfocus_win(cfw); } @@ -3536,9 +3690,6 @@ focus_win(struct ws_win *win) client_msg(win, a_takefocus, last_event_time); } - xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL, - &ws->r->s->c[SWM_S_COLOR_FOCUS].pixel); - if (ws->cur_layout->flags & SWM_L_MAPONFOCUS || ws->always_raise) { /* If a parent exists, map it first. */ @@ -3547,20 +3698,25 @@ focus_win(struct ws_win *win) map_window(parent); /* Map siblings next. */ - TAILQ_FOREACH(w, &ws->winlist, entry) + TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry, + tmpw) if (w != win && !ICONIC(w) && - win->transient == parent->id) + w->transient == parent->id) { + raise_window(w); map_window(w); + } } /* Map focused window. */ raise_window(win); map_window(win); - /* Finally, map children of focus window. */ - TAILQ_FOREACH(w, &ws->winlist, entry) - if (w->transient == win->id && !ICONIC(w)) + /* Stack any children of focus window. */ + TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry, tmpw) + if (w->transient == win->id && !ICONIC(w)) { + raise_window(w); map_window(w); + } } else if (tile_gap < 0 && !ABOVE(win)) { /* * Windows overlap in the layout. @@ -3577,6 +3733,10 @@ focus_win(struct ws_win *win) &win->id); } + if (cfw != win) + /* Update window border even if workspace is hidden. */ + update_window_color(win); + out: bar_draw(); @@ -3706,7 +3866,8 @@ switchws(struct swm_region *r, union arg *args) struct ws_win *win; struct workspace *new_ws, *old_ws; xcb_window_t none = XCB_WINDOW_NONE; - int wsid = args->id, unmap_old = 0; + int wsid = args->id; + bool unmap_old = false; if (!(r && r->s)) return; @@ -3726,26 +3887,39 @@ switchws(struct swm_region *r, union arg *args) if (new_ws == old_ws) return; + other_r = new_ws->r; + if (other_r && workspace_clamp) { + DNPRINTF(SWM_D_WS, "switchws: ws clamped.\n"); + + if (warp_focus) { + DNPRINTF(SWM_D_WS, "switchws: warping focus to region " + "with ws %d.\n", wsid); + focus_region(other_r); + center_pointer(other_r); + focus_flush(); + } + return; + } + 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); + update_window_color(win); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none); } - other_r = new_ws->r; - if (other_r == NULL) { - /* the other workspace is hidden, hide this one */ - old_ws->r = NULL; - unmap_old = 1; - } else { + if (other_r) { /* the other ws is visible in another region, exchange them */ other_r->ws_prior = new_ws; other_r->ws = old_ws; old_ws->r = other_r; + } else { + /* the other workspace is hidden, hide this one */ + old_ws->r = NULL; + unmap_old = true; } + this_r->ws_prior = old_ws; this_r->ws = new_ws; new_ws->r = this_r; @@ -3785,6 +3959,7 @@ switchws(struct swm_region *r, union arg *args) ewmh_update_current_desktop(); + center_pointer(r); focus_flush(); new_ws->state = SWM_WS_STATE_MAPPED; @@ -3796,8 +3971,7 @@ cyclews(struct swm_region *r, union arg *args) { union arg a; struct swm_screen *s = r->s; - int cycle_all = 0; - int move = 0; + bool cycle_all = false, mv = false; DNPRINTF(SWM_D_WS, "cyclews: id: %d, 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); @@ -3807,19 +3981,19 @@ cyclews(struct swm_region *r, union arg *args) do { switch (args->id) { case SWM_ARG_ID_CYCLEWS_MOVE_UP: - move = 1; + mv = true; /* FALLTHROUGH */ case SWM_ARG_ID_CYCLEWS_UP_ALL: - cycle_all = 1; + cycle_all = true; /* FALLTHROUGH */ case SWM_ARG_ID_CYCLEWS_UP: a.id = (a.id < workspace_limit - 1) ? a.id + 1 : 0; break; case SWM_ARG_ID_CYCLEWS_MOVE_DOWN: - move = 1; + mv = true; /* FALLTHROUGH */ case SWM_ARG_ID_CYCLEWS_DOWN_ALL: - cycle_all = 1; + cycle_all = true; /* FALLTHROUGH */ case SWM_ARG_ID_CYCLEWS_DOWN: a.id = (a.id > 0) ? a.id - 1 : workspace_limit - 1; @@ -3834,7 +4008,7 @@ cyclews(struct swm_region *r, union arg *args) if (!cycle_visible && s->ws[a.id].r != NULL) continue; - if (move) + if (mv) send_to_ws(r, &a); switchws(r, &a); @@ -3882,6 +4056,7 @@ focusrg(struct swm_region *r, union arg *args) return; focus_region(rr); + center_pointer(rr); focus_flush(); DNPRINTF(SWM_D_FOCUS, "focusrg: done\n"); } @@ -3889,6 +4064,7 @@ focusrg(struct swm_region *r, union arg *args) void cyclerg(struct swm_region *r, union arg *args) { + union arg a; struct swm_region *rr = NULL; int i, num_screens; @@ -3902,11 +4078,13 @@ cyclerg(struct swm_region *r, union arg *args) switch (args->id) { case SWM_ARG_ID_CYCLERG_UP: + case SWM_ARG_ID_CYCLERG_MOVE_UP: rr = TAILQ_NEXT(r, entry); if (rr == NULL) rr = TAILQ_FIRST(&screens[i].rl); break; case SWM_ARG_ID_CYCLERG_DOWN: + case SWM_ARG_ID_CYCLERG_MOVE_DOWN: rr = TAILQ_PREV(r, swm_region_list, entry); if (rr == NULL) rr = TAILQ_LAST(&screens[i].rl, swm_region_list); @@ -3917,8 +4095,22 @@ cyclerg(struct swm_region *r, union arg *args) if (rr == NULL) return; - focus_region(rr); - focus_flush(); + switch (args->id) { + case SWM_ARG_ID_CYCLERG_UP: + case SWM_ARG_ID_CYCLERG_DOWN: + focus_region(rr); + center_pointer(rr); + focus_flush(); + break; + case SWM_ARG_ID_CYCLERG_MOVE_UP: + case SWM_ARG_ID_CYCLERG_MOVE_DOWN: + a.id = rr->ws->idx; + switchws(r, &a); + break; + default: + return; + }; + DNPRINTF(SWM_D_FOCUS, "cyclerg: done\n"); } @@ -3956,9 +4148,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; @@ -4018,12 +4240,13 @@ swapwin(struct swm_region *r, union arg *args) } sort_windows(wl); - ewmh_update_client_list(); stack(); - + center_pointer(r); focus_flush(); +out: + DNPRINTF(SWM_D_MOVE, "swapwin: done\n"); } struct ws_win * @@ -4174,22 +4397,25 @@ focus(struct swm_region *r, union arg *args) struct workspace *ws = NULL; union arg a; int i; - xcb_icccm_wm_hints_t hints; if (!(r && r->ws)) goto out; - DNPRINTF(SWM_D_FOCUS, "focus: id: %d\n", args->id); - cur_focus = r->ws->focus; ws = r->ws; wl = &ws->winlist; + DNPRINTF(SWM_D_FOCUS, "focus: id: %d, cur_focus: %#x\n", args->id, + WINID(cur_focus)); + /* Make sure an uniconified window has focus, if one exists. */ if (cur_focus == NULL) { cur_focus = TAILQ_FIRST(wl); while (cur_focus != NULL && ICONIC(cur_focus)) cur_focus = TAILQ_NEXT(cur_focus, entry); + + DNPRINTF(SWM_D_FOCUS, "focus: new cur_focus: %#x\n", + WINID(cur_focus)); } switch (args->id) { @@ -4204,8 +4430,11 @@ focus(struct swm_region *r, union arg *args) winfocus = TAILQ_LAST(wl, ws_win_list); if (winfocus == cur_focus) break; - } while (winfocus != NULL && - (ICONIC(winfocus) || winfocus->id == cur_focus->transient)); + } while (winfocus && (ICONIC(winfocus) || + winfocus->id == cur_focus->transient || + (cur_focus->transient != XCB_WINDOW_NONE && + winfocus->transient == cur_focus->transient) || + (winfocus->quirks & SWM_Q_NOFOCUSCYCLE))); break; case SWM_ARG_ID_FOCUSNEXT: if (cur_focus == NULL) @@ -4218,8 +4447,11 @@ focus(struct swm_region *r, union arg *args) winfocus = TAILQ_FIRST(wl); if (winfocus == cur_focus) break; - } while (winfocus != NULL && - (ICONIC(winfocus) || winfocus->id == cur_focus->transient)); + } while (winfocus && (ICONIC(winfocus) || + winfocus->id == cur_focus->transient || + (cur_focus->transient != XCB_WINDOW_NONE && + winfocus->transient == cur_focus->transient) || + (winfocus->quirks & SWM_Q_NOFOCUSCYCLE))); break; case SWM_ARG_ID_FOCUSMAIN: if (cur_focus == NULL) @@ -4239,27 +4471,26 @@ focus(struct swm_region *r, union arg *args) head = TAILQ_FIRST(&r->s->ws[(ws->idx + i) % workspace_limit].winlist); - while (head != NULL && - (head = TAILQ_NEXT(head, entry)) != NULL) { + while (head) { if (head == cur_focus) { - winfocus = cur_focus; - break; - } - if (xcb_icccm_get_wm_hints_reply(conn, - xcb_icccm_get_wm_hints(conn, head->id), - &hints, NULL) != 0 && - xcb_icccm_wm_hints_get_urgency(&hints)) { + if (i > 0) { + winfocus = cur_focus; + break; + } + } else if (get_urgent(head)) { winfocus = head; break; } + + head = TAILQ_NEXT(head, entry); } - if (winfocus != NULL) + if (winfocus) break; } /* Switch ws if new focus is on a different ws. */ - if (winfocus != NULL && winfocus->ws != ws) { + if (winfocus && winfocus->ws != ws) { a.id = winfocus->ws->idx; switchws(r, &a); } @@ -4272,6 +4503,7 @@ focus(struct swm_region *r, union arg *args) stack(); focus_win(get_focus_magic(winfocus)); + center_pointer(r); focus_flush(); out: @@ -4299,6 +4531,7 @@ cycle_layout(struct swm_region *r, union arg *args) focus_win(get_region_focus(r)); + center_pointer(r); focus_flush(); } @@ -4320,6 +4553,7 @@ stack_config(struct swm_region *r, union arg *args) stack(); bar_draw(); + center_pointer(r); focus_flush(); } @@ -4399,7 +4633,7 @@ store_float_geom(struct ws_win *win) win->g_float = win->g; win->g_float.x -= X(win->ws->r); win->g_float.y -= Y(win->ws->r); - win->g_floatvalid = 1; + win->g_floatvalid = true; DNPRINTF(SWM_D_MISC, "store_float_geom: win %#x, 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, @@ -4441,13 +4675,15 @@ update_floater(struct ws_win *win) DNPRINTF(SWM_D_MISC, "update_floater: win %#x\n", win->id); + win->bordered = true; + if (FULLSCREEN(win)) { /* _NET_WM_FULLSCREEN: fullscreen without border. */ if (!win->g_floatvalid) store_float_geom(win); win->g = r->g; - win->bordered = 0; + win->bordered = false; } else if (MAXIMIZED(win)) { /* Maximize: like a single stacked window. */ if (!win->g_floatvalid) @@ -4455,15 +4691,12 @@ update_floater(struct ws_win *win) win->g = r->g; - if (bar_enabled && ws->bar_enabled) { - win->bordered = 1; + if (bar_enabled && ws->bar_enabled && !maximize_hide_bar) { if (!bar_at_bottom) Y(win) += bar_height; HEIGHT(win) -= bar_height; } else if (disable_border) { - win->bordered = 0; - } else { - win->bordered = 1; + win->bordered = false; } if (win->bordered) { @@ -4479,7 +4712,7 @@ update_floater(struct ws_win *win) if ((win->quirks & SWM_Q_FULLSCREEN) && WIDTH(win) >= WIDTH(r) && HEIGHT(win) >= HEIGHT(r)) { /* Remove border for FULLSCREEN quirk. */ - win->bordered = 0; + win->bordered = false; } else if (!MANUAL(win)) { if (TRANS(win) && (win->quirks & SWM_Q_TRANSSZ)) { /* Adjust size on TRANSSZ quirk. */ @@ -4543,7 +4776,7 @@ adjust_font(struct ws_win *win) tmp = (g)->h; (g)->h = (g)->w; (g)->w = tmp; \ } while (0) void -stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) +stack_master(struct workspace *ws, struct swm_geometry *g, int rot, bool flip) { struct swm_geometry win_g, r_g = *g; struct ws_win *win; @@ -4551,14 +4784,14 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) 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 = 0; - int bordered = 1; + int remain, missing, v_slice; + bool bordered = true, reconfigure = false; DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, " "flip: %s\n", ws->idx, YESNO(rot), YESNO(flip)); /* Prepare tiling variables, if needed. */ - if ((winno = count_win(ws, 0)) > 0) { + if ((winno = count_win(ws, false)) > 0) { /* Find first tiled window. */ TAILQ_FOREACH(win, &ws->winlist, entry) if (!FLOATING(win) && !ICONIC(win)) @@ -4684,18 +4917,18 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) win_g.y += last_h + 2 * border_width + tile_gap; if (disable_border && !(bar_enabled && ws->bar_enabled) && - winno == 1){ - bordered = 0; + winno == 1) { + bordered = false; win_g.w += 2 * border_width; win_g.h += 2 * border_width; } else { - bordered = 1; + bordered = true; } 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; + reconfigure = true; X(win) = win_g.y; Y(win) = win_g.x; WIDTH(win) = win_g.h; @@ -4704,7 +4937,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) } else { if (X(win) != win_g.x || Y(win) != win_g.y || WIDTH(win) != win_g.w || HEIGHT(win) != win_g.h) { - reconfigure = 1; + reconfigure = true; X(win) = win_g.x; Y(win) = win_g.y; WIDTH(win) = win_g.w; @@ -4713,7 +4946,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) } if (bordered != win->bordered) { - reconfigure = 1; + reconfigure = true; win->bordered = bordered; } @@ -4768,6 +5001,9 @@ vertical_config(struct workspace *ws, int id) if (ws->l_state.vertical_mwin > 0) ws->l_state.vertical_mwin--; break; + case SWM_ARG_ID_STACKBALANCE: + ws->l_state.vertical_msize = SWM_V_SLICE / (ws->l_state.vertical_stacks + 1); + break; case SWM_ARG_ID_STACKINC: ws->l_state.vertical_stacks++; break; @@ -4818,6 +5054,9 @@ horizontal_config(struct workspace *ws, int id) if (ws->l_state.horizontal_mwin > 0) ws->l_state.horizontal_mwin--; break; + case SWM_ARG_ID_STACKBALANCE: + ws->l_state.horizontal_msize = SWM_H_SLICE / (ws->l_state.horizontal_stacks + 1); + break; case SWM_ARG_ID_STACKINC: ws->l_state.horizontal_stacks++; break; @@ -4846,7 +5085,7 @@ void max_stack(struct workspace *ws, struct swm_geometry *g) { struct swm_geometry gg = *g; - struct ws_win *w, *win = NULL, *parent = NULL; + struct ws_win *w, *win = NULL, *parent = NULL, *tmpw; int winno; DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx); @@ -4854,8 +5093,8 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (ws == NULL) return; - winno = count_win(ws, 0); - if (winno == 0 && count_win(ws, 1) == 0) + winno = count_win(ws, false); + if (winno == 0 && count_win(ws, true) == 0) return; /* Figure out which top level window should be visible. */ @@ -4868,7 +5107,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) { @@ -4894,30 +5136,33 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w || HEIGHT(w) != gg.h) { w->g = gg; - if (bar_enabled && ws->bar_enabled){ - w->bordered = 1; - } else { - w->bordered = 0; + + if (disable_border && !(bar_enabled && ws->bar_enabled)) { + w->bordered = false; WIDTH(w) += 2 * border_width; HEIGHT(w) += 2 * border_width; + } else { + w->bordered = true; } update_window(w); } } - if (TRANS(win)) { - parent = find_window(win->transient); + /* If transient, stack parent and its children. */ + if (TRANS(win) && (parent = find_window(win->transient))) { raise_window(parent); - TAILQ_FOREACH(w, &ws->stack, stack_entry) + TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry, tmpw) if (w->transient == parent->id) raise_window(w); } + /* Make sure focus window is on top. */ raise_window(win); - TAILQ_FOREACH(w, &ws->stack, stack_entry) + /* Stack any children of focus window. */ + TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry, tmpw) if (w->transient == win->id) raise_window(w); @@ -4970,6 +5215,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) { @@ -4983,41 +5229,60 @@ 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) return; - win_to_ws(win, wsid, 1); + win_to_ws(win, wsid, true); + + /* Set new focus on target ws. */ + if (focus_mode != SWM_FOCUS_FOLLOW) { + win->ws->focus_prev = win->ws->focus; + win->ws->focus = win; + win->ws->focus_pending = NULL; + + if (win->ws->focus_prev) + update_window_color(win->ws->focus_prev); + } + + 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. */ + /* Restack and set new focus on current ws. */ + 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(); } } + center_pointer(r); focus_flush(); } void -win_to_ws(struct ws_win *win, int wsid, int unfocus) +win_to_ws(struct ws_win *win, int wsid, bool 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) @@ -5029,7 +5294,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. */ @@ -5073,6 +5340,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); @@ -5084,10 +5359,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); @@ -5114,7 +5385,7 @@ pressbutton(struct swm_region *r, union arg *args) void raise_toggle(struct swm_region *r, union arg *args) { - /* suppress unused warning since var is needed */ + /* Suppress warning. */ (void)args; if (r == NULL || r->ws == NULL) @@ -5125,9 +5396,8 @@ raise_toggle(struct swm_region *r, union arg *args) r->ws->always_raise = !r->ws->always_raise; - /* bring floaters back to top */ - if (!r->ws->always_raise) - stack(); + /* Update focused win stacking order based on new always_raise value. */ + raise_window(r->ws->focus); focus_flush(); } @@ -5136,7 +5406,8 @@ void iconify(struct swm_region *r, union arg *args) { struct ws_win *w; - /* suppress unused warning since var is needed */ + + /* Suppress warning. */ (void)args; if ((w = r->ws->focus) == NULL) @@ -5303,7 +5574,8 @@ search_win(struct swm_region *r, union arg *args) struct ws_win *win = NULL; struct search_window *sw = NULL; xcb_window_t w; - uint32_t wa[2]; + uint32_t wa[3]; + xcb_screen_t *screen; int i, width, height; char s[8]; FILE *lfile; @@ -5324,6 +5596,9 @@ search_win(struct swm_region *r, union arg *args) if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) return; + if ((screen = get_screen(r->s->idx)) == NULL) + errx(1, "ERROR: can't get screen %d.", r->s->idx); + TAILQ_INIT(&search_wl); i = 1; @@ -5347,6 +5622,7 @@ search_win(struct swm_region *r, union arg *args) w = xcb_generate_id(conn); wa[0] = r->s->c[SWM_S_COLOR_FOCUS].pixel; wa[1] = r->s->c[SWM_S_COLOR_UNFOCUS].pixel; + wa[2] = screen->default_colormap; if (bar_font_legacy) { XmbTextExtents(bar_fs, s, len, &l_ibox, &l_lbox); @@ -5359,10 +5635,10 @@ search_win(struct swm_region *r, union arg *args) height = bar_font->height + 4; } - xcb_create_window(conn, XCB_COPY_FROM_PARENT, w, win->id, 0, 0, + xcb_create_window(conn, screen->root_depth, w, win->id, 0, 0, width, height, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, - XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | - XCB_CW_BORDER_PIXEL, wa); + screen->root_visual, XCB_CW_BACK_PIXEL | + XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, wa); xcb_map_window(conn, w); @@ -5387,7 +5663,7 @@ search_win(struct swm_region *r, union arg *args) DefaultVisual(display, r->s->idx), DefaultColormap(display, r->s->idx)); - XftDrawStringUtf8(draw, &bar_font_color, bar_font, 2, + XftDrawStringUtf8(draw, &search_font_color, bar_font, 2, (HEIGHT(r->bar) + bar_font->height) / 2 - bar_font->descent, (FcChar8 *)s, len); @@ -5478,7 +5754,7 @@ ewmh_update_desktop_names(void) ++len; } - if((name_list = calloc(sizeof(char *), len)) == NULL) + if((name_list = calloc(len, sizeof(char))) == NULL) err(1, "update_desktop_names: calloc: failed to " "allocate memory."); @@ -5561,7 +5837,7 @@ ewmh_update_client_list(void) if (count == 0) continue; - wins = calloc(sizeof(xcb_window_t), count); + wins = calloc(count, sizeof(xcb_window_t)); if (wins == NULL) err(1, "ewmh_update_client_list: calloc: failed to " "allocate memory."); @@ -5584,10 +5860,13 @@ ewmh_update_current_desktop(void) int num_screens, i; 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_CURRENT_DESKTOP].atom, - XCB_ATOM_CARDINAL, 32, 1, &screens[i].r_focus->ws->idx); + for (i = 0; i < num_screens; ++i) { + if (screens[i].r_focus) + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, + screens[i].root, ewmh[_NET_CURRENT_DESKTOP].atom, + XCB_ATOM_CARDINAL, 32, 1, + &screens[i].r_focus->ws->idx); + } } void @@ -5596,7 +5875,7 @@ ewmh_update_desktops(void) int num_screens, i, j; uint32_t *vals; - vals = calloc(sizeof(uint32_t), workspace_limit * 2); + vals = calloc(workspace_limit * 2, sizeof(uint32_t)); if (vals == NULL) err(1, "ewmh_update_desktops: calloc: failed to allocate " "memory."); @@ -5812,6 +6091,7 @@ maximize_toggle(struct swm_region *r, union arg *args) if (w == w->ws->focus) focus_win(w); + center_pointer(r); focus_flush(); DNPRINTF(SWM_D_MISC, "maximize_toggle: done\n"); } @@ -5819,26 +6099,33 @@ 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); + center_pointer(r); focus_flush(); + DNPRINTF(SWM_D_MISC, "floating_toggle: done\n"); } void @@ -5928,6 +6215,24 @@ constrain_window(struct ws_win *win, struct swm_geometry *b, int *opts) } } +void +update_window_color(struct ws_win *win) +{ + uint32_t *pixel; + + if (WS_FOCUSED(win->ws) && win->ws->focus == win) + pixel = MAXIMIZED(win) ? + &win->s->c[SWM_S_COLOR_FOCUS_MAXIMIZED].pixel : + &win->s->c[SWM_S_COLOR_FOCUS].pixel; + else + pixel = MAXIMIZED(win) ? + &win->s->c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].pixel : + &win->s->c[SWM_S_COLOR_UNFOCUS].pixel; + + xcb_change_window_attributes(conn, win->id, + XCB_CW_BORDER_PIXEL, pixel); +} + void update_window(struct ws_win *win) { @@ -5959,12 +6264,13 @@ resize(struct ws_win *win, union arg *args) struct swm_region *r = NULL; struct swm_geometry g; int resize_stp = 0; - int top = 0, left = 0, resizing; + int top = 0, left = 0; int dx, dy; xcb_cursor_t cursor; xcb_query_pointer_reply_t *xpr = NULL; xcb_generic_event_t *evt; xcb_motion_notify_event_t *mne; + bool resizing; if (win == NULL) return; @@ -6060,12 +6366,12 @@ resize(struct ws_win *win, union arg *args) XCB_CURRENT_TIME), xcb_flush(conn); - resizing = 1; + resizing = true; while (resizing && (evt = xcb_wait_for_event(conn))) { switch (XCB_EVENT_RESPONSE_TYPE(evt)) { case XCB_BUTTON_RELEASE: DNPRINTF(SWM_D_EVENT, "resize: BUTTON_RELEASE\n"); - resizing = 0; + resizing = false; break; case XCB_MOTION_NOTIFY: mne = (xcb_motion_notify_event_t *)evt; @@ -6124,6 +6430,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); @@ -6160,6 +6472,7 @@ resize_step(struct swm_region *r, union arg *args) return; resize(win, args); + center_pointer(r); focus_flush(); } @@ -6174,9 +6487,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) { - win_to_ws(win, r->ws->idx, 0); + if (r != NULL && r != win->ws->r) { + if (clear_maximized(r->ws) > 0) + stack(); + + win_to_ws(win, r->ws->idx, false); + + /* Set focus on new ws. */ + unfocus_win(r->ws->focus); + r->ws->focus = win; + set_region(r); + raise_window(win); } } @@ -6187,10 +6509,11 @@ move(struct ws_win *win, union arg *args) { struct swm_region *r; xcb_timestamp_t timestamp = 0; - int move_stp = 0, moving, restack = 0; + int move_stp = 0; xcb_query_pointer_reply_t *qpr = NULL; xcb_generic_event_t *evt; xcb_motion_notify_event_t *mne; + bool moving, restack = false; if (win == NULL) return; @@ -6210,7 +6533,7 @@ move(struct ws_win *win, union arg *args) if (!(ABOVE(win) || TRANS(win)) || MAXIMIZED(win)) { store_float_geom(win); - restack = 1; + restack = true; } ewmh_apply_flags(win, (win->ewmh_flags | SWM_F_MANUAL | EWMH_F_ABOVE) & @@ -6274,12 +6597,12 @@ move(struct ws_win *win, union arg *args) SWM_CW_SOFTBOUNDARY); update_window(win); xcb_flush(conn); - moving = 1; + moving = true; while (moving && (evt = xcb_wait_for_event(conn))) { switch (XCB_EVENT_RESPONSE_TYPE(evt)) { case XCB_BUTTON_RELEASE: DNPRINTF(SWM_D_EVENT, "move: BUTTON_RELEASE\n"); - moving = 0; + moving = false; break; case XCB_MOTION_NOTIFY: mne = (xcb_motion_notify_event_t *)evt; @@ -6297,6 +6620,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); @@ -6316,6 +6645,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); @@ -6336,6 +6672,7 @@ move_step(struct swm_region *r, union arg *args) return; move(win, args); + center_pointer(r); focus_flush(); } @@ -6412,6 +6749,8 @@ struct keyfunc { { "rg_7", focusrg, {.id = 6} }, { "rg_8", focusrg, {.id = 7} }, { "rg_9", focusrg, {.id = 8} }, + { "rg_move_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_UP} }, + { "rg_move_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_DOWN} }, { "rg_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} }, { "rg_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_DOWN} }, { "screen_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} }, @@ -6419,6 +6758,7 @@ struct keyfunc { { "search_win", search_win, {0} }, { "search_workspace", search_workspace, {0} }, { "spawn_custom", NULL, {0} }, + { "stack_balance", stack_config, {.id = SWM_ARG_ID_STACKBALANCE} }, { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} }, { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} }, { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, @@ -6572,11 +6912,21 @@ spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name, strdup(r->s->c[SWM_S_COLOR_FOCUS].name)) == NULL) err(1, "spawn_custom color focus"); + } else if (strcasecmp(ap, "$color_focus_maximized") == 0) { + if ((real_args[c] = + strdup(r->s->c[SWM_S_COLOR_FOCUS_MAXIMIZED].name)) + == NULL) + err(1, "spawn_custom color focus maximized"); } else if (strcasecmp(ap, "$color_unfocus") == 0) { if ((real_args[c] = strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name)) == NULL) err(1, "spawn_custom color unfocus"); + } else if (strcasecmp(ap, "$color_unfocus_maximized") == 0) { + if ((real_args[c] = + strdup(r->s->c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].name)) + == NULL) + err(1, "spawn_custom color unfocus maximized"); } else if (strcasecmp(ap, "$region_index") == 0) { if (asprintf(&real_args[c], "%d", get_region_index(r) + 1) < 1) @@ -6620,7 +6970,7 @@ spawn_custom(struct swm_region *r, union arg *args, const char *spawn_name) return; a.argv = real_args; if (fork() == 0) - spawn(r->ws->idx, &a, 1); + spawn(r->ws->idx, &a, true); for (i = 0; i < spawn_argc; i++) free(real_args[i]); @@ -6657,7 +7007,7 @@ spawn_select(struct swm_region *r, union arg *args, const char *spawn_name, err(1, "dup2"); close(select_list_pipe[1]); close(select_resp_pipe[0]); - spawn(r->ws->idx, &a, 0); + spawn(r->ws->idx, &a, false); break; default: /* parent */ close(select_list_pipe[0]); @@ -6673,8 +7023,8 @@ spawn_select(struct swm_region *r, union arg *args, const char *spawn_name, /* Argument tokenizer. */ char * argsep(char **sp) { - int single_quoted = 0, double_quoted = 0; char *arg, *cp, *next; + bool single_quoted = false, double_quoted = false; if (*sp == NULL) return NULL; @@ -6720,7 +7070,7 @@ void spawn_insert(const char *name, const char *args, int flags) { struct spawn_prog *sp; - char *arg, *dup, *ptr; + char *arg, *cp, *ptr; DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s[%s]\n", name, args); @@ -6733,7 +7083,7 @@ spawn_insert(const char *name, const char *args, int flags) err(1, "spawn_insert: strdup"); /* Convert the arguments to an argument list. */ - if ((ptr = dup = strdup(args)) == NULL) + if ((ptr = cp = strdup(args)) == NULL) err(1, "spawn_insert: strdup"); while ((arg = argsep(&ptr)) != NULL) { /* Null argument; skip it. */ @@ -6747,7 +7097,7 @@ spawn_insert(const char *name, const char *args, int flags) if ((sp->argv[sp->argc - 1] = strdup(arg)) == NULL) err(1, "spawn_insert: strdup"); } - free(dup); + free(cp); sp->flags = flags; @@ -6773,6 +7123,16 @@ spawn_remove(struct spawn_prog *sp) DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n"); } +void +clear_spawns(void) +{ + struct spawn_prog *sp; + + while ((sp = TAILQ_FIRST(&spawns)) != NULL) { + spawn_remove(sp); + } +} + struct spawn_prog* spawn_find(const char *name) { @@ -6937,6 +7297,8 @@ parsekeys(const char *keystr, unsigned int currmod, unsigned int *mod, KeySym *k *mod |= XCB_MOD_MASK_3; else if (strncmp(name, "Mod4", SWM_MODNAME_SIZE) == 0) *mod |= XCB_MOD_MASK_4; + else if (strncmp(name, "Mod5", SWM_MODNAME_SIZE) == 0) + *mod |= XCB_MOD_MASK_5; else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0) *mod |= XCB_MOD_MASK_SHIFT; else if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0) @@ -7381,12 +7743,16 @@ const char *quirkname[] = { "FOCUSPREV", "NOFOCUSONMAP", "FOCUSONMAP_SINGLE", + "OBEYAPPFOCUSREQ", + "IGNOREPID", + "IGNORESPAWNWS", + "NOFOCUSCYCLE", }; -/* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */ -#define SWM_Q_WS "\n|+ \t" +/* SWM_Q_DELIM: retain '|' for back compat for now (2009-08-11) */ +#define SWM_Q_DELIM "\n|+ \t" int -parsequirks(const char *qstr, unsigned long *quirk) +parsequirks(const char *qstr, uint32_t *quirk, int *ws) { char *str, *cp, *name; int i; @@ -7399,9 +7765,16 @@ parsequirks(const char *qstr, unsigned long *quirk) cp = str; *quirk = 0; - while ((name = strsep(&cp, SWM_Q_WS)) != NULL) { + while ((name = strsep(&cp, SWM_Q_DELIM)) != NULL) { if (cp) - cp += (long)strspn(cp, SWM_Q_WS); + cp += (long)strspn(cp, SWM_Q_DELIM); + + if (sscanf(name, "WS[%d]", ws) == 1) { + if (*ws > 0) + *ws -= 1; + continue; + } + for (i = 0; i < LENGTH(quirkname); i++) { if (strncasecmp(name, quirkname[i], SWM_QUIRK_LEN) == 0) { @@ -7430,14 +7803,14 @@ parsequirks(const char *qstr, unsigned long *quirk) void quirk_insert(const char *class, const char *instance, const char *name, - unsigned long quirk) + uint32_t quirk, int ws) { struct quirk *qp; - int failed = 0; char *str; + bool failed = false; DNPRINTF(SWM_D_QUIRK, "quirk_insert: class: %s, instance: %s, name: %s," - " value: %lu\n", class, instance, name, quirk); + " value: %u, ws: %d\n", class, instance, name, quirk, ws); if ((qp = malloc(sizeof *qp)) == NULL) err(1, "quirk_insert: malloc"); @@ -7454,7 +7827,7 @@ quirk_insert(const char *class, const char *instance, const char *name, if (regcomp(&qp->regex_class, str, REG_EXTENDED | REG_NOSUB)) { add_startup_exception("regex failed to compile quirk 'class' " "field: %s", class); - failed = 1; + failed = true; } DNPRINTF(SWM_D_QUIRK, "quirk_insert: compiled: %s\n", str); free(str); @@ -7464,7 +7837,7 @@ quirk_insert(const char *class, const char *instance, const char *name, if (regcomp(&qp->regex_instance, str, REG_EXTENDED | REG_NOSUB)) { add_startup_exception("regex failed to compile quirk 'instance'" " field: %s", instance); - failed = 1; + failed = true; } DNPRINTF(SWM_D_QUIRK, "quirk_insert: compiled: %s\n", str); free(str); @@ -7474,7 +7847,7 @@ quirk_insert(const char *class, const char *instance, const char *name, if (regcomp(&qp->regex_name, str, REG_EXTENDED | REG_NOSUB)) { add_startup_exception("regex failed to compile quirk 'name' " "field: %s", name); - failed = 1; + failed = true; } DNPRINTF(SWM_D_QUIRK, "quirk_insert: compiled: %s\n", str); free(str); @@ -7484,6 +7857,7 @@ quirk_insert(const char *class, const char *instance, const char *name, quirk_free(qp); } else { qp->quirk = quirk; + qp->ws = ws; TAILQ_INSERT_TAIL(&quirks, qp, entry); } DNPRINTF(SWM_D_QUIRK, "quirk_insert: leave\n"); @@ -7492,7 +7866,7 @@ quirk_insert(const char *class, const char *instance, const char *name, void quirk_remove(struct quirk *qp) { - DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%lu]\n", qp->class, + DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%u]\n", qp->class, qp->name, qp->quirk); TAILQ_REMOVE(&quirks, qp, entry); @@ -7513,45 +7887,56 @@ quirk_free(struct quirk *qp) free(qp); } +void +clear_quirks(void) +{ + struct quirk *qp; + + while ((qp = TAILQ_FIRST(&quirks)) != NULL) { + quirk_remove(qp); + } +} + void quirk_replace(struct quirk *qp, const char *class, const char *instance, - const char *name, unsigned long quirk) + const char *name, uint32_t quirk, int ws) { - DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%lu]\n", qp->class, - qp->instance, qp->name, qp->quirk); + DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%u], ws: %d\n", qp->class, + qp->instance, qp->name, qp->quirk, qp->ws); quirk_remove(qp); - quirk_insert(class, instance, name, quirk); + quirk_insert(class, instance, name, quirk, ws); DNPRINTF(SWM_D_QUIRK, "quirk_replace: leave\n"); } void setquirk(const char *class, const char *instance, const char *name, - unsigned long quirk) + uint32_t quirk, int ws) { struct quirk *qp; - DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%lu]\n", class, - instance, name, quirk); + DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%u], ws: %d\n", class, + instance, name, quirk, ws); /* Remove/replace existing quirk. */ TAILQ_FOREACH(qp, &quirks, entry) { if (strcmp(qp->class, class) == 0 && strcmp(qp->instance, instance) == 0 && strcmp(qp->name, name) == 0) { - if (quirk == 0) + if (quirk == 0 && ws == -1) quirk_remove(qp); else - quirk_replace(qp, class, instance, name, quirk); + quirk_replace(qp, class, instance, name, quirk, + ws); DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); return; } } - /* Only insert if quirk is not NONE. */ - if (quirk) - quirk_insert(class, instance, name, quirk); + /* Only insert if quirk is not NONE or forced ws is set. */ + if (quirk || ws != -1) + quirk_insert(class, instance, name, quirk, ws); DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); } @@ -7577,8 +7962,8 @@ setconfquirk(const char *selector, const char *value, int flags) { char *str, *cp, *class; char *instance = NULL, *name = NULL; - int retval, count = 0; - unsigned long qrks; + int retval, count = 0, ws = -1; + uint32_t qrks; /* suppress unused warning since var is needed */ (void)flags; @@ -7621,8 +8006,8 @@ setconfquirk(const char *selector, const char *value, int flags) DNPRINTF(SWM_D_CONF, "setconfquirk: class: %s, instance: %s, " "name: %s\n", class, instance, name); - if ((retval = parsequirks(value, &qrks)) == 0) - setquirk(class, instance, name, qrks); + if ((retval = parsequirks(value, &qrks, &ws)) == 0) + setquirk(class, instance, name, qrks, ws); free(str); return (retval); @@ -7631,19 +8016,32 @@ setconfquirk(const char *selector, const char *value, int flags) void setup_quirks(void) { - setquirk("MPlayer", "xv", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV); - setquirk("OpenOffice.org 3.2", "VCLSalFrame", ".*", SWM_Q_FLOAT); - setquirk("Firefox-bin", "firefox-bin", ".*", SWM_Q_TRANSSZ); - setquirk("Firefox", "Dialog", ".*", SWM_Q_FLOAT); - setquirk("Gimp", "gimp", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("XTerm", "xterm", ".*", SWM_Q_XTERM_FONTADJ); - setquirk("xine", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xitk Combo", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Panel", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Video Fullscreen Window", ".*", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); - setquirk("pcb", "pcb", ".*", SWM_Q_FLOAT); - setquirk("SDL_App", "SDL_App", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); + setquirk("MPlayer", "xv", ".*", + SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV, -1); + setquirk("OpenOffice.org 3.2", "VCLSalFrame", ".*", + SWM_Q_FLOAT, -1); + setquirk("Firefox-bin", "firefox-bin", ".*", + SWM_Q_TRANSSZ, -1); + setquirk("Firefox", "Dialog", ".*", + SWM_Q_FLOAT, -1); + setquirk("Gimp", "gimp", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("XTerm", "xterm", ".*", + SWM_Q_XTERM_FONTADJ, -1); + setquirk("xine", "Xine Window", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("Xitk", "Xitk Combo", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("xine", "xine Panel", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("Xitk", "Xine Window", ".*", + SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1); + setquirk("xine", "xine Video Fullscreen Window", ".*", + SWM_Q_FULLSCREEN | SWM_Q_FLOAT, -1); + setquirk("pcb", "pcb", ".*", + SWM_Q_FLOAT, -1); + setquirk("SDL_App", "SDL_App", ".*", + SWM_Q_FLOAT | SWM_Q_FULLSCREEN, -1); } /* conf file stuff */ @@ -7673,6 +8071,8 @@ enum { SWM_S_FOCUS_DEFAULT, SWM_S_FOCUS_MODE, SWM_S_ICONIC_ENABLED, + SWM_S_JAVA_WORKAROUND, + SWM_S_MAXIMIZE_HIDE_BAR, SWM_S_REGION_PADDING, SWM_S_SPAWN_ORDER, SWM_S_SPAWN_TERM, @@ -7681,11 +8081,15 @@ enum { SWM_S_STACK_ENABLED, SWM_S_TERM_WIDTH, SWM_S_TILE_GAP, + SWM_S_URGENT_COLLAPSE, SWM_S_URGENT_ENABLED, SWM_S_VERBOSE_LAYOUT, + SWM_S_WARP_FOCUS, + SWM_S_WARP_POINTER, SWM_S_WINDOW_CLASS_ENABLED, SWM_S_WINDOW_INSTANCE_ENABLED, SWM_S_WINDOW_NAME_ENABLED, + SWM_S_WORKSPACE_CLAMP, SWM_S_WORKSPACE_LIMIT, SWM_S_WORKSPACE_NAME, }; @@ -7704,7 +8108,7 @@ setconfvalue(const char *selector, const char *value, int flags) err(1, "setconfvalue: bar_action"); break; case SWM_S_BAR_AT_BOTTOM: - bar_at_bottom = atoi(value); + bar_at_bottom = (atoi(value) != 0); break; case SWM_S_BAR_BORDER_WIDTH: bar_border_width = atoi(value); @@ -7715,7 +8119,7 @@ setconfvalue(const char *selector, const char *value, int flags) /* No longer needed; leave to not break old conf files. */ break; case SWM_S_BAR_ENABLED: - bar_enabled = atoi(value); + bar_enabled = (atoi(value) != 0); break; case SWM_S_BAR_ENABLED_WS: ws_id = atoi(selector) - 1; @@ -7726,7 +8130,7 @@ setconfvalue(const char *selector, const char *value, int flags) num_screens = get_screen_count(); for (i = 0; i < num_screens; i++) { ws = (struct workspace *)&screens[i].ws; - ws[ws_id].bar_enabled = atoi(value); + ws[ws_id].bar_enabled = (atoi(value) != 0); } break; case SWM_S_BAR_FONT: @@ -7748,7 +8152,7 @@ setconfvalue(const char *selector, const char *value, int flags) if (*b == '\0') continue; if (!isxlfd(b)) { - bar_font_legacy = 0; + bar_font_legacy = false; break; } } @@ -7781,7 +8185,7 @@ setconfvalue(const char *selector, const char *value, int flags) boundary_width = 0; break; case SWM_S_CLOCK_ENABLED: - clock_enabled = atoi(value); + clock_enabled = (atoi(value) != 0); break; case SWM_S_CLOCK_FORMAT: #ifndef SWM_DENY_CLOCK_FORMAT @@ -7791,10 +8195,10 @@ setconfvalue(const char *selector, const char *value, int flags) #endif break; case SWM_S_CYCLE_EMPTY: - cycle_empty = atoi(value); + cycle_empty = (atoi(value) != 0); break; case SWM_S_CYCLE_VISIBLE: - cycle_visible = atoi(value); + cycle_visible = (atoi(value) != 0); break; case SWM_S_DIALOG_RATIO: dialog_ratio = atof(value); @@ -7802,7 +8206,7 @@ setconfvalue(const char *selector, const char *value, int flags) dialog_ratio = .6; break; case SWM_S_DISABLE_BORDER: - disable_border = atoi(value); + disable_border = (atoi(value) != 0); break; case SWM_S_FOCUS_CLOSE: if (strcmp(value, "first") == 0) @@ -7817,7 +8221,7 @@ setconfvalue(const char *selector, const char *value, int flags) errx(1, "focus_close"); break; case SWM_S_FOCUS_CLOSE_WRAP: - focus_close_wrap = atoi(value); + focus_close_wrap = (atoi(value) != 0); break; case SWM_S_FOCUS_DEFAULT: if (strcmp(value, "last") == 0) @@ -7839,7 +8243,13 @@ setconfvalue(const char *selector, const char *value, int flags) errx(1, "focus_mode"); break; case SWM_S_ICONIC_ENABLED: - iconic_enabled = atoi(value); + iconic_enabled = (atoi(value) != 0); + break; + case SWM_S_JAVA_WORKAROUND: + java_workaround = (atoi(value) != 0); + break; + case SWM_S_MAXIMIZE_HIDE_BAR: + maximize_hide_bar = atoi(value); break; case SWM_S_REGION_PADDING: region_padding = atoi(value); @@ -7869,7 +8279,7 @@ setconfvalue(const char *selector, const char *value, int flags) /* No longer needed; leave to not break old conf files. */ break; case SWM_S_STACK_ENABLED: - stack_enabled = atoi(value); + stack_enabled = (atoi(value) != 0); break; case SWM_S_TERM_WIDTH: term_width = atoi(value); @@ -7879,11 +8289,14 @@ setconfvalue(const char *selector, const char *value, int flags) case SWM_S_TILE_GAP: tile_gap = atoi(value); break; + case SWM_S_URGENT_COLLAPSE: + urgent_collapse = (atoi(value) != 0); + break; case SWM_S_URGENT_ENABLED: - urgent_enabled = atoi(value); + urgent_enabled = (atoi(value) != 0); break; case SWM_S_VERBOSE_LAYOUT: - verbose_layout = atoi(value); + verbose_layout = (atoi(value) != 0); for (i = 0; layouts[i].l_stack != NULL; i++) { if (verbose_layout) layouts[i].l_string = fancy_stacker; @@ -7891,14 +8304,23 @@ setconfvalue(const char *selector, const char *value, int flags) layouts[i].l_string = plain_stacker; } break; + case SWM_S_WARP_FOCUS: + warp_focus = (atoi(value) != 0); + break; + case SWM_S_WARP_POINTER: + warp_pointer = (atoi(value) != 0); + break; case SWM_S_WINDOW_CLASS_ENABLED: - window_class_enabled = atoi(value); + window_class_enabled = (atoi(value) != 0); break; case SWM_S_WINDOW_INSTANCE_ENABLED: - window_instance_enabled = atoi(value); + window_instance_enabled = (atoi(value) != 0); break; case SWM_S_WINDOW_NAME_ENABLED: - window_name_enabled = atoi(value); + window_name_enabled = (atoi(value) != 0); + break; + case SWM_S_WORKSPACE_CLAMP: + workspace_clamp = (atoi(value) != 0); break; case SWM_S_WORKSPACE_LIMIT: workspace_limit = atoi(value); @@ -7956,6 +8378,8 @@ setconfmodkey(const char *selector, const char *value, int flags) update_modkey(XCB_MOD_MASK_3); else if (strncasecmp(value, "Mod4", strlen("Mod4")) == 0) update_modkey(XCB_MOD_MASK_4); + else if (strncasecmp(value, "Mod5", strlen("Mod5")) == 0) + update_modkey(XCB_MOD_MASK_5); else return (1); return (0); @@ -7964,9 +8388,42 @@ setconfmodkey(const char *selector, const char *value, int flags) int setconfcolor(const char *selector, const char *value, int flags) { - setscreencolor(value, - (selector == NULL || strlen(selector) == 0) ? -1 : atoi(selector), - flags); + int first, last, i = 0, num_screens; + + num_screens = get_screen_count(); + + /* conf screen indices begin at 1; treat vals <= 0 as 'all screens.' */ + if (selector == NULL || strlen(selector) == 0 || + (last = atoi(selector) - 1) < 0) { + first = 0; + last = num_screens - 1; + } else { + first = last; + } + + if (last >= num_screens) { + add_startup_exception("invalid screen index: %d out of bounds " + "(maximum %d)", last + 1, num_screens); + return (1); + } + + for (i = first; i <= last; ++i) { + setscreencolor(value, i, flags); + + /* + * When setting focus/unfocus colors, we need to also + * set maximize colors to match if they haven't been customized. + */ + if (flags == SWM_S_COLOR_FOCUS && + !screens[i].c[SWM_S_COLOR_FOCUS_MAXIMIZED].manual) + setscreencolor(value, i, SWM_S_COLOR_FOCUS_MAXIMIZED); + else if (flags == SWM_S_COLOR_UNFOCUS && + !screens[i].c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].manual) + setscreencolor(value, i, SWM_S_COLOR_UNFOCUS_MAXIMIZED); + + screens[i].c[flags].manual = 1; + } + return (0); } @@ -8032,7 +8489,7 @@ setautorun(const char *selector, const char *value, int flags) a.argv[argc] = NULL; if ((pid = fork()) == 0) { - spawn(ws_id, &a, 1); + spawn(ws_id, &a, true); /* NOTREACHED */ _exit(1); } @@ -8056,10 +8513,11 @@ setautorun(const char *selector, const char *value, int flags) int setlayout(const char *selector, const char *value, int flags) { - int ws_id, i, x, mg, ma, si, ar, f = 0; + struct workspace *ws; + int ws_id, i, x, mg, ma, si, ar; int st = SWM_V_STACK, num_screens; char s[1024]; - struct workspace *ws; + bool f = false; /* suppress unused warnings since vars are needed */ (void)selector; @@ -8082,12 +8540,12 @@ setlayout(const char *selector, const char *value, int flags) st = SWM_V_STACK; else if (strcasecmp(s, "vertical_flip") == 0) { st = SWM_V_STACK; - f = 1; + f = true; } else if (strcasecmp(s, "horizontal") == 0) st = SWM_H_STACK; else if (strcasecmp(s, "horizontal_flip") == 0) { st = SWM_H_STACK; - f = 1; + f = true; } else if (strcasecmp(s, "fullscreen") == 0) st = SWM_MAX_STACK; else @@ -8100,7 +8558,7 @@ setlayout(const char *selector, const char *value, int flags) ws = (struct workspace *)&screens[i].ws; ws[ws_id].cur_layout = &layouts[st]; - ws[ws_id].always_raise = ar; + ws[ws_id].always_raise = (ar != 0); if (st == SWM_MAX_STACK) continue; @@ -8109,32 +8567,26 @@ setlayout(const char *selector, const char *value, int flags) ws[ws_id].cur_layout->l_config(&ws[ws_id], mg >= 0 ? SWM_ARG_ID_MASTERGROW : SWM_ARG_ID_MASTERSHRINK); - stack(); } /* master add */ for (x = 0; x < abs(ma); x++) { ws[ws_id].cur_layout->l_config(&ws[ws_id], ma >= 0 ? SWM_ARG_ID_MASTERADD : SWM_ARG_ID_MASTERDEL); - stack(); } /* stack inc */ for (x = 0; x < abs(si); x++) { ws[ws_id].cur_layout->l_config(&ws[ws_id], si >= 0 ? SWM_ARG_ID_STACKINC : SWM_ARG_ID_STACKDEC); - stack(); } /* Apply flip */ if (f) { ws[ws_id].cur_layout->l_config(&ws[ws_id], SWM_ARG_ID_FLIPLAYOUT); - stack(); } } - focus_flush(); - return (0); } @@ -8165,7 +8617,9 @@ struct config_option configopt[] = { { "clock_enabled", setconfvalue, SWM_S_CLOCK_ENABLED }, { "clock_format", setconfvalue, SWM_S_CLOCK_FORMAT }, { "color_focus", setconfcolor, SWM_S_COLOR_FOCUS }, + { "color_focus_maximized", setconfcolor, SWM_S_COLOR_FOCUS_MAXIMIZED }, { "color_unfocus", setconfcolor, SWM_S_COLOR_UNFOCUS }, + { "color_unfocus_maximized", setconfcolor, SWM_S_COLOR_UNFOCUS_MAXIMIZED }, { "cycle_empty", setconfvalue, SWM_S_CYCLE_EMPTY }, { "cycle_visible", setconfvalue, SWM_S_CYCLE_VISIBLE }, { "dialog_ratio", setconfvalue, SWM_S_DIALOG_RATIO }, @@ -8175,8 +8629,10 @@ struct config_option configopt[] = { { "focus_default", setconfvalue, SWM_S_FOCUS_DEFAULT }, { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, { "iconic_enabled", setconfvalue, SWM_S_ICONIC_ENABLED }, + { "java_workaround", setconfvalue, SWM_S_JAVA_WORKAROUND }, { "keyboard_mapping", setkeymapping, 0 }, { "layout", setlayout, 0 }, + { "maximize_hide_bar", setconfvalue, SWM_S_MAXIMIZE_HIDE_BAR }, { "modkey", setconfmodkey, 0 }, { "program", setconfspawn, 0 }, { "quirk", setconfquirk, 0 }, @@ -8191,11 +8647,15 @@ struct config_option configopt[] = { { "tile_gap", setconfvalue, SWM_S_TILE_GAP }, { "title_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED }, /* For backwards compat. */ { "title_name_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, /* For backwards compat. */ + { "urgent_collapse", setconfvalue, SWM_S_URGENT_COLLAPSE }, { "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED }, { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, + { "warp_focus", setconfvalue, SWM_S_WARP_FOCUS }, + { "warp_pointer", setconfvalue, SWM_S_WARP_POINTER }, { "window_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED }, { "window_instance_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, + { "workspace_clamp", setconfvalue, SWM_S_WORKSPACE_CLAMP }, { "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT }, { "name", setconfvalue, SWM_S_WORKSPACE_NAME }, }; @@ -8218,7 +8678,7 @@ add_startup_exception(const char *fmt, ...) return; /* force bar to be enabled due to exception */ - bar_enabled = 1; + bar_enabled = true; va_start(ap, fmt); _add_startup_exception(fmt, ap); @@ -8474,13 +8934,16 @@ get_swm_ws(xcb_window_t id) } int -get_ws_idx(xcb_window_t id) +get_ws_idx(struct ws_win *win) { xcb_get_property_reply_t *gpr; int ws_idx = -1; + if (win == NULL) + return -1; + gpr = xcb_get_property_reply(conn, - xcb_get_property(conn, 0, id, ewmh[_NET_WM_DESKTOP].atom, + xcb_get_property(conn, 0, win->id, ewmh[_NET_WM_DESKTOP].atom, XCB_ATOM_CARDINAL, 0, 1), NULL); if (gpr) { @@ -8489,30 +8952,30 @@ get_ws_idx(xcb_window_t id) free(gpr); } - if (ws_idx == -1) - if ((ws_idx = get_swm_ws(id)) != -1) - xcb_delete_property(conn, id, a_swm_ws); + if (ws_idx == -1 && !(win->quirks & SWM_Q_IGNORESPAWNWS)) + ws_idx = get_swm_ws(win->id); if (ws_idx > workspace_limit - 1 || ws_idx < -1) ws_idx = -1; - DNPRINTF(SWM_D_PROP, "get_ws_idx: win %#x, ws_idx: %d\n", id, ws_idx); + DNPRINTF(SWM_D_PROP, "get_ws_idx: win %#x, ws_idx: %d\n", win->id, + ws_idx); return ws_idx; } struct ws_win * -manage_window(xcb_window_t id, uint16_t mapped) +manage_window(xcb_window_t id, int spawn_pos, bool 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, force_ws = -1; + char *class, *instance, *name; if ((win = find_window(id)) != NULL) { DNPRINTF(SWM_D_MISC, "manage_window: win %#x already " @@ -8556,7 +9019,7 @@ manage_window(xcb_window_t id, uint16_t mapped) HEIGHT(win) = gr->height; X(win) = gr->x + gr->border_width - border_width; Y(win) = gr->y + gr->border_width - border_width; - win->bordered = 1; + win->bordered = true; win->mapped = mapped; win->s = r->s; /* this never changes */ @@ -8595,32 +9058,6 @@ manage_window(xcb_window_t id, uint16_t mapped) /* Get WM_PROTOCOLS. */ get_wm_protocols(win); - /* Figure out which workspace the window belongs to. */ - if ((p = find_pid(window_get_pid(win->id))) != NULL) { - win->ws = &r->s->ws[p->ws]; - TAILQ_REMOVE(&pidlist, p, entry); - free(p); - p = NULL; - } else if ((ws_idx = get_ws_idx(win->id)) != -1 && - !TRANS(win)) { - /* _SWM_WS is set; use that. */ - win->ws = &r->s->ws[ws_idx]; - } else if (trans && (ww = find_window(trans)) != NULL) { - /* Launch transients in the same ws as parent. */ - win->ws = ww->ws; - } else { - win->ws = r->ws; - } - - /* Set the _NET_WM_DESKTOP atom. */ - DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n", - win->ws->idx); - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id, - ewmh[_NET_WM_DESKTOP].atom, XCB_ATOM_CARDINAL, 32, 1, &win->ws->idx); - - /* WS must already be set for this to work. */ - store_float_geom(win); - /* Set initial quirks based on EWMH. */ ewmh_autoquirk(win); @@ -8639,7 +9076,7 @@ manage_window(xcb_window_t id, uint16_t mapped) /* java is retarded so treat it special */ if (strstr(instance, "sun-awt")) { DNPRINTF(SWM_D_CLASS, "manage_window: java window detected.\n"); - win->java = 1; + win->java = true; } TAILQ_FOREACH(qp, &quirks, entry) { @@ -8647,9 +9084,11 @@ manage_window(xcb_window_t id, uint16_t mapped) regexec(&qp->regex_instance, instance, 0, NULL, 0) == 0 && regexec(&qp->regex_name, name, 0, NULL, 0) == 0) { DNPRINTF(SWM_D_CLASS, "manage_window: matched " - "quirk: %s:%s:%s mask: %#lx\n", qp->class, - qp->instance, qp->name, qp->quirk); + "quirk: %s:%s:%s mask: %#x, ws: %d\n", qp->class, + qp->instance, qp->name, qp->quirk, qp->ws); win->quirks = qp->quirk; + if (qp->ws >= 0 && qp->ws < workspace_limit) + force_ws = qp->ws; } } @@ -8663,6 +9102,39 @@ manage_window(xcb_window_t id, uint16_t mapped) fake_keypress(win, XK_KP_Add, XCB_MOD_MASK_SHIFT); } + /* Figure out which workspace the window belongs to. */ + if (!(win->quirks & SWM_Q_IGNOREPID) && + (p = find_pid(window_get_pid(win->id))) != NULL) { + win->ws = &r->s->ws[p->ws]; + TAILQ_REMOVE(&pidlist, p, entry); + free(p); + p = NULL; + } else if ((ws_idx = get_ws_idx(win)) != -1 && + !TRANS(win)) { + /* _SWM_WS is set; use that. */ + win->ws = &r->s->ws[ws_idx]; + } else if (trans && (ww = find_window(trans)) != NULL) { + /* Launch transients in the same ws as parent. */ + win->ws = ww->ws; + } else { + win->ws = r->ws; + } + + if (force_ws != -1) + win->ws = &r->s->ws[force_ws]; + + /* Set the _NET_WM_DESKTOP atom. */ + DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n", + win->ws->idx); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id, + ewmh[_NET_WM_DESKTOP].atom, XCB_ATOM_CARDINAL, 32, 1, &win->ws->idx); + + /* Remove any _SWM_WS now that we set _NET_WM_DESKTOP. */ + xcb_delete_property(conn, win->id, a_swm_ws); + + /* WS must already be set for this to work. */ + store_float_geom(win); + /* Make sure window is positioned inside its region, if its active. */ if (win->ws->r) { region_containment(win, r, SWM_CW_ALLSIDES | @@ -8671,15 +9143,15 @@ manage_window(xcb_window_t id, uint16_t mapped) } out: - /* Figure out where to stack the window in the workspace. */ + /* Figure out where to insert the window in the workspace list. */ if (trans && (ww = find_window(trans))) TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); - else if (win->ws->focus && spawn_position == SWM_STACK_ABOVE) + else if (win->ws->focus && spawn_pos == SWM_STACK_ABOVE) TAILQ_INSERT_AFTER(&win->ws->winlist, win->ws->focus, win, entry); - else if (win->ws->focus && spawn_position == SWM_STACK_BELOW) + else if (win->ws->focus && spawn_pos == SWM_STACK_BELOW) TAILQ_INSERT_BEFORE(win->ws->focus, win, entry); - else switch (spawn_position) { + else switch (spawn_pos) { default: case SWM_STACK_TOP: case SWM_STACK_ABOVE: @@ -8692,7 +9164,8 @@ out: ewmh_update_client_list(); - TAILQ_INSERT_TAIL(&win->ws->stack, win, stack_entry); + TAILQ_INSERT_HEAD(&win->ws->stack, win, stack_entry); + lower_window(win); /* Get/apply initial _NET_WM_STATE */ ewmh_get_wm_state(win); @@ -8841,7 +9314,7 @@ buttonpress(xcb_button_press_event_t *e) struct ws_win *win = NULL; struct swm_region *r, *old_r; int i; - int handled = 0; + bool handled = false; DNPRINTF(SWM_D_EVENT, "buttonpress: win (x,y): %#x (%d,%d), " "detail: %u, time: %u, root (x,y): %#x (%d,%d), child: %#x, " @@ -8876,7 +9349,7 @@ buttonpress(xcb_button_press_event_t *e) /* Clear bar since empty. */ bar_draw(); - handled = 1; + handled = true; goto out; } } @@ -8896,7 +9369,7 @@ buttonpress(xcb_button_press_event_t *e) buttons[i].button == e->detail && CLEANMASK(buttons[i].mask) == CLEANMASK(e->state)) { buttons[i].func(win, &buttons[i].args); - handled = 1; + handled = true; } out: @@ -8970,13 +9443,14 @@ configurerequest(xcb_configure_request_event_t *e) { struct ws_win *win; struct swm_region *r = NULL; - int new = 0, i = 0; - uint16_t mask = 0; + int i = 0; uint32_t wc[7] = {0}; + uint16_t mask = 0; + bool new = false; if ((win = find_window(e->window)) == NULL) if ((win = find_unmanaged_window(e->window)) == NULL) - new = 1; + new = true; #ifdef SWM_DEBUG if (swm_debug & SWM_D_EVENT) { @@ -9066,16 +9540,20 @@ configurerequest(xcb_configure_request_event_t *e) if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) win->g_float.h = e->height; - win->g_floatvalid = 1; + win->g_floatvalid = true; - 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); @@ -9236,6 +9714,12 @@ enternotify(xcb_enter_notify_event_t *e) return; } + if (focus_mode != SWM_FOCUS_FOLLOW && + e->mode == XCB_NOTIFY_MODE_UNGRAB) { + DNPRINTF(SWM_D_EVENT, "enternotify: ungrab; ignoring.\n"); + return; + } + last_event_time = e->time; if ((win = find_window(e->event)) == NULL) { @@ -9255,6 +9739,13 @@ enternotify(xcb_enter_notify_event_t *e) return; } } else { + if (e->mode == XCB_NOTIFY_MODE_NORMAL && + e->detail == XCB_NOTIFY_DETAIL_INFERIOR) { + DNPRINTF(SWM_D_EVENT, "enternotify: entering from " + "inferior; ignoring\n"); + return; + } + focus_win(get_focus_magic(win)); } @@ -9284,7 +9775,7 @@ mapnotify(xcb_map_notify_event_t *e) DNPRINTF(SWM_D_EVENT, "mapnotify: win %#x\n", e->window); - if ((win = manage_window(e->window, 1)) == NULL) + if ((win = manage_window(e->window, spawn_position, true)) == NULL) return; ws = win->ws; @@ -9299,13 +9790,14 @@ mapnotify(xcb_map_notify_event_t *e) stack(); } - win->mapped = 1; + win->mapped = true; set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL); if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(win->ws)) { if (ws->focus_pending == win) { focus_win(win); ws->focus_pending = NULL; + center_pointer(win->ws->r); focus_flush(); } } @@ -9357,7 +9849,7 @@ maprequest(xcb_map_request_event_t *e) goto out; } - win = manage_window(e->window, + win = manage_window(e->window, spawn_position, (war->map_state == XCB_MAP_STATE_VIEWABLE)); if (win == NULL) goto out; @@ -9529,7 +10021,7 @@ unmapnotify(xcb_unmap_notify_event_t *e) return; ws = win->ws; - win->mapped = 0; + win->mapped = false; /* If win was focused, make sure to focus on something else. */ if (win == ws->focus) { @@ -9568,9 +10060,34 @@ unmapnotify(xcb_unmap_notify_event_t *e) } } + center_pointer(ws->r); focus_flush(); } +#ifdef SWM_DEBUG +char * +get_source_type_label(uint32_t type) +{ + char *label; + + switch (type) { + case EWMH_SOURCE_TYPE_NONE: + label = "None"; + break; + case EWMH_SOURCE_TYPE_NORMAL: + label = "Normal"; + break; + case EWMH_SOURCE_TYPE_OTHER: + label = "Other"; + break; + default: + label = "Invalid"; + } + + return label; +} +#endif + void clientmessage(xcb_client_message_event_t *e) { @@ -9597,8 +10114,7 @@ clientmessage(xcb_client_message_event_t *e) break; } - if (r && e->data.data32[0] < - (uint32_t)workspace_limit) { + if (r && e->data.data32[0] < (uint32_t)workspace_limit) { a.id = e->data.data32[0]; switchws(r, &a); focus_flush(); @@ -9620,11 +10136,22 @@ clientmessage(xcb_client_message_event_t *e) } if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) { - DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n"); - if (WS_FOCUSED(win->ws)) - focus_win(win); - else - win->ws->focus_pending = win; + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW, " + "source_type: %s(%d)\n", + get_source_type_label(e->data.data32[0]), + e->data.data32[0]); + + /* + * Allow focus changes that are a result of direct user + * action and from applications that use the old EWMH spec. + */ + if (e->data.data32[0] != EWMH_SOURCE_TYPE_NORMAL || + win->quirks & SWM_Q_OBEYAPPFOCUSREQ) { + if (WS_FOCUSED(win->ws)) + focus_win(win); + else + win->ws->focus_pending = win; + } } else if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) { DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n"); if (win->can_delete) @@ -9646,9 +10173,9 @@ clientmessage(xcb_client_message_event_t *e) update_window(win); } else { - /* TODO: Change stack sizes */ - /* notify no change was made. */ + /* 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"); @@ -9666,6 +10193,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], true); + + /* 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(); @@ -9833,7 +10373,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h) } void -scan_xrandr(int i) +scan_randr(int idx) { #ifdef SWM_XRR_HAS_CRTC int c; @@ -9849,34 +10389,34 @@ scan_xrandr(int i) xcb_randr_crtc_t *crtc; xcb_screen_t *screen; - DNPRINTF(SWM_D_MISC, "scan_xrandr: screen: %d\n", i); + DNPRINTF(SWM_D_MISC, "scan_randr: screen: %d\n", idx); - if ((screen = get_screen(i)) == NULL) - errx(1, "ERROR: can't get screen %d.", i); + if ((screen = get_screen(idx)) == NULL) + errx(1, "ERROR: can't get screen %d.", idx); num_screens = get_screen_count(); - if (i >= num_screens) - errx(1, "scan_xrandr: invalid screen"); + if (idx >= num_screens) + errx(1, "scan_randr: invalid screen"); /* remove any old regions */ - while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) { + while ((r = TAILQ_FIRST(&screens[idx].rl)) != NULL) { r->ws->old_r = r->ws->r = NULL; bar_cleanup(r); xcb_destroy_window(conn, r->id); - TAILQ_REMOVE(&screens[i].rl, r, entry); - TAILQ_INSERT_TAIL(&screens[i].orl, r, entry); + TAILQ_REMOVE(&screens[idx].rl, r, entry); + TAILQ_INSERT_TAIL(&screens[idx].orl, r, entry); } outputs = 0; /* map virtual screens onto physical screens */ #ifdef SWM_XRR_HAS_CRTC - if (xrandr_support) { + if (randr_support) { src = xcb_randr_get_screen_resources_current(conn, - screens[i].root); + screens[idx].root); srr = xcb_randr_get_screen_resources_current_reply(conn, src, NULL); if (srr == NULL) { - new_region(&screens[i], 0, 0, + new_region(&screens[idx], 0, 0, screen->width_in_pixels, screen->height_in_pixels); goto out; @@ -9896,11 +10436,11 @@ scan_xrandr(int i) } if (cir->mode == 0) - new_region(&screens[i], 0, 0, + new_region(&screens[idx], 0, 0, screen->width_in_pixels, screen->height_in_pixels); else - new_region(&screens[i], + new_region(&screens[idx], cir->x, cir->y, cir->width, cir->height); free(cir); } @@ -9909,23 +10449,23 @@ scan_xrandr(int i) #endif /* SWM_XRR_HAS_CRTC */ /* If detection failed, create a single region that spans the screen. */ - if (TAILQ_EMPTY(&screens[i].rl)) - new_region(&screens[i], 0, 0, screen->width_in_pixels, + if (TAILQ_EMPTY(&screens[idx].rl)) + new_region(&screens[idx], 0, 0, screen->width_in_pixels, screen->height_in_pixels); out: /* Cleanup unused previously visible workspaces. */ - TAILQ_FOREACH(r, &screens[i].orl, entry) { + TAILQ_FOREACH(r, &screens[idx].orl, entry) { TAILQ_FOREACH(win, &r->ws->winlist, entry) unmap_window(win); r->ws->state = SWM_WS_STATE_HIDDEN; /* The screen shouldn't focus on an unused region. */ - if (screens[i].r_focus == r) - screens[i].r_focus = NULL; + if (screens[idx].r_focus == r) + screens[idx].r_focus = NULL; } - DNPRINTF(SWM_D_MISC, "scan_xrandr: done.\n"); + DNPRINTF(SWM_D_MISC, "scan_randr: done.\n"); } void @@ -9945,7 +10485,7 @@ screenchange(xcb_randr_screen_change_notify_event_t *e) errx(1, "screenchange: screen not found"); /* brute force for now, just re-enumerate the regions */ - scan_xrandr(i); + scan_randr(i); #ifdef SWM_DEBUG print_win_geom(e->root); @@ -9981,8 +10521,9 @@ grab_windows(void) { struct swm_region *r = NULL; xcb_window_t *wins = NULL, trans, *cwins = NULL; - int i, j, k, n, no, num_screens, manage, mapped; + int i, j, k, n, no, num_screens; uint8_t state; + bool manage, mapped; xcb_query_tree_cookie_t qtc; xcb_query_tree_reply_t *qtr; @@ -10033,6 +10574,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; } } @@ -10063,11 +10609,11 @@ 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) - manage_window(wins[j], mapped); + manage_window(wins[j], SWM_STACK_TOP, mapped); free(gar); } /* transient windows */ @@ -10088,13 +10634,13 @@ 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]); if (xcb_icccm_get_wm_transient_for_reply(conn, pc, &trans, NULL) && manage) - manage_window(wins[j], mapped); + manage_window(wins[j], SWM_STACK_TOP, mapped); free(gar); } free(qtr); @@ -10119,16 +10665,16 @@ setup_screens(void) err(1, "setup_screens: calloc: failed to allocate memory for " "screens"); - /* initial Xrandr setup */ - xrandr_support = 0; + /* Initial RandR setup. */ + randr_support = false; qep = xcb_get_extension_data(conn, &xcb_randr_id); if (qep->present) { c = xcb_randr_query_version(conn, 1, 1); r = xcb_randr_query_version_reply(conn, c, NULL); if (r) { if (r->major_version >= 1) { - xrandr_support = 1; - xrandr_eventbase = qep->first_event; + randr_support = true; + randr_eventbase = qep->first_event; } free(r); } @@ -10149,13 +10695,16 @@ setup_screens(void) screens[i].root = screen->root; /* set default colors */ - setscreencolor("red", i + 1, SWM_S_COLOR_FOCUS); - setscreencolor("rgb:88/88/88", i + 1, SWM_S_COLOR_UNFOCUS); - setscreencolor("rgb:00/80/80", i + 1, SWM_S_COLOR_BAR_BORDER); - setscreencolor("rgb:00/40/40", i + 1, + setscreencolor("red", i, SWM_S_COLOR_FOCUS); + setscreencolor("rgb:88/88/88", i, SWM_S_COLOR_UNFOCUS); + setscreencolor("rgb:00/80/80", i, SWM_S_COLOR_BAR_BORDER); + setscreencolor("rgb:00/40/40", i, SWM_S_COLOR_BAR_BORDER_UNFOCUS); - setscreencolor("black", i + 1, SWM_S_COLOR_BAR); - setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT); + setscreencolor("black", i, SWM_S_COLOR_BAR); + setscreencolor("rgb:a0/a0/a0", i, SWM_S_COLOR_BAR_FONT); + setscreencolor("red", i, SWM_S_COLOR_FOCUS_MAXIMIZED); + setscreencolor("rgb:88/88/88", i, + SWM_S_COLOR_UNFOCUS_MAXIMIZED); /* create graphics context on screen */ screens[i].bar_gc = xcb_generate_id(conn); @@ -10173,7 +10722,7 @@ setup_screens(void) ws = &screens[i].ws[j]; ws->idx = j; ws->name = NULL; - ws->bar_enabled = 1; + ws->bar_enabled = true; ws->focus = NULL; ws->focus_prev = NULL; ws->focus_pending = NULL; @@ -10192,9 +10741,9 @@ setup_screens(void) ws->cur_layout->l_string(ws); } - scan_xrandr(i); + scan_randr(i); - if (xrandr_support) + if (randr_support) xcb_randr_select_input(conn, screens[i].root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); } @@ -10225,7 +10774,7 @@ setup_globals(void) void shutdown_cleanup(void) { - int i, num_screens; + int i, num_screens; /* disable alarm because the following code may not be interrupted */ alarm(0); @@ -10237,19 +10786,40 @@ shutdown_cleanup(void) cursors_cleanup(); + clear_quirks(); + clear_spawns(); + clear_keys(); + teardown_ewmh(); num_screens = get_screen_count(); for (i = 0; i < num_screens; ++i) { + int j; + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, screens[i].root, XCB_CURRENT_TIME); if (screens[i].bar_gc != XCB_NONE) xcb_free_gc(conn, screens[i].bar_gc); - if (!bar_font_legacy) + if (!bar_font_legacy) { XftColorFree(display, DefaultVisual(display, i), DefaultColormap(display, i), &bar_font_color); + XftColorFree(display, DefaultVisual(display, i), + DefaultColormap(display, i), &search_font_color); + } + + for (j = 0; j < SWM_S_COLOR_MAX; ++j) { + free(screens[i].c[j].name); + } + + for (j = 0; j < SWM_WS_MAX; ++j) { + free(screens[i].ws[j].name); + } } + free(screens); + + free(bar_format); + free(clock_format); if (bar_font_legacy) XFreeFontSet(display, bar_fs); @@ -10277,7 +10847,7 @@ event_error(xcb_generic_error_t *e) void event_handle(xcb_generic_event_t *evt) { - uint8_t type = XCB_EVENT_RESPONSE_TYPE(evt); + uint8_t type = XCB_EVENT_RESPONSE_TYPE(evt); DNPRINTF(SWM_D_EVENT, "XCB Event: %s(%d), seq %u\n", xcb_event_get_label(XCB_EVENT_RESPONSE_TYPE(evt)), @@ -10325,7 +10895,7 @@ event_handle(xcb_generic_event_t *evt) /*EVENT(XCB_VISIBILITY_NOTIFY, );*/ #undef EVENT } - if (type - xrandr_eventbase == XCB_RANDR_SCREEN_CHANGE_NOTIFY) + if (type - randr_eventbase == XCB_RANDR_SCREEN_CHANGE_NOTIFY) screenchange((void *)evt); } @@ -10335,19 +10905,19 @@ main(int argc, char *argv[]) struct swm_region *r; char conf[PATH_MAX], *cfile = NULL; struct stat sb; - int xfd, i, num_screens, startup = 1; + int xfd, i, num_screens; struct sigaction sact; xcb_generic_event_t *evt; - struct timeval tv; - fd_set rd; - int rd_max; - int stdin_ready = 0; int num_readable; + struct pollfd pfd[2]; + bool stdin_ready = false, startup = true; /* suppress unused warning since var is needed */ (void)argc; +#ifdef SWM_DEBUG time_started = time(NULL); +#endif start_argv = argv; warnx("Welcome to spectrwm V%s Build: %s", SPECTRWM_VERSION, buildstr); @@ -10452,9 +11022,6 @@ noconfig: validate_spawns(); - /* grab existing windows (before we build the bars) */ - grab_windows(); - if (getenv("SWM_STARTED") == NULL) setenv("SWM_STARTED", "YES", 1); @@ -10464,6 +11031,9 @@ noconfig: TAILQ_FOREACH(r, &screens[i].rl, entry) bar_setup(r); + /* Manage existing windows. */ + grab_windows(); + grabkeys(); stack(); bar_draw(); @@ -10476,7 +11046,11 @@ noconfig: TAILQ_FOREACH(r, &screens[i].rl, entry) r->ws->state = SWM_WS_STATE_MAPPED; - rd_max = xfd > STDIN_FILENO ? xfd : STDIN_FILENO; + memset(&pfd, 0, sizeof(pfd)); + pfd[0].fd = xfd; + pfd[0].events = POLLIN; + pfd[1].fd = STDIN_FILENO; + pfd[1].events = POLLIN; while (running) { while ((evt = xcb_poll_for_event(conn))) { @@ -10488,7 +11062,7 @@ noconfig: /* If just (re)started, set default focus if needed. */ if (startup) { - startup = 0; + startup = false; if (focus_mode != SWM_FOCUS_FOLLOW) { r = TAILQ_FIRST(&screens[0].rl); @@ -10500,19 +11074,11 @@ noconfig: } } - FD_ZERO(&rd); - - if (bar_extra) - FD_SET(STDIN_FILENO, &rd); - - FD_SET(xfd, &rd); - tv.tv_sec = 1; - tv.tv_usec = 0; - num_readable = select(rd_max + 1, &rd, NULL, NULL, &tv); - if (num_readable == -1 && errno != EINTR) { - DNPRINTF(SWM_D_MISC, "select failed"); - } else if (num_readable > 0 && FD_ISSET(STDIN_FILENO, &rd)) { - stdin_ready = 1; + num_readable = poll(pfd, bar_extra ? 2 : 1, 1000); + if (num_readable == -1) { + DNPRINTF(SWM_D_MISC, "poll failed: %s", strerror(errno)); + } else if (num_readable > 0 && bar_extra && pfd[1].revents & POLLIN) { + stdin_ready = true; } if (restart_wm) @@ -10525,7 +11091,7 @@ noconfig: goto done; if (stdin_ready) { - stdin_ready = 0; + stdin_ready = false; bar_extra_update(); }