xwm: Read motif wm hints
authorKristian Høgsberg <krh@bitplanet.net>
Fri, 18 May 2012 16:12:36 +0000 (12:12 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Fri, 18 May 2012 16:12:36 +0000 (12:12 -0400)
For now, just support the "no decorations" combination.

src/xserver-launcher.c

index de90a46..323c03b 100644 (file)
@@ -65,6 +65,42 @@ struct weston_xserver {
        struct wl_listener destroy_listener;
 };
 
+struct motif_wm_hints {
+       uint32_t flags;
+       uint32_t functions;
+       uint32_t decorations;
+       int32_t input_mode;
+       uint32_t status;
+};
+
+#define MWM_HINTS_FUNCTIONS     (1L << 0)
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define MWM_HINTS_INPUT_MODE    (1L << 2)
+#define MWM_HINTS_STATUS        (1L << 3)
+
+#define MWM_FUNC_ALL            (1L << 0)
+#define MWM_FUNC_RESIZE         (1L << 1)
+#define MWM_FUNC_MOVE           (1L << 2)
+#define MWM_FUNC_MINIMIZE       (1L << 3)
+#define MWM_FUNC_MAXIMIZE       (1L << 4)
+#define MWM_FUNC_CLOSE          (1L << 5)
+
+#define MWM_DECOR_ALL           (1L << 0)
+#define MWM_DECOR_BORDER        (1L << 1)
+#define MWM_DECOR_RESIZEH       (1L << 2)
+#define MWM_DECOR_TITLE         (1L << 3)
+#define MWM_DECOR_MENU          (1L << 4)
+#define MWM_DECOR_MINIMIZE      (1L << 5)
+#define MWM_DECOR_MAXIMIZE      (1L << 6)
+
+#define MWM_INPUT_MODELESS 0
+#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
+#define MWM_INPUT_SYSTEM_MODAL 2
+#define MWM_INPUT_FULL_APPLICATION_MODAL 3
+#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
+
+#define MWM_TEAROFF_WINDOW      (1L<<0)
+
 struct weston_wm {
        xcb_connection_t *conn;
        const xcb_query_extension_reply_t *xfixes;
@@ -104,6 +140,7 @@ struct weston_wm {
                xcb_atom_t               net_wm_moveresize;
                xcb_atom_t               net_supporting_wm_check;
                xcb_atom_t               net_supported;
+               xcb_atom_t               motif_wm_hints;
                xcb_atom_t               clipboard;
                xcb_atom_t               targets;
                xcb_atom_t               utf8_string;
@@ -134,6 +171,7 @@ struct weston_wm_window {
        uint32_t protocols;
        xcb_atom_t type;
        int width, height;
+       int decorate;
 };
 
 static struct weston_wm_window *
@@ -252,7 +290,8 @@ dump_window_properties(struct weston_wm *wm, xcb_window_t window)
 }
 
 /* We reuse some predefined, but otherwise useles atoms */
-#define TYPE_WM_PROTOCOLS XCB_ATOM_CUT_BUFFER0
+#define TYPE_WM_PROTOCOLS      XCB_ATOM_CUT_BUFFER0
+#define TYPE_MOTIF_WM_HINTS    XCB_ATOM_CUT_BUFFER1
 
 static void
 weston_wm_window_read_properties(struct weston_wm_window *window)
@@ -270,6 +309,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
                { wm->atom.wm_protocols, TYPE_WM_PROTOCOLS, F(protocols) },
                { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) },
                { wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) },
+               { wm->atom.motif_wm_hints, TYPE_MOTIF_WM_HINTS, 0 },
        };
 #undef F
 
@@ -279,6 +319,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
        uint32_t *xid;
        xcb_atom_t *atom;
        uint32_t i;
+       struct motif_wm_hints *hints;
 
        if (!window->properties_dirty)
                return;
@@ -293,6 +334,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
                                             props[i].atom,
                                             XCB_ATOM_ANY, 0, 2048);
 
+       window->decorate = 1;
        for (i = 0; i < ARRAY_LENGTH(props); i++)  {
                reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
                if (!reply)
@@ -325,6 +367,11 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
                        break;
                case TYPE_WM_PROTOCOLS:
                        break;
+               case TYPE_MOTIF_WM_HINTS:
+                       hints = xcb_get_property_value(reply);
+                       if (hints->flags & MWM_HINTS_DECORATIONS)
+                               window->decorate = hints->decorations > 0;
+                       break;
                default:
                        break;
                }
@@ -626,13 +673,43 @@ weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *ev
 }
 
 static void
