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);