]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Fix check_conn.
[spectrwm] / spectrwm.c
index c674051ba5193ab1b88e3a161039e1256b3c50aa..753bbf039a21153f5f5ee8a837ea986e39140666 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright (c) 2011-2012 Reginald Kennedy <rk@rejii.com>
  * Copyright (c) 2011-2012 Lawrence Teo <lteo@lteo.net>
  * Copyright (c) 2011-2012 Tiago Cunha <tcunha@gmx.com>
+ * Copyright (c) 2012 David Hill <dhill@mindcry.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -121,7 +122,7 @@ static const char   *buildstr = SPECTRWM_VERSION;
 #endif
 #endif
 
-#if defined(__OpenBSD__)
+#ifndef XCB_ICCCM_NUM_WM_HINTS_ELEMENTS
 #define XCB_ICCCM_SIZE_HINT_P_MIN_SIZE         XCB_SIZE_HINT_P_MIN_SIZE
 #define XCB_ICCCM_SIZE_HINT_P_MAX_SIZE         XCB_SIZE_HINT_P_MAX_SIZE
 #define XCB_ICCCM_SIZE_HINT_P_RESIZE_INC       XCB_SIZE_HINT_P_RESIZE_INC
@@ -647,29 +648,98 @@ 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 *);
+void    configurerequest(xcb_configure_request_event_t *);
 void    constrain_window(struct ws_win *, struct swm_region *, int);
+void    destroynotify(xcb_destroy_notify_event_t *);
 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 *);
 void    focus(struct swm_region *, union arg *);
 void    focus_magic(struct ws_win *);
+#ifdef SWM_DEBUG
+void    focusin(xcb_focus_in_event_t *);
+#endif
 xcb_atom_t get_atom_from_string(const char *);
+#ifdef SWM_DEBUG
+char   *get_atom_name(xcb_atom_t);
+char   *get_notify_detail_label(uint8_t);
+char   *get_notify_mode_label(uint8_t);
+#endif
 xcb_screen_t   *get_screen(int);
 char   *get_win_name(xcb_window_t);
 uint32_t getstate(xcb_window_t);
 void    grabbuttons(struct ws_win *, int);
+void    keypress(xcb_key_press_event_t *);
+#ifdef SWM_DEBUG
+void    leavenotify(xcb_leave_notify_event_t *);
+#endif
 void    map_window_raised(xcb_window_t);
+void    mapnotify(xcb_map_notify_event_t *);
+void    mappingnotify(xcb_mapping_notify_event_t *);
+void    maprequest(xcb_map_request_event_t *);
 void    new_region(struct swm_screen *, int, int, int, int);
 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    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 *);
-#ifdef SWM_DEBUG
-char   *get_atom_name(xcb_atom_t);
-#endif
+/*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)
@@ -689,12 +759,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);
 }
@@ -820,15 +896,16 @@ teardown_ewmh(void)
                pc = xcb_get_property(conn, 0, screens[i].root, sup_check,
                    XCB_ATOM_WINDOW, 0, 1);
                pr = xcb_get_property_reply(conn, pc, NULL);
-               if (pr && pr->format == sup_check) {
+               if (!pr)
+                       continue;
+               if (pr->format == sup_check) {
                        id = *((xcb_window_t *)xcb_get_property_value(pr));
 
                        xcb_destroy_window(conn, id);
                        xcb_delete_property(conn, screens[i].root, sup_check);
                        xcb_delete_property(conn, screens[i].root, sup_list);
-
-                       free(pr);
                }
+               free(pr);
        }
 }
 
@@ -1098,23 +1175,6 @@ dumpwins(struct swm_region *r, union arg *args)
 }
 #endif /* SWM_DEBUG */
 
-void                   event_error(xcb_generic_error_t *);
-void                   expose(xcb_expose_event_t *);
-void                   keypress(xcb_key_press_event_t *);
-void                   buttonpress(xcb_button_press_event_t *);
-void                   configurerequest(xcb_configure_request_event_t *);
-void                   configurenotify(xcb_configure_notify_event_t *);
-void                   destroynotify(xcb_destroy_notify_event_t *);
-void                   enternotify(xcb_enter_notify_event_t *);
-void                   mapnotify(xcb_map_notify_event_t *);
-void                   mappingnotify(xcb_mapping_notify_event_t *);
-void                   maprequest(xcb_map_request_event_t *);
-void                   propertynotify(xcb_property_notify_event_t *);
-void                   unmapnotify(xcb_unmap_notify_event_t *);
-/*void                 visibilitynotify(xcb_visibility_notify_event_t *);*/
-void                   clientmessage(xcb_client_message_event_t *);
-void                   screenchange(xcb_randr_screen_change_notify_event_t *);
-
 void
 sighdlr(int sig)
 {
@@ -1294,7 +1354,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);
 
