]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Fix scan_xrandr to fallback when a scan results in no new regions.
[spectrwm] / spectrwm.c
index c69245b5b6db985a3f92242a8e3ea8bc15dd2638..893d5208003d825ba5ac3986a1405036b755325c 100644 (file)
@@ -90,6 +90,7 @@
 #include <util.h>
 #include <X11/cursorfont.h>
 #include <X11/extensions/Xrandr.h>
+#include <X11/Xcursor/Xcursor.h>
 #include <X11/Xft/Xft.h>
 #include <X11/Xlib-xcb.h>
 #include <xcb/xcb_atom.h>
@@ -672,11 +673,37 @@ struct ewmh_hint {
     {"_SWM_WM_STATE_MANUAL", XCB_ATOM_NONE},
 };
 
+/* Cursors */
+enum {
+       XC_FLEUR,
+       XC_LEFT_PTR,
+       XC_BOTTOM_LEFT_CORNER,
+       XC_BOTTOM_RIGHT_CORNER,
+       XC_SIZING,
+       XC_TOP_LEFT_CORNER,
+       XC_TOP_RIGHT_CORNER,
+       XC_MAX
+};
+
+struct cursors {
+       char            *name; /* Name used by Xcursor .*/
+       uint8_t         cf_char; /* cursorfont index. */
+       xcb_cursor_t    cid;
+} cursors[XC_MAX] =    {
+       {"fleur", XC_fleur, XCB_CURSOR_NONE},
+       {"left_ptr", XC_left_ptr, XCB_CURSOR_NONE},
+       {"bottom_left_corner", XC_bottom_left_corner, XCB_CURSOR_NONE},
+       {"bottom_right_corner", XC_bottom_right_corner, XCB_CURSOR_NONE},
+       {"sizing", XC_sizing, XCB_CURSOR_NONE},
+       {"top_left_corner", XC_top_left_corner, XCB_CURSOR_NONE},
+       {"top_right_corner", XC_top_right_corner, XCB_CURSOR_NONE},
+};
+
 /* 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);
+int     conf_load(const 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);
@@ -685,7 +712,7 @@ void         enternotify(xcb_enter_notify_event_t *);
 void    event_drain(uint8_t);
 void    event_error(xcb_generic_error_t *);
 void    event_handle(xcb_generic_event_t *);
-char   *expand_tilde(char *);
+char   *expand_tilde(const char *);
 void    expose(xcb_expose_event_t *);
 struct ws_win  *find_window(xcb_window_t);
 int     floating_toggle_win(struct ws_win *);
@@ -722,7 +749,7 @@ 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    spawn_select(struct swm_region *, union arg *, const 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 *);
@@ -732,8 +759,47 @@ void        unfocus_win(struct ws_win *);
 void    update_window(struct ws_win *);
 /*void  visibilitynotify(xcb_visibility_notify_event_t *);*/
 
+void
+cursors_load(void)
+{
+       xcb_font_t      cf = XCB_NONE;
+       int             i;
+
+       for (i = 0; i < LENGTH(cursors); ++i) {
+               /* try to load Xcursor first. */
+               cursors[i].cid = XcursorLibraryLoadCursor(display,
+                   cursors[i].name);
+
+               /* fallback to cursorfont. */
+               if (cursors[i].cid == XCB_CURSOR_NONE) {
+                       if (cf == XCB_NONE) {
+                               cf = xcb_generate_id(conn);
+                               xcb_open_font(conn, cf, strlen("cursor"),
+                                   "cursor");
+                       }
+
+                       cursors[i].cid = xcb_generate_id(conn);
+                       xcb_create_glyph_cursor(conn, cursors[i].cid, cf, cf,
+                           cursors[i].cf_char, cursors[i].cf_char + 1, 0, 0, 0,
+                           0xffff, 0xffff, 0xffff);
+
+               }
+       }
+
+       if (cf != XCB_NONE)
+               xcb_close_font(conn, cf);
+}
+
+void
+cursors_cleanup(void)
+{
+       int     i;
+       for (i = 0; i < LENGTH(cursors); ++i)
+               xcb_free_cursor(conn, cursors[i].cid);
+}
+
 char *
