Skip to content

Implement AppChooser portal#27

Open
Sunderland93 wants to merge 6 commits into
linuxmint:masterfrom
Sunderland93:appchooser_portal
Open

Implement AppChooser portal#27
Sunderland93 wants to merge 6 commits into
linuxmint:masterfrom
Sunderland93:appchooser_portal

Conversation

@Sunderland93

Copy link
Copy Markdown

This portal is used when the system has several programs capable of opening the selected file type. If such programs are missing, they are offered for installation through the system application manager (in this case, mintinstall). Without this PR, a similar portal for GNOME, linked to gnome-software, is used. Tested with Dolphin installed from Flatpak.

Before:
Снимок экрана_20260112_003613

After:
Снимок экрана_20260112_003833
Снимок экрана_20260112_003851

@mtwebster

Copy link
Copy Markdown
Member

Hi sorry I missed this one...

Is there more to this? I don't see where HAVE_GTK_X11 or HAVE_GTK_WAYLAND are defined anywhere in the build, so right now create_external_window_from_handle() just falls out the bottom. You need to add depends for gdk-wayland-3.0 and -x11- as well (probably tie those defines to them).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an org.freedesktop.impl.portal.AppChooser backend to xdg-desktop-portal-xapp, providing an “Open With…” chooser UI and offering app installation via mintinstall when no suitable apps are present.

Changes:

  • Add AppChooser D-Bus backend implementation and hook it into portal startup.
  • Introduce GTK UI (dialog + row) bundled via GResources.
  • Add external parent window handling helpers (X11/Wayland) for transient/modal dialog parenting.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/xdg-desktop-portal-xapp.gresource.xml Adds UI resources (dialog/row templates) to the compiled resource bundle.
src/xdg-desktop-portal-xapp.c Initializes the new AppChooser portal on bus acquisition.
src/meson.build Adds AppChooser DBus interface codegen, GResources compilation, and new source files.
src/appchooser.h Declares AppChooser portal init entrypoint.
src/appchooser.c Implements AppChooser D-Bus handlers and request/dialog lifecycle.
src/appchooserdialog.ui Defines the AppChooser dialog UI (list + empty state).
src/appchooserdialog.h Declares AppChooserDialog API.
src/appchooserdialog.c Implements dialog behavior, selection, “more” expansion, and mintinstall launch.
src/appchooserrow.ui Defines the list row UI for an application entry.
src/appchooserrow.h Declares AppChooserRow API.
src/appchooserrow.c Implements the row widget binding app info -> UI.
src/externalwindow.h Introduces ExternalWindow abstraction for parenting portal windows to external handles.
src/externalwindow.c Implements handle parsing and ExternalWindow base type.
src/externalwindow-x11.h Declares X11 backend for ExternalWindow.
src/externalwindow-x11.c Implements X11 external window parenting via foreign XID.
src/externalwindow-wayland.h Declares Wayland backend for ExternalWindow.
src/externalwindow-wayland.c Implements Wayland external window parenting via exported handle.
data/xapp.portal Registers the new AppChooser interface in the backend’s advertised interfaces list.
Comments suppressed due to low confidence (2)

src/externalwindow-x11.h:36

  • externalwindow-x11.h declares GType external_window_get_type (void); but the type macro uses external_window_x11_get_type(). This mismatch will cause build failures or wrong symbol usage. The header should declare external_window_x11_get_type() (and the base type getter is already declared in externalwindow.h).
#define EXTERNAL_TYPE_WINDOW_X11 (external_window_x11_get_type ())
#define EXTERNAL_WINDOW_X11(object) (G_TYPE_CHECK_INSTANCE_CAST (object, EXTERNAL_TYPE_WINDOW_X11, ExternalWindowX11))

typedef struct _ExternalWindowX11 ExternalWindowX11;
typedef struct _ExternalWindowX11Class ExternalWindowX11Class;

GType external_window_get_type (void);
ExternalWindowX11 *external_window_x11_new (const char *handle_str);

src/meson.build:93

  • meson.build unconditionally compiles externalwindow-x11.c/externalwindow-wayland.c, but config.h doesn't define HAVE_GTK_X11/HAVE_GTK_WAYLAND. As a result, externalwindow.c compiles with both backends disabled and create_external_window_from_handle() will always return NULL, breaking parent window association. Add proper Meson feature detection (e.g., gdk-x11-3.0 / gdk-wayland-3.0 deps) and define HAVE_GTK_X11/HAVE_GTK_WAYLAND in config.h, or remove the ifdefs if these backends are always expected.
config_entries = {
    'GETTEXT_PACKAGE' : '"@0@"'.format(meson.project_name()),
    'LOCALEDIR': '"@0@"'.format(prefix / get_option('localedir')),
    'PACKAGE_STRING': '"xdg-desktop-portal-xapp @0@"'.format(meson.project_version()),
    'G_LOG_DOMAIN': '"xdg-desktop-portal-xapp"'

}
config = configuration_data(config_entries)
built_sources += configure_file(output: 'config.h', configuration: config)

deps = [
  meson.get_compiler('c').find_library('m'),
  dependency('glib-2.0', version: '>= 2.44'),
  dependency('gio-unix-2.0'),
  dependency('gtk+-3.0'),
  xdg_desktop_portal_dep,
]