@@ -1846,12 +1908,15 @@ bar_refresh(void)
 void
 bar_setup(struct swm_region *r)
 {
-       char                    *font, *fontpos;
+       char                    *font, *fontpos, *dup, *search;
        int                     count;
-       xcb_screen_t            *screen = get_screen(r->s->idx);
+       xcb_screen_t            *screen;
        uint32_t                wa[3];
        XRenderColor            color;
 
+       if ((screen = get_screen(r->s->idx)) == NULL)
+               errx(1, "ERROR: can't get screen %d.", r->s->idx);
+
        if (r->bar != NULL)
                return;
 
@@ -1859,7 +1924,10 @@ bar_setup(struct swm_region *r)
                err(1, "bar_setup: calloc: failed to allocate memory.");
 
        if (bar_font == NULL) {
-               while ((font = strsep(&bar_fonts, ",")) != NULL) {
+               if ((dup = strdup(bar_fonts)) == NULL)
+                       errx(1, "insufficient memory.");
+               search = dup;
+               while ((font = strsep(&search, ",")) != NULL) {
                        if (*font == '\0')
                                continue;
 
@@ -1887,6 +1955,7 @@ bar_setup(struct swm_region *r)
                                break;
                        }
                }
+               free(dup);
        }
 
        if (bar_font == NULL)
@@ -1923,8 +1992,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);
@@ -2199,6 +2269,8 @@ fake_keypress(struct ws_win *win, xcb_keysym_t keysym, uint16_t modifiers)
        event.response_type = XCB_KEY_RELEASE;
        xcb_send_event(conn, 1, win->id,
            XCB_EVENT_MASK_KEY_RELEASE, (const char *)&event);
+
+       free(keycode);
 }
 
 void
@@ -2299,8 +2371,10 @@ find_window(xcb_window_t id)
                return (NULL);
 
        /* if we were looking for the parent return that window instead */
-       if (r->parent == 0 || r->root == r->parent)
+       if (r->parent == 0 || r->root == r->parent) {
+               free(r);
                return (NULL);
+       }
 
        /* look for parent */
        for (i = 0; i < num_screens; i++)
@@ -4278,8 +4352,6 @@ resize(struct ws_win *win, union arg *args)
        unsigned int            shape; /* cursor style */
        xcb_cursor_t            cursor;
        xcb_font_t              cursor_font;
-       xcb_grab_pointer_cookie_t       gpc;
-       xcb_grab_pointer_reply_t        *gpr;
        xcb_query_pointer_reply_t       *xpr;
        xcb_generic_event_t             *evt;
        xcb_motion_notify_event_t       *mne;
@@ -4363,16 +4435,9 @@ resize(struct ws_win *win, union arg *args)
        xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
            shape, shape + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
 
-       gpc = xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
+       xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
            XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, cursor,
            XCB_CURRENT_TIME),
-       gpr = xcb_grab_pointer_reply(conn, gpc, NULL);
-       if (!gpr) {
-               xcb_free_cursor(conn, cursor);
-               xcb_close_font(conn, cursor_font);
-               free(xpr);
-               return;
-       }
 
        xcb_flush(conn);
        resizing = 1;
@@ -4452,7 +4517,6 @@ resize(struct ws_win *win, union arg *args)
        xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
        xcb_free_cursor(conn, cursor);
        xcb_close_font(conn, cursor_font);
-       free(gpr);
        free(xpr);
        DNPRINTF(SWM_D_EVENT, "resize: done\n");
 }
@@ -4480,8 +4544,6 @@ move(struct ws_win *win, union arg *args)
        struct swm_region       *r = NULL;
        xcb_font_t                      cursor_font;
        xcb_cursor_t                    cursor;
-       xcb_grab_pointer_cookie_t       gpc;
-       xcb_grab_pointer_reply_t        *gpr;
        xcb_query_pointer_reply_t       *qpr;
        xcb_generic_event_t             *evt;
        xcb_motion_notify_event_t       *mne;
@@ -4546,15 +4608,9 @@ move(struct ws_win *win, union arg *args)
        xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
                XC_fleur, XC_fleur + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
 
-       gpc = xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
+       xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
            XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
            XCB_WINDOW_NONE, cursor, XCB_CURRENT_TIME);