-expand_tilde(char *s)
+expand_tilde(const char *s)
 {
        struct passwd           *ppwd;
        int                     i, max;
@@ -763,6 +829,8 @@ expand_tilde(char *s)
        s = &s[i];
 
        ppwd = strlen(user) == 0 ? getpwuid(getuid()) : getpwnam(user);
+       free(user);
+
        if (ppwd == NULL)
                result = strdup(sc);
        else
@@ -1983,7 +2051,7 @@ isxlfd(char *s)
 }
 
 void
-fontset_init()
+fontset_init(void)
 {
        char                    *default_string;
        char                    **missing_charsets;
@@ -4171,7 +4239,7 @@ get_win_name(xcb_window_t win)
                    xcb_get_property_value_length(r));
 
        free(r);
-       return name;
+       return (name);
 }
 
 void
@@ -4396,7 +4464,7 @@ search_win(struct swm_region *r, union arg *args)
 }
 
 void
-search_resp_uniconify(char *resp, unsigned long len)
+search_resp_uniconify(const char *resp, unsigned long len)
 {
        char                    *name;
        struct ws_win           *win;
@@ -4426,7 +4494,7 @@ search_resp_uniconify(char *resp, unsigned long len)
 }
 
 void
-search_resp_name_workspace(char *resp, unsigned long len)
+search_resp_name_workspace(const char *resp, unsigned long len)
 {
        struct workspace        *ws;
 
@@ -4452,7 +4520,7 @@ search_resp_name_workspace(char *resp, unsigned long len)
 }
 
 void
-search_resp_search_workspace(char *resp)
+search_resp_search_workspace(const char *resp)
 {
        char                    *p, *q;
        int                     ws_idx;
@@ -4483,7 +4551,7 @@ search_resp_search_workspace(char *resp)
 }
 
 void
-search_resp_search_window(char *resp)
+search_resp_search_window(const char *resp)
 {
        char                    *s;
        int                     idx;
@@ -4721,9 +4789,7 @@ resize(struct ws_win *win, union arg *args)
        struct swm_geometry     g;
        int                     top = 0, left = 0, resizing;
        int                     dx, dy;
-       unsigned int            shape; /* cursor style */
-       xcb_cursor_t            cursor;
-       xcb_font_t              cursor_font;
+       xcb_cursor_t                    cursor;
        xcb_query_pointer_reply_t       *xpr;
        xcb_generic_event_t             *evt;
        xcb_motion_notify_event_t       *mne;
@@ -4796,18 +4862,13 @@ resize(struct ws_win *win, union arg *args)
                top = 1;
 
        if (args->id == SWM_ARG_ID_CENTER)
-               shape = XC_sizing;
+               cursor = cursors[XC_SIZING].cid;
        else if (top)
-               shape = (left) ? XC_top_left_corner : XC_top_right_corner;
+               cursor = cursors[left ? XC_TOP_LEFT_CORNER :
+                   XC_TOP_RIGHT_CORNER].cid;
        else
-               shape = (left) ? XC_bottom_left_corner : XC_bottom_right_corner;
-
-       cursor_font = xcb_generate_id(conn);
-       xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor");
-
-       cursor = xcb_generate_id(conn);
-       xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
-           shape, shape + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
+               cursor = cursors[left ? XC_BOTTOM_LEFT_CORNER :
+                   XC_BOTTOM_RIGHT_CORNER].cid;
 
        xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
            XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, cursor,
@@ -4889,8 +4950,6 @@ resize(struct ws_win *win, union arg *args)
        store_float_geom(win,r);
 
        xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
-       xcb_free_cursor(conn, cursor);
-       xcb_close_font(conn, cursor_font);
        free(xpr);
        DNPRINTF(SWM_D_EVENT, "resize: done.\n");
 }
@@ -4917,8 +4976,6 @@ move(struct ws_win *win, union arg *args)
        xcb_timestamp_t         timestamp = 0;
        int                     move_step = 0, moving;
        struct swm_region       *r = NULL;
-       xcb_font_t                      cursor_font;
-       xcb_cursor_t                    cursor;
        xcb_query_pointer_reply_t       *qpr;
        xcb_generic_event_t             *evt;
        xcb_motion_notify_event_t       *mne;
@@ -4978,24 +5035,15 @@ move(struct ws_win *win, union arg *args)
                return;
        }
 
-       cursor_font = xcb_generate_id(conn);
-       xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor");
-
-       cursor = xcb_generate_id(conn);
-       xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
-               XC_fleur, XC_fleur + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
-
        xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
            XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
