From e60da6c006094db82fe146182afdc1b3d6a633f8 Mon Sep 17 00:00:00 2001 From: Rob Adams Date: Sat, 31 Jul 2004 19:56:10 +0000 Subject: [PATCH] Fix some support for EWMH hints, and fix USER_TIME support to include the 2004-07-31 Rob Adams Fix some support for EWMH hints, and fix USER_TIME support to include the DEMANDS_ATTENTION hint. Also includes some code for implementing _NET_RESTACK_WINDOW and _NET_MOVERESIZE_WINDOW, but this is disabled pending feature thaw. * COMPLIANCE: update with new information * src/display.c (meta_display_open): add new hints to list * src/display.h (_MetaDisplay): Add new atoms to struct * src/screen.c (set_supported_hint): update the list of support hints. (set_desktop_viewport_hint): new function sets the viewport hint to (0,0) as required by the spec for WMs with no viewport support. (set_desktop_geometry_hint): new function to set the desktop size hint to the size of the display, since we don't implement large desktop support, as required by the spec. (meta_screen_resize): update the geometry hint on screen resize * src/window.c (meta_window_new_with_attrs): Initialize demands_attention state (set_net_wm_state): Set demands_attention hint in the window state (meta_window_show): If we don't pop up a window because of USER_TIME, set DEMANDS_ATTENTION on the window. (meta_window_focus): When a window receives focus, remove DEMANDS_ATTENTION hint (meta_window_client_message): Allow other apps to set DEMANDS_ATTENTION on a window. Also, if the _NET_ACTIVE_WINDOW hint includes a timestamp, use it. (update_net_wm_state): Read DEMANDS_ATTENTION state also * src/window.h (_MetaWindow): add wm_state_demands_attention bit. --- COMPLIANCE | 32 ++++++------- ChangeLog | 36 +++++++++++++++ src/display.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/display.h | 5 ++ src/screen.c | 61 +++++++++++++++++++++++- src/window.c | 53 ++++++++++++++++++--- src/window.h | 3 ++ 7 files changed, 288 insertions(+), 27 deletions(-) diff --git a/COMPLIANCE b/COMPLIANCE index c0e8dce4b..b45a6724f 100644 --- a/COMPLIANCE +++ b/COMPLIANCE @@ -48,15 +48,12 @@ standard is available at http://freedesktop.org/Standards/wm-spec/ + _NET_NUMBER_OF_DESKTOPS (1.3) -- _NET_DESKTOP_GEOMETRY (-) - Metacity does not implement large desktops. Regardless, according - to the specification, metacity SHOULD set this property to the - screen size, and update it if the screen size changes because of a - RandR change. ++ _NET_DESKTOP_GEOMETRY (1.3) + Metacity does not implement large desktops, so this is kept set to + the screen size. -- _NET_DESKTOP_VIEWPORT (-) - Metacity does not implement viewports. However, according to the - specification, metacity MUST set this property to (0,0) ++ _NET_DESKTOP_VIEWPORT (1.3) + Metacity does not implement viewports, so this is a constant (0,0). + _NET_CURRENT_DESKTOP (1.3) @@ -82,15 +79,16 @@ standard is available at http://freedesktop.org/Standards/wm-spec/ + _NET_CLOSE_WINDOW (1.3) -- _NET_MOVERESIZE_WINDOW (-) - Metacity does not support this message. The specification states - that metacity should treat this message like a ConfigureRequest. - Not hard to implement; just hasn't been done. +- _NET_MOVERESIZE_WINDOW (1.3) + Metacity supports this message, but the specification is unclear on + the layout of the detail value, and as such it is #if 0'd in the code + _NET_WM_MOVERESIZE (1.3) -- _NET_RESTACK_WINDOW (-) - Metacity does not currently support this message. +- _NET_RESTACK_WINDOW (1.3) + Metacity will raise or lower windows in response to this message, + but the sibling restack modes are not supported, and it is currently + #if 0'd in the code. + _NET_REQUEST_FRAME_EXTENTS (1.3) @@ -114,14 +112,14 @@ standard is available at http://freedesktop.org/Standards/wm-spec/ + _NET_WM_WINDOW_TYPE (1.3) / _NET_WM_STATE (1.3) + This property is read and updated according to the specification, + but see caveat below. Metacity does not recognize separate vertical and horizontal maximization states. Currently metacity will do a two-dimensional maximization if either property is set. See: http://bugzilla.gnome.org/show_bug.cgi?id=113601 Metacity doesn't implement viewports so _NET_WM_STATE_STICKY is unimplemented. - _NET_WM_STATE_DEMANDS_ATTENTION is neither read nor updated by - metacity. Metacity should unset it on window activation. + _NET_WM_ALLOWED_ACTIONS (1.3) Metacity keeps this hint up to date. The code is somewhat crufty @@ -141,7 +139,7 @@ standard is available at http://freedesktop.org/Standards/wm-spec/ + _NET_WM_HANDLED_ICONS (1.3) Metacity does not read or set this property. However, metacity - never managed iconified windows, and so has no need to do so. + never manages iconified windows, and so has no need to do so. + _NET_WM_USER_TIME (1.3) Metacity uses this property to prevent applications from stealing diff --git a/ChangeLog b/ChangeLog index 1ac74184f..42d0fe1ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2004-07-31 Rob Adams + + Fix some support for EWMH hints, and fix USER_TIME support to + include the DEMANDS_ATTENTION hint. Also includes some code for + implementing _NET_RESTACK_WINDOW and _NET_MOVERESIZE_WINDOW, but + this is disabled pending feature thaw. + + * COMPLIANCE: update with new information + + * src/display.c (meta_display_open): add new hints to list + + * src/display.h (_MetaDisplay): Add new atoms to struct + + * src/screen.c (set_supported_hint): update the list of support + hints. + (set_desktop_viewport_hint): new function sets the viewport hint + to (0,0) as required by the spec for WMs with no viewport support. + (set_desktop_geometry_hint): new function to set the desktop size + hint to the size of the display, since we don't implement large + desktop support, as required by the spec. + (meta_screen_resize): update the geometry hint on screen resize + + * src/window.c (meta_window_new_with_attrs): Initialize + demands_attention state + (set_net_wm_state): Set demands_attention hint in the window state + (meta_window_show): If we don't pop up a window because of + USER_TIME, set DEMANDS_ATTENTION on the window. + (meta_window_focus): When a window receives focus, remove + DEMANDS_ATTENTION hint + (meta_window_client_message): Allow other apps to set + DEMANDS_ATTENTION on a window. Also, if the _NET_ACTIVE_WINDOW + hint includes a timestamp, use it. + (update_net_wm_state): Read DEMANDS_ATTENTION state also + + * src/window.h (_MetaWindow): add wm_state_demands_attention bit. + 2004-07-22 Rob Adams * src/metacity.schemas.in: Add trailing quotes to keybinding diff --git a/src/display.c b/src/display.c index fa574bfeb..4949ba040 100644 --- a/src/display.c +++ b/src/display.c @@ -282,6 +282,11 @@ meta_display_open (const char *name) "_NET_FRAME_EXTENTS", "_NET_REQUEST_FRAME_EXTENTS", "_NET_WM_USER_TIME", + "_NET_WM_STATE_DEMANDS_ATTENTION", + "_NET_RESTACK_WINDOW", + "_NET_MOVERESIZE_WINDOW", + "_NET_DESKTOP_GEOMETRY", + "_NET_DESKTOP_VIEWPORT" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -429,6 +434,11 @@ meta_display_open (const char *name) display->atom_net_frame_extents = atoms[83]; display->atom_net_request_frame_extents = atoms[84]; display->atom_net_wm_user_time = atoms[85]; + display->atom_net_wm_state_demands_attention = atoms[86]; + display->atom_net_restack_window = atoms[87]; + display->atom_net_moveresize_window = atoms[88]; + display->atom_net_desktop_geometry = atoms[89]; + display->atom_net_desktop_viewport = atoms[90]; display->prop_hooks = NULL; meta_display_init_window_prop_hooks (display); @@ -1170,6 +1180,107 @@ double_click_timeout_for_event (MetaDisplay *display, return meta_ui_get_double_click_timeout (screen->ui); } +#if 0 +static void +handle_net_moveresize_window (MetaDisplay* display, + XEvent *event) +{ + MetaWindow *window; + int x, y, width, height; + gboolean only_resize; + unsigned int gravity; + unsigned int mode; + + window = meta_display_lookup_x_window (display, + event->xclient.window); + + /* + * FIXME: The specification seems to have serious endian issues + * here. Does bits 8-11 mean the high-order byte, or the low-order + * byte? + */ + gravity = (event->xclient.data.l[0] & ~0xff); + mode = (event->xclient.data.l[0] & ~0xff00) >> 8; + + if (window) + { + meta_window_get_gravity_position (window, &x, &y); + width = window->rect.width; + height = window->rect.height; + + if (mode & (CWX | CWY)) + only_resize = FALSE; + else + only_resize = TRUE; + + if (mode & CWX) + x = event->xclient.data.l[1]; + if (mode & CWY) + y = event->xclient.data.l[2]; + if (mode & CWWidth) + width = event->xclient.data.l[3]; + if (mode & CWHeight) + height = event->xclient.data.l[4]; + + if (only_resize) + { + if (gravity) + meta_window_resize_with_gravity (window, + TRUE, + width, + height, + gravity); + else + meta_window_resize (window, + TRUE, + width, + height); + } + else + { + meta_window_move_resize (window, + TRUE, + x, + y, + width, + height); + } + } +} + +static void +handle_net_restack_window (MetaDisplay* display, + XEvent *event) +{ + MetaWindow *window; + + window = meta_display_lookup_x_window (display, + event->xclient.window); + + if (window) + { + /* + * The EWMH includes a sibling for the restack request, but we + * don't currently support these types of raises. + * + */ + switch (event->xclient.data.l[2]) + { + case Above: + meta_window_raise (window); + break; + case Below: + meta_window_lower (window); + break; + case TopIf: + case BottomIf: + case Opposite: + break; + } + } +} +#endif + static gboolean event_callback (XEvent *event, gpointer data) @@ -1873,10 +1984,18 @@ event_callback (XEvent *event, else if (event->xproperty.atom == display->atom_net_desktop_names) meta_screen_update_workspace_names (screen); +#if 0 + else if (event->xproperty.atom == + display->atom_net_restack_window) + handle_net_restack_window (display, event); + else if (event->xproperty.atom == + display->atom_net_moveresize_window) + handle_net_moveresize_window (display, event); +#endif - /* we just use this property as a sentinel to avoid - * certain race conditions. See the comment for the - * sentinel_counter variable declaration in display.h + /* we just use this property as a sentinel to avoid + * certain race conditions. See the comment for the + * sentinel_counter variable declaration in display.h */ if (event->xproperty.atom == display->atom_metacity_sentinel) diff --git a/src/display.h b/src/display.h index 08255fe1d..174f0538c 100644 --- a/src/display.h +++ b/src/display.h @@ -176,6 +176,11 @@ struct _MetaDisplay Atom atom_net_frame_extents; Atom atom_net_request_frame_extents; Atom atom_net_wm_user_time; + Atom atom_net_wm_state_demands_attention; + Atom atom_net_restack_window; + Atom atom_net_moveresize_window; + Atom atom_net_desktop_geometry; + Atom atom_net_desktop_viewport; /* This is the actual window from focus events, * not the one we last set diff --git a/src/screen.c b/src/screen.c index c08e957f6..f9e4cd8d2 100644 --- a/src/screen.c +++ b/src/screen.c @@ -57,6 +57,9 @@ static void set_workspace_names (MetaScreen *screen); static void prefs_changed_callback (MetaPreference pref, gpointer data); +static void set_desktop_geometry_hint (MetaScreen *screen); +static void set_desktop_viewport_hint (MetaScreen *screen); + #ifdef HAVE_STARTUP_NOTIFICATION static void meta_screen_sn_event (SnMonitorEvent *event, void *user_data); @@ -82,7 +85,7 @@ set_wm_check_hint (MetaScreen *screen) static int set_supported_hint (MetaScreen *screen) { -#define N_SUPPORTED 54 +#define N_SUPPORTED 58 Atom atoms[N_SUPPORTED]; atoms[0] = screen->display->atom_net_wm_name; @@ -139,6 +142,12 @@ set_supported_hint (MetaScreen *screen) atoms[51] = screen->display->atom_net_wm_action_minimize; atoms[52] = screen->display->atom_net_frame_extents; atoms[53] = screen->display->atom_net_request_frame_extents; + atoms[54] = screen->display->atom_net_wm_user_time; + atoms[55] = screen->display->atom_net_wm_state_demands_attention; + atoms[56] = screen->display->atom_net_desktop_geometry; + atoms[57] = screen->display->atom_net_desktop_viewport; + //atoms[58] = screen->display->atom_net_restack_window; + //atoms[59] = screen->display->atom_net_moveresize_window; XChangeProperty (screen->display->xdisplay, screen->xroot, screen->display->atom_net_supported, @@ -575,6 +584,10 @@ meta_screen_new (MetaDisplay *display, set_wm_check_hint (screen); + set_desktop_viewport_hint (screen); + + set_desktop_geometry_hint (screen); + meta_screen_update_workspace_layout (screen); /* Get current workspace */ @@ -965,6 +978,51 @@ set_number_of_spaces_hint (MetaScreen *screen, meta_error_trap_pop (screen->display, FALSE); } +static void +set_desktop_geometry_hint (MetaScreen *screen) +{ + unsigned long data[2]; + + if (screen->closing > 0) + return; + + data[0] = screen->width; + data[1] = screen->height; + + meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %ld, %ld\n", data[0], data[1]); + + meta_error_trap_push (screen->display); + XChangeProperty (screen->display->xdisplay, screen->xroot, + screen->display->atom_net_desktop_geometry, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 2); + meta_error_trap_pop (screen->display, FALSE); +} + +static void +set_desktop_viewport_hint (MetaScreen *screen) +{ + unsigned long data[2]; + + if (screen->closing > 0) + return; + + /* + * Metacity does not implement viewports, so this is a fixed 0,0 + */ + data[0] = 0; + data[1] = 0; + + meta_verbose ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n"); + + meta_error_trap_push (screen->display); + XChangeProperty (screen->display->xdisplay, screen->xroot, + screen->display->atom_net_desktop_viewport, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 2); + meta_error_trap_pop (screen->display, FALSE); +} + static void update_num_workspaces (MetaScreen *screen) { @@ -2101,6 +2159,7 @@ meta_screen_resize (MetaScreen *screen, screen->height = height; reload_xinerama_infos (screen); + set_desktop_geometry_hint (screen); /* Queue a resize on all the windows */ meta_screen_foreach_window (screen, meta_screen_resize_func, 0); diff --git a/src/window.c b/src/window.c index 3421c3222..17182ebd9 100644 --- a/src/window.c +++ b/src/window.c @@ -491,6 +491,7 @@ meta_window_new_with_attrs (MetaDisplay *display, window->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; + window->wm_state_demands_attention = FALSE; window->res_class = NULL; window->res_name = NULL; @@ -1125,7 +1126,7 @@ static void set_net_wm_state (MetaWindow *window) { int i; - unsigned long data[10]; + unsigned long data[11]; i = 0; if (window->shaded) @@ -1175,7 +1176,12 @@ set_net_wm_state (MetaWindow *window) data[i] = window->display->atom_net_wm_state_below; ++i; } - + if (window->wm_state_demands_attention) + { + data[i] = window->display->atom_net_wm_state_demands_attention; + ++i; + } + meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i); meta_error_trap_push (window->display); @@ -1810,12 +1816,14 @@ meta_window_show (MetaWindow *window) meta_window_focus (window, meta_display_get_current_time (window->display)); } + else + window->wm_state_demands_attention = TRUE; } if (did_show) { set_net_wm_state (window); - + if (window->struts) { meta_topic (META_DEBUG_WORKAREA, @@ -3266,7 +3274,7 @@ meta_window_focus (MetaWindow *window, window->desc); return; } - + /* For output-only or shaded windows, focus the frame. * This seems to result in the client window getting key events * though, so I don't know if it's icccm-compliant. @@ -3317,6 +3325,12 @@ meta_window_focus (MetaWindow *window, meta_error_trap_pop (window->display, FALSE); } + + if (window->wm_state_demands_attention) + { + window->wm_state_demands_attention = FALSE; + set_net_wm_state (window); + } } static void @@ -3956,6 +3970,16 @@ meta_window_client_message (MetaWindow *window, meta_window_update_layer (window); set_net_wm_state (window); } + + if (first == display->atom_net_wm_state_demands_attention || + second == display->atom_net_wm_state_demands_attention) + { + window->wm_state_demands_attention = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention); + + set_net_wm_state (window); + } return TRUE; } @@ -4100,8 +4124,22 @@ meta_window_client_message (MetaWindow *window, meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating", window->desc); - meta_window_activate (window, meta_display_get_current_time (window->display)); - + if (event->xclient.data.l[0] != 0) + { + /* Client supports newer _NET_ACTIVE_WINDOW with a + * convenient timestamp + */ + meta_window_activate (window, + event->xclient.data.l[1]); + + } + else + { + /* Client using older EWMH _NET_ACTIVE_WINDOW without a + * timestamp + */ + meta_window_activate (window, meta_display_get_current_time (window->display)); + } return TRUE; } @@ -4568,6 +4606,7 @@ update_net_wm_state (MetaWindow *window) window->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; + window->wm_state_demands_attention = FALSE; if (meta_prop_get_atom_list (window->display, window->xwindow, window->display->atom_net_wm_state, @@ -4596,6 +4635,8 @@ update_net_wm_state (MetaWindow *window) window->wm_state_above = TRUE; else if (atoms[i] == window->display->atom_net_wm_state_below) window->wm_state_below = TRUE; + else if (atoms[i] == window->display->atom_net_wm_state_demands_attention) + window->wm_state_demands_attention = TRUE; ++i; } diff --git a/src/window.h b/src/window.h index ca7948416..183c58f16 100644 --- a/src/window.h +++ b/src/window.h @@ -190,6 +190,9 @@ struct _MetaWindow /* TRUE if client set these */ guint wm_state_above : 1; guint wm_state_below : 1; + + /* EWHH demands attention flag */ + guint wm_state_demands_attention : 1; /* this flag tracks receipt of focus_in focus_out and * determines whether we draw the focus