]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Add 'name' configuration option.
[spectrwm] / spectrwm.c
index f4b0fa59b0887cd25f6c4443e810ac862cb9d7ab..40c5416e09452015083fa8734e2b1f694dfd204b 100644 (file)
@@ -415,6 +415,7 @@ int          disable_border = 0;
 int             border_width = 1;
 int             region_padding = 0;
 int             tile_gap = 0;
+int             java_workaround = 1;
 int             verbose_layout = 0;
 time_t          time_started;
 pid_t           bar_pid;
@@ -676,8 +677,12 @@ enum {
        _NET_CLIENT_LIST,
        _NET_CLOSE_WINDOW,
        _NET_CURRENT_DESKTOP,
+       _NET_DESKTOP_GEOMETRY,
        _NET_DESKTOP_NAMES,
+       _NET_DESKTOP_VIEWPORT,
        _NET_MOVERESIZE_WINDOW,
+       _NET_NUMBER_OF_DESKTOPS,
+       _NET_RESTACK_WINDOW,
        _NET_WM_ACTION_ABOVE,
        _NET_WM_ACTION_CLOSE,
        _NET_WM_ACTION_FULLSCREEN,
@@ -687,7 +692,6 @@ enum {
        _NET_WM_DESKTOP,
        _NET_WM_FULL_PLACEMENT,
        _NET_WM_NAME,
-       _NET_NUMBER_OF_DESKTOPS,
        _NET_WM_STATE,
        _NET_WM_STATE_ABOVE,
        _NET_WM_STATE_FULLSCREEN,
@@ -716,8 +720,12 @@ struct ewmh_hint {
     {"_NET_CLIENT_LIST", XCB_ATOM_NONE},
     {"_NET_CLOSE_WINDOW", XCB_ATOM_NONE},
     {"_NET_CURRENT_DESKTOP", XCB_ATOM_NONE},
+    {"_NET_DESKTOP_GEOMETRY", XCB_ATOM_NONE},
     {"_NET_DESKTOP_NAMES", XCB_ATOM_NONE},
+    {"_NET_DESKTOP_VIEWPORT", XCB_ATOM_NONE},
     {"_NET_MOVERESIZE_WINDOW", XCB_ATOM_NONE},
+    {"_NET_NUMBER_OF_DESKTOPS", XCB_ATOM_NONE},
+    {"_NET_RESTACK_WINDOW", XCB_ATOM_NONE},
     {"_NET_WM_ACTION_ABOVE", XCB_ATOM_NONE},
     {"_NET_WM_ACTION_CLOSE", XCB_ATOM_NONE},
     {"_NET_WM_ACTION_FULLSCREEN", XCB_ATOM_NONE},
@@ -727,7 +735,6 @@ struct ewmh_hint {
     {"_NET_WM_DESKTOP", XCB_ATOM_NONE},
     {"_NET_WM_FULL_PLACEMENT", XCB_ATOM_NONE},
     {"_NET_WM_NAME", XCB_ATOM_NONE},
-    {"_NET_NUMBER_OF_DESKTOPS", XCB_ATOM_NONE},
     {"_NET_WM_STATE", XCB_ATOM_NONE},
     {"_NET_WM_STATE_ABOVE", XCB_ATOM_NONE},
     {"_NET_WM_STATE_FULLSCREEN", XCB_ATOM_NONE},
@@ -979,6 +986,7 @@ void         ewmh_update_actions(struct ws_win *);
 void    ewmh_update_client_list(void);
 void    ewmh_update_current_desktop(void);
 void    ewmh_update_desktop_names(void);
+void    ewmh_update_desktops(void);
 void    ewmh_change_wm_state(struct ws_win *, xcb_atom_t, long);
 void    ewmh_update_wm_state(struct ws_win *);
 char   *expand_tilde(const char *);
@@ -1150,7 +1158,6 @@ void       version(struct swm_region *, union arg *);
 void    win_to_ws(struct ws_win *, int, int);
 pid_t   window_get_pid(xcb_window_t);
 void    wkill(struct swm_region *, union arg *);
-void    workaround(void);
 void    update_ws_stack(struct workspace *);
 void    xft_init(struct swm_region *);
 void    _add_startup_exception(const char *, va_list);
@@ -1362,27 +1369,51 @@ get_wm_protocols(struct ws_win *win) {
 void
 setup_ewmh(void)
 {
+       xcb_window_t                    root, win;
        int                             i, j, num_screens;
 
-
        for (i = 0; i < LENGTH(ewmh); i++)
                ewmh[i].atom = get_atom_from_string(ewmh[i].name);
 
        num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
-               /* Support check window will be created by workaround(). */
+               root = screens[i].root;
+
+               /* Set up _NET_SUPPORTING_WM_CHECK. */
+               win = xcb_generate_id(conn);
+               xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, root,
+                   0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+                   XCB_COPY_FROM_PARENT, 0, NULL);
+
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
+                   a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win);
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
+                   a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win);
+
+               /*
+                * Impersonate LG3D non-reparenting WM, written by Sun, to
+                * workaround a Java GUI rendering issue.
+                */
+               if (java_workaround)
+                       xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
+                           ewmh[_NET_WM_NAME].atom, a_utf8_string,
+                           8, strlen("LG3D"), "LG3D");
+               else
+                       xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
+                           ewmh[_NET_WM_NAME].atom, a_utf8_string,
+                           8, strlen("spectrwm"), "spectrwm");
 
                /* Report supported atoms */
-               xcb_delete_property(conn, screens[i].root, a_net_supported);
+               xcb_delete_property(conn, root, a_net_supported);
                for (j = 0; j < LENGTH(ewmh); j++)
-                       xcb_change_property(conn, XCB_PROP_MODE_APPEND,
-                           screens[i].root, a_net_supported, XCB_ATOM_ATOM,
-                           32, 1, &ewmh[j].atom);
+                       xcb_change_property(conn, XCB_PROP_MODE_APPEND, root,
+                           a_net_supported, XCB_ATOM_ATOM, 32, 1,
+                           &ewmh[j].atom);
 
-               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
-                   screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
-                   XCB_ATOM_CARDINAL, 32, 1, &workspace_limit);
        }