-           XCB_WINDOW_NONE, cursor, XCB_CURRENT_TIME);
+           XCB_WINDOW_NONE, cursors[XC_FLEUR].cid, XCB_CURRENT_TIME);
 
        /* get cursor offset from window root */
        qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, win->id),
                NULL);
        if (!qpr) {
                xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
-               xcb_free_cursor(conn, cursor);
-               xcb_close_font(conn, cursor_font);
                return;
        }
 
@@ -5033,8 +5081,6 @@ move(struct ws_win *win, union arg *args)
        }
        store_float_geom(win, r);
        free(qpr);
-       xcb_free_cursor(conn, cursor);
-       xcb_close_font(conn, cursor_font);
        xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
        DNPRINTF(SWM_D_EVENT, "move: done.\n");
 }
@@ -5326,7 +5372,7 @@ TAILQ_HEAD(spawn_list, spawn_prog);
 struct spawn_list              spawns = TAILQ_HEAD_INITIALIZER(spawns);
 
 int
-spawn_expand(struct swm_region *r, union arg *args, char *spawn_name,
+spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name,
     char ***ret_args)
 {
        struct spawn_prog       *prog = NULL;
@@ -5405,7 +5451,7 @@ spawn_expand(struct swm_region *r, union arg *args, char *spawn_name,
 }
 
 void
-spawn_custom(struct swm_region *r, union arg *args, char *spawn_name)
+spawn_custom(struct swm_region *r, union arg *args, const char *spawn_name)
 {
        union arg               a;
        char                    **real_args;
@@ -5423,7 +5469,8 @@ spawn_custom(struct swm_region *r, union arg *args, char *spawn_name)
 }
 
 void
-spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid)
+spawn_select(struct swm_region *r, union arg *args, const char *spawn_name,
+    int *pid)
 {
        union arg               a;
        char                    **real_args;
@@ -5465,7 +5512,7 @@ spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid)
 }
 
 void
-spawn_insert(char *name, char *args)
+spawn_insert(const char *name, const char *args)
 {
        char                    *arg, *cp, *ptr;
        struct spawn_prog       *sp;
@@ -5516,7 +5563,7 @@ spawn_remove(struct spawn_prog *sp)
 }
 
 void
-spawn_replace(struct spawn_prog *sp, char *name, char *args)
+spawn_replace(struct spawn_prog *sp, const char *name, const char *args)
 {
        DNPRINTF(SWM_D_SPAWN, "spawn_replace: %s [%s]\n", sp->name, name);
 
@@ -5527,7 +5574,7 @@ spawn_replace(struct spawn_prog *sp, char *name, char *args)
 }
 
 void
-setspawn(char *name, char *args)
+setspawn(const char *name, const char *args)
 {
        struct spawn_prog       *sp;
 
@@ -5659,7 +5706,7 @@ parsekeys(char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks)
 }
 
 char *
-strdupsafe(char *str)
+strdupsafe(const char *str)
 {
        if (str == NULL)
                return (NULL);
@@ -5668,7 +5715,8 @@ strdupsafe(char *str)
 }
 
 void
-key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name)
+key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid,
+    const char *spawn_name)
 {
        struct key              *kp;
 
@@ -5712,7 +5760,7 @@ key_remove(struct key *kp)
 
 void
 key_replace(struct key *kp, unsigned int mod, KeySym ks, enum keyfuncid kfid,
-    char *spawn_name)
+    const char *spawn_name)
 {
        DNPRINTF(SWM_D_KEY, "key_replace: %s [%s]\n", keyfuncs[kp->funcid].name,
            spawn_name);
@@ -5725,7 +5773,7 @@ key_replace(struct key *kp, unsigned int mod, KeySym ks, enum keyfuncid kfid,
 
 void
 setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid,
-    char *spawn_name)
+    const char *spawn_name)
 {
        struct key              *kp;
 
@@ -6127,6 +6175,7 @@ setquirk(const char *class, const char *name, unsigned long quirk)
        DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s [%lu]\n", class, name,
           quirk);
 
+       /* Remove/replace existing quirk. */
        TAILQ_FOREACH(qp, &quirks, entry) {
                if (!strcmp(qp->class, class) && !strcmp(qp->name, name)) {
                        if (!quirk)
@@ -6137,12 +6186,11 @@ setquirk(const char *class, const char *name, unsigned long quirk)
                        return;
                }
        }
-       if (!quirk) {
-               warnx("error: setquirk: cannot find class/name combination");
-               return;
-       }
 
