Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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: 1 addition & 1 deletion data/xapp.portal
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[portal]
DBusName=org.freedesktop.impl.portal.desktop.xapp
Interfaces=org.freedesktop.impl.portal.Wallpaper;org.freedesktop.impl.portal.Inhibit;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Lockdown;org.freedesktop.impl.portal.Settings;org.freedesktop.impl.portal.Background;
Interfaces=org.freedesktop.impl.portal.AppChooser;org.freedesktop.impl.portal.Wallpaper;org.freedesktop.impl.portal.Inhibit;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Lockdown;org.freedesktop.impl.portal.Settings;org.freedesktop.impl.portal.Background;
UseIn=X-Cinnamon;MATE;XFCE;
282 changes: 282 additions & 0 deletions src/appchooser.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
/*
* Copyright © 2016 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Matthias Clasen <mclasen@redhat.com>
*/

#define _GNU_SOURCE 1

#include "config.h"

#include "appchooser.h"
#include "request.h"
#include "utils.h"

#include <string.h>

#include <gtk/gtk.h>

#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>
#include <gio/gunixfdlist.h>

#include <glib/gi18n.h>

#include "xdg-desktop-portal-dbus.h"

#include "appchooserdialog.h"
#include "externalwindow.h"

static GHashTable *handles;

typedef struct {
XdpImplAppChooser *impl;
GDBusMethodInvocation *invocation;
Request *request;
GtkWidget *dialog;
ExternalWindow *external_parent;

char *chosen;
int response;

} AppDialogHandle;

static void
app_dialog_handle_free (gpointer data)
{
AppDialogHandle *handle = data;

g_hash_table_remove (handles, handle->request->id);
g_clear_object (&handle->external_parent);
g_object_unref (handle->request);
g_object_unref (handle->dialog);
g_free (handle->chosen);

g_free (handle);
}

static void
app_dialog_handle_close (AppDialogHandle *handle)
{
gtk_widget_destroy (handle->dialog);
app_dialog_handle_free (handle);
}

static void
send_response (AppDialogHandle *handle)
{
GVariantBuilder opt_builder;

g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&opt_builder, "{sv}", "choice", g_variant_new_string (handle->chosen ? handle->chosen : ""));

if (handle->request->exported)
request_unexport (handle->request);

xdp_impl_app_chooser_complete_choose_application (handle->impl,
handle->invocation,
handle->response,
g_variant_builder_end (&opt_builder));

app_dialog_handle_close (handle);
}

static void
handle_app_chooser_close (AppChooserDialog *dialog,
gpointer data)
{
AppDialogHandle *handle = data;
GAppInfo *info;

info = app_chooser_dialog_get_info (dialog);
if (info != NULL)
{
const char *desktop_id = g_app_info_get_id (info);
handle->response = 0;
handle->chosen = g_strndup (desktop_id, strlen (desktop_id) - strlen (".desktop"));
Comment thread
Sunderland93 marked this conversation as resolved.
Outdated
}
else
{
handle->response = 1;
handle->chosen = NULL;
}

send_response (handle);
}

static gboolean
handle_close (XdpImplRequest *object,
GDBusMethodInvocation *invocation,
AppDialogHandle *handle)
{
GVariantBuilder opt_builder;

g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
xdp_impl_app_chooser_complete_choose_application (handle->impl,
handle->invocation,
2,
g_variant_builder_end (&opt_builder));
app_dialog_handle_close (handle);

if (handle->request->exported)
request_unexport (handle->request);

Comment thread
Sunderland93 marked this conversation as resolved.
Outdated
xdp_impl_request_complete_close (object, invocation);

return TRUE;
}

