Skip to content

Commit

Permalink
Implement screen cast portal (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
leolost2605 authored Jun 17, 2024
1 parent 5a75c17 commit ad05247
Show file tree
Hide file tree
Showing 12 changed files with 939 additions and 27 deletions.
2 changes: 1 addition & 1 deletion data/pantheon.portal
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[portal]
DBusName=org.freedesktop.impl.portal.desktop.pantheon
Interfaces=org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.AppChooser;org.freedesktop.impl.portal.Background;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Wallpaper
Interfaces=org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.AppChooser;org.freedesktop.impl.portal.Background;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Wallpaper;org.freedesktop.impl.portal.ScreenCast
UseIn=pantheon
32 changes: 6 additions & 26 deletions src/Background/Portal.vala
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,6 @@
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

[DBus (name = "org.pantheon.gala.DesktopIntegration")]
private interface Gala.DesktopIntegration : Object {
public signal void running_applications_changed ();

public const string NAME = "org.pantheon.gala";
public const string PATH = "/org/pantheon/gala/DesktopInterface";

public struct RunningApplications {
string app_id;
HashTable<string,Variant> details;
}

public abstract async RunningApplications[] get_running_applications () throws DBusError, IOError;
}

[DBus (name = "org.freedesktop.impl.portal.Background")]
public class Background.Portal : Object {
public signal void running_applications_changed ();
Expand All @@ -28,18 +13,13 @@ public class Background.Portal : Object {
public Portal (DBusConnection connection) {
this.connection = connection;

connection.get_proxy.begin<Gala.DesktopIntegration> (
Gala.DesktopIntegration.NAME,
Gala.DesktopIntegration.PATH,
NONE, null, (obj, res) => {
try {
desktop_integration = connection.get_proxy.end (res);
desktop_integration.running_applications_changed.connect (() => running_applications_changed ());
} catch {
warning ("Cannot connect to compositor, portal working with reduced functionality.");
}
Gala.DesktopIntegration.get_instance.begin ((obj, res) => {
desktop_integration = Gala.DesktopIntegration.get_instance.end (res);

if (desktop_integration != null) {
desktop_integration.running_applications_changed.connect (() => running_applications_changed ());
}
);
});
}

[CCode (type_signature = "u")]
Expand Down
41 changes: 41 additions & 0 deletions src/DesktopIntegration.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2023 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

[DBus (name = "org.pantheon.gala.DesktopIntegration")]
public interface Gala.DesktopIntegration : Object {
public struct RunningApplications {
string app_id;
HashTable<string, Variant> details;
}

public struct Window {
uint64 uid;
HashTable<string, Variant> details;
}

private const string NAME = "org.pantheon.gala";
private const string PATH = "/org/pantheon/gala/DesktopInterface";

public signal void running_applications_changed ();

public abstract async RunningApplications[] get_running_applications () throws DBusError, IOError;
public abstract async Window[] get_windows () throws DBusError, IOError;

private static Gala.DesktopIntegration? instance;

public static async Gala.DesktopIntegration? get_instance () {
if (instance != null) {
return instance;
}

try {
instance = yield Bus.get_proxy (SESSION, NAME, PATH);
} catch (Error e) {
warning ("Cannot connect to compositor, portal working with reduced functionality.");
}

return instance;
}
}
184 changes: 184 additions & 0 deletions src/ScreenCast/Dialog.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* Authored by: Leonhard Kargl <leo.kargl@proton.me>
*/

public class ScreenCast.Dialog : Granite.Dialog {
public SourceType source_types { get; construct; }
public bool allow_multiple { get; construct; }

public int n_selected { get; private set; default = 0; }

private List<SelectionRow> window_rows;
private List<SelectionRow> monitor_rows;
private SelectionRow? virtual_row;

private Gtk.ListBox list_box;
private Gtk.CheckButton? group = null;

public Dialog (SourceType source_types, bool allow_multiple) {
Object (source_types: source_types, allow_multiple: allow_multiple);
}

construct {
window_rows = new List<SelectionRow> ();
monitor_rows = new List<SelectionRow> ();

list_box = new Gtk.ListBox () {
vexpand = true
};
list_box.add_css_class (Granite.STYLE_CLASS_RICH_LIST);
list_box.set_header_func (header_func);

if (MONITOR in source_types) {
var monitor_tracker = new MonitorTracker ();

foreach (var monitor in monitor_tracker.monitors) {
var row = new SelectionRow (MONITOR, monitor.connector,
monitor.display_name, null, allow_multiple ? null : group);

monitor_rows.append (row);
setup_row (row);
}
}

if (WINDOW in source_types) {
populate_windows.begin ();
}

if (VIRTUAL in source_types) {
virtual_row = new SelectionRow (VIRTUAL, "unused", _("Entire Display"),
new ThemedIcon ("preferences-desktop-display"), allow_multiple ? null : group);
setup_row (virtual_row);
}

var scrolled_window = new Gtk.ScrolledWindow () {
child = list_box,
hscrollbar_policy = NEVER
};

var frame = new Gtk.Frame (null) {
child = scrolled_window
};

get_content_area ().append (frame);

default_height = 400;
default_width = 300;

add_button (_("Cancel"), Gtk.ResponseType.CANCEL);

var accept_button = add_button (_("Share"), Gtk.ResponseType.ACCEPT);
accept_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION);
bind_property ("n-selected", accept_button, "sensitive", SYNC_CREATE, (binding, from_val, ref to_val) => {
to_val.set_boolean (n_selected > 0);
return true;
});
}

private async void populate_windows () {
var desktop_integration = yield Gala.DesktopIntegration.get_instance ();

if (desktop_integration == null) {
return;
}

Gala.DesktopIntegration.Window[] windows;
try {
windows = yield desktop_integration.get_windows ();
} catch (Error e) {
warning ("Failed to get windows from desktop integration: %s", e.message);
return;
}

foreach (var window in windows) {
var label = _("Unknown Window");

if ("title" in window.details) {
label = (string) window.details["title"];
}

Icon icon = new ThemedIcon ("application-x-executable");
if ("app-id" in window.details) {
var app_info = new DesktopAppInfo ((string) window.details["app-id"]);
if (app_info != null && app_info.get_icon () != null) {
icon = app_info.get_icon ();
}
}

var row = new SelectionRow (WINDOW, window.uid,
label, icon, allow_multiple ? null : group);

window_rows.append (row);
setup_row (row);
}
}

private void setup_row (SelectionRow row) {
group = row.check_button;

list_box.append (row);

row.notify["selected"].connect (() => {
if (row.selected) {
n_selected++;
} else {
n_selected--;
}
});
}

private void header_func (Gtk.ListBoxRow row, Gtk.ListBoxRow? prev) {
if (!(row is SelectionRow) && prev != null && !(prev is SelectionRow)) {
return;
}

var selection_row = (SelectionRow) row;

if (prev == null || ((SelectionRow) prev).source_type != selection_row.source_type) {
string label = "";

switch (selection_row.source_type) {
case WINDOW:
label = _("Windows");
break;

case MONITOR:
label = _("Monitors");
break;

case VIRTUAL:
label = _("Entire Display");
break;
}

selection_row.set_header (new Granite.HeaderLabel (label));
}
}

public uint64[] get_selected_windows () {
uint64[] result = {};
foreach (var row in window_rows) {
if (row.selected) {
result += (uint64) row.id;
}
}
return result;
}

public string[] get_selected_monitors () {
string[] result = {};
foreach (var row in monitor_rows) {
if (row.selected) {
result += (string) row.id;
}
}
return result;
}

public bool get_virtual () {
return virtual_row != null && virtual_row.selected;
}
}
Loading

0 comments on commit ad05247

Please sign in to comment.