mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 09:30:45 -05:00
wayland: implement transient hints for wayland clients
wl_shell supports a set_transient() map request that is equivalent to setting WM_TRANSIENT_FOR in X11, so implement that. https://bugzilla.gnome.org/show_bug.cgi?id=707401
This commit is contained in:
parent
12d6c70000
commit
81d9797544
@ -127,6 +127,7 @@ struct _MetaWindow
|
|||||||
Window xtransient_for;
|
Window xtransient_for;
|
||||||
Window xgroup_leader;
|
Window xgroup_leader;
|
||||||
Window xclient_leader;
|
Window xclient_leader;
|
||||||
|
MetaWindow *transient_for;
|
||||||
|
|
||||||
/* Initial workspace property */
|
/* Initial workspace property */
|
||||||
int initial_workspace;
|
int initial_workspace;
|
||||||
@ -727,4 +728,7 @@ void meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
|||||||
const char *application_object_path,
|
const char *application_object_path,
|
||||||
const char *window_object_path);
|
const char *window_object_path);
|
||||||
|
|
||||||
|
void meta_window_set_transient_for (MetaWindow *window,
|
||||||
|
MetaWindow *parent);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1518,7 +1518,7 @@ reload_transient_for (MetaWindow *window,
|
|||||||
gboolean initial)
|
gboolean initial)
|
||||||
{
|
{
|
||||||
MetaWindow *parent = NULL;
|
MetaWindow *parent = NULL;
|
||||||
Window transient_for, old_transient_for;
|
Window transient_for;
|
||||||
|
|
||||||
if (value->type != META_PROP_VALUE_INVALID)
|
if (value->type != META_PROP_VALUE_INVALID)
|
||||||
{
|
{
|
||||||
@ -1553,10 +1553,6 @@ reload_transient_for (MetaWindow *window,
|
|||||||
if (transient_for == window->xtransient_for)
|
if (transient_for == window->xtransient_for)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (meta_window_appears_focused (window) && window->xtransient_for != None)
|
|
||||||
meta_window_propagate_focus_appearance (window, FALSE);
|
|
||||||
|
|
||||||
old_transient_for = window->xtransient_for;
|
|
||||||
window->xtransient_for = transient_for;
|
window->xtransient_for = transient_for;
|
||||||
|
|
||||||
window->transient_parent_is_root_window =
|
window->transient_parent_is_root_window =
|
||||||
@ -1568,46 +1564,14 @@ reload_transient_for (MetaWindow *window,
|
|||||||
else
|
else
|
||||||
meta_verbose ("Window %s is not transient\n", window->desc);
|
meta_verbose ("Window %s is not transient\n", window->desc);
|
||||||
|
|
||||||
/* may now be a dialog */
|
if (window->transient_parent_is_root_window || window->xtransient_for == None)
|
||||||
meta_window_recalc_window_type (window);
|
meta_window_set_transient_for (window, NULL);
|
||||||
|
else
|
||||||
if (!window->constructing)
|
|
||||||
{
|
{
|
||||||
/* If the window attaches, detaches, or changes attached
|
parent = meta_display_lookup_x_window (window->display,
|
||||||
* parents, we need to destroy the MetaWindow and let a new one
|
window->xtransient_for);
|
||||||
* be created (which happens as a side effect of
|
meta_window_set_transient_for (window, parent);
|
||||||
* meta_window_unmanage()). The condition below is correct
|
|
||||||
* because we know window->xtransient_for has changed.
|
|
||||||
*/
|
|
||||||
if (window->attached || meta_window_should_attach_to_parent (window))
|
|
||||||
{
|
|
||||||
guint32 timestamp;
|
|
||||||
|
|
||||||
window->xtransient_for = old_transient_for;
|
|
||||||
timestamp = meta_display_get_current_time_roundtrip (window->display);
|
|
||||||
meta_window_unmanage (window, timestamp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update stacking constraints */
|
|
||||||
if (!window->override_redirect)
|
|
||||||
meta_stack_update_transient (window->screen->stack, window);
|
|
||||||
|
|
||||||
/* possibly change its group. We treat being a window's transient as
|
|
||||||
* equivalent to making it your group leader, to work around shortcomings
|
|
||||||
* in programs such as xmms-- see #328211.
|
|
||||||
*/
|
|
||||||
if (window->xtransient_for != None &&
|
|
||||||
window->xgroup_leader != None &&
|
|
||||||
window->xtransient_for != window->xgroup_leader)
|
|
||||||
meta_window_group_leader_changed (window);
|
|
||||||
|
|
||||||
if (!window->constructing && !window->override_redirect)
|
|
||||||
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
|
|
||||||
|
|
||||||
if (meta_window_appears_focused (window) && window->xtransient_for != None)
|
|
||||||
meta_window_propagate_focus_appearance (window, TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -242,6 +242,9 @@ meta_window_finalize (GObject *object)
|
|||||||
if (window->opaque_region)
|
if (window->opaque_region)
|
||||||
cairo_region_destroy (window->opaque_region);
|
cairo_region_destroy (window->opaque_region);
|
||||||
|
|
||||||
|
if (window->transient_for)
|
||||||
|
g_object_unref (window->transient_for);
|
||||||
|
|
||||||
meta_icon_cache_free (&window->icon_cache);
|
meta_icon_cache_free (&window->icon_cache);
|
||||||
|
|
||||||
g_free (window->sm_client_id);
|
g_free (window->sm_client_id);
|
||||||
@ -1119,11 +1122,6 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
* can use this time as a fallback.
|
* can use this time as a fallback.
|
||||||
*/
|
*/
|
||||||
if (!window->override_redirect && !window->net_wm_user_time_set) {
|
if (!window->override_redirect && !window->net_wm_user_time_set) {
|
||||||
MetaWindow *parent = NULL;
|
|
||||||
if (window->xtransient_for)
|
|
||||||
parent = meta_display_lookup_x_window (window->display,
|
|
||||||
window->xtransient_for);
|
|
||||||
|
|
||||||
/* First, maybe the app was launched with startup notification using an
|
/* First, maybe the app was launched with startup notification using an
|
||||||
* obsolete version of the spec; use that timestamp if it exists.
|
* obsolete version of the spec; use that timestamp if it exists.
|
||||||
*/
|
*/
|
||||||
@ -1132,8 +1130,8 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
* being recorded as a fallback for potential transients
|
* being recorded as a fallback for potential transients
|
||||||
*/
|
*/
|
||||||
window->net_wm_user_time = window->initial_timestamp;
|
window->net_wm_user_time = window->initial_timestamp;
|
||||||
else if (parent != NULL)
|
else if (window->transient_for != NULL)
|
||||||
meta_window_set_user_time(window, parent->net_wm_user_time);
|
meta_window_set_user_time (window, window->transient_for->net_wm_user_time);
|
||||||
else
|
else
|
||||||
/* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
|
/* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
|
||||||
* being recorded as a fallback for potential transients
|
* being recorded as a fallback for potential transients
|
||||||
@ -1223,21 +1221,16 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
if (!window->override_redirect)
|
if (!window->override_redirect)
|
||||||
{
|
{
|
||||||
if (window->workspace == NULL &&
|
if (window->workspace == NULL &&
|
||||||
window->xtransient_for != None)
|
window->transient_for != NULL)
|
||||||
{
|
{
|
||||||
/* Try putting dialog on parent's workspace */
|
/* Try putting dialog on parent's workspace */
|
||||||
MetaWindow *parent;
|
if (window->transient_for->workspace)
|
||||||
|
|
||||||
parent = meta_display_lookup_x_window (window->display,
|
|
||||||
window->xtransient_for);
|
|
||||||
|
|
||||||
if (parent && parent->workspace)
|
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_PLACEMENT,
|
meta_topic (META_DEBUG_PLACEMENT,
|
||||||
"Putting window %s on same workspace as parent %s\n",
|
"Putting window %s on same workspace as parent %s\n",
|
||||||
window->desc, parent->desc);
|
window->desc, window->transient_for->desc);
|
||||||
|
|
||||||
if (parent->on_all_workspaces_requested)
|
if (window->transient_for->on_all_workspaces_requested)
|
||||||
{
|
{
|
||||||
window->on_all_workspaces_requested = TRUE;
|
window->on_all_workspaces_requested = TRUE;
|
||||||
window->on_all_workspaces = TRUE;
|
window->on_all_workspaces = TRUE;
|
||||||
@ -1245,7 +1238,7 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
|
|
||||||
/* this will implicitly add to the appropriate MRU lists
|
/* this will implicitly add to the appropriate MRU lists
|
||||||
*/
|
*/
|
||||||
meta_workspace_add_window (parent->workspace, window);
|
meta_workspace_add_window (window->transient_for->workspace, window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4463,14 +4456,14 @@ window_activate (MetaWindow *window,
|
|||||||
/* For non-transient windows, we just set up a pulsing indicator,
|
/* For non-transient windows, we just set up a pulsing indicator,
|
||||||
rather than move windows or workspaces.
|
rather than move windows or workspaces.
|
||||||
See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
|
See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
|
||||||
if (window->xtransient_for == None &&
|
if (window->transient_for == NULL &&
|
||||||
!meta_window_located_on_workspace (window, workspace))
|
!meta_window_located_on_workspace (window, workspace))
|
||||||
{
|
{
|
||||||
meta_window_set_demands_attention (window);
|
meta_window_set_demands_attention (window);
|
||||||
/* We've marked it as demanding, don't need to do anything else. */
|
/* We've marked it as demanding, don't need to do anything else. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (window->xtransient_for != None)
|
else if (window->transient_for != NULL)
|
||||||
{
|
{
|
||||||
/* Move transients to current workspace - preference dialogs should appear over
|
/* Move transients to current workspace - preference dialogs should appear over
|
||||||
the source window. */
|
the source window. */
|
||||||
@ -6136,7 +6129,7 @@ get_modal_transient (MetaWindow *window)
|
|||||||
{
|
{
|
||||||
MetaWindow *transient = tmp->data;
|
MetaWindow *transient = tmp->data;
|
||||||
|
|
||||||
if (transient->xtransient_for == modal_transient->xwindow &&
|
if (transient->transient_for == modal_transient &&
|
||||||
transient->wm_state_modal)
|
transient->wm_state_modal)
|
||||||
{
|
{
|
||||||
modal_transient = transient;
|
modal_transient = transient;
|
||||||
@ -8506,7 +8499,7 @@ recalc_window_type (MetaWindow *window)
|
|||||||
XFree (atom_name);
|
XFree (atom_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (window->xtransient_for != None)
|
else if (window->transient_for != NULL)
|
||||||
{
|
{
|
||||||
window->type = META_WINDOW_DIALOG;
|
window->type = META_WINDOW_DIALOG;
|
||||||
}
|
}
|
||||||
@ -8849,8 +8842,7 @@ recalc_window_features (MetaWindow *window)
|
|||||||
case META_WINDOW_MODAL_DIALOG:
|
case META_WINDOW_MODAL_DIALOG:
|
||||||
/* only skip taskbar if we have a real transient parent
|
/* only skip taskbar if we have a real transient parent
|
||||||
(and ignore the application hints) */
|
(and ignore the application hints) */
|
||||||
if (window->xtransient_for != None &&
|
if (window->transient_for != NULL)
|
||||||
window->xtransient_for != window->screen->xroot)
|
|
||||||
window->skip_taskbar = TRUE;
|
window->skip_taskbar = TRUE;
|
||||||
else
|
else
|
||||||
window->skip_taskbar = FALSE;
|
window->skip_taskbar = FALSE;
|
||||||
@ -10454,11 +10446,10 @@ meta_window_foreach_ancestor (MetaWindow *window,
|
|||||||
w = window;
|
w = window;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (w->xtransient_for == None ||
|
if (w->transient_for == NULL)
|
||||||
w->transient_parent_is_root_window)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
w = meta_display_lookup_x_window (w->display, w->xtransient_for);
|
w = w->transient_for;
|
||||||
}
|
}
|
||||||
while (w && (* func) (w, user_data));
|
while (w && (* func) (w, user_data));
|
||||||
}
|
}
|
||||||
@ -11281,7 +11272,9 @@ meta_window_get_transient_for (MetaWindow *window)
|
|||||||
{
|
{
|
||||||
g_return_val_if_fail (META_IS_WINDOW (window), NULL);
|
g_return_val_if_fail (META_IS_WINDOW (window), NULL);
|
||||||
|
|
||||||
if (window->xtransient_for)
|
if (window->transient_for)
|
||||||
|
return window->transient_for;
|
||||||
|
else if (window->xtransient_for)
|
||||||
return meta_display_lookup_x_window (window->display,
|
return meta_display_lookup_x_window (window->display,
|
||||||
window->xtransient_for);
|
window->xtransient_for);
|
||||||
else
|
else
|
||||||
@ -11686,3 +11679,55 @@ meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
|||||||
|
|
||||||
g_object_thaw_notify (G_OBJECT (window));
|
g_object_thaw_notify (G_OBJECT (window));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_set_transient_for (MetaWindow *window,
|
||||||
|
MetaWindow *parent)
|
||||||
|
{
|
||||||
|
if (meta_window_appears_focused (window) && window->transient_for != None)
|
||||||
|
meta_window_propagate_focus_appearance (window, FALSE);
|
||||||
|
|
||||||
|
/* may now be a dialog */
|
||||||
|
meta_window_recalc_window_type (window);
|
||||||
|
|
||||||
|
if (!window->constructing)
|
||||||
|
{
|
||||||
|
/* If the window attaches, detaches, or changes attached
|
||||||
|
* parents, we need to destroy the MetaWindow and let a new one
|
||||||
|
* be created (which happens as a side effect of
|
||||||
|
* meta_window_unmanage()). The condition below is correct
|
||||||
|
* because we know window->transient_for has changed.
|
||||||
|
*/
|
||||||
|
if (window->attached || meta_window_should_attach_to_parent (window))
|
||||||
|
{
|
||||||
|
guint32 timestamp;
|
||||||
|
|
||||||
|
timestamp = meta_display_get_current_time_roundtrip (window->display);
|
||||||
|
meta_window_unmanage (window, timestamp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update stacking constraints */
|
||||||
|
if (!window->override_redirect)
|
||||||
|
meta_stack_update_transient (window->screen->stack, window);
|
||||||
|
|
||||||
|
/* We know this won't create a reference cycle because we check for loops */
|
||||||
|
g_clear_object (&window->transient_for);
|
||||||
|
window->transient_for = parent ? g_object_ref (parent) : NULL;
|
||||||
|
|
||||||
|
/* possibly change its group. We treat being a window's transient as
|
||||||
|
* equivalent to making it your group leader, to work around shortcomings
|
||||||
|
* in programs such as xmms-- see #328211.
|
||||||
|
*/
|
||||||
|
if (window->xtransient_for != None &&
|
||||||
|
window->xgroup_leader != None &&
|
||||||
|
window->xtransient_for != window->xgroup_leader)
|
||||||
|
meta_window_group_leader_changed (window);
|
||||||
|
|
||||||
|
if (!window->constructing && !window->override_redirect)
|
||||||
|
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
|
||||||
|
|
||||||
|
if (meta_window_appears_focused (window) && window->transient_for != None)
|
||||||
|
meta_window_propagate_focus_appearance (window, TRUE);
|
||||||
|
}
|
||||||
|
@ -712,13 +712,22 @@ shell_surface_set_transient (struct wl_client *client,
|
|||||||
{
|
{
|
||||||
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
|
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
|
||||||
MetaWaylandSurface *surface = shell_surface->surface;
|
MetaWaylandSurface *surface = shell_surface->surface;
|
||||||
|
MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent);
|
||||||
MetaWaylandCompositor *compositor = surface->compositor;
|
MetaWaylandCompositor *compositor = surface->compositor;
|
||||||
|
|
||||||
/* NB: Surfaces from xwayland become managed based on X events. */
|
/* NB: Surfaces from xwayland become managed based on X events. */
|
||||||
if (client == compositor->xwayland_client)
|
if (client == compositor->xwayland_client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ensure_surface_window (surface);
|
if (surface->window)
|
||||||
|
meta_window_set_transient_for (surface->window, parent_surface->window);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ensure_initial_state (surface);
|
||||||
|
|
||||||
|
surface->initial_state->initial_type = META_WAYLAND_SURFACE_TOPLEVEL;
|
||||||
|
surface->initial_state->transient_for = parent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1070,6 +1079,14 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
|||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initial->transient_for)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *parent = wl_resource_get_user_data (initial->transient_for);
|
||||||
|
if (parent)
|
||||||
|
window->transient_for = g_object_ref (parent->window);
|
||||||
|
}
|
||||||
|
|
||||||
if (initial->title)
|
if (initial->title)
|
||||||
meta_window_set_title (window, initial->title);
|
meta_window_set_title (window, initial->title);
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ typedef enum {
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
MetaWaylandSurfaceType initial_type;
|
MetaWaylandSurfaceType initial_type;
|
||||||
|
struct wl_resource *transient_for;
|
||||||
|
|
||||||
char *title;
|
char *title;
|
||||||
char *wm_class;
|
char *wm_class;
|
||||||
|
Loading…
Reference in New Issue
Block a user