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

Allow multiple viewports on Wayland platform #675

Merged
merged 3 commits into from
Nov 27, 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
181 changes: 159 additions & 22 deletions core/cog-shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ typedef struct {
GHashTable *request_handlers; /* (string, RequestHandlerMapEntry) */
gboolean automated;

WebKitSettings *web_settings;
WebKitWebContext *web_context;
CogViewport *viewport;
WebKitSettings *web_settings;
WebKitWebContext *web_context;
GPtrArray *viewports;

#if !COG_USE_WPE2
WebKitWebsiteDataManager *web_data_manager;
Expand Down Expand Up @@ -68,9 +68,9 @@ enum {

static GParamSpec *s_properties[N_PROPERTIES] = { NULL, };


enum {
CREATE_VIEW,
CREATE_VIEWPORT,
STARTUP,
SHUTDOWN,
N_SIGNALS,
Expand Down Expand Up @@ -179,9 +179,10 @@ cog_shell_startup_base(CogShell *shell)

webkit_web_context_set_automation_allowed(priv->web_context, priv->automated);
g_signal_connect(priv->web_context, "automation-started", G_CALLBACK(cog_shell_automation_started_callback), shell);
g_signal_connect_swapped(web_view, "close", G_CALLBACK(cog_viewport_remove), priv->viewport);
CogViewport *viewport = cog_shell_get_viewport(shell);
g_assert(viewport);

cog_viewport_add(priv->viewport, COG_VIEW(web_view));
cog_viewport_add(viewport, COG_VIEW(web_view));
}

static void
Expand Down Expand Up @@ -274,7 +275,7 @@ cog_shell_set_property (GObject *object,
#endif
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}

Expand All @@ -283,6 +284,9 @@ cog_shell_viewport_visible_view_changed(CogViewport *viewport G_GNUC_UNUSED,
GParamSpec *pspec G_GNUC_UNUSED,
GObject *shell)
{
g_assert(COG_IS_SHELL(shell));
g_assert(COG_IS_VIEWPORT(viewport));

g_object_notify_by_pspec(shell, s_properties[PROP_WEB_VIEW]);
}

Expand Down Expand Up @@ -320,32 +324,31 @@ cog_shell_constructed(GObject *object)
#endif
NULL);

priv->viewport = cog_viewport_new();
g_signal_connect_object(priv->viewport, "notify::visible-view", G_CALLBACK(cog_shell_viewport_visible_view_changed),
object, 0);
priv->viewports = g_ptr_array_new_full(3, g_object_unref);
}

static void
cog_shell_dispose(GObject *object)
{
CogShellPrivate *priv = PRIV(object);

g_clear_object(&priv->viewport);
g_ptr_array_free(priv->viewports, TRUE);

g_clear_object(&priv->web_context);
g_clear_object(&priv->web_settings);
#if !COG_USE_WPE2
g_clear_object(&priv->web_data_manager);
#endif

g_clear_pointer (&priv->request_handlers, g_hash_table_unref);
g_clear_pointer (&priv->name, g_free);
g_clear_pointer (&priv->config_file, g_key_file_unref);
g_clear_pointer(&priv->request_handlers, g_hash_table_unref);
g_clear_pointer(&priv->name, g_free);
g_clear_pointer(&priv->config_file, g_key_file_unref);

G_OBJECT_CLASS (cog_shell_parent_class)->dispose (object);
G_OBJECT_CLASS(cog_shell_parent_class)->dispose(object);
}

static void
cog_shell_class_init (CogShellClass *klass)
cog_shell_class_init(CogShellClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = cog_shell_dispose;
Expand Down Expand Up @@ -383,6 +386,23 @@ cog_shell_class_init (CogShellClass *klass)
COG_TYPE_VIEW,
0);

