window: Move client-type-specific managing / unmanaging to a vfunc

This commit is contained in:
Jasper St. Pierre 2014-03-19 09:36:15 -04:00
parent 74a1e00e30
commit a377a1a110
4 changed files with 250 additions and 236 deletions

View File

@ -454,6 +454,8 @@ struct _MetaWindowClass
{
GObjectClass parent_class;
void (*manage) (MetaWindow *window);
void (*unmanage) (MetaWindow *window);
void (*get_default_skip_hints) (MetaWindow *window,
gboolean *skip_taskbar_out,
gboolean *skip_pager_out);

View File

@ -73,7 +73,6 @@
static int destroying_windows_disallowed = 0;
static void update_sm_hints (MetaWindow *window);
static void update_net_frame_extents (MetaWindow *window);
static void invalidate_work_areas (MetaWindow *window);
static void set_wm_state (MetaWindow *window);
@ -971,25 +970,9 @@ _meta_window_shared_new (MetaDisplay *display,
*/
window->stable_sequence = ++display->window_sequence_counter;
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
{
meta_display_register_x_window (display, &window->xwindow, window);
meta_window_x11_update_shape_region (window);
meta_window_x11_update_input_region (window);
}
else
meta_display_register_wayland_window (display, window);
window->opacity = 0xFF;
/* assign the window to its group, or create a new group if needed
*/
window->group = NULL;
window->xgroup_leader = None;
meta_window_compute_group (window);
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
meta_window_load_initial_properties (window);
META_WINDOW_GET_CLASS (window)->manage (window);
if (window->override_redirect)
{
@ -1001,13 +984,6 @@ _meta_window_shared_new (MetaDisplay *display,
window->has_resize_func = FALSE;
}
if (!window->override_redirect &&
client_type == META_WINDOW_CLIENT_TYPE_X11)
update_sm_hints (window); /* must come after transient_for */
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
meta_window_x11_update_net_wm_type (window);
if (!window->override_redirect)
meta_window_update_icon_now (window);
@ -1068,16 +1044,6 @@ _meta_window_shared_new (MetaDisplay *display,
if (window->decorated)
meta_window_ensure_frame (window);
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
MetaStackWindow stack_window;
stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
stack_window.wayland.meta_window = window;
meta_stack_tracker_record_add (window->screen->stack_tracker,
&stack_window,
0);
}
meta_window_grab_keys (window);
if (window->type != META_WINDOW_DOCK && !window->override_redirect)
{
@ -1502,19 +1468,11 @@ meta_window_unmanage (MetaWindow *window,
meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
/* This needs to happen for both Wayland and XWayland clients,
* so it can't be in MetaWindowWayland. */
if (window->surface)
meta_wayland_surface_window_unmanaged (window->surface);
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
MetaStackWindow stack_window;
stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
stack_window.wayland.meta_window = window;
meta_stack_tracker_record_remove (window->screen->stack_tracker,
&stack_window,
0);
}
if (window->visible_to_compositor)
meta_compositor_hide_window (window->display->compositor, window,
META_COMP_EFFECT_DESTROY);
@ -1670,105 +1628,15 @@ meta_window_unmanage (MetaWindow *window,
*/
meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
if (window->withdrawn)
{
/* We need to clean off the window's state so it
* won't be restored if the app maps it again.
*/
meta_error_trap_push (window->display);
meta_verbose ("Cleaning state from window %s\n", window->desc);
XDeleteProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_DESKTOP);
XDeleteProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_STATE);
XDeleteProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_FULLSCREEN_MONITORS);
set_wm_state (window);
meta_error_trap_pop (window->display);
}
else
{
/* We need to put WM_STATE so that others will understand it on
* restart.
*/
if (!window->minimized)
{
meta_error_trap_push (window->display);
set_wm_state (window);
meta_error_trap_pop (window->display);
}
/* If we're unmanaging a window that is not withdrawn, then
* either (a) mutter is exiting, in which case we need to map
* the window so the next WM will know that it's not Withdrawn,
* or (b) we want to create a new MetaWindow to replace the
* current one, which will happen automatically if we re-map
* the X Window.
*/
meta_error_trap_push (window->display);
XMapWindow (window->display->xdisplay,
window->xwindow);
meta_error_trap_pop (window->display);
}
meta_window_ungrab_keys (window);
meta_display_ungrab_window_buttons (window->display, window->xwindow);
meta_display_ungrab_focus_window_button (window->display, window);
if (window->display->autoraise_window == window)
meta_display_remove_autoraise_callback (window->display);
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
meta_display_unregister_x_window (window->display, window->xwindow);
meta_error_trap_push (window->display);
/* Put back anything we messed up */
if (window->border_width != 0)
XSetWindowBorderWidth (window->display->xdisplay,
window->xwindow,
window->border_width);
/* No save set */
XRemoveFromSaveSet (window->display->xdisplay,
window->xwindow);
/* Even though the window is now unmanaged, we can't unselect events. This
* window might be a window from this process, like a GdkMenu, in
* which case it will have pointer events and so forth selected
* for it by GDK. There's no way to disentangle those events from the events
* we've selected. Even for a window from a different X client,
* GDK could also have selected events for it for IPC purposes, so we
* can't unselect in that case either.
*
* Similarly, we can't unselected for events on window->user_time_window.
* It might be our own GDK focus window, or it might be a window that a
* different client is using for multiple different things:
* _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
*/
if (window->user_time_window != None)
{
meta_display_unregister_x_window (window->display,
window->user_time_window);
window->user_time_window = None;
}
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (window->display))
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
#endif
meta_error_trap_pop (window->display);
}
else
meta_display_unregister_wayland_window (window->display, window);
META_WINDOW_GET_CLASS (window)->unmanage (window);
meta_prefs_remove_listener (prefs_changed_callback, window);
meta_screen_queue_check_fullscreen (window->screen);
g_signal_emit (window, window_signals[UNMANAGED], 0);
@ -6541,106 +6409,6 @@ meta_window_set_icon_geometry (MetaWindow *window,
}
}
static Window
read_client_leader (MetaDisplay *display,
Window xwindow)
{
Window retval = None;
meta_prop_get_window (display, xwindow,
display->atom_WM_CLIENT_LEADER,
&retval);
return retval;
}
typedef struct
{
Window leader;
} ClientLeaderData;
static gboolean
find_client_leader_func (MetaWindow *ancestor,
void *data)
{
ClientLeaderData *d;
d = data;
d->leader = read_client_leader (ancestor->display,
ancestor->xwindow);
/* keep going if no client leader found */
return d->leader == None;
}
static void
update_sm_hints (MetaWindow *window)
{
Window leader;
window->xclient_leader = None;
window->sm_client_id = NULL;
/* If not on the current window, we can get the client
* leader from transient parents. If we find a client
* leader, we read the SM_CLIENT_ID from it.
*/
leader = read_client_leader (window->display, window->xwindow);
if (leader == None)
{
ClientLeaderData d;
d.leader = None;
meta_window_foreach_ancestor (window, find_client_leader_func,
&d);
leader = d.leader;
}
if (leader != None)
{
char *str;
window->xclient_leader = leader;
if (meta_prop_get_latin1_string (window->display, leader,
window->display->atom_SM_CLIENT_ID,
&str))
{
window->sm_client_id = g_strdup (str);
meta_XFree (str);
}
}
else
{
meta_verbose ("Didn't find a client leader for %s\n", window->desc);
if (!meta_prefs_get_disable_workarounds ())
{
/* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app
* instead of the client leader
*/
char *str;
str = NULL;
if (meta_prop_get_latin1_string (window->display, window->xwindow,
window->display->atom_SM_CLIENT_ID,
&str))
{
if (window->sm_client_id == NULL) /* first time through */
meta_warning ("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n",
window->desc);
window->sm_client_id = g_strdup (str);
meta_XFree (str);
}
}
}
meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n",
window->desc, window->xclient_leader,
window->sm_client_id ? window->sm_client_id : "none");
}
static void
redraw_icon (MetaWindow *window)
{

View File

@ -27,6 +27,8 @@
#include "window-wayland.h"
#include "window-private.h"
#include "stack-tracker.h"
#include "meta-wayland-surface.h"
struct _MetaWindowWayland
{
@ -40,6 +42,38 @@ struct _MetaWindowWaylandClass
G_DEFINE_TYPE (MetaWindowWayland, meta_window_wayland, META_TYPE_WINDOW)
static void
meta_window_wayland_manage (MetaWindow *window)
{
MetaDisplay *display = window->display;
meta_display_register_wayland_window (display, window);
{
MetaStackWindow stack_window;
stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
stack_window.wayland.meta_window = window;
meta_stack_tracker_record_add (window->screen->stack_tracker,
&stack_window,
0);
}
}
static void
meta_window_wayland_unmanage (MetaWindow *window)
{
{
MetaStackWindow stack_window;
stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
stack_window.wayland.meta_window = window;
meta_stack_tracker_record_remove (window->screen->stack_tracker,
&stack_window,
0);
}
meta_display_unregister_wayland_window (window->display, window);
}
static void
meta_window_wayland_init (MetaWindowWayland *window_wayland)
{
@ -48,4 +82,8 @@ meta_window_wayland_init (MetaWindowWayland *window_wayland)
static void
meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
{
MetaWindowClass *window_class = META_WINDOW_CLASS (klass);
window_class->manage = meta_window_wayland_manage;
window_class->unmanage = meta_window_wayland_unmanage;
}

View File

@ -58,6 +58,210 @@ meta_window_x11_init (MetaWindowX11 *window_x11)
window_x11->priv = meta_window_x11_get_instance_private (window_x11);
}
static Window
read_client_leader (MetaDisplay *display,
Window xwindow)
{
Window retval = None;
meta_prop_get_window (display, xwindow,
display->atom_WM_CLIENT_LEADER,
&retval);
return retval;
}
typedef struct
{
Window leader;
} ClientLeaderData;
static gboolean
find_client_leader_func (MetaWindow *ancestor,
void *data)
{
ClientLeaderData *d;
d = data;
d->leader = read_client_leader (ancestor->display,
ancestor->xwindow);
/* keep going if no client leader found */
return d->leader == None;
}
static void
update_sm_hints (MetaWindow *window)
{
Window leader;
window->xclient_leader = None;
window->sm_client_id = NULL;
/* If not on the current window, we can get the client
* leader from transient parents. If we find a client
* leader, we read the SM_CLIENT_ID from it.
*/
leader = read_client_leader (window->display, window->xwindow);
if (leader == None)
{
ClientLeaderData d;
d.leader = None;
meta_window_foreach_ancestor (window, find_client_leader_func,
&d);
leader = d.leader;
}
if (leader != None)
{
char *str;
window->xclient_leader = leader;
if (meta_prop_get_latin1_string (window->display, leader,
window->display->atom_SM_CLIENT_ID,
&str))
{
window->sm_client_id = g_strdup (str);
meta_XFree (str);
}
}
else
{
meta_verbose ("Didn't find a client leader for %s\n", window->desc);
if (!meta_prefs_get_disable_workarounds ())
{
/* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app
* instead of the client leader
*/
char *str;
str = NULL;
if (meta_prop_get_latin1_string (window->display, window->xwindow,
window->display->atom_SM_CLIENT_ID,
&str))
{
if (window->sm_client_id == NULL) /* first time through */
meta_warning ("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n",
window->desc);
window->sm_client_id = g_strdup (str);
meta_XFree (str);
}
}
}
meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n",
window->desc, window->xclient_leader,
window->sm_client_id ? window->sm_client_id : "none");
}
static void
meta_window_x11_manage (MetaWindow *window)
{
MetaDisplay *display = window->display;
meta_display_register_x_window (display, &window->xwindow, window);
meta_window_x11_update_shape_region (window);
meta_window_x11_update_input_region (window);
/* assign the window to its group, or create a new group if needed */
window->group = NULL;
window->xgroup_leader = None;
meta_window_compute_group (window);
meta_window_load_initial_properties (window);
if (!window->override_redirect)
update_sm_hints (window); /* must come after transient_for */
meta_window_x11_update_net_wm_type (window);
}
static void
meta_window_x11_unmanage (MetaWindow *window)
{
meta_error_trap_push (window->display);
if (window->withdrawn)
{
/* We need to clean off the window's state so it
* won't be restored if the app maps it again.
*/
meta_verbose ("Cleaning state from window %s\n", window->desc);
XDeleteProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_DESKTOP);
XDeleteProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_STATE);
XDeleteProperty (window->display->xdisplay,
window->xwindow,
window->display->atom__NET_WM_FULLSCREEN_MONITORS);
meta_window_x11_set_wm_state (window);
}
else
{
/* We need to put WM_STATE so that others will understand it on
* restart.
*/
if (!window->minimized)
meta_window_x11_set_wm_state (window);
/* If we're unmanaging a window that is not withdrawn, then
* either (a) mutter is exiting, in which case we need to map
* the window so the next WM will know that it's not Withdrawn,
* or (b) we want to create a new MetaWindow to replace the
* current one, which will happen automatically if we re-map
* the X Window.
*/
XMapWindow (window->display->xdisplay,
window->xwindow);
}
meta_display_unregister_x_window (window->display, window->xwindow);
/* Put back anything we messed up */
if (window->border_width != 0)
XSetWindowBorderWidth (window->display->xdisplay,
window->xwindow,
window->border_width);
/* No save set */
XRemoveFromSaveSet (window->display->xdisplay,
window->xwindow);
/* Even though the window is now unmanaged, we can't unselect events. This
* window might be a window from this process, like a GdkMenu, in
* which case it will have pointer events and so forth selected
* for it by GDK. There's no way to disentangle those events from the events
* we've selected. Even for a window from a different X client,
* GDK could also have selected events for it for IPC purposes, so we
* can't unselect in that case either.
*
* Similarly, we can't unselected for events on window->user_time_window.
* It might be our own GDK focus window, or it might be a window that a
* different client is using for multiple different things:
* _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
*/
if (window->user_time_window != None)
{
meta_display_unregister_x_window (window->display,
window->user_time_window);
window->user_time_window = None;
}
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (window->display))
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
#endif
meta_error_trap_pop (window->display);
}
static void
meta_window_x11_get_default_skip_hints (MetaWindow *window,
gboolean *skip_taskbar_out,
@ -75,6 +279,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
{
MetaWindowClass *window_class = META_WINDOW_CLASS (klass);
window_class->manage = meta_window_x11_manage;
window_class->unmanage = meta_window_x11_unmanage;
window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints;
}