Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions data/dock.metainfo.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
<p>Updated translations</p>
</description>
<issues>
<issue url="https://github.com/elementary/dock/issues/467">Uninstall Menu Item</issue>
<issue url="https://github.com/elementary/dock/issues/468">Add View in AppCenter menu item</issue>
<issue url="https://github.com/elementary/dock/issues/533">Give workspaces an activate state/animation</issue>
</issues>
</release>
Expand Down
73 changes: 72 additions & 1 deletion src/AppSystem/App.vala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@

public class Dock.App : Object {
public const string ACTION_GROUP_PREFIX = "app-actions";
private const string ACTION_PREFIX = ACTION_GROUP_PREFIX + ".";
public const string ACTION_PREFIX = ACTION_GROUP_PREFIX + ".";
public const string UNINSTALL_ACTION = "uninstall";
public const string VIEW_ACTION = "view-in-appcenter";

private const string SWITCHEROO_ACTION = "switcheroo";
private const string APP_ACTION = "action.%s";

Expand Down Expand Up @@ -51,6 +54,10 @@ public class Dock.App : Object {
public GLib.GenericArray<Window> windows { get; private owned set; } // Ordered by stacking order with topmost at 0

private static Dock.SwitcherooControl switcheroo_control;
private GLib.SimpleAction uninstall_action;
private GLib.SimpleAction view_action;

private string appstream_comp_id = "";

public App (GLib.DesktopAppInfo app_info, bool pinned) {
Object (app_info: app_info, pinned: pinned);
Expand Down Expand Up @@ -101,6 +108,21 @@ public class Dock.App : Object {
app_action_group.add_action (simple_action);
}

if (Environment.find_program_in_path ("io.elementary.appcenter") != null) {
uninstall_action = new SimpleAction (UNINSTALL_ACTION, null);
uninstall_action.activate.connect (action_uninstall);

view_action = new SimpleAction (VIEW_ACTION, null);
view_action.activate.connect (open_in_appcenter);

app_action_group.add_action (uninstall_action);
app_action_group.add_action (view_action);

var appcenter = Dock.AppCenter.get_default ();
appcenter.notify["dbus"].connect (() => on_appcenter_dbus_changed.begin (appcenter));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this causes a memory leak (we have to capture the app center local and therefore the instance as well)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops thanks for catching this. I'll make a branch to fix it

on_appcenter_dbus_changed.begin (appcenter);
}

notify["pinned"].connect (() => {
check_remove ();
ItemManager.get_default ().sync_pinned ();
Expand Down Expand Up @@ -269,4 +291,53 @@ public class Dock.App : Object {
return Source.REMOVE;
});
}

private void action_uninstall () {
var appcenter = Dock.AppCenter.get_default ();
if (appcenter.dbus == null || appstream_comp_id == "") {
return;
}

appcenter.dbus.uninstall.begin (appstream_comp_id, (obj, res) => {
try {
appcenter.dbus.uninstall.end (res);
} catch (GLib.Error e) {
warning (e.message);
}
});
}

private void open_in_appcenter () {
AppInfo.launch_default_for_uri_async.begin ("appstream://" + appstream_comp_id, null, null, (obj, res) => {
try {
AppInfo.launch_default_for_uri_async.end (res);
} catch (Error error) {
var message_dialog = new Granite.MessageDialog.with_image_from_icon_name (
"Unable to open %s in AppCenter".printf (app_info.get_display_name ()),
"",
"dialog-error",
Gtk.ButtonsType.CLOSE
);
message_dialog.show_error_details (error.message);
message_dialog.response.connect (message_dialog.destroy);
message_dialog.present ();
}
});
}

private async void on_appcenter_dbus_changed (Dock.AppCenter appcenter) {
if (appcenter.dbus != null) {
try {
appstream_comp_id = yield appcenter.dbus.get_component_from_desktop_id (app_info.get_id ());
} catch (GLib.Error e) {
appstream_comp_id = "";
warning (e.message);
}
} else {
appstream_comp_id = "";
}

uninstall_action.set_enabled (appstream_comp_id != "");
view_action.set_enabled (appstream_comp_id != "");
}
}
11 changes: 8 additions & 3 deletions src/AppSystem/Launcher.vala
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,17 @@ public class Dock.Launcher : BaseItem {

insert_action_group (App.ACTION_GROUP_PREFIX, app.app_action_group);

var pinned_section = new Menu ();
pinned_section.append (_("Keep in Dock"), ACTION_PREFIX + PINNED_ACTION);
var shell_section = new Menu ();
shell_section.append (_("Keep in Dock"), ACTION_PREFIX + PINNED_ACTION);

if (Environment.find_program_in_path ("io.elementary.appcenter") != null) {
shell_section.append (_("Uninstall"), App.ACTION_PREFIX + App.UNINSTALL_ACTION);
shell_section.append (_("View in AppCenter"), App.ACTION_PREFIX + App.VIEW_ACTION);
}

var menu = new Menu ();
menu.append_section (null, app.app_action_menu);
menu.append_section (null, pinned_section);
menu.append_section (null, shell_section);

popover_menu = new Gtk.PopoverMenu.from_model (menu) {
autohide = true,
Expand Down
57 changes: 57 additions & 0 deletions src/DBus/AppCenter.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* SPDX-License-Identifier: GPL-3.0
* SPDX-FileCopyrightText: 2026 elementary, Inc. (https://elementary.io)
*/

[DBus (name = "io.elementary.appcenter")]
public interface AppCenterDBus : Object {
public abstract async void install (string component_id) throws GLib.Error;
public abstract async void update (string component_id) throws GLib.Error;
public abstract async void uninstall (string component_id) throws GLib.Error;
public abstract async string get_component_from_desktop_id (string desktop_id) throws GLib.Error;
public abstract async string[] search_components (string query) throws GLib.Error;
}

public class Dock.AppCenter : Object {
private const string DBUS_NAME = "io.elementary.appcenter";
private const string DBUS_PATH = "/io/elementary/appcenter";
private const uint RECONNECT_TIMEOUT = 5000U;

private static AppCenter? instance;
public static unowned AppCenter get_default () {
if (instance == null) {
instance = new AppCenter ();
}

return instance;
}

public AppCenterDBus? dbus { public get; private set; default = null; }

construct {
Bus.watch_name (BusType.SESSION, DBUS_NAME, BusNameWatcherFlags.AUTO_START,
() => try_connect (), name_vanished_callback);
}

private AppCenter () {

}

private void try_connect () {
Bus.get_proxy.begin<AppCenterDBus> (BusType.SESSION, DBUS_NAME, DBUS_PATH, 0, null, (obj, res) => {
try {
dbus = Bus.get_proxy.end (res);
} catch (Error e) {
warning (e.message);
Timeout.add (RECONNECT_TIMEOUT, () => {
try_connect ();
return false;
});
}
});
}

private void name_vanished_callback (DBusConnection connection, string name) {
dbus = null;
}
}
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ sources = [
'AppSystem' / 'Background' / 'BackgroundAppRow.vala',
'AppSystem' / 'Background' / 'BackgroundItem.vala',
'AppSystem' / 'Background' / 'BackgroundMonitor.vala',
'DBus' / 'AppCenter.vala',
'DBus' / 'GalaDBus.vala',
'DBus' / 'ItemInterface.vala',
'DBus' / 'ShellKeyGrabber.vala',
Expand Down