Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add file chooser on wl, x11 and gtk4 #606

Merged
merged 5 commits into from
Oct 19, 2023
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
1 change: 1 addition & 0 deletions core/cog-config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define COG_DEFAULT_APPID "@COG_DEFAULT_APPID@"
#define COG_DEFAULT_HOME_URI "@COG_DEFAULT_HOME_URI@"
#define COG_HAVE_MEM_PRESSURE @HAVE_WEBKIT_MEM_PRESSURE_API@
#define COG_HAVE_LIBPORTAL @HAVE_LIBPORTAL@
#define COG_ENABLE_GAMEPAD_MANETTE @ENABLE_GAMEPAD_MANETTE@

/* FIXME: Perhaps make this a meson define instead. */
Expand Down
1 change: 1 addition & 0 deletions core/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ cog_config.set('COG_DEFAULT_APPID', cog_launcher_appid)
cog_config.set('COG_DEFAULT_HOME_URI', cog_launcher_home_uri)
cog_config.set10('HAVE_WEBKIT_MEM_PRESSURE_API',
wpewebkit_dep.version().version_compare('>=2.34.0'))
cog_config.set10('HAVE_LIBPORTAL', libportal_dep.found())
cog_config.set10('ENABLE_GAMEPAD_MANETTE', gamepad_manette)

