From dd03b3afde035718810e5bb15bbd365cbaafebcd Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 7 Jul 2024 17:10:07 +0200 Subject: [PATCH 1/6] wayland: Add make_modal protocol method --- protocol/pantheon-desktop-shell-v1.xml | 5 ++ protocol/pantheon-desktop-shell.vapi | 3 + src/InternalUtils.vala | 10 ++++ src/PantheonShell.vala | 19 +++++++ src/ShellClients/ShellClientsManager.vala | 10 +++- src/Widgets/ModalActor.vala | 67 +++++++++++++++++++++++ src/WindowManager.vala | 9 +++ src/meson.build | 1 + 8 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 src/Widgets/ModalActor.vala diff --git a/protocol/pantheon-desktop-shell-v1.xml b/protocol/pantheon-desktop-shell-v1.xml index 18a7da64f..a596a776e 100644 --- a/protocol/pantheon-desktop-shell-v1.xml +++ b/protocol/pantheon-desktop-shell-v1.xml @@ -111,5 +111,10 @@ Tell the shell to keep the surface above on all workspaces + + + This will block all user input outside the surface and most system shortcuts. + + diff --git a/protocol/pantheon-desktop-shell.vapi b/protocol/pantheon-desktop-shell.vapi index b699c45c5..69b1113da 100644 --- a/protocol/pantheon-desktop-shell.vapi +++ b/protocol/pantheon-desktop-shell.vapi @@ -56,6 +56,7 @@ namespace Pantheon.Desktop { public static Wl.Interface iface; public Destroy destroy; public SetKeepAbove set_keep_above; + public MakeModal make_modal; } [CCode (has_target = false, has_typedef = false)] @@ -75,5 +76,7 @@ namespace Pantheon.Desktop { [CCode (has_target = false, has_typedef = false)] public delegate void SetKeepAbove (Wl.Client client, Wl.Resource resource); [CCode (has_target = false, has_typedef = false)] + public delegate void MakeModal (Wl.Client client, Wl.Resource resource); + [CCode (has_target = false, has_typedef = false)] public delegate void Destroy (Wl.Client client, Wl.Resource resource); } diff --git a/src/InternalUtils.vala b/src/InternalUtils.vala index 9177d7cbe..80a2f746f 100644 --- a/src/InternalUtils.vala +++ b/src/InternalUtils.vala @@ -336,5 +336,15 @@ namespace Gala { return { 0, 0, (int) screen_width, (int) screen_height }; } } + + public static void clutter_actor_reparent (Clutter.Actor actor, Clutter.Actor new_parent) { + if (actor == new_parent) + return; + + actor.ref (); + actor.get_parent ().remove_child (actor); + new_parent.add_child (actor); + actor.unref (); + } } } diff --git a/src/PantheonShell.vala b/src/PantheonShell.vala index 1a3b93f06..f56c76b7c 100644 --- a/src/PantheonShell.vala +++ b/src/PantheonShell.vala @@ -67,9 +67,11 @@ namespace Gala { wayland_pantheon_extended_behavior_interface = { destroy_extended_behavior_surface, set_keep_above, + make_modal, }; PanelSurface.quark = GLib.Quark.from_string ("-gala-wayland-panel-surface-data"); + ExtendedBehaviorSurface.quark = GLib.Quark.from_string ("-gala-wayland-extended-behavior-surface-data"); shell_global = Wl.Global.create (wl_disp, ref Pantheon.Desktop.ShellInterface.iface, 1, (client, version, id) => { unowned var resource = client.create_resource (ref Pantheon.Desktop.ShellInterface.iface, (int) version, id); @@ -326,6 +328,23 @@ namespace Gala { window.make_above (); } + internal static void make_modal (Wl.Client client, Wl.Resource resource) { + unowned ExtendedBehaviorSurface? eb_surface = resource.get_user_data (); + if (eb_surface.wayland_surface == null) { + warning ("Window tried to make modal but wayland surface is null."); + return; + } + + Meta.Window? window; + eb_surface.wayland_surface.get ("window", out window, null); + if (window == null) { + warning ("Window tried to make modal but wayland surface had no associated window."); + return; + } + + ShellClientsManager.get_instance ().make_modal (window); + } + internal static void destroy_panel_surface (Wl.Client client, Wl.Resource resource) { resource.destroy (); } diff --git a/src/ShellClients/ShellClientsManager.vala b/src/ShellClients/ShellClientsManager.vala index 37074668a..4e6d9a240 100644 --- a/src/ShellClients/ShellClientsManager.vala +++ b/src/ShellClients/ShellClientsManager.vala @@ -8,7 +8,7 @@ public class Gala.ShellClientsManager : Object { private static ShellClientsManager instance; - public static void init (WindowManager wm) { + public static void init (WindowManagerGala wm) { if (instance != null) { return; } @@ -20,14 +20,14 @@ public class Gala.ShellClientsManager : Object { return instance; } - public WindowManager wm { get; construct; } + public WindowManagerGala wm { get; construct; } private NotificationsClient notifications_client; private ManagedClient[] protocol_clients = {}; private GLib.HashTable windows = new GLib.HashTable (null, null); - private ShellClientsManager (WindowManager wm) { + private ShellClientsManager (WindowManagerGala wm) { Object (wm: wm); } @@ -143,4 +143,8 @@ public class Gala.ShellClientsManager : Object { windows[window].set_hide_mode (hide_mode); } + + public void make_modal (Meta.Window window) { + wm.modal_actor.make_modal (window); + } } diff --git a/src/Widgets/ModalActor.vala b/src/Widgets/ModalActor.vala new file mode 100644 index 000000000..48a6a1926 --- /dev/null +++ b/src/Widgets/ModalActor.vala @@ -0,0 +1,67 @@ +/* + * Copyright 2024 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Authored by: Leonhard Kargl + */ + +/** + * This class allows to make windows system modal i.e. dim + * the desktop behind them and only allow interaction with them. + * Not to be confused with WindowManager.push_modal which only + * works for our own Clutter.Actors. + */ + public class Gala.ModalActor : Clutter.Actor { + public Meta.Display display { get; construct; } + + private int modal_dialogs = 0; + + public ModalActor (Meta.Display display) { + Object (display: display); + } + + construct { + background_color = { 0, 0, 0, 200 }; + x = 0; + y = 0; + visible = false; + reactive = true; + + unowned var monitor_manager = display.get_context ().get_backend ().get_monitor_manager (); + monitor_manager.monitors_changed.connect (update_size); + + update_size (); + } + + private void update_size () { + int width, height; + display.get_size (out width, out height); + + set_size (width, height); + } + + public void make_modal (Meta.Window window) { + modal_dialogs++; + window.unmanaged.connect (unmake_modal); + + var actor = (Meta.WindowActor) window.get_compositor_private (); + InternalUtils.clutter_actor_reparent (actor, this); + + check_visible (); + } + + public void unmake_modal (Meta.Window window) { + modal_dialogs--; + window.unmanaged.disconnect (unmake_modal); + + check_visible (); + } + + private void check_visible () { + visible = modal_dialogs > 0; + } + + public bool is_modal () { + return modal_dialogs > 0; + } +} diff --git a/src/WindowManager.vala b/src/WindowManager.vala index 707d1e6f2..a6784977e 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -49,6 +49,8 @@ namespace Gala { */ public Gala.ActivatableComponent workspace_view { get; protected set; } + public ModalActor modal_actor { get; private set; } + /** * {@inheritDoc} */ @@ -241,6 +243,9 @@ namespace Gala { stage.remove_child (feedback_group); ui_group.add_child (feedback_group); + modal_actor = new ModalActor (display); + ui_group.insert_child_above (modal_actor, null); + FilterManager.init (this); /*keybindings*/ @@ -2293,6 +2298,10 @@ namespace Gala { } public override bool keybinding_filter (Meta.KeyBinding binding) { + if (modal_actor.is_modal ()) { + return true; + } + if (!is_modal ()) return false; diff --git a/src/meson.build b/src/meson.build index afe387c9d..9c2ad300c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -49,6 +49,7 @@ gala_bin_sources = files( 'Widgets/DwellClickTimer.vala', 'Widgets/IconGroup.vala', 'Widgets/IconGroupContainer.vala', + 'Widgets/ModalActor.vala', 'Widgets/MonitorClone.vala', 'Widgets/MultitaskingView.vala', 'Widgets/PixelPicker.vala', From 7481383314eeecd6300684919e996f95d7636e08 Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 7 Jul 2024 17:19:00 +0200 Subject: [PATCH 2/6] Make dimming optional --- protocol/pantheon-desktop-shell-v1.xml | 2 ++ protocol/pantheon-desktop-shell.vapi | 2 +- src/PantheonShell.vala | 4 ++-- src/ShellClients/ShellClientsManager.vala | 3 ++- src/Widgets/ModalActor.vala | 14 ++++++++++++++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/protocol/pantheon-desktop-shell-v1.xml b/protocol/pantheon-desktop-shell-v1.xml index a596a776e..c6d80b14c 100644 --- a/protocol/pantheon-desktop-shell-v1.xml +++ b/protocol/pantheon-desktop-shell-v1.xml @@ -115,6 +115,8 @@ This will block all user input outside the surface and most system shortcuts. + + diff --git a/protocol/pantheon-desktop-shell.vapi b/protocol/pantheon-desktop-shell.vapi index 69b1113da..26c3be43f 100644 --- a/protocol/pantheon-desktop-shell.vapi +++ b/protocol/pantheon-desktop-shell.vapi @@ -76,7 +76,7 @@ namespace Pantheon.Desktop { [CCode (has_target = false, has_typedef = false)] public delegate void SetKeepAbove (Wl.Client client, Wl.Resource resource); [CCode (has_target = false, has_typedef = false)] - public delegate void MakeModal (Wl.Client client, Wl.Resource resource); + public delegate void MakeModal (Wl.Client client, Wl.Resource resource, uint dim); [CCode (has_target = false, has_typedef = false)] public delegate void Destroy (Wl.Client client, Wl.Resource resource); } diff --git a/src/PantheonShell.vala b/src/PantheonShell.vala index f56c76b7c..93f2054e9 100644 --- a/src/PantheonShell.vala +++ b/src/PantheonShell.vala @@ -328,7 +328,7 @@ namespace Gala { window.make_above (); } - internal static void make_modal (Wl.Client client, Wl.Resource resource) { + internal static void make_modal (Wl.Client client, Wl.Resource resource, uint dim) { unowned ExtendedBehaviorSurface? eb_surface = resource.get_user_data (); if (eb_surface.wayland_surface == null) { warning ("Window tried to make modal but wayland surface is null."); @@ -342,7 +342,7 @@ namespace Gala { return; } - ShellClientsManager.get_instance ().make_modal (window); + ShellClientsManager.get_instance ().make_modal (window, dim == 1); } internal static void destroy_panel_surface (Wl.Client client, Wl.Resource resource) { diff --git a/src/ShellClients/ShellClientsManager.vala b/src/ShellClients/ShellClientsManager.vala index 4e6d9a240..aa992daa0 100644 --- a/src/ShellClients/ShellClientsManager.vala +++ b/src/ShellClients/ShellClientsManager.vala @@ -144,7 +144,8 @@ public class Gala.ShellClientsManager : Object { windows[window].set_hide_mode (hide_mode); } - public void make_modal (Meta.Window window) { + public void make_modal (Meta.Window window, bool dim) { wm.modal_actor.make_modal (window); + wm.modal_actor.dim = dim; } } diff --git a/src/Widgets/ModalActor.vala b/src/Widgets/ModalActor.vala index 48a6a1926..79a308815 100644 --- a/src/Widgets/ModalActor.vala +++ b/src/Widgets/ModalActor.vala @@ -14,6 +14,16 @@ public class Gala.ModalActor : Clutter.Actor { public Meta.Display display { get; construct; } + public bool dim { + set { + if (value) { + background_color = { 0, 0, 0, 200 }; + } else { + background_color = { 0, 0, 0, 0 }; + } + } + } + private int modal_dialogs = 0; public ModalActor (Meta.Display display) { @@ -59,6 +69,10 @@ private void check_visible () { visible = modal_dialogs > 0; + + if (visible) { + get_parent ().set_child_above_sibling (this, null); + } } public bool is_modal () { From 3fb108dc1f359efbb2fe8dba4707434a4803968e Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Wed, 10 Jul 2024 12:49:03 +0200 Subject: [PATCH 3/6] Cleanup --- src/ShellClients/ShellClientsManager.vala | 3 +-- src/Widgets/ModalActor.vala | 18 +++++++----------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/ShellClients/ShellClientsManager.vala b/src/ShellClients/ShellClientsManager.vala index aa992daa0..024a3e2f0 100644 --- a/src/ShellClients/ShellClientsManager.vala +++ b/src/ShellClients/ShellClientsManager.vala @@ -145,7 +145,6 @@ public class Gala.ShellClientsManager : Object { } public void make_modal (Meta.Window window, bool dim) { - wm.modal_actor.make_modal (window); - wm.modal_actor.dim = dim; + wm.modal_actor.make_modal (window, dim); } } diff --git a/src/Widgets/ModalActor.vala b/src/Widgets/ModalActor.vala index 79a308815..b0cfbf1ca 100644 --- a/src/Widgets/ModalActor.vala +++ b/src/Widgets/ModalActor.vala @@ -14,16 +14,6 @@ public class Gala.ModalActor : Clutter.Actor { public Meta.Display display { get; construct; } - public bool dim { - set { - if (value) { - background_color = { 0, 0, 0, 200 }; - } else { - background_color = { 0, 0, 0, 0 }; - } - } - } - private int modal_dialogs = 0; public ModalActor (Meta.Display display) { @@ -50,13 +40,19 @@ set_size (width, height); } - public void make_modal (Meta.Window window) { + public void make_modal (Meta.Window window, bool dim) { modal_dialogs++; window.unmanaged.connect (unmake_modal); var actor = (Meta.WindowActor) window.get_compositor_private (); InternalUtils.clutter_actor_reparent (actor, this); + if (dim) { + background_color = { 0, 0, 0, 200 }; + } else { + background_color = { 0, 0, 0, 0 }; + } + check_visible (); } From 58af398f9d0b625b3a2b146d14cc8574c756ffe0 Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:19:06 +0200 Subject: [PATCH 4/6] Update pantheon-desktop-shell.vapi --- protocol/pantheon-desktop-shell.vapi | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/protocol/pantheon-desktop-shell.vapi b/protocol/pantheon-desktop-shell.vapi index 22de03875..a01eaa402 100644 --- a/protocol/pantheon-desktop-shell.vapi +++ b/protocol/pantheon-desktop-shell.vapi @@ -56,12 +56,9 @@ namespace Pantheon.Desktop { public static Wl.Interface iface; public Destroy destroy; public SetKeepAbove set_keep_above; -<<<<<<< leolost/make-modal - public MakeModal make_modal; -======= public MakeCentered make_centered; + public MakeModal make_modal; public Focus focus; ->>>>>>> main } [CCode (has_target = false, has_typedef = false)] @@ -81,11 +78,9 @@ namespace Pantheon.Desktop { [CCode (has_target = false, has_typedef = false)] public delegate void SetKeepAbove (Wl.Client client, Wl.Resource resource); [CCode (has_target = false, has_typedef = false)] -<<<<<<< leolost/make-modal - public delegate void MakeModal (Wl.Client client, Wl.Resource resource, uint dim); -======= public delegate void MakeCentered (Wl.Client client, Wl.Resource resource); ->>>>>>> main + [CCode (has_target = false, has_typedef = false)] + public delegate void MakeModal (Wl.Client client, Wl.Resource resource, uint dim); [CCode (has_target = false, has_typedef = false)] public delegate void Destroy (Wl.Client client, Wl.Resource resource); } From 77b84676f7b634df372484fc5bed05ee28efa083 Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:20:24 +0200 Subject: [PATCH 5/6] Update ShellClientsManager.vala --- src/ShellClients/ShellClientsManager.vala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ShellClients/ShellClientsManager.vala b/src/ShellClients/ShellClientsManager.vala index e0a493a2d..ce86e2c3e 100644 --- a/src/ShellClients/ShellClientsManager.vala +++ b/src/ShellClients/ShellClientsManager.vala @@ -183,10 +183,6 @@ public class Gala.ShellClientsManager : Object { windows[window].set_hide_mode (hide_mode); } -<<<<<<< leolost/make-modal - public void make_modal (Meta.Window window, bool dim) { - wm.modal_actor.make_modal (window, dim); -======= public void make_centered (Meta.Window window) { if (window in centered_windows) { return; @@ -197,6 +193,10 @@ public class Gala.ShellClientsManager : Object { window.unmanaging.connect_after (() => centered_windows.remove (window)); } + public void make_modal (Meta.Window window, bool dim) { + wm.modal_actor.make_modal (window, dim); + } + public bool is_positioned_window (Meta.Window window) { bool positioned = (window in centered_windows) || (window in windows); window.foreach_ancestor ((ancestor) => { @@ -267,6 +267,5 @@ public class Gala.ShellClientsManager : Object { break; } } ->>>>>>> main } } From 46d8a2da589e7f8898b354ea072e729676baaf40 Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:21:29 +0200 Subject: [PATCH 6/6] Update pantheon-desktop-shell-v1.xml --- protocol/pantheon-desktop-shell-v1.xml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/protocol/pantheon-desktop-shell-v1.xml b/protocol/pantheon-desktop-shell-v1.xml index 8c4183b63..87beeb950 100644 --- a/protocol/pantheon-desktop-shell-v1.xml +++ b/protocol/pantheon-desktop-shell-v1.xml @@ -111,14 +111,6 @@ Tell the shell to keep the surface above on all workspaces -<<<<<<< leolost/make-modal - - - This will block all user input outside the surface and most system shortcuts. - - - -======= @@ -127,6 +119,14 @@ + + + This will block all user input outside the surface and most system shortcuts. + + + + + Request keyboard focus, taking it away from any other window. @@ -134,7 +134,6 @@ - in contrast to normal windows - never automatically granted by the compositor. ->>>>>>> main