-       quirk_insert(class, name, quirk);
+       /* Only insert if quirk is not NONE. */
+       if (quirk)
+               quirk_insert(class, name, quirk);
+
        DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n");
 }
 
@@ -6458,7 +6506,7 @@ setautorun(char *selector, char *value, int flags)
 {
        int                     ws_id;
        char                    s[1024];
-       char                    *ap, *sp = s;
+       char                    *ap, *sp;
        union arg               a;
        int                     argc = 0;
        pid_t                   pid;
@@ -6478,6 +6526,8 @@ setautorun(char *selector, char *value, int flags)
        if (ws_id < 0 || ws_id >= workspace_limit)
                errx(1, "autorun: invalid workspace %d", ws_id + 1);
 
+       sp = expand_tilde((char *)&s);
+
        /*
         * This is a little intricate
         *
@@ -6495,6 +6545,7 @@ setautorun(char *selector, char *value, int flags)
                        err(1, "setautorun: realloc");
                a.argv[argc - 1] = ap;
        }
+       free(sp);
 
        if ((a.argv = realloc(a.argv, (argc + 1) * sizeof(char *))) == NULL)
                err(1, "setautorun: realloc");
@@ -6661,7 +6712,7 @@ struct config_option configopt[] = {
 };
 
 int
-conf_load(char *filename, int keymapping)
+conf_load(const char *filename, int keymapping)
 {
        FILE                    *config;
        char                    *line, *cp, *optsub, *optval;
@@ -8126,6 +8177,8 @@ scan_xrandr(int i)
        xcb_randr_crtc_t                                *crtc;
        xcb_screen_t                                    *screen;
 
+       DNPRINTF(SWM_D_MISC, "scan_xrandr: screen: %d\n", i);
+
        if ((screen = get_screen(i)) == NULL)
                errx(1, "ERROR: can't get screen %d.", i);
 
@@ -8153,7 +8206,7 @@ scan_xrandr(int i)
                        new_region(&screens[i], 0, 0,
                            screen->width_in_pixels,
                            screen->height_in_pixels);
-                       return;
+                       goto out;
                } else
                        ncrtc = srr->num_crtcs;
 
@@ -8179,12 +8232,16 @@ scan_xrandr(int i)
                        free(cir);
                }
                free(srr);
-       } else
+       }
 #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,
                    screen->height_in_pixels);
-       }
+
+out:
+       DNPRINTF(SWM_D_MISC, "scan_xrandr: done.\n");
 }
 
 void
@@ -8289,7 +8346,6 @@ grab_windows(void)
                                free(r);
                                continue;
                        }
-                       free(r);
 
                        state = getstate(wins[j]);
                        manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
@@ -8298,6 +8354,7 @@ grab_windows(void)
                        if (xcb_icccm_get_wm_transient_for_reply(conn, pc,
                            &trans, NULL) && manage)
                                manage_window(wins[j], mapped);
+                       free(r);
                }
                free(qtr);
        }
@@ -8312,8 +8369,6 @@ setup_screens(void)
        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;
        xcb_randr_query_version_reply_t         *r;
 
@@ -8338,13 +8393,7 @@ setup_screens(void)
                }
        }
 
-       cursor_font = xcb_generate_id(conn);
-       xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor");
-
-       cursor = xcb_generate_id(conn);
-       xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
-           XC_left_ptr, XC_left_ptr + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
-       wa[0] = cursor;
+       wa[0] = cursors[XC_LEFT_PTR].cid;
 
        /* map physical screens */
        for (i = 0; i < num_screens; i++) {
@@ -8401,8 +8450,6 @@ setup_screens(void)
                        xcb_randr_select_input(conn, screens[i].root,
                            XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
        }
-       xcb_free_cursor(conn, cursor);
-       xcb_close_font(conn, cursor_font);
 }
 
 void
@@ -8471,6 +8518,8 @@ shutdown_cleanup(void)
        bar_extra = 1;
        unmap_all();
 
+       cursors_cleanup();
+
        teardown_ewmh();
 
        num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
@@ -8627,6 +8676,9 @@ main(int argc, char *argv[])
        if (enable_wm() != 0)
                errx(1, "another window manager is currently running");
 
+       /* Load Xcursors and/or cursorfont glyph cursors. */
+       cursors_load();
+
        xcb_aux_sync(conn);
 
        setup_globals();