-       gpr = xcb_grab_pointer_reply(conn, gpc, NULL);
-       if (!gpr) {
-               xcb_free_cursor(conn, cursor);
-               xcb_close_font(conn, cursor_font);
-               return;
-       }
 
        /* get cursor offset from window root */
        qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, win->id),
@@ -5123,12 +5179,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);
+
+       DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, args);
 
-       setspawn(selector, value);
+       setspawn(selector, args);
+       free(args);
 
        DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n");
        return (0);
@@ -5506,7 +5567,7 @@ updatenumlockmask(void)
 {
        unsigned int                            i, j;
        xcb_get_modifier_mapping_reply_t        *modmap_r;
-       xcb_keycode_t                           *modmap, kc;
+       xcb_keycode_t                           *modmap, kc, *keycode;
 
        DNPRINTF(SWM_D_MISC, "updatenumlockmask\n");
        numlockmask = 0;
@@ -5520,10 +5581,11 @@ updatenumlockmask(void)
                        for (j = 0; j < modmap_r->keycodes_per_modifier; j++) {
                                kc = modmap[i * modmap_r->keycodes_per_modifier
                                    + j];
-
-                               if (kc == *((xcb_keycode_t *)xcb_key_symbols_get_keycode(syms,
-                                   XK_Num_Lock)))
+                               keycode = xcb_key_symbols_get_keycode(syms,
+                                               XK_Num_Lock);
+                               if (kc == *keycode)
                                        numlockmask = (1 << i);
+                               free(keycode);
                        }
                }
                free(modmap_r);
@@ -5558,6 +5620,7 @@ grabkeys(void)
                                            kp->mod | modifiers[j],
                                            *code, XCB_GRAB_MODE_ASYNC,
                                            XCB_GRAB_MODE_ASYNC);
+                               free(code);
                }
        }
 }
@@ -5717,7 +5780,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;
@@ -5729,8 +5792,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);
 }
 
@@ -5802,7 +5865,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:
@@ -6420,7 +6483,9 @@ get_ws_idx(xcb_window_t id)
                xcb_get_property(conn, 0, id, a_swm_ws,
                    XCB_ATOM_STRING, 0, SWM_PROPLEN),
                NULL);
-       if (gpr && gpr->type) {
+       if (!gpr)
+               return (-1);
+       if (gpr->type) {
                proplen = xcb_get_property_value_length(gpr);
                if (proplen > 0) {
                        prop = malloc(proplen + 1);
@@ -6431,8 +6496,8 @@ get_ws_idx(xcb_window_t id)
                                prop[proplen] = '\0';
                        }
                }
-               free(gpr);
        }
+       free(gpr);
 
        if (prop) {
                DNPRINTF(SWM_D_PROP, "get_ws_idx: _SWM_WS: %s\n", prop);
@@ -6682,6 +6747,9 @@ manage_window(xcb_window_t id)
 
        event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
            XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+#ifdef SWM_DEBUG
+       event_mask |= XCB_EVENT_MASK_LEAVE_WINDOW;
+#endif
 
        xcb_change_window_attributes(conn, id, XCB_CW_EVENT_MASK, &event_mask);
 
@@ -6800,6 +6868,16 @@ expose(xcb_expose_event_t *e)
        xcb_flush(conn);
 }
 
+#ifdef SWM_DEBUG
+void
+focusin(xcb_focus_in_event_t *e)
+{
+       DNPRINTF(SWM_D_EVENT, "focusin: window: 0x%x, mode: %s(%u), "
+           "detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode),
+           e->mode, get_notify_detail_label(e->detail), e->detail);
+}
+#endif
+
 void
 keypress(xcb_key_press_event_t *e)
 {
@@ -6990,13 +7068,78 @@ destroynotify(xcb_destroy_notify_event_t *e)
        free_window(win);
 }
 