static gboolean
handle_choose_application (XdpImplAppChooser *object,
GDBusMethodInvocation *invocation,
const char *arg_handle,
const char *arg_app_id,
const char *arg_parent_window,
const char **choices,
GVariant *arg_options)
{
g_autoptr(Request) request = NULL;
GtkWidget *dialog;
AppDialogHandle *handle;
const char *sender;
const char *latest_chosen_id;
const char *content_type;
const char *location;
gboolean modal;
GdkDisplay *display;
GdkScreen *screen;
ExternalWindow *external_parent = NULL;
GtkWidget *fake_parent;

sender = g_dbus_method_invocation_get_sender (invocation);

request = request_new (sender, arg_app_id, arg_handle);

if (!g_variant_lookup (arg_options, "last_choice", "&s", &latest_chosen_id))
latest_chosen_id = NULL;
if (!g_variant_lookup (arg_options, "modal", "b", &modal))
modal = TRUE;
if (!g_variant_lookup (arg_options, "content_type", "&s", &content_type))
content_type = NULL;
if (!g_variant_lookup (arg_options, "filename", "&s", &location) &&
!g_variant_lookup (arg_options, "uri", "&s", &location))
location = NULL;

if (arg_parent_window)
{
external_parent = create_external_window_from_handle (arg_parent_window);
if (!external_parent)
g_warning ("Failed to associate portal window with parent window %s",
arg_parent_window);
}

if (external_parent)
display = external_window_get_display (external_parent);
else
display = gdk_display_get_default ();
screen = gdk_display_get_default_screen (display);

fake_parent = g_object_new (GTK_TYPE_WINDOW,
"type", GTK_WINDOW_TOPLEVEL,
"screen", screen,
NULL);
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));

gtk_window_set_modal (GTK_WINDOW (dialog), modal);

handle = g_new0 (AppDialogHandle, 1);
handle->impl = object;
handle->invocation = invocation;
handle->request = g_object_ref (request);
handle->dialog = g_object_ref (dialog);
handle->external_parent = external_parent;

g_hash_table_insert (handles, handle->request->id, handle);

g_signal_connect (request, "handle-close",
G_CALLBACK (handle_close), handle);

g_signal_connect (dialog, "close",
G_CALLBACK (handle_app_chooser_close), handle);

gtk_widget_realize (dialog);

if (external_parent)
external_window_set_parent_of (external_parent, gtk_widget_get_window (dialog));

gtk_window_present (GTK_WINDOW (dialog));

request_export (request, g_dbus_method_invocation_get_connection (invocation));

return TRUE;
}

static gboolean
handle_update_choices (XdpImplAppChooser *object,
GDBusMethodInvocation *invocation,
const char *arg_handle,
const char **choices)
{
AppDialogHandle *handle;
g_autofree char *a = NULL;

handle = g_hash_table_lookup (handles, arg_handle);

if (handle == NULL)
{
g_dbus_method_invocation_return_error (invocation,
XDG_DESKTOP_PORTAL_ERROR,
XDG_DESKTOP_PORTAL_ERROR_NOT_FOUND,
"Request not found");
return TRUE;
}

g_debug ("Updating choices: %s\n", a = g_strjoinv (", ", (char **)choices));

app_chooser_dialog_update_choices (APP_CHOOSER_DIALOG (handle->dialog), choices);

g_dbus_method_invocation_return_value (invocation, NULL);

return TRUE;
}

gboolean
app_chooser_init (GDBusConnection *bus,
GError **error)
{
GDBusInterfaceSkeleton *helper;

helper = G_DBUS_INTERFACE_SKELETON (xdp_impl_app_chooser_skeleton_new ());

g_signal_connect (helper, "handle-choose-application", G_CALLBACK (handle_choose_application), NULL);
g_signal_connect (helper, "handle-update-choices", G_CALLBACK (handle_update_choices), NULL);

if (!g_dbus_interface_skeleton_export (helper,
bus,
DESKTOP_PORTAL_OBJECT_PATH,
error))
return FALSE;

handles = g_hash_table_new (g_str_hash, g_str_equal);

g_debug ("providing %s", g_dbus_interface_skeleton_get_info (helper)->name);

return TRUE;
}
25 changes: 25 additions & 0 deletions src/appchooser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright © 2016 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Matthias Clasen <mclasen@redhat.com>
*/

#pragma once

#include <gio/gio.h>

gboolean app_chooser_init (GDBusConnection *bus, GError **error);
Loading