+
+       ewmh_update_desktops();
+       ewmh_get_desktop_names();
 }
 
 void
@@ -3605,13 +3636,14 @@ void
 set_region(struct swm_region *r)
 {
        struct swm_region       *rf;
+       int                     vals[2];
 
        if (r == NULL)
                return;
 
        rf = r->s->r_focus;
        /* Unfocus old region bar. */
-       if (rf) {
+       if (rf != NULL) {
                if (rf == r)
                        return;
 
@@ -3620,6 +3652,16 @@ set_region(struct swm_region *r)
                    &r->s->c[SWM_S_COLOR_BAR_BORDER_UNFOCUS].pixel);
        }
 
+       if (rf != NULL && rf != r && (X(rf) != X(r) || Y(rf) != Y(r) ||
+           WIDTH(rf) != WIDTH(r) || HEIGHT(rf) != HEIGHT(r))) {
+               /* Set _NET_DESKTOP_GEOMETRY. */
+               vals[0] = WIDTH(r);
+               vals[1] = HEIGHT(r);
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, r->s->root,
+                   ewmh[_NET_DESKTOP_GEOMETRY].atom, XCB_ATOM_CARDINAL, 32, 2,
+                   &vals);
+       }
+
        /* Set region bar border to focus_color. */
        xcb_change_window_attributes(conn, r->bar->id,
            XCB_CW_BORDER_PIXEL, &r->s->c[SWM_S_COLOR_BAR_BORDER].pixel);
@@ -5548,6 +5590,43 @@ ewmh_update_current_desktop(void)
                    XCB_ATOM_CARDINAL, 32, 1, &screens[i].r_focus->ws->idx);
 }
 