/**
* CogShell::create-viewport:
* @self: The shell creating the new CogViewport.
* @viewport: The created new viewport.
* @user_data: User data.
*
* The `create-viewport` signal is emitted when the shell creates a new a
* new CogViewport.
*
* Handling this signal allows to customize the actions required to be
* done during the creation of a new viewport.
*
* Returns: (void).
*/
s_signals[CREATE_VIEWPORT] = g_signal_new("create-viewport", COG_TYPE_SHELL, G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
NULL, G_TYPE_NONE, 1, COG_TYPE_VIEWPORT);

/**
* CogShell:name: (attributes org.gtk.Property.get=cog_shell_get_name):
*
Expand Down Expand Up @@ -581,11 +601,12 @@ cog_shell_get_web_settings (CogShell *shell)
*
* Returns: (nullable): A web view.
*/
WebKitWebView*
cog_shell_get_web_view (CogShell *shell)
WebKitWebView *
cog_shell_get_web_view(CogShell *shell)
{
g_return_val_if_fail (COG_IS_SHELL (shell), NULL);
return WEBKIT_WEB_VIEW(cog_viewport_get_visible_view(PRIV(shell)->viewport));
g_return_val_if_fail(COG_IS_SHELL(shell), NULL);
CogViewport *viewport = cog_shell_get_viewport(shell);
return WEBKIT_WEB_VIEW(cog_viewport_get_visible_view(viewport));
}

/**
Expand Down Expand Up @@ -706,7 +727,7 @@ cog_shell_shutdown (CogShell *shell)
/**
* cog_shell_get_viewport:
*
* Gets the viewport managed by the shell.
* Gets the default viewport managed by the shell.
*
* Returns: (transfer none): A viewport.
*
Expand All @@ -716,5 +737,121 @@ CogViewport *
cog_shell_get_viewport(CogShell *shell)
{
g_return_val_if_fail(COG_IS_SHELL(shell), NULL);
return PRIV(shell)->viewport;

gsize size = cog_shell_get_n_viewports(shell);
CogViewport *viewport;

// Create and add the default viewport if this doesn't exist already
if (size == 0) {
viewport = cog_viewport_new();
cog_shell_add_viewport(shell, viewport);
} else
viewport = cog_shell_get_nth_viewport(shell, COG_SHELL_DEFAULT_VIEWPORT_INDEX);
return viewport;
}

GPtrArray *
cog_shell_get_viewports(CogShell *shell)
Comment on lines +753 to +754
Copy link
Member

Choose a reason for hiding this comment

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

I'm not a fan of this, because in general it's a bad idea to use GPtrArray in public API (it is not introspectable) but provided that we would do #634 later I think we can land this patch as-is.

{
g_return_val_if_fail(COG_IS_SHELL(shell), NULL);
return PRIV(shell)->viewports;
}

/**
* cog_shell_add_viewport:
* @shell: Shell to add the viewport to.
* @viewport: The viewport to add.
*
* Adds a viewport to a shell.
*
* The next available index will be assigned to the viewport.
*/
void
cog_shell_add_viewport(CogShell *shell, CogViewport *viewport)
{
g_return_if_fail(COG_IS_SHELL(shell));
g_return_if_fail(COG_IS_VIEWPORT(viewport));

CogShellPrivate *priv = PRIV(shell);
g_return_if_fail(!g_ptr_array_find(priv->viewports, viewport, NULL));

g_ptr_array_add(priv->viewports, g_object_ref(viewport));

g_signal_connect_object(viewport, "notify::visible-view", G_CALLBACK(cog_shell_viewport_visible_view_changed),
shell, 0);

g_signal_emit(shell, s_signals[CREATE_VIEWPORT], 0, viewport);
}