+#ifdef SWM_DEBUG
+char *
+get_notify_detail_label(uint8_t detail)
+{
+       char *label;
+
+       switch (detail) {
+       case XCB_NOTIFY_DETAIL_ANCESTOR:
+               label = "Ancestor";
+               break;
+       case XCB_NOTIFY_DETAIL_VIRTUAL:
+               label = "Virtual";
+               break;
+       case XCB_NOTIFY_DETAIL_INFERIOR:
+               label = "Inferior";
+               break;
+       case XCB_NOTIFY_DETAIL_NONLINEAR:
+               label = "Nonlinear";
+               break;
+       case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL:
+               label = "NonlinearVirtual";
+               break;
+       case XCB_NOTIFY_DETAIL_POINTER:
+               label = "Pointer";
+               break;
+       case XCB_NOTIFY_DETAIL_POINTER_ROOT:
+               label = "PointerRoot";
+               break;
+       case XCB_NOTIFY_DETAIL_NONE:
+               label = "None";
+               break;
+       default:
+               label = "Unknown";
+       }
+
+       return label;
+}
+
+char *
+get_notify_mode_label(uint8_t mode)
+{
+       char *label;
+
+       switch (mode) {
+       case XCB_NOTIFY_MODE_NORMAL:
+               label = "Normal";
+               break;
+       case XCB_NOTIFY_MODE_GRAB:
+               label = "Grab";
+               break;
+       case XCB_NOTIFY_MODE_UNGRAB:
+               label = "Ungrab";
+               break;
+       case XCB_NOTIFY_MODE_WHILE_GRABBED:
+               label = "WhileGrabbed";
+               break;
+       default:
+               label = "Unknown";
+       }
+
+       return label;
+}
+#endif
+
 void
 enternotify(xcb_enter_notify_event_t *e)
 {
        struct ws_win           *win;
-       DNPRINTF(SWM_D_FOCUS, "enternotify: window: 0x%x, mode: %d, detail: "
-           "%d, root: 0x%x, subwindow: 0x%x, same_screen_focus: %s, "
-           "state: %d\n", e->event, e->mode, e->detail, e->root,
+       DNPRINTF(SWM_D_FOCUS, "enternotify: 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),
+           e->mode, get_notify_detail_label(e->detail), e->detail, e->root,
            e->child, YESNO(e->same_screen_focus), e->state);
 
        if (e->mode != XCB_NOTIFY_MODE_NORMAL) {
@@ -7024,6 +7167,18 @@ enternotify(xcb_enter_notify_event_t *e)
        xcb_flush(conn);
 }
 
+#ifdef SWM_DEBUG
+void
+leavenotify(xcb_leave_notify_event_t *e)
+{
+       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),
+           e->mode, get_notify_detail_label(e->detail), e->detail, e->root,
+           e->child, YESNO(e->same_screen_focus), e->state);
+}
+#endif
+
 /* lets us use one switch statement for arbitrary mode/detail combinations */
 #define MERGE_MEMBERS(a,b)     (((a & 0xffff) << 16) | (b & 0xffff))
 
@@ -7252,6 +7407,39 @@ clientmessage(xcb_client_message_event_t *e)
        xcb_flush(conn);
 }
 
+void
+check_conn(void)
+{
+       int      errcode = xcb_connection_has_error(conn);
+       char    *s;
+#ifdef XCB_CONN_ERROR
+       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)
 {
@@ -7264,7 +7452,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,
@@ -7369,7 +7558,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)
@@ -7398,8 +7590,9 @@ scan_xrandr(int i)
                        return;
                } else
                        ncrtc = srr->num_crtcs;
+
+               crtc = xcb_randr_get_screen_resources_current_crtcs(srr);
                for (c = 0; c < ncrtc; c++) {
-                       crtc = xcb_randr_get_screen_resources_current_crtcs(srr);
                        cic = xcb_randr_get_crtc_info(conn, crtc[c],
                            XCB_CURRENT_TIME);
                        cir = xcb_randr_get_crtc_info_reply(conn, cic, NULL);
@@ -7536,6 +7729,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;
@@ -7549,15 +7743,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");
@@ -7573,7 +7770,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);
@@ -7711,14 +7910,18 @@ event_handle(xcb_generic_event_t *evt)
        EVENT(XCB_DESTROY_NOTIFY, destroynotify);
        EVENT(XCB_ENTER_NOTIFY, enternotify);
        EVENT(XCB_EXPOSE, expose);
-       /*EVENT(XCB_FOCUS_IN, );*/
+#ifdef SWM_DEBUG
+       EVENT(XCB_FOCUS_IN, focusin);
+#endif
        /*EVENT(XCB_FOCUS_OUT, );*/
        /*EVENT(XCB_GRAPHICS_EXPOSURE, );*/
        /*EVENT(XCB_GRAVITY_NOTIFY, );*/
        EVENT(XCB_KEY_PRESS, keypress);
        /*EVENT(XCB_KEY_RELEASE, keypress);*/
        /*EVENT(XCB_KEYMAP_NOTIFY, );*/
-       /*EVENT(XCB_LEAVE_NOTIFY, );*/
+#ifdef SWM_DEBUG
+       EVENT(XCB_LEAVE_NOTIFY, leavenotify);
+#endif
        EVENT(XCB_MAP_NOTIFY, mapnotify);
        EVENT(XCB_MAP_REQUEST, maprequest);
        EVENT(XCB_MAPPING_NOTIFY, mappingnotify);