+void
+ewmh_update_desktops(void)
+{
+       int                     num_screens, i, j;
+       uint32_t                *vals;
+
+       vals = calloc(sizeof(uint32_t), workspace_limit * 2);
+       if (vals == NULL)
+               err(1, "ewmh_update_desktops: calloc: failed to allocate "
+                   "memory.");
+
+       num_screens = get_screen_count();
+       for (i = 0; i < num_screens; i++) {
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                   screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
+                   XCB_ATOM_CARDINAL, 32, 1, &workspace_limit);
+
+               for (j = 0; j < workspace_limit; ++j) {
+                       if (screens[i].ws[j].r != NULL) {
+                               vals[j * 2] = X(screens[i].ws[j].r);
+                               vals[j * 2 + 1] = Y(screens[i].ws[j].r);
+                       } else if (screens[i].ws[j].old_r != NULL) {
+                               vals[j * 2] = X(screens[i].ws[j].old_r);
+                               vals[j * 2 + 1] = Y(screens[i].ws[j].old_r);
+                       } else {
+                               vals[j * 2] = vals[j * 2 + 1] = 0;
+                       }
+               }
+
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                   screens[i].root, ewmh[_NET_DESKTOP_VIEWPORT].atom,
+                   XCB_ATOM_CARDINAL, 32, workspace_limit * 2, vals);
+       }
+
+       free(vals);
+}
+
 void
 search_resp_search_workspace(const char *resp)
 {
@@ -7607,7 +7686,8 @@ enum {
        SWM_S_WINDOW_CLASS_ENABLED,
        SWM_S_WINDOW_INSTANCE_ENABLED,
        SWM_S_WINDOW_NAME_ENABLED,
-       SWM_S_WORKSPACE_LIMIT
+       SWM_S_WORKSPACE_LIMIT,
+       SWM_S_WORKSPACE_NAME,
 };
 
 int
@@ -7615,7 +7695,7 @@ setconfvalue(const char *selector, const char *value, int flags)
 {
        struct workspace        *ws;
        int                     i, ws_id, num_screens;
-       char                    *b, *str;
+       char                    *b, *str, s[1024];
 
        switch (flags) {
        case SWM_S_BAR_ACTION:
@@ -7827,11 +7907,32 @@ setconfvalue(const char *selector, const char *value, int flags)
                else if (workspace_limit < 1)
                        workspace_limit = 1;
 
+               ewmh_update_desktops();
+               break;
+       case SWM_S_WORKSPACE_NAME:
+               if (getenv("SWM_STARTED") != NULL)
+                       return (0);
+
+               bzero(s, sizeof s);
+               if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2)
+                       errx(1, "invalid entry, should be 'ws[<idx>]:name'");
+               ws_id--;
+               if (ws_id < 0 || ws_id >= workspace_limit)
+                       errx(1, "setconfvalue: workspace_name: invalid "
+                           "workspace %d.", ws_id + 1);
+
                num_screens = get_screen_count();
-               for (i = 0; i < num_screens; i++) {
-                       xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
-                           screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
-                           XCB_ATOM_CARDINAL, 32, 1, &workspace_limit);
+               for (i = 0; i < num_screens; ++i) {
+                       ws = (struct workspace *)&screens[i].ws;
+
+                       if (strlen(s) > 0) {
+                               free(ws[ws_id].name);
+                               if ((ws[ws_id].name = strdup(s)) == NULL)
+                                       err(1, "setconfvalue: workspace_name.");
+
+                               ewmh_update_desktop_names();
+                               ewmh_get_desktop_names();
+                       }
                }
                break;
        default:
@@ -8096,6 +8197,7 @@ struct config_option configopt[] = {
        { "window_instance_enabled",    setconfvalue,   SWM_S_WINDOW_INSTANCE_ENABLED },
        { "window_name_enabled",        setconfvalue,   SWM_S_WINDOW_NAME_ENABLED },
        { "workspace_limit",            setconfvalue,   SWM_S_WORKSPACE_LIMIT },
+       { "name",                       setconfvalue,   SWM_S_WORKSPACE_NAME },
 };
 
 void
@@ -9475,6 +9577,7 @@ clientmessage(xcb_client_message_event_t *e)
        struct ws_win           *win;
        struct swm_region       *r = NULL;
        union arg               a;
+       uint32_t                val[2];
        int                     num_screens, i;
        xcb_map_request_event_t mre;
 #ifdef SWM_DEBUG
@@ -9542,12 +9645,18 @@ clientmessage(xcb_client_message_event_t *e)
                                HEIGHT(win) = e->data.data32[4];
 
                        update_window(win);
-               }
-               else {
+               } else {
                        /* TODO: Change stack sizes */
                        /* notify no change was made. */
                        config_win(win, NULL);
                }
+       } else if (e->type == ewmh[_NET_RESTACK_WINDOW].atom) {
+               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_RESTACK_WINDOW\n");
+               val[0] = e->data.data32[1]; /* Sibling window. */
+               val[1] = e->data.data32[2]; /* Stack mode detail. */
+
+               xcb_configure_window(conn, win->id, XCB_CONFIG_WINDOW_SIBLING |
+                   XCB_CONFIG_WINDOW_STACK_MODE, val);
        } else  if (e->type == ewmh[_NET_WM_STATE].atom) {
                DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE\n");
                ewmh_change_wm_state(win, e->data.data32[1], e->data.data32[0]);
@@ -10113,33 +10222,6 @@ setup_globals(void)
        a_swm_ws = get_atom_from_string("_SWM_WS");
 }
 
-void
-workaround(void)
-{
-       int                     i, num_screens;
-       xcb_window_t            root, win;
-
-       /* work around sun jdk bugs, code from wmname */
-
-       num_screens = get_screen_count();
-       for (i = 0; i < num_screens; i++) {
-               root = screens[i].root;
-
-               win = xcb_generate_id(conn);
-               xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, root,
-                   0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
-                   XCB_COPY_FROM_PARENT, 0, NULL);
-
-               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
-                   a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win);
-               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
-                   a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win);
-               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
-                   ewmh[_NET_WM_NAME].atom, a_utf8_string, 8, strlen("LG3D"),
-                   "LG3D");
-       }
-}
-
 void
 shutdown_cleanup(void)
 {
@@ -10370,8 +10452,6 @@ noconfig:
 
        validate_spawns();
 
-       /* set some values to work around bad programs */
-       workaround();
        /* grab existing windows (before we build the bars) */
        grab_windows();