/**
* cog_shell_remove_viewport:
* @shell: Shell to remove the viewport from.
* @viewport: The viewport to remove.
*
* Removes a viewport from the shell.
*
* Removing a viewport preserves the relative ordering of the rest of viewports in
* the shell. This also means that the index used to retrieve them may
* change after removal.
*/
void
cog_shell_remove_viewport(CogShell *shell, CogViewport *viewport)
{
g_return_if_fail(COG_IS_VIEWPORT(shell));
g_return_if_fail(COG_IS_VIEW(viewport));

CogShellPrivate *priv = PRIV(shell);

unsigned index;
if (!g_ptr_array_find(priv->viewports, viewport, &index)) {
g_warning("Attempted to remove viewport %p, which was not in shell %p.", viewport, shell);
return;
}

g_ptr_array_remove_index(priv->viewports, index);
}

/**
* cog_shell_get_n_viewports:
* @shell: Shell.
*
* Gets the number of viewports in a shell.
*
* Returns: Number of viewports.
*/
gsize
cog_shell_get_n_viewports(CogShell *shell)
{
g_return_val_if_fail(COG_IS_SHELL(shell), 0);

return PRIV(shell)->viewports->len;
}

/**
* cog_shell_get_nth_viewport:
* @shell: Shell.
* @index: Index of the viewport to get.
*
* Gets a viewport from the shell given its index.
*
* This is typically used along [[email protected]_n_viewports] to iterate
* over the viewports:
*
* ```c
* CogShell *shell = get_shell();
* for (gsize i = 0; i < cog_shell_get_n_viewports(shell); i++)
* handle_viewport(cog_shell_get_nth_viewport(shell, i));
* ```
*
* Returns: (transfer none): Viewport at the given @index.
*/
CogViewport *
cog_shell_get_nth_viewport(CogShell *shell, gsize index)
{
g_return_val_if_fail(COG_IS_SHELL(shell), NULL);

CogShellPrivate *priv = PRIV(shell);
g_return_val_if_fail(index < priv->viewports->len, NULL);

return g_ptr_array_index(priv->viewports, index);
}
11 changes: 10 additions & 1 deletion core/cog-shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

G_BEGIN_DECLS

#define COG_SHELL_DEFAULT_VIEWPORT_INDEX 0

typedef struct _CogViewport CogViewport;
typedef struct _WebKitWebView WebKitWebView;

#define COG_TYPE_SHELL (cog_shell_get_type ())
#define COG_TYPE_SHELL (cog_shell_get_type())

COG_API
G_DECLARE_DERIVABLE_TYPE(CogShell, cog_shell, COG, SHELL, GObject)
Expand All @@ -45,6 +47,13 @@ COG_API void cog_shell_set_request_handler(CogShell *shell, const char *scheme,

COG_API void cog_shell_startup(CogShell *shell);
COG_API void cog_shell_shutdown(CogShell *shell);

COG_API CogViewport *cog_shell_get_viewport(CogShell *shell);
COG_API GPtrArray *cog_shell_get_viewports(CogShell *shell);

COG_API void cog_shell_add_viewport(CogShell *shell, CogViewport *viewport);
COG_API void cog_shell_remove_viewport(CogShell *shell, CogViewport *viewport);
COG_API gsize cog_shell_get_n_viewports(CogShell *shell);
COG_API CogViewport *cog_shell_get_nth_viewport(CogShell *shell, gsize index);

G_END_DECLS
2 changes: 2 additions & 0 deletions core/cog-viewport.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ cog_viewport_add(CogViewport *self, CogView *view)
wpe_view_backend_remove_activity_state(backend, wpe_view_activity_state_visible);
wpe_view_backend_remove_activity_state(backend, wpe_view_activity_state_focused);
}

g_signal_connect_swapped(WEBKIT_WEB_VIEW(view), "close", G_CALLBACK(cog_viewport_remove), self);
}

/**
Expand Down
7 changes: 7 additions & 0 deletions examples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ executable('viewport',
dependencies: cogcore_dep,
install: false,
)

executable('viewports',
'viewports.c',
c_args: examples_c_args,
dependencies: cogcore_dep,
install: false,
)
Loading