+weston_wm_window_get_frame_size(struct weston_wm_window *window,
+                               int *width, int *height)
+{
+       struct theme *t = window->wm->theme;
+
+       if (window->decorate) {
+               *width = window->width + (t->margin + t->width) * 2;
+               *height = window->height +
+                       t->margin * 2 + t->width + t->titlebar_height;
+       } else {
+               *width = window->width + t->margin * 2;
+               *height = window->height + t->margin * 2;
+       }
+}
+
+static void
+weston_wm_window_get_child_position(struct weston_wm_window *window,
+                                   int *x, int *y)
+{
+       struct theme *t = window->wm->theme;
+
+       if (window->decorate) {
+               *x = t->margin + t->width;
+               *y = t->margin + t->titlebar_height;
+       } else {
+               *x = t->margin;
+               *y = t->margin;
+       }
+}
+static void
 weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *event)
 {
        xcb_configure_notify_event_t *configure_notify = 
                (xcb_configure_notify_event_t *) event;
        struct weston_wm_window *window;
-       struct theme *t = wm->theme;
        uint32_t values[2];
+       int width, height;
 
        fprintf(stderr, "XCB_CONFIGURE_NOTIFY (window %d) %d,%d @ %dx%d\n",
                configure_notify->window,
@@ -647,9 +724,9 @@ weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *eve
        window->width = configure_notify->width;
        window->height = configure_notify->height;
 
-       values[0] = window->width + (t->margin + t->width) * 2;
-       values[1] =
-               window->height + t->margin * 2 + t->width + t->titlebar_height;
+       weston_wm_window_get_frame_size(window, &width, &height);
+       values[0] = width;
+       values[1] = height;
 
        xcb_configure_window(wm->conn,
                             window->frame_id,
@@ -725,8 +802,8 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
        xcb_map_request_event_t *map_request =
                (xcb_map_request_event_t *) event;
        struct weston_wm_window *window;
-       struct theme *t = wm->theme;
        uint32_t values[1];
+       int x, y, width, height;
 
        if (our_resource(wm, map_request->window)) {
                fprintf(stderr, "XCB_MAP_REQUEST (window %d, ours)\n",
@@ -736,6 +813,11 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
 
        window = hash_table_lookup(wm->window_hash, map_request->window);
 
+       weston_wm_window_read_properties(window);
+
+       weston_wm_window_get_frame_size(window, &width, &height);
+       weston_wm_window_get_child_position(window, &x, &y);
+
        values[0] =
                XCB_EVENT_MASK_KEY_PRESS |
                XCB_EVENT_MASK_KEY_RELEASE |
@@ -750,15 +832,12 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
                          window->frame_id,
                          wm->screen->root,
                          0, 0,
-                         window->width + (t->margin + t->width) * 2,
-                         window->height + t->margin * 2 + t->width + t->titlebar_height,
+                         width, height,
                          0,
                          XCB_WINDOW_CLASS_INPUT_OUTPUT,
                          wm->screen->root_visual,
                          XCB_CW_EVENT_MASK, values);
-       xcb_reparent_window(wm->conn, window->id, window->frame_id,
-                           t->margin + t->width,
-                           t->margin + t->titlebar_height);
+       xcb_reparent_window(wm->conn, window->id, window->frame_id, x, y);
 
        fprintf(stderr, "XCB_MAP_REQUEST (window %d, %p, frame %d)\n",
                window->id, window, window->frame_id);
@@ -830,16 +909,16 @@ weston_wm_window_draw_decoration(void *data)
        cairo_surface_t *surface;
        cairo_t *cr;
        xcb_render_pictforminfo_t *render_format;
-       int width, height;
+       int x, y, width, height;
        const char *title;
        uint32_t flags = 0;
 
        weston_wm_window_read_properties(window);
 
        window->repaint_source = NULL;
-       width = window->width + (t->margin + t->width) * 2;
-       height = window->height +
-               t->margin * 2 + t->titlebar_height + t->width;
+
+       weston_wm_window_get_frame_size(window, &width, &height);
+       weston_wm_window_get_child_position(window, &x, &y);
 
        render_format = find_depth(wm->conn, 24);
        surface = cairo_xcb_surface_create_with_xrender_format(wm->conn,
@@ -850,15 +929,25 @@ weston_wm_window_draw_decoration(void *data)
                                                               height);
        cr = cairo_create(surface);
 
-       if (wm->focus_window == window)
-               flags |= THEME_FRAME_ACTIVE;
+       if (window->decorate) {
+               if (wm->focus_window == window)
+                       flags |= THEME_FRAME_ACTIVE;
 
-       if (window->name)
-               title = window->name;
-       else
-               title = "untitled";
+               if (window->name)
+                       title = window->name;
+               else
+                       title = "untitled";
 
-       theme_render_frame(t, cr, width, height, title, flags);
+               theme_render_frame(t, cr, width, height, title, flags);
+       } else {
+               cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+               cairo_set_source_rgba(cr, 0, 0, 0, 0);
+               cairo_paint(cr);
+
+               cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+               cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
+               tile_mask(cr, t->shadow, 2, 2, width + 8, height + 8, 64, 64);
+       }
 
        cairo_destroy(cr);
        cairo_surface_destroy(surface);
@@ -868,21 +957,18 @@ weston_wm_window_draw_decoration(void *data)
                 * make sure we don't sample from the undefined alpha
                 * channel when filtering. */
                window->surface->opaque_rect[0] =
-                       (double) (t->margin + t->width - 1) / width;
+                       (double) (x - 1) / width;
                window->surface->opaque_rect[1] =
-                       (double) (t->margin + t->width + 
-                                 window->width + 1) / width;
+                       (double) (x + window->width + 1) / width;
                window->surface->opaque_rect[2] =
-                       (double) (t->margin + t->titlebar_height - 1) / height;
+                       (double) (y - 1) / height;
                window->surface->opaque_rect[3] =
-                       (double) (t->margin + t->titlebar_height +
-                                 window->height + 1) / height;
+                       (double) (y + window->height + 1) / height;
 
                pixman_region32_init_rect(&window->surface->input,
                                          t->margin, t->margin,
-                                         t->width * 2 + window->width,
-                                         t->titlebar_height +
-                                         t->width + window->height);
+                                         width - 2 * t->margin,
+                                         height - 2 * t->margin);
        }
 }
 
@@ -1431,6 +1517,7 @@ wxs_wm_get_resources(struct weston_wm *wm)
                { "_NET_SUPPORTING_WM_CHECK",
                                        F(atom.net_supporting_wm_check) },
                { "_NET_SUPPORTED",     F(atom.net_supported) },
+               { "_MOTIF_WM_HINTS",    F(atom.motif_wm_hints) },
                { "CLIPBOARD",          F(atom.clipboard) },
                { "TARGETS",            F(atom.targets) },
                { "UTF8_STRING",        F(atom.utf8_string) },