sources = built_sources + files(
  'appchooser.c',
  'appchooserdialog.c',
  'appchooserrow.c',
  'background.c',
  'externalwindow.c',
  'externalwindow-wayland.c',
  'externalwindow-x11.c',
  'inhibit.c',
  'lockdown.c',
  'request.c',
  'screenshot.c',
  'session.c',
  'settings.c',
  'utils.c',
  'wallpaper.c',
  'xdg-desktop-portal-xapp.c',
)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/appchooser.c Outdated
Comment thread src/appchooserdialog.c
Comment on lines +312 to +340
static void
ensure_default_in_initial_list (const char **choices,
const char *default_id)
{
int i;
guint n_choices;

if (default_id == NULL)
return;

n_choices = g_strv_length ((char **)choices);
if (n_choices <= INITIAL_LIST_SIZE)
return;

for (i = 0; i < INITIAL_LIST_SIZE; i++)
{
if (strcmp (choices[i], default_id) == 0)
return;
}

for (i = INITIAL_LIST_SIZE; i < n_choices; i++)
{
if (strcmp (choices[i], default_id) == 0)
{
const char *tmp = choices[0];
choices[0] = choices[i];
choices[i] = tmp;
return;
}
Comment thread src/appchooserdialog.c
Comment on lines +472 to +491
for (i = 0; choices[i]; i++)
{
if (g_strv_contains ((const char * const *)dialog->choices, choices[i]))
continue;

g_ptr_array_add (new_choices, g_strdup (choices[i]));

if (!gtk_widget_get_visible (dialog->more_row))
{
g_autofree char *desktop_id = NULL;
g_autoptr(GAppInfo) info = NULL;
GtkWidget *row;

desktop_id = g_strconcat (choices[i], ".desktop", NULL);
info = G_APP_INFO (g_desktop_app_info_new (desktop_id));

row = GTK_WIDGET (app_chooser_row_new (info));
gtk_widget_set_visible (row, TRUE);
gtk_list_box_insert (GTK_LIST_BOX (dialog->list), row, -1);
}
Comment thread src/appchooser.c
g_object_ref_sink (fake_parent);

dialog = GTK_WIDGET (app_chooser_dialog_new (choices, latest_chosen_id, content_type, location));
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fake_parent));
Comment thread src/appchooserdialog.ui Outdated
Comment thread src/appchooserrow.c
Comment on lines +79 to +86
g_set_object (&row->info, info);

icon = g_app_info_get_icon (info);
if (!icon)
icon = g_themed_icon_new ("application-x-executable");

gtk_image_set_from_gicon (GTK_IMAGE (row->icon), icon, GTK_ICON_SIZE_DIALOG);
gtk_image_set_pixel_size (GTK_IMAGE (row->icon), 32);
Comment thread src/appchooser.c Outdated
Comment thread src/appchooserdialog.c
Comment thread src/appchooserdialog.c
Comment thread src/appchooserdialog.c
@leigh123linux

Copy link
Copy Markdown
Member

Please fix

src/meson.build:93

meson.build unconditionally compiles externalwindow-x11.c/externalwindow-wayland.c, but config.h doesn't define HAVE_GTK_X11/HAVE_GTK_WAYLAND. As a result, externalwindow.c compiles with both backends disabled and create_external_window_from_handle() will always return NULL, breaking parent window association. Add proper Meson feature detection (e.g., gdk-x11-3.0 / gdk-wayland-3.0 deps) and define HAVE_GTK_X11/HAVE_GTK_WAYLAND in config.h, or remove the ifdefs if these backends are always expected.

@Sunderland93

Copy link
Copy Markdown
Author

Done

@clefebvre clefebvre added the invalid This doesn't seem right label Jun 16, 2026
@clefebvre

Copy link
Copy Markdown
Member

Cinnamon (or XAPP DE in general) do not have any associated software manager. Mintinstall is a distribution-specific tool.

Also, I think this is going way too far in terms of scope and responsibility. I am not keen in reinventing the wheel and re-implementing DE parts like this inside the portal. If something can't be open, just say it can't be open. A file manager which is running sandboxed, in flatpak, with no idea about the distro, shouldn't try to go that far, referencing other apps, playing with mimes and package management. This is pure distro-land at this stage and it's done natively.

@Sunderland93

Copy link
Copy Markdown
Author

Cinnamon (or XAPP DE in general) do not have any associated software manager. Mintinstall is a distribution-specific tool.

It can be added with list of popular software managers, e.g. GNOME Software or Ubuntu's App Center, and not break the user experience just like in first screenshot, where using xdg-desktop-portal-gtk requested GNOME Software on Mint.

A file manager which is running sandboxed, in flatpak, with no idea about the distro, shouldn't try to go that far, referencing other apps, playing with mimes and package management

It didn't. AppChooser portal handle this for sandboxed apps, and it's useful in Wayland

@clefebvre

Copy link
Copy Markdown
Member

OK, xdg-desktop-portal-gtk isn't suitable as an AppChooser implementation because it's designed to be GNOME-specific.

  • It uses GNOME HIG (buttons on top etc..)
  • It hardcodes GNOME Software without even checking that it's present.

We can implement an AppChooser in the XApp portal but:

  • We don't need to recommend any Software Manager. That's not something we even do natively.
  • When we list apps, we need to do so in normal looking dialogs, with buttons at the bottom and all.

Note: Dolphin should use org.freedesktop.portal.OpenURI.OpenFile on double-click, I don't understand why it's requesting org.freedesktop.impl.portal.AppChooser.ChooseApplication every time. By doing so, it ignores default MIME choices.

@clefebvre

Copy link
Copy Markdown
Member

@Sunderland93 I can work on adapting the PR if you want, unless you want to do it. Let me know.

@Sunderland93

Copy link
Copy Markdown
Author

@Sunderland93 I can work on adapting the PR if you want, unless you want to do it. Let me know.

Yes, thank you. I'm currently don't have enough time to work on it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

invalid This doesn't seem right

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants