diff --git a/protocol/pantheon-desktop-shell-v1.xml b/protocol/pantheon-desktop-shell-v1.xml index 2f1d92a74..210d3a2f5 100644 --- a/protocol/pantheon-desktop-shell-v1.xml +++ b/protocol/pantheon-desktop-shell-v1.xml @@ -35,6 +35,14 @@ + + + + Create a greeter surface from an existing surface. + + + + @@ -169,4 +177,15 @@ + + + + + + + Request to make the surface a Greeter window, which will be displayed bellow other windows + when running in greeter compositor mode. + + + diff --git a/protocol/pantheon-desktop-shell.vapi b/protocol/pantheon-desktop-shell.vapi index f7ddc93ba..ba95c891e 100644 --- a/protocol/pantheon-desktop-shell.vapi +++ b/protocol/pantheon-desktop-shell.vapi @@ -1,5 +1,5 @@ /* - * Copyright 2023 elementary, Inc. + * Copyright 2023-2026 elementary, Inc. * Copyright 2023 Corentin Noël * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -12,7 +12,7 @@ namespace Pantheon.Desktop { public Pantheon.Desktop.GetPanel get_panel; public Pantheon.Desktop.GetWidget get_widget; public Pantheon.Desktop.GetExtendedBehavior get_extended_behavior; - + public Pantheon.Desktop.GetGreeter get_greeter; } [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "enum io_elementary_pantheon_panel_v1_anchor", cprefix="IO_ELEMENTARY_PANTHEON_PANEL_V1_ANCHOR_", has_type_id = false)] @@ -65,6 +65,14 @@ namespace Pantheon.Desktop { public MakeMonitorLabel make_monitor_label; } + [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "struct io_elementary_pantheon_greeter_v1_interface")] + public struct GreeterInterface { + [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "io_elementary_pantheon_greeter_v1_interface")] + public static Wl.Interface iface; + public Destroy destroy; + public MakeGreeter make_greeter; + } + [CCode (has_target = false, has_typedef = false)] public delegate void GetPanel (Wl.Client client, Wl.Resource resource, uint32 output, Wl.Resource surface); [CCode (has_target = false, has_typedef = false)] @@ -72,6 +80,8 @@ namespace Pantheon.Desktop { [CCode (has_target = false, has_typedef = false)] public delegate void GetExtendedBehavior (Wl.Client client, Wl.Resource resource, uint32 output, Wl.Resource surface); [CCode (has_target = false, has_typedef = false)] + public delegate void GetGreeter (Wl.Client client, Wl.Resource resource, uint32 output, Wl.Resource surface); + [CCode (has_target = false, has_typedef = false)] public delegate void SetAnchor (Wl.Client client, Wl.Resource resource, [CCode (type = "uint32_t")] Anchor anchor); [CCode (has_target = false, has_typedef = false)] public delegate void Focus (Wl.Client client, Wl.Resource resource); @@ -94,5 +104,7 @@ namespace Pantheon.Desktop { [CCode (has_target = false, has_typedef = false)] public delegate void MakeMonitorLabel (Wl.Client client, Wl.Resource resource, int monitor_index); [CCode (has_target = false, has_typedef = false)] + public delegate void MakeGreeter (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/PantheonShell.vala b/src/PantheonShell.vala index 46136696d..2d187916a 100644 --- a/src/PantheonShell.vala +++ b/src/PantheonShell.vala @@ -18,6 +18,7 @@ namespace Gala { private static Pantheon.Desktop.PanelInterface wayland_pantheon_panel_interface; private static Pantheon.Desktop.WidgetInterface wayland_pantheon_widget_interface; private static Pantheon.Desktop.ExtendedBehaviorInterface wayland_pantheon_extended_behavior_interface; + private static Pantheon.Desktop.GreeterInterface wayland_pantheon_greeter_interface; private static Wl.Global shell_global; public void init_pantheon_shell (Meta.Context context) { @@ -31,6 +32,7 @@ namespace Gala { get_panel, get_widget, get_extended_behavior, + get_greeter, }; wayland_pantheon_panel_interface = { @@ -57,9 +59,15 @@ namespace Gala { make_monitor_label, }; + wayland_pantheon_greeter_interface = { + destroy_greeter_surface, + make_greeter, + }; + PanelSurface.quark = GLib.Quark.from_string ("-gala-wayland-panel-surface-data"); WidgetSurface.quark = GLib.Quark.from_string ("-gala-wayland-widget-surface-data"); ExtendedBehaviorSurface.quark = GLib.Quark.from_string ("-gala-wayland-extended-behavior-surface-data"); + GreeterSurface.quark = GLib.Quark.from_string ("-gala-wayland-greeter-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); @@ -124,6 +132,25 @@ namespace Gala { } } + public class GreeterSurface : GLib.Object { + public static GLib.Quark quark = 0; + public unowned GLib.Object? wayland_surface; + + public GreeterSurface (GLib.Object wayland_surface) { + this.wayland_surface = wayland_surface; + } + + ~GreeterSurface () { + if (wayland_surface != null) { + wayland_surface.steal_qdata (quark); + } + } + + public void on_wayland_surface_disposed () { + wayland_surface = null; + } + } + static void unref_obj_on_destroy (Wl.Resource resource) { resource.get_user_data ().unref (); } @@ -215,6 +242,35 @@ namespace Gala { ); } + internal static void get_greeter (Wl.Client client, Wl.Resource resource, uint32 output, Wl.Resource surface_resource) { + unowned GLib.Object? wayland_surface = surface_resource.get_user_data (); + GreeterSurface? greeter_surface = wayland_surface.get_qdata (GreeterSurface.quark); + if (greeter_surface != null) { + surface_resource.post_error ( + Wl.DisplayError.INVALID_OBJECT, + "io_elementary_pantheon_shell_v1_interface::get_greeter already requested" + ); + return; + } + + greeter_surface = new GreeterSurface (wayland_surface); + unowned var greeter_resource = client.create_resource ( + ref Pantheon.Desktop.GreeterInterface.iface, + resource.get_version (), + output + ); + greeter_resource.set_implementation ( + &wayland_pantheon_greeter_interface, + greeter_surface.ref (), + unref_obj_on_destroy + ); + wayland_surface.set_qdata_full ( + GreeterSurface.quark, + greeter_surface, + (GLib.DestroyNotify) GreeterSurface.on_wayland_surface_disposed + ); + } + internal static void set_anchor (Wl.Client client, Wl.Resource resource, [CCode (type = "uint32_t")] Pantheon.Desktop.Anchor anchor) { unowned PanelSurface? panel_surface = resource.get_user_data (); if (panel_surface.wayland_surface == null) { @@ -408,6 +464,23 @@ namespace Gala { ShellClientsManager.get_instance ().make_monitor_label (window, monitor_index); } + internal static void make_greeter (Wl.Client client, Wl.Resource resource) { + unowned GreeterSurface? greeter_surface = resource.get_user_data (); + if (greeter_surface.wayland_surface == null) { + warning ("Window tried to make greeter but wayland surface is null."); + return; + } + + Meta.Window? window; + greeter_surface.wayland_surface.get ("window", out window, null); + if (window == null) { + warning ("Window tried to make greeter but wayland surface had no associated window."); + return; + } + + ShellClientsManager.get_instance ().make_greeter (window); + } + internal static void destroy_panel_surface (Wl.Client client, Wl.Resource resource) { resource.destroy (); } @@ -419,4 +492,8 @@ namespace Gala { internal static void destroy_extended_behavior_surface (Wl.Client client, Wl.Resource resource) { resource.destroy (); } + + internal static void destroy_greeter_surface (Wl.Client client, Wl.Resource resource) { + resource.destroy (); + } } diff --git a/src/ShellClients/ShellClientsManager.vala b/src/ShellClients/ShellClientsManager.vala index bcaf1d4a2..4f9f2d9fb 100644 --- a/src/ShellClients/ShellClientsManager.vala +++ b/src/ShellClients/ShellClientsManager.vala @@ -138,7 +138,7 @@ public class Gala.ShellClientsManager : Object, GestureTarget { } } - public void make_dock (Meta.Window window) { + private void make_dock (Meta.Window window) { #if HAS_MUTTER49 window.set_type (Meta.WindowType.DOCK); #else @@ -182,6 +182,31 @@ public class Gala.ShellClientsManager : Object, GestureTarget { } #endif + private void make_desktop (Meta.Window window) { +#if HAS_MUTTER49 + window.set_type (Meta.WindowType.DESKTOP); +#else + if (Meta.Util.is_wayland_compositor ()) { + make_desktop_wayland (window); + } else { + critical ("Making desktop window on X11 is not supported."); + } +#endif + } + +#if !HAS_MUTTER49 + private void make_desktop_wayland (Meta.Window window) requires (Meta.Util.is_wayland_compositor ()) { + foreach (var client in protocol_clients) { + if (client.wayland_client.owns_window (window)) { +#if HAS_MUTTER46 + client.wayland_client.make_desktop (window); +#endif + break; + } + } + } +#endif + public void set_anchor (Meta.Window window, Pantheon.Desktop.Anchor anchor) { if (window in panel_windows) { panel_windows[window].anchor = anchor; @@ -290,6 +315,12 @@ public class Gala.ShellClientsManager : Object, GestureTarget { window.unmanaged.connect_after (() => ibus_candidate_window = null); } + public void make_greeter (Meta.Window window) { + make_desktop (window); + + wm.override_window_group (window, LOCK_SCREEN); + } + public void propagate (UpdateType update_type, GestureAction action, double progress) { foreach (var window in positioned_windows.get_values ()) { window.propagate (update_type, action, progress);