X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=bd98c9d0b9ab5dc1c13d1a953149e0f2df0d28e0;hb=8e5c5f067be2b08dfa8f6ebc9e9582d8c0c57131;hp=e86f14b80fe3e5e3c667ad9ea11b1d27662c3bdb;hpb=a5985d7974c114fa3e773def2f45a7c9f0f09ddb;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index e86f14b..bd98c9d 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -112,15 +112,17 @@ static const char *buildstr = SPECTRWM_BUILDSTR; static const char *buildstr = SPECTRWM_VERSION; #endif -#if RANDR_MAJOR < 1 -# error XRandR versions less than 1.0 are not supported +#if !defined(__CYGWIN__) /* cygwin chokes on xrandr stuff */ +# if RANDR_MAJOR < 1 +# error XRandR versions less than 1.0 are not supported #endif -#if RANDR_MAJOR >= 1 -#if RANDR_MINOR >= 2 -#define SWM_XRR_HAS_CRTC -#endif -#endif +# if RANDR_MAJOR >= 1 +# if RANDR_MINOR >= 2 +# define SWM_XRR_HAS_CRTC +# endif +# endif +#endif /* __CYGWIN__ */ #ifndef XCB_ICCCM_NUM_WM_HINTS_ELEMENTS #define XCB_ICCCM_SIZE_HINT_P_MIN_SIZE XCB_SIZE_HINT_P_MIN_SIZE @@ -151,7 +153,7 @@ static const char *buildstr = SPECTRWM_VERSION; #define xcb_icccm_wm_hints_t xcb_wm_hints_t #endif -#define SWM_DEBUG +/*#define SWM_DEBUG*/ #ifdef SWM_DEBUG #define DPRINTF(x...) do { \ if (swm_debug) \ @@ -323,49 +325,58 @@ double dialog_ratio = 0.6; #define SWM_BAR_JUSTIFY_CENTER (1) #define SWM_BAR_JUSTIFY_RIGHT (2) #define SWM_BAR_OFFSET (4) -#define SWM_BAR_FONTS "-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*," \ - "-*-profont-*-*-*-*-*-*-*-*-*-*-*-*," \ - "-*-times-medium-r-*-*-*-*-*-*-*-*-*-*," \ - "-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*," \ - "-*-*-*-r-*--*-*-*-*-*-*-*-*" - -char *bar_argv[] = { NULL, NULL }; -int bar_pipe[2]; -unsigned char bar_ext[SWM_BAR_MAX]; -char bar_vertext[SWM_BAR_MAX]; -int bar_version = 0; -sig_atomic_t bar_alarm = 0; -int bar_delay = 30; -int bar_enabled = 1; -int bar_border_width = 1; -int bar_at_bottom = 0; -int bar_extra = 1; -int bar_extra_running = 0; -int bar_verbose = 1; -int bar_height = 0; -int bar_justify = SWM_BAR_JUSTIFY_LEFT; -char *bar_format = NULL; -int stack_enabled = 1; -int clock_enabled = 1; -int urgent_enabled = 0; -char *clock_format = NULL; -int title_name_enabled = 0; -int title_class_enabled = 0; -int window_name_enabled = 0; -int focus_mode = SWM_FOCUS_DEFAULT; -int focus_close = SWM_STACK_BELOW; -int focus_close_wrap = 1; -int focus_default = SWM_STACK_TOP; -int spawn_position = SWM_STACK_TOP; -int disable_border = 0; -int border_width = 1; -int verbose_layout = 0; -time_t time_started; -pid_t bar_pid; -XftFont *bar_font; -char *bar_fonts; -XftColor bar_font_color; -struct passwd *pwd; +#define SWM_BAR_FONTS "-*-terminus-medium-*-*-*-12-*-*-*-*-*-*-*," \ + "-*-profont-*-*-*-*-12-*-*-*-*-*-*-*," \ + "-*-times-medium-r-*-*-12-*-*-*-*-*-*-*," \ + "-misc-fixed-medium-r-*-*-12-*-*-*-*-*-*-*," \ + "-*-*-*-r-*-*-*-*-*-*-*-*-*-*" + +#ifdef X_HAVE_UTF8_STRING +#define DRAWSTRING(x...) Xutf8DrawString(x) +#else +#define DRAWSTRING(x...) XmbDrawString(x) +#endif + +char *bar_argv[] = { NULL, NULL }; +int bar_pipe[2]; +unsigned char bar_ext[SWM_BAR_MAX]; +char bar_vertext[SWM_BAR_MAX]; +int bar_version = 0; +sig_atomic_t bar_alarm = 0; +int bar_delay = 30; +int bar_enabled = 1; +int bar_border_width = 1; +int bar_at_bottom = 0; +int bar_extra = 1; +int bar_extra_running = 0; +int bar_verbose = 1; +int bar_height = 0; +int bar_justify = SWM_BAR_JUSTIFY_LEFT; +char *bar_format = NULL; +int stack_enabled = 1; +int clock_enabled = 1; +int urgent_enabled = 0; +char *clock_format = NULL; +int title_name_enabled = 0; +int title_class_enabled = 0; +int window_name_enabled = 0; +int focus_mode = SWM_FOCUS_DEFAULT; +int focus_close = SWM_STACK_BELOW; +int focus_close_wrap = 1; +int focus_default = SWM_STACK_TOP; +int spawn_position = SWM_STACK_TOP; +int disable_border = 0; +int border_width = 1; +int verbose_layout = 0; +time_t time_started; +pid_t bar_pid; +XFontSet bar_fs; +XFontSetExtents *bar_fs_extents; +XftFont *bar_font; +int bar_font_legacy = 1; +char *bar_fonts; +XftColor bar_font_color; +struct passwd *pwd; /* layout manager data */ struct swm_geometry { @@ -522,6 +533,7 @@ struct swm_screen { } c[SWM_S_COLOR_MAX]; xcb_gcontext_t bar_gc; + GC bar_gc_legacy; }; struct swm_screen *screens; @@ -597,6 +609,7 @@ enum { _NET_WM_ACTION_MOVE, _NET_WM_ACTION_RESIZE, _NET_WM_ALLOWED_ACTIONS, + _NET_WM_NAME, _NET_WM_STATE, _NET_WM_STATE_ABOVE, _NET_WM_STATE_FULLSCREEN, @@ -629,6 +642,7 @@ struct ewmh_hint { {"_NET_WM_ACTION_MOVE", XCB_ATOM_NONE}, {"_NET_WM_ACTION_RESIZE", XCB_ATOM_NONE}, {"_NET_WM_ALLOWED_ACTIONS", XCB_ATOM_NONE}, + {"_NET_WM_NAME", XCB_ATOM_NONE}, {"_NET_WM_STATE", XCB_ATOM_NONE}, {"_NET_WM_STATE_ABOVE", XCB_ATOM_NONE}, {"_NET_WM_STATE_FULLSCREEN", XCB_ATOM_NONE}, @@ -649,6 +663,7 @@ struct ewmh_hint { /* function prototypes */ void buttonpress(xcb_button_press_event_t *); +void check_conn(void); void clientmessage(xcb_client_message_event_t *); int conf_load(char *, int); void configurenotify(xcb_configure_notify_event_t *); @@ -659,6 +674,7 @@ void do_sync(void); void enternotify(xcb_enter_notify_event_t *); void event_error(xcb_generic_error_t *); void event_handle(xcb_generic_event_t *); +char *expand_tilde(char *); void expose(xcb_expose_event_t *); struct ws_win *find_window(xcb_window_t); int floating_toggle_win(struct ws_win *); @@ -690,12 +706,56 @@ int parse_rgb(const char *, uint16_t *, uint16_t *, uint16_t *); void propertynotify(xcb_property_notify_event_t *); void spawn_select(struct swm_region *, union arg *, char *, int *); void screenchange(xcb_randr_screen_change_notify_event_t *); +void shutdown_cleanup(void); void store_float_geom(struct ws_win *, struct swm_region *); void unmanage_window(struct ws_win *); void unmapnotify(xcb_unmap_notify_event_t *); void update_window(struct ws_win *); /*void visibilitynotify(xcb_visibility_notify_event_t *);*/ +char * +expand_tilde(char *s) +{ + struct passwd *ppwd; + int i, max; + char *user; + const char *sc = s; + char *result; + + if (s == NULL) + errx(1, "expand_tilde: NULL string."); + + if (s[0] != '~') { + result = strdup(sc); + goto out; + } + + ++s; + + if ((max = sysconf(_SC_LOGIN_NAME_MAX)) == -1) + errx(1, "expand_tilde: sysconf"); + + if ((user = calloc(1, max + 1)) == NULL) + errx(1, "expand_tilde: calloc"); + + for (i = 0; s[i] != '/' && s[i] != '\0'; ++i) + user[i] = s[i]; + user[i] = '\0'; + s = &s[i]; + + ppwd = strlen(user) == 0 ? getpwuid(getuid()) : getpwnam(user); + if (ppwd == NULL) + result = strdup(sc); + else + if (asprintf(&result, "%s%s", ppwd->pw_dir, s) == -1) + result = NULL; +out: + if (result == NULL) + errx(1, "expand_tilde: failed to allocate memory."); + + return result; +} + int parse_rgb(const char *rgb, uint16_t *rr, uint16_t *gg, uint16_t *bb) { @@ -714,12 +774,18 @@ parse_rgb(const char *rgb, uint16_t *rr, uint16_t *gg, uint16_t *bb) xcb_screen_t * get_screen(int screen) { - xcb_screen_iterator_t i; + const xcb_setup_t *r; + xcb_screen_iterator_t iter; + + if ((r = xcb_get_setup(conn)) == NULL) { + DNPRINTF(SWM_D_MISC, "get_screen: xcb_get_setup\n"); + check_conn(); + } - i = xcb_setup_roots_iterator(xcb_get_setup(conn)); - for (; i.rem; --screen, xcb_screen_next(&i)) + iter = xcb_setup_roots_iterator(r); + for (; iter.rem; --screen, xcb_screen_next(&iter)) if (screen == 0) - return (i.data); + return (iter.data); return (NULL); } @@ -958,7 +1024,7 @@ ewmh_update_actions(struct ws_win *win) #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ void -ewmh_update_win_state(struct ws_win *win, long state, long action) +ewmh_update_win_state(struct ws_win *win, xcb_atom_t state, long action) { unsigned int mask = 0; unsigned int changed = 0; @@ -968,7 +1034,7 @@ ewmh_update_win_state(struct ws_win *win, long state, long action) return; DNPRINTF(SWM_D_PROP, "ewmh_update_win_state: window: 0x%x, state: %ld, " - "action: %ld\n", win->id, state, action); + "action: %ld\n", win->id, (unsigned long)state, action); if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) mask = EWMH_F_FULLSCREEN; @@ -1119,8 +1185,10 @@ dumpwins(struct swm_region *r, union arg *args) } #else void -dumpwins(struct swm_region *r, union arg *args) +dumpwins(struct swm_region *r, union arg *s) { + (void)r; + (void)s; } #endif /* SWM_DEBUG */ @@ -1303,7 +1371,9 @@ custom_region(char *val) sidx, num_screens); sidx--; - screen = get_screen(sidx); + if ((screen = get_screen(sidx)) == NULL) + errx(1, "ERROR: can't get screen %d.", sidx); + if (w < 1 || h < 1) errx(1, "region %ux%u+%u+%u too small", w, h, x, y); @@ -1333,6 +1403,60 @@ socket_setnonblock(int fd) } void +bar_print_legacy(struct swm_region *r, const char *s) +{ + xcb_rectangle_t rect; + uint32_t gcv[1]; + XGCValues gcvd; + int x = 0; + size_t len; + XRectangle ibox, lbox; + GC draw; + + len = strlen(s); + XmbTextExtents(bar_fs, s, len, &ibox, &lbox); + + switch (bar_justify) { + case SWM_BAR_JUSTIFY_LEFT: + x = SWM_BAR_OFFSET; + break; + case SWM_BAR_JUSTIFY_CENTER: + x = (WIDTH(r) - lbox.width) / 2; + break; + case SWM_BAR_JUSTIFY_RIGHT: + x = WIDTH(r) - lbox.width - SWM_BAR_OFFSET; + break; + } + + if (x < SWM_BAR_OFFSET) + x = SWM_BAR_OFFSET; + + rect.x = 0; + rect.y = 0; + rect.width = WIDTH(r->bar); + rect.height = HEIGHT(r->bar); + + /* clear back buffer */ + gcv[0] = r->s->c[SWM_S_COLOR_BAR].pixel; + xcb_change_gc(conn, r->s->bar_gc, XCB_GC_FOREGROUND, gcv); + xcb_poly_fill_rectangle(conn, r->bar->buffer, r->s->bar_gc, + sizeof(rect), &rect); + + /* draw back buffer */ + gcvd.graphics_exposures = 0; + draw = XCreateGC(display, r->bar->buffer, GCGraphicsExposures, &gcvd); + XSetForeground(display, draw, r->s->c[SWM_S_COLOR_BAR_FONT].pixel); + DRAWSTRING(display, r->bar->buffer, bar_fs, draw, + x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 - + lbox.y, s, len); + XFreeGC(display, draw); + + /* blt */ + xcb_copy_area(conn, r->bar->buffer, r->bar->id, r->s->bar_gc, 0, 0, + 0, 0, WIDTH(r->bar), HEIGHT(r->bar)); +} + +void bar_print(struct swm_region *r, const char *s) { size_t len; @@ -1373,11 +1497,6 @@ bar_print(struct swm_region *r, const char *s) sizeof(rect), &rect); /* draw back buffer */ - gcv[0] = r->s->c[SWM_S_COLOR_BAR].pixel; - xcb_change_gc(conn, r->s->bar_gc, XCB_GC_BACKGROUND, gcv); - gcv[0] = r->s->c[SWM_S_COLOR_BAR_FONT].pixel; - xcb_change_gc(conn, r->s->bar_gc, XCB_GC_FOREGROUND, gcv); - draw = XftDrawCreate(display, r->bar->buffer, DefaultVisual(display, r->s->idx), DefaultColormap(display, r->s->idx)); @@ -1729,7 +1848,10 @@ bar_fmt_print(void) continue; bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew); bar_replace(fmtnew, fmtrep, r, sizeof fmtrep); - bar_print(r, fmtrep); + if (bar_font_legacy) + bar_print_legacy(r, fmtrep); + else + bar_print(r, fmtrep); } } } @@ -1852,44 +1974,88 @@ bar_refresh(void) bar_update(); } +int +isxlfd(char *s) +{ + int count = 0; + + while ((s = index(s, '-'))) { + ++count; + ++s; + } + + return (count == 14); +} + void -bar_setup(struct swm_region *r) +fontset_init() { - char *font, *fontpos, *dup, *search; - int count; - xcb_screen_t *screen = get_screen(r->s->idx); - uint32_t wa[3]; - XRenderColor color; + char *default_string; + char **missing_charsets; + int num_missing_charsets = 0; + int i; - if (r->bar != NULL) - return; + if (bar_fs) { + XFreeFontSet(display, bar_fs); + bar_fs = NULL; + } - if ((r->bar = calloc(1, sizeof(struct swm_bar))) == NULL) - err(1, "bar_setup: calloc: failed to allocate memory."); + DNPRINTF(SWM_D_INIT, "fontset_init: loading bar_fonts: %s\n", bar_fonts); + + bar_fs = XCreateFontSet(display, bar_fonts, &missing_charsets, + &num_missing_charsets, &default_string); + + if (num_missing_charsets > 0) { + warnx("Unable to load charset(s):"); + + for (i = 0; i < num_missing_charsets; ++i) + warnx("%s", missing_charsets[i]); + + XFreeStringList(missing_charsets); + + if (strcmp(default_string, "")) + warnx("Glyphs from those sets will be replaced " + "by '%s'.", default_string); + else + warnx("Glyphs from those sets won't be drawn."); + } + + if (bar_fs == NULL) + errx(1, "Error creating font set structure."); + + bar_fs_extents = XExtentsOfFontSet(bar_fs); + + bar_height = bar_fs_extents->max_logical_extent.height + + 2 * bar_border_width; + + if (bar_height < 1) + bar_height = 1; +} + +void +xft_init(struct swm_region *r) +{ + char *font, *d, *search; + XRenderColor color; if (bar_font == NULL) { - if ((dup = strdup(bar_fonts)) == NULL) + if ((d = strdup(bar_fonts)) == NULL) errx(1, "insufficient memory."); - search = dup; + search = d; while ((font = strsep(&search, ",")) != NULL) { if (*font == '\0') continue; - DNPRINTF(SWM_D_INIT, "bar_setup: try font %s\n", font); + DNPRINTF(SWM_D_INIT, "xft_init: try font %s\n", font); - count = 0; - fontpos = font; - while ((fontpos = index(fontpos, '-'))) { - count++; - fontpos++; - } - - if (count == 14) + if (isxlfd(font)) { bar_font = XftFontOpenXlfd(display, r->s->idx, font); - else + } else { bar_font = XftFontOpenName(display, r->s->idx, font); + } + if (!bar_font) { warnx("unable to load font %s", font); continue; @@ -1899,22 +2065,46 @@ bar_setup(struct swm_region *r) break; } } - free(dup); + free(d); } if (bar_font == NULL) errx(1, "unable to open a font"); + PIXEL_TO_XRENDERCOLOR(r->s->c[SWM_S_COLOR_BAR_FONT].pixel, color); + + if (!XftColorAllocValue(display, DefaultVisual(display, r->s->idx), + DefaultColormap(display, r->s->idx), &color, &bar_font_color)) + warn("unable to allocate Xft color"); + bar_height = bar_font->height + 2 * bar_border_width; if (bar_height < 1) bar_height = 1; +} - PIXEL_TO_XRENDERCOLOR(r->s->c[SWM_S_COLOR_BAR_FONT].pixel, color); +void +bar_setup(struct swm_region *r) +{ + xcb_screen_t *screen; + uint32_t wa[3]; - if (!XftColorAllocValue(display, DefaultVisual(display, r->s->idx), - DefaultColormap(display, r->s->idx), &color, &bar_font_color)) - warn("unable to allocate Xft color"); + DNPRINTF(SWM_D_BAR, "bar_setup: screen %d.\n", + r->s->idx); + + if ((screen = get_screen(r->s->idx)) == NULL) + errx(1, "ERROR: can't get screen %d.", r->s->idx); + + if (r->bar != NULL) + return; + + if ((r->bar = calloc(1, sizeof(struct swm_bar))) == NULL) + err(1, "bar_setup: calloc: failed to allocate memory."); + + if (bar_font_legacy) + fontset_init(); + else + xft_init(r); X(r->bar) = X(r); Y(r->bar) = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r); @@ -1936,8 +2126,9 @@ bar_setup(struct swm_region *r) xcb_create_pixmap(conn, screen->root_depth, r->bar->buffer, r->bar->id, WIDTH(r->bar), HEIGHT(r->bar)); - xcb_randr_select_input(conn, r->bar->id, - XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE); + if (xrandr_support) + xcb_randr_select_input(conn, r->bar->id, + XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE); if (bar_enabled) map_window_raised(r->bar->id); @@ -2065,12 +2256,13 @@ config_win(struct ws_win *win, xcb_configure_request_event_t *ev) ce.window = ev->window; /* make response appear more WM_SIZE_HINTS-compliant */ - if (win->sh.flags) + if (win->sh.flags) { DNPRINTF(SWM_D_MISC, "config_win: hints: window: 0x%x," " sh.flags: %u, min: %d x %d, max: %d x %d, inc: " "%d x %d\n", win->id, win->sh.flags, SH_MIN_W(win), SH_MIN_H(win), SH_MAX_W(win), SH_MAX_H(win), SH_INC_W(win), SH_INC_H(win)); + } /* min size */ if (SH_MIN(win)) { @@ -2220,25 +2412,12 @@ void restart(struct swm_region *r, union arg *args) { /* suppress unused warning since var is needed */ + (void)r; (void)args; DNPRINTF(SWM_D_MISC, "restart: %s\n", start_argv[0]); - /* disable alarm because the following code may not be interrupted */ - alarm(0); - if (signal(SIGALRM, SIG_IGN) == SIG_ERR) - err(1, "can't disable alarm"); - - bar_extra_stop(); - bar_extra = 1; - unmap_all(); - - XftFontClose(display, bar_font); - XftColorFree(display, DefaultVisual(display, r->s->idx), - DefaultColormap(display, r->s->idx), &bar_font_color); - xcb_key_symbols_free(syms); - xcb_flush(conn); - xcb_disconnect(conn); + shutdown_cleanup(); execvp(start_argv[0], start_argv); warn("execvp failed"); @@ -2703,6 +2882,8 @@ priorws(struct swm_region *r, union arg *args) { union arg a; + (void)args; + DNPRINTF(SWM_D_WS, "priorws: 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); @@ -3741,21 +3922,32 @@ get_win_name(xcb_window_t win) { char *name = NULL; xcb_get_property_cookie_t c; - xcb_icccm_get_text_property_reply_t r; + xcb_get_property_reply_t *r; - c = xcb_icccm_get_wm_name(conn, win); - if (xcb_icccm_get_wm_name_reply(conn, c, &r, NULL)) { - if (r.name_len > 0) { - name = malloc(r.name_len + 1); - if (name) { - memcpy(name, r.name, r.name_len); - name[r.name_len] = '\0'; - } + /* First try _NET_WM_NAME for UTF-8. */ + c = xcb_get_property(conn, 0, win, a_netwmname, + XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); + r = xcb_get_property_reply(conn, c, NULL); + + if (!r || r->type == XCB_NONE) { + free(r); + /* Use WM_NAME instead; no UTF-8. */ + c = xcb_get_property(conn, 0, win, XCB_ATOM_WM_NAME, + XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); + r = xcb_get_property_reply(conn, c, NULL); + + if(!r || r->type == XCB_NONE) { + free(r); + return NULL; } - xcb_icccm_get_text_property_reply_wipe(&r); } - return (name); + if (r->length > 0) + name = strndup(xcb_get_property_value(r), + xcb_get_property_value_length(r)); + + free(r); + return name; } void @@ -3868,7 +4060,6 @@ search_win_cleanup(void) while ((sw = TAILQ_FIRST(&search_wl)) != NULL) { xcb_destroy_window(conn, sw->indicator); - xcb_free_gc(conn, sw->gc); TAILQ_REMOVE(&search_wl, sw, entry); free(sw); } @@ -3880,13 +4071,16 @@ 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 gcv[3], wa[2]; - int i; + uint32_t wa[2]; + int i, width, height; char s[8]; FILE *lfile; size_t len; XftDraw *draw; XGlyphInfo info; + GC l_draw; + XGCValues l_gcv; + XRectangle l_ibox, l_lbox; DNPRINTF(SWM_D_MISC, "search_win\n"); @@ -3918,36 +4112,55 @@ search_win(struct swm_region *r, union arg *args) snprintf(s, sizeof s, "%d", i); len = strlen(s); - XftTextExtentsUtf8(display, bar_font, (FcChar8 *)s, len, &info); - 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; + + if (bar_font_legacy) { + XmbTextExtents(bar_fs, s, len, &l_ibox, &l_lbox); + width = l_lbox.width + 4; + height = bar_fs_extents->max_logical_extent.height + 4; + } else { + XftTextExtentsUtf8(display, bar_font, (FcChar8 *)s, len, + &info); + width = info.width + 4; + height = bar_font->height + 4; + } + xcb_create_window(conn, XCB_COPY_FROM_PARENT, w, win->id, 0, 0, - info.width + 4, bar_font->height + 4, - 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, - XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL, wa); + width, height, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | + XCB_CW_BORDER_PIXEL, wa); + + map_window_raised(w); sw->indicator = w; TAILQ_INSERT_TAIL(&search_wl, sw, entry); - sw->gc = xcb_generate_id(conn); - gcv[0] = r->s->c[SWM_S_COLOR_BAR].pixel; - gcv[1] = r->s->c[SWM_S_COLOR_FOCUS].pixel; - gcv[2] = 0; - xcb_create_gc(conn, sw->gc, w, XCB_GC_FOREGROUND | - XCB_GC_BACKGROUND | XCB_GC_GRAPHICS_EXPOSURES, gcv); - map_window_raised(w); + if (bar_font_legacy) { + l_gcv.graphics_exposures = 0; + l_draw = XCreateGC(display, w, 0, &l_gcv); + + XSetForeground(display, l_draw, + r->s->c[SWM_S_COLOR_BAR].pixel); + + DRAWSTRING(display, w, bar_fs, l_draw, 2, + (bar_fs_extents->max_logical_extent.height - + l_lbox.height) / 2 - l_lbox.y, s, len); - draw = XftDrawCreate(display, w, - DefaultVisual(display, r->s->idx), - DefaultColormap(display, r->s->idx)); + XFreeGC(display, l_draw); + } else { + + draw = XftDrawCreate(display, w, + DefaultVisual(display, r->s->idx), + DefaultColormap(display, r->s->idx)); - XftDrawStringUtf8(draw, &bar_font_color, bar_font, 2, - (HEIGHT(r->bar) + bar_font->height) / 2 - bar_font->descent, - (FcChar8 *)s, len); + XftDrawStringUtf8(draw, &bar_font_color, bar_font, 2, + (HEIGHT(r->bar) + bar_font->height) / 2 - + bar_font->descent, (FcChar8 *)s, len); - XftDrawDestroy(draw); + XftDrawDestroy(draw); + } DNPRINTF(SWM_D_MISC, "search_win: mapped window: 0x%x\n", w); @@ -5122,12 +5335,17 @@ setspawn(char *name, char *args) int setconfspawn(char *selector, char *value, int flags) { + char *args; + /* suppress unused warning since var is needed */ (void)flags; - DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, value); + args = expand_tilde(value); - setspawn(selector, value); + DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, args); + + setspawn(selector, args); + free(args); DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n"); return (0); @@ -5718,7 +5936,7 @@ setconfquirk(char *selector, char *value, int flags) { char *cp, *class, *name; int retval; - unsigned long quirks; + unsigned long qrks; /* suppress unused warning since var is needed */ (void)flags; @@ -5730,8 +5948,8 @@ setconfquirk(char *selector, char *value, int flags) *cp = '\0'; class = selector; name = cp + 1; - if ((retval = parsequirks(value, &quirks)) == 0) - setquirk(class, name, quirks); + if ((retval = parsequirks(value, &qrks)) == 0) + setquirk(class, name, qrks); return (retval); } @@ -5803,7 +6021,7 @@ setconfvalue(char *selector, char *value, int flags) switch (flags) { case SWM_S_BAR_ACTION: free(bar_argv[0]); - if ((bar_argv[0] = strdup(value)) == NULL) + if ((bar_argv[0] = expand_tilde(value)) == NULL) err(1, "setconfvalue: bar_action"); break; case SWM_S_BAR_AT_BOTTOM: @@ -5826,6 +6044,20 @@ setconfvalue(char *selector, char *value, int flags) err(1, "setconfvalue: asprintf: failed to allocate " "memory for bar_fonts."); free(b); + + /* If already in xft mode, then we are done. */ + if (!bar_font_legacy) + break; + + /* If there are any non-XLFD entries, switch to Xft mode. */ + while ((b = strsep(&value, ",")) != NULL) { + if (*b == '\0') + continue; + if (!isxlfd(b)) { + bar_font_legacy = 0; + break; + } + } break; case SWM_S_BAR_FORMAT: free(bar_format); @@ -6077,7 +6309,7 @@ setautorun(char *selector, char *value, int flags) int setlayout(char *selector, char *value, int flags) { - int ws_id, i, x, mg, ma, si, raise, f = 0; + int ws_id, i, x, mg, ma, si, ar, f = 0; int st = SWM_V_STACK, num_screens; char s[1024]; struct workspace *ws; @@ -6091,7 +6323,7 @@ setlayout(char *selector, char *value, int flags) bzero(s, sizeof s); if (sscanf(value, "ws[%d]:%d:%d:%d:%d:%1023c", - &ws_id, &mg, &ma, &si, &raise, s) != 6) + &ws_id, &mg, &ma, &si, &ar, s) != 6) errx(1, "invalid layout entry, should be 'ws[]:" "::::" "'"); @@ -6121,7 +6353,7 @@ setlayout(char *selector, char *value, int flags) ws = (struct workspace *)&screens[i].ws; ws[ws_id].cur_layout = &layouts[st]; - ws[ws_id].always_raise = raise; + ws[ws_id].always_raise = ar; if (st == SWM_MAX_STACK) continue; @@ -6217,7 +6449,7 @@ conf_load(char *filename, int keymapping) FILE *config; char *line, *cp, *optsub, *optval; size_t linelen, lineno = 0; - int wordlen, i, optind; + int wordlen, i, optidx; struct config_option *opt; DNPRINTF(SWM_D_CONF, "conf_load: begin\n"); @@ -6253,16 +6485,16 @@ conf_load(char *filename, int keymapping) filename, lineno); goto out; } - optind = -1; + optidx = -1; for (i = 0; i < LENGTH(configopt); i++) { opt = &configopt[i]; if (!strncasecmp(cp, opt->optname, wordlen) && (int)strlen(opt->optname) == wordlen) { - optind = i; + optidx = i; break; } } - if (optind == -1) { + if (optidx == -1) { warnx("%s: line %zd: unknown option %.*s", filename, lineno, wordlen, cp); goto out; @@ -6301,10 +6533,10 @@ conf_load(char *filename, int keymapping) /* get RHS value */ optval = strdup(cp); /* call function to deal with it all */ - if (configopt[optind].func(optsub, optval, - configopt[optind].funcflags) != 0) + if (configopt[optidx].func(optsub, optval, + configopt[optidx].funcflags) != 0) errx(1, "%s: line %zd: invalid data for %s", - filename, lineno, configopt[optind].optname); + filename, lineno, configopt[optidx].optname); free(optval); free(optsub); free(line); @@ -6463,7 +6695,6 @@ manage_window(xcb_window_t id) struct quirk *qp; uint32_t event_mask, i; xcb_icccm_get_wm_protocols_reply_t wpr; - xcb_icccm_get_wm_class_reply_t tmpch; if ((win = find_window(id)) != NULL) return (win); /* already being managed */ @@ -6629,12 +6860,7 @@ manage_window(xcb_window_t id) if (xcb_icccm_get_wm_class_reply(conn, xcb_icccm_get_wm_class(conn, win->id), - &tmpch, NULL)) { - win->ch.class_name = tmpch.class_name; - win->ch.instance_name = tmpch.instance_name; - - xcb_icccm_get_wm_class_reply_wipe(&tmpch); - + &win->ch, NULL)) { DNPRINTF(SWM_D_CLASS, "manage_window: class: %s, name: %s\n", win->ch.class_name, win->ch.instance_name); @@ -6717,6 +6943,8 @@ free_window(struct ws_win *win) if (win->wa) free(win->wa); + xcb_icccm_get_wm_class_reply_wipe(&win->ch); + kill_refs(win); /* paint memory */ @@ -7113,7 +7341,6 @@ enternotify(xcb_enter_notify_event_t *e) void leavenotify(xcb_leave_notify_event_t *e) { - struct ws_win *win; DNPRINTF(SWM_D_FOCUS, "leavenotify: window: 0x%x, mode: %s(%d), " "detail: %s(%d), root: 0x%x, subwindow: 0x%x, same_screen_focus: " "%s, state: %d\n", e->event, get_notify_mode_label(e->mode), @@ -7350,6 +7577,39 @@ clientmessage(xcb_client_message_event_t *e) xcb_flush(conn); } +void +check_conn(void) +{ + int errcode = xcb_connection_has_error(conn); +#ifdef XCB_CONN_ERROR + char *s; + switch (errcode) { + case XCB_CONN_ERROR: + s = "Socket error, pipe error or other stream error."; + break; + case XCB_CONN_CLOSED_EXT_NOTSUPPORTED: + s = "Extension not supported."; + break; + case XCB_CONN_CLOSED_MEM_INSUFFICIENT: + s = "Insufficient memory."; + break; + case XCB_CONN_CLOSED_REQ_LEN_EXCEED: + s = "Request length was exceeded."; + break; + case XCB_CONN_CLOSED_PARSE_ERR: + s = "Error parsing display string."; + break; + default: + s = "Unknown error."; + } + if (errcode) + errx(errcode, "X CONNECTION ERROR: %s", s); +#else + if (errcode) + errx(errcode, "X CONNECTION ERROR"); +#endif +} + int enable_wm(void) { @@ -7362,7 +7622,8 @@ enable_wm(void) /* this causes an error if some other window manager is running */ num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); for (i = 0; i < num_screens; i++) { - sc = get_screen(i); + if ((sc = get_screen(i)) == NULL) + errx(1, "ERROR: can't get screen %d.", i); DNPRINTF(SWM_D_INIT, "enable_wm: screen %d, root: 0x%x\n", i, sc->root); wac = xcb_change_window_attributes_checked(conn, sc->root, @@ -7467,7 +7728,10 @@ scan_xrandr(int i) xcb_randr_get_crtc_info_cookie_t cic; xcb_randr_get_crtc_info_reply_t *cir = NULL; xcb_randr_crtc_t *crtc; - xcb_screen_t *screen = get_screen(i); + xcb_screen_t *screen; + + if ((screen = get_screen(i)) == NULL) + errx(1, "ERROR: can't get screen %d.", i); num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); if (i >= num_screens) @@ -7635,6 +7899,7 @@ setup_screens(void) struct workspace *ws; uint32_t gcv[1], wa[1]; const xcb_query_extension_reply_t *qep; + xcb_screen_t *screen; xcb_cursor_t cursor; xcb_font_t cursor_font; xcb_randr_query_version_cookie_t c; @@ -7648,15 +7913,18 @@ setup_screens(void) /* initial Xrandr setup */ xrandr_support = 0; - 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; - free(r); - } qep = xcb_get_extension_data(conn, &xcb_randr_id); - xrandr_eventbase = qep->first_event; + 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; + } + free(r); + } + } cursor_font = xcb_generate_id(conn); xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor"); @@ -7672,7 +7940,9 @@ setup_screens(void) screens[i].idx = i; TAILQ_INIT(&screens[i].rl); TAILQ_INIT(&screens[i].orl); - screens[i].root = get_screen(i)->root; + if ((screen = get_screen(i)) == NULL) + errx(1, "ERROR: can't get screen %d.", i); + screens[i].root = screen->root; /* set default colors */ setscreencolor("red", i + 1, SWM_S_COLOR_FOCUS); @@ -7777,8 +8047,46 @@ workaround(void) } void +shutdown_cleanup(void) +{ + int i, num_screens; + + /* disable alarm because the following code may not be interrupted */ + alarm(0); + if (signal(SIGALRM, SIG_IGN) == SIG_ERR) + err(1, "can't disable alarm"); + + bar_extra_stop(); + bar_extra = 1; + unmap_all(); + + teardown_ewmh(); + + num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); + for (i = 0; i < num_screens; ++i) { + if (screens[i].bar_gc != 0) + xcb_free_gc(conn, screens[i].bar_gc); + if (!bar_font_legacy) + XftColorFree(display, DefaultVisual(display, i), + DefaultColormap(display, i), &bar_font_color); + } + + if (bar_font_legacy) + XFreeFontSet(display, bar_fs); + else { + XftFontClose(display, bar_font); + } + + xcb_key_symbols_free(syms); + xcb_flush(conn); + xcb_disconnect(conn); +} + +void event_error(xcb_generic_error_t *e) { + (void)e; + DNPRINTF(SWM_D_EVENT, "event_error: %s(%u) from %s(%u), sequence: %u, " "resource_id: %u, minor_code: %u\n", xcb_event_get_error_label(e->error_code), e->error_code, @@ -8016,8 +8324,9 @@ noconfig: tv.tv_sec = 1; tv.tv_usec = 0; if (select(xfd + 1, &rd, NULL, NULL, &tv) == -1) - if (errno != EINTR) + if (errno != EINTR) { DNPRINTF(SWM_D_MISC, "select failed"); + } if (restart_wm == 1) restart(NULL, NULL); if (search_resp == 1) @@ -8030,19 +8339,7 @@ noconfig: } } done: - teardown_ewmh(); - bar_extra_stop(); - - for (i = 0; i < num_screens; ++i) - if (screens[i].bar_gc != 0) - xcb_free_gc(conn, screens[i].bar_gc); - - XftFontClose(display, bar_font); - XftColorFree(display, DefaultVisual(display, 0), - DefaultColormap(display, 0), &bar_font_color); - xcb_key_symbols_free(syms); - xcb_flush(conn); - xcb_disconnect(conn); + shutdown_cleanup(); return (0); }