cogcore_config_h = configure_file(
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ endif

wpe_dep = dependency('wpe-1.0')
manette_dep = dependency('manette-0.2', version: '>=0.2.4', required: false)
libportal_dep = dependency('libportal', required: false)

subdir('core')

Expand Down
61 changes: 61 additions & 0 deletions platform/common/cog-file-chooser.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* cog-file-chooser.c
* Copyright (C) 2023 SUSE Software Solutions Germany GmbH
*
* Distributed under terms of the MIT license.
*/

#include "cog-file-chooser.h"

static void
on_file_chooser_response(GObject *object, GAsyncResult *result, gpointer user_data)
{
g_autoptr(GError) error = NULL;
g_autoptr(XdpPortal) xdp_portal = XDP_PORTAL(object);
g_autoptr(WebKitFileChooserRequest) request = WEBKIT_FILE_CHOOSER_REQUEST(user_data);
g_autoptr(GVariant) val = xdp_portal_open_file_finish(xdp_portal, result, &error);
if (!val) {
g_debug("File chooser failed: %s", error->message);
webkit_file_chooser_request_cancel(request);
return;
}

g_autofree const char **uris = NULL;
g_variant_lookup(val, "uris", "^a&s", &uris);
webkit_file_chooser_request_select_files(request, uris);
}

void
run_file_chooser(WebKitWebView *view, WebKitFileChooserRequest *request, XdpParent *xdp_parent)
{
XdpPortal *xdp_portal = xdp_portal_new();
if (!xdp_portal)
return;

GVariantBuilder all_filters_builder;
g_variant_builder_init(&all_filters_builder, G_VARIANT_TYPE("a(sa(us))"));

// Add "Supported files" filters from mime types
const char *const *mime_types = webkit_file_chooser_request_get_mime_types(request);
if (mime_types) {
GVariantBuilder one_filter_builder;
g_variant_builder_init(&one_filter_builder, G_VARIANT_TYPE("a(us)"));
for (int i = 0; mime_types[i]; i++) {
g_variant_builder_add(&one_filter_builder, "(us)", 1, mime_types[i]);
}
g_variant_builder_add(&all_filters_builder, "(s@a(us))", "Supported files",
g_variant_builder_end(&one_filter_builder));
}

// Add "All files" filter
GVariantBuilder one_filter_builder;
g_variant_builder_init(&one_filter_builder, G_VARIANT_TYPE("a(us)"));
g_variant_builder_add(&one_filter_builder, "(us)", 0, "*");
g_variant_builder_add(&all_filters_builder, "(s@a(us))", "All files", g_variant_builder_end(&one_filter_builder));

gboolean select_multiple = webkit_file_chooser_request_get_select_multiple(request);
xdp_portal_open_file(xdp_portal, xdp_parent, select_multiple ? "Select Files" : "Select File",
g_variant_builder_end(&all_filters_builder), NULL, NULL,
select_multiple ? XDP_OPEN_FILE_FLAG_MULTIPLE : XDP_OPEN_FILE_FLAG_NONE, NULL,
on_file_chooser_response, g_object_ref(request));
}
17 changes: 17 additions & 0 deletions platform/common/cog-file-chooser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* cog-file-chooser.h
* Copyright (C) 2023 SUSE Software Solutions Germany GmbH
*
* Distributed under terms of the MIT license.
*/

#pragma once

#include <libportal/portal.h>
#include <wpe/webkit.h>

G_BEGIN_DECLS

void run_file_chooser(WebKitWebView *view, WebKitFileChooserRequest *request, XdpParent *xdp_parent);

G_END_DECLS
7 changes: 7 additions & 0 deletions platform/common/meson.build
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
cogplatformcommon_dependencies = [
cogcore_dep,
libportal_dep,
dependency('epoxy'),
]

cogplatformcommon_sources = []
if libportal_dep.found()
cogplatformcommon_sources += ['cog-file-chooser.c']
endif

cogplatformcommon_lib = static_library('cogplatformcommon',
'cog-gl-utils.c',
cogplatformcommon_sources,
dependencies: cogplatformcommon_dependencies,
build_by_default: false,
gnu_symbol_visibility: 'hidden',
Expand Down
47 changes: 47 additions & 0 deletions platform/common/xdp-parent-private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2021, Georges Basile Stavracas Neto
*
* This file 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, version 3.0 of the
* License.
*
* This file 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 program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-3.0-only
*/

/*
* This must be in sync with parent-private.h header from libportal.
*/

#pragma once

#include <libportal/types.h>

G_BEGIN_DECLS

typedef void (* XdpParentExported) (XdpParent *parent,
const char *handle,
gpointer data);
typedef gboolean (* XdpParentExport) (XdpParent *parent,
XdpParentExported callback,
gpointer data);
typedef void (* XdpParentUnexport) (XdpParent *parent);

struct _XdpParent {
/*< private >*/
XdpParentExport parent_export;
XdpParentUnexport parent_unexport;
GObject *object;
XdpParentExported callback;
gpointer data;
};

G_END_DECLS
22 changes: 21 additions & 1 deletion platform/gtk4/cog-platform-gtk4.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@
* Distributed under terms of the MIT license.
*/

#include "../../core/cog.h"

#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <wpe/fdo-egl.h>
#include <wpe/fdo.h>
#if COG_HAVE_LIBPORTAL
# include <libportal-gtk4/portal-gtk4.h>
#endif /* COG_HAVE_LIBPORTAL */

#include "../../core/cog.h"
#if COG_HAVE_LIBPORTAL
# include "../common/cog-file-chooser.h"
#endif /* COG_HAVE_LIBPORTAL */
#include "../common/cog-gl-utils.h"
#include "cog-gtk-settings-dialog.h"

Expand Down Expand Up @@ -745,6 +752,16 @@ on_back_forward_changed(WebKitBackForwardList* back_forward_list,
webkit_web_view_can_go_forward(win->web_view));
}

#if COG_HAVE_LIBPORTAL
static void
on_run_file_chooser(WebKitWebView *view, WebKitFileChooserRequest *request)
{
g_autoptr(XdpParent) xdp_parent = xdp_parent_new_gtk(GTK_WINDOW(win.gtk_window));

run_file_chooser(view, request, xdp_parent);
}
#endif /* COG_HAVE_LIBPORTAL */

static void
cog_gtk4_platform_init_web_view(CogPlatform* platform, WebKitWebView* view)
{
Expand All @@ -754,6 +771,9 @@ cog_gtk4_platform_init_web_view(CogPlatform* platform, WebKitWebView* view)
G_CALLBACK(on_load_progress), &win);
g_signal_connect(webkit_web_view_get_back_forward_list(view), "changed",
G_CALLBACK(on_back_forward_changed), &win);
#if COG_HAVE_LIBPORTAL
g_signal_connect(view, "run-file-chooser", G_CALLBACK(on_run_file_chooser), NULL);
joantolo marked this conversation as resolved.
Show resolved Hide resolved
#endif /* COG_HAVE_LIBPORTAL */
win.web_view = view;

win.device_scale_factor = gtk_widget_get_scale_factor(win.gl_drawing_area);
Expand Down
1 change: 1 addition & 0 deletions platform/gtk4/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ gtk4_platform_plugin = shared_module('cogplatform-gtk4',
dependencies: [
cogplatformcommon_dep,
wpebackend_fdo_dep,
dependency('libportal-gtk4', required: libportal_dep.found()),
dependency('gtk4'),
],
gnu_symbol_visibility: 'hidden',
Expand Down
38 changes: 38 additions & 0 deletions platform/wayland/cog-platform-wl.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,25 @@
#include <xkbcommon/xkbcommon-compose.h>
#include <locale.h>

#if COG_HAVE_LIBPORTAL
# include "../common/cog-file-chooser.h"
#endif /* COG_HAVE_LIBPORTAL */
#include "../common/egl-proc-address.h"
#include "os-compatibility.h"

#include "cog-im-context-wl-v1.h"
#include "cog-im-context-wl.h"
#include "cog-popup-menu-wl.h"
#if COG_HAVE_LIBPORTAL
# include "cog-xdp-parent-wl.h"
#endif /* COG_HAVE_LIBPORTAL */

#include "fullscreen-shell-unstable-v1-client.h"
#include "linux-dmabuf-unstable-v1-client.h"
#include "presentation-time-client.h"
#include "text-input-unstable-v1-client.h"
#include "text-input-unstable-v3-client.h"
#include "xdg-foreign-unstable-v2-client.h"
#include "xdg-shell-client.h"

#if COG_ENABLE_WESTON_DIRECT_DISPLAY
Expand Down Expand Up @@ -181,6 +188,7 @@ static struct {

struct zwp_text_input_manager_v3 *text_input_manager;
struct zwp_text_input_manager_v1 *text_input_manager_v1;
struct zxdg_exporter_v2 *zxdg_exporter;

struct wp_presentation *presentation;

Expand Down Expand Up @@ -242,6 +250,10 @@ static struct {
struct xdg_toplevel *xdg_toplevel;
struct wl_shell_surface *shell_surface;

#if COG_HAVE_LIBPORTAL
struct xdp_parent_wl_data xdp_parent_wl_data;
#endif /* COG_HAVE_LIBPORTAL */

uint32_t width;
uint32_t height;
uint32_t width_before_fullscreen;
Expand Down Expand Up @@ -831,6 +843,8 @@ registry_global (void *data,
wl_data.text_input_manager = wl_registry_bind(registry, name, &zwp_text_input_manager_v3_interface, 1);
} else if (strcmp(interface, zwp_text_input_manager_v1_interface.name) == 0) {
wl_data.text_input_manager_v1 = wl_registry_bind(registry, name, &zwp_text_input_manager_v1_interface, 1);
} else if (strcmp(interface, zxdg_exporter_v2_interface.name) == 0) {
wl_data.zxdg_exporter = wl_registry_bind(registry, name, &zxdg_exporter_v2_interface, 1);
} else if (strcmp(interface, wp_presentation_interface.name) == 0) {
wl_data.presentation = wl_registry_bind(registry, name, &wp_presentation_interface, 1);
} else {
Expand Down Expand Up @@ -1985,6 +1999,8 @@ clear_wayland (void)
zwp_fullscreen_shell_v1_destroy (wl_data.fshell);
if (wl_data.shell != NULL)
wl_shell_destroy (wl_data.shell);
if (wl_data.zxdg_exporter != NULL)
zxdg_exporter_v2_destroy(wl_data.zxdg_exporter);

g_clear_pointer (&wl_data.shm, wl_shm_destroy);
g_clear_pointer (&wl_data.subcompositor, wl_subcompositor_destroy);
Expand Down Expand Up @@ -2193,6 +2209,11 @@ create_window (GError **error)
configure_surface_geometry(0, 0);
}

#if COG_HAVE_LIBPORTAL
win_data.xdp_parent_wl_data.zxdg_exporter = wl_data.zxdg_exporter;
win_data.xdp_parent_wl_data.wl_surface = win_data.wl_surface;
#endif /* COG_HAVE_LIBPORTAL */

const char *env_var;
if ((env_var = g_getenv("COG_PLATFORM_WL_VIEW_FULLSCREEN")) && g_ascii_strtoll(env_var, NULL, 10) > 0) {
win_data.is_maximized = false;
Expand Down Expand Up @@ -2548,10 +2569,27 @@ on_show_option_menu(WebKitWebView *view, WebKitOptionMenu *menu, WebKitRectangle
create_popup (g_object_ref (menu));
}

#if COG_HAVE_LIBPORTAL
static void
on_run_file_chooser(WebKitWebView *view, WebKitFileChooserRequest *request)
{
g_autoptr(XdpParent) xdp_parent = NULL;

if (win_data.xdp_parent_wl_data.zxdg_exporter && win_data.xdp_parent_wl_data.wl_surface) {
xdp_parent = xdp_parent_new_wl(&win_data.xdp_parent_wl_data);
}

run_file_chooser(view, request, xdp_parent);
}
#endif /* COG_HAVE_LIBPORTAL */

static void
cog_wl_platform_init_web_view(CogPlatform *platform, WebKitWebView *view)
{
g_signal_connect (view, "show-option-menu", G_CALLBACK (on_show_option_menu), NULL);
#if COG_HAVE_LIBPORTAL
g_signal_connect(view, "run-file-chooser", G_CALLBACK(on_run_file_chooser), NULL);
#endif /* COG_HAVE_LIBPORTAL */
COG_WL_PLATFORM(platform)->web_view = view;
}

Expand Down
54 changes: 54 additions & 0 deletions platform/wayland/cog-xdp-parent-wl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* cog-xdp-parent-wl.c
* Copyright (C) 2023 SUSE Software Solutions Germany GmbH
*
* Distributed under terms of the MIT license.
*/

#include "cog-xdp-parent-wl.h"

#include "../common/xdp-parent-private.h"

static void
handle_exported(void *data, struct zxdg_exported_v2 *zxdg_exported_v2, const char *handle)
{
XdpParent *parent = data;
struct xdp_parent_wl_data *wl_data = (struct xdp_parent_wl_data *) parent->data;
g_autofree char *handle_str = g_strdup_printf("wayland:%s", handle);

parent->callback(parent, handle_str, wl_data->user_data);
}

static const struct zxdg_exported_v2_listener zxdg_exported_listener = {
.handle = handle_exported,
};

static gboolean
xdp_parent_export_wl(XdpParent *parent, XdpParentExported callback, gpointer user_data)
{
struct xdp_parent_wl_data *wl_data = (struct xdp_parent_wl_data *) parent->data;

parent->callback = callback;
wl_data->user_data = user_data;
wl_data->zxdg_exported = zxdg_exporter_v2_export_toplevel(wl_data->zxdg_exporter, wl_data->wl_surface);

return zxdg_exported_v2_add_listener(wl_data->zxdg_exported, &zxdg_exported_listener, parent);
}

static void
xdp_parent_unexport_wl(XdpParent *parent)
{
struct xdp_parent_wl_data *wl_data = (struct xdp_parent_wl_data *) parent->data;

zxdg_exported_v2_destroy(wl_data->zxdg_exported);
}

XdpParent *
xdp_parent_new_wl(struct xdp_parent_wl_data *wl_data)
{
XdpParent *parent = g_new0(XdpParent, 1);
parent->parent_export = xdp_parent_export_wl;
parent->parent_unexport = xdp_parent_unexport_wl;
parent->data = (gpointer) wl_data;
return parent;
}
Loading
Loading