Skip to content

Commit

Permalink
platform: Add GTK4 plugin (#262)
Browse files Browse the repository at this point in the history
This new platform plugin relies on WPEBackend-FDO and renders the WebView in a ES GLArea. Some basic
navigation control widgets are included as well. This makes Cog more usable on desktop environments
not providing Server-Side window decorations, such as GNOME.
  • Loading branch information
philn authored Apr 1, 2021
1 parent fe73b38 commit 0743c78
Show file tree
Hide file tree
Showing 7 changed files with 1,452 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ set(COG_DBUS_OWN_USER "" CACHE STRING
option(COG_PLATFORM_FDO "Build the FDO platform module" ON)
option(COG_PLATFORM_DRM "Build the DRM platform module" ON)
option(COG_PLATFORM_X11 "Build the X11 platform module" OFF)
option(COG_PLATFORM_GTK4 "Build the GTK4 platform module" OFF)

option(COG_BUILD_PROGRAMS "Build and install programs as well" ON)
option(INSTALL_MAN_PAGES "Install the man(1) pages if COG_BUILD_PROGRAMS is enabled" ON)
option(COG_WESTON_DIRECT_DISPLAY "Build direct display support for the FDO platform module" OFF)
Expand Down Expand Up @@ -223,3 +225,6 @@ endif ()
if (COG_PLATFORM_X11)
add_subdirectory(platform/x11)
endif ()
if (COG_PLATFORM_GTK4)
add_subdirectory(platform/gtk4)
endif ()
17 changes: 17 additions & 0 deletions platform/gtk4/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pkg_check_modules(COGPLATFORM_GTK4_DEPS REQUIRED
IMPORTED_TARGET gtk4 wpebackend-fdo-1.0)
add_library(cogplatform-gtk4 MODULE
cog-platform-gtk4.c
cog-gtk-settings-dialog.c
cog-gtk-settings-cell-renderer-variant.c)
target_link_libraries(cogplatform-gtk4 PRIVATE
PkgConfig::COGPLATFORM_GTK4_DEPS
PkgConfig::WEB_ENGINE
)
set_target_properties(cogplatform-gtk4 PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_compile_options(cogplatform-gtk4
PRIVATE -DG_LOG_DOMAIN=\"Cog-Gtk4\")
install(TARGETS cogplatform-gtk4
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT "runtime")
361 changes: 361 additions & 0 deletions platform/gtk4/cog-gtk-settings-cell-renderer-variant.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,361 @@
/*
* Copyright (C) 2011 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "cog-gtk-settings-cell-renderer-variant.h"

#include <errno.h>

enum {
PROP_0,

PROP_VALUE,
PROP_ADJUSTMENT
};

enum {
CHANGED,

LAST_SIGNAL
};

struct _BrowserCellRendererVariant {
GtkCellRenderer parent;

GValue *value;

GtkCellRenderer *textRenderer;
GtkCellRenderer *toggleRenderer;
GtkCellRenderer *spinRenderer;
};

struct _BrowserCellRendererVariantClass {
GtkCellRendererClass parent;
};

static guint signals[LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE(BrowserCellRendererVariant, browser_cell_renderer_variant, GTK_TYPE_CELL_RENDERER)

static void browserCellRendererVariantFinalize(GObject *object)
{
BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(object);

g_object_unref(renderer->toggleRenderer);
g_object_unref(renderer->spinRenderer);
g_object_unref(renderer->textRenderer);
if (renderer->value)
g_boxed_free(G_TYPE_VALUE, renderer->value);

G_OBJECT_CLASS(browser_cell_renderer_variant_parent_class)->finalize(object);
}

static void browserCellRendererVariantGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
{
BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(object);

switch (propId) {
case PROP_VALUE:
g_value_set_boxed(value, renderer->value);
break;
case PROP_ADJUSTMENT: {
GtkAdjustment *adjustment = NULL;
g_object_get(G_OBJECT(renderer->spinRenderer), "adjustment", &adjustment, NULL);
if (adjustment) {
g_value_set_object(value, adjustment);
g_object_unref(adjustment);
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
}
}

static void browserCellRendererVariantSetModeForValue(BrowserCellRendererVariant *renderer)
{
if (!renderer->value)
return;

GtkCellRendererMode mode;
if (G_VALUE_HOLDS_BOOLEAN(renderer->value))
mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
else if (G_VALUE_HOLDS_STRING(renderer->value) || G_VALUE_HOLDS_UINT(renderer->value))
mode = GTK_CELL_RENDERER_MODE_EDITABLE;
else
return;

g_object_set(G_OBJECT(renderer), "mode", mode, NULL);
}

static void browserCellRendererVariantSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
{
BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(object);

switch (propId) {
case PROP_VALUE:
if (renderer->value)
g_boxed_free(G_TYPE_VALUE, renderer->value);
renderer->value = g_value_dup_boxed(value);
browserCellRendererVariantSetModeForValue(renderer);
break;
case PROP_ADJUSTMENT:
g_object_set(G_OBJECT(renderer->spinRenderer), "adjustment", g_value_get_object(value), NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
}
}

static GtkCellRenderer *browserCellRendererVariantGetRendererForValue(BrowserCellRendererVariant *renderer)
{
if (!renderer->value)
return NULL;

if (G_VALUE_HOLDS_BOOLEAN(renderer->value)) {
g_object_set(G_OBJECT(renderer->toggleRenderer),
"active", g_value_get_boolean(renderer->value),
NULL);
return renderer->toggleRenderer;
}

if (G_VALUE_HOLDS_STRING(renderer->value)) {
g_object_set(G_OBJECT(renderer->textRenderer),
"text", g_value_get_string(renderer->value),
NULL);
return renderer->textRenderer;
}

if (G_VALUE_HOLDS_UINT(renderer->value)) {
gchar *text = g_strdup_printf("%u", g_value_get_uint(renderer->value));
g_object_set(G_OBJECT(renderer->spinRenderer), "text", text, NULL);
g_free(text);
return renderer->spinRenderer;
}

return NULL;
}

static void browserCellRendererVariantCellRendererTextEdited(BrowserCellRendererVariant *renderer, const gchar *path, const gchar *newText)
{
if (!renderer->value)
return;

if (!G_VALUE_HOLDS_STRING(renderer->value))
return;

g_value_set_string(renderer->value, newText);
g_signal_emit(renderer, signals[CHANGED], 0, path, renderer->value);
}

static void browserCellRendererVariantCellRendererSpinEdited(BrowserCellRendererVariant *renderer, const gchar *path, const gchar *newText)
{
if (!renderer->value)
return;

if (!G_VALUE_HOLDS_UINT(renderer->value))
return;

GtkAdjustment *adjustment;
g_object_get(G_OBJECT(renderer->spinRenderer), "adjustment", &adjustment, NULL);
if (!adjustment)
return;

errno = 0;
gchar *endPtr;
gdouble value = g_strtod(newText, &endPtr);
if (errno || value > gtk_adjustment_get_upper(adjustment) || value < gtk_adjustment_get_lower(adjustment) || endPtr == newText) {
g_warning("Invalid input for cell: %s\n", newText);
return;
}

g_value_set_uint(renderer->value, (guint)value);
g_signal_emit(renderer, signals[CHANGED], 0, path, renderer->value);
}

static gboolean browserCellRendererVariantCellRendererActivate(GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path, const GdkRectangle *bgArea, const GdkRectangle *cellArea, GtkCellRendererState flags)
{
BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(cell);

if (!renderer->value)
return TRUE;

if (!G_VALUE_HOLDS_BOOLEAN(renderer->value))
return TRUE;

g_value_set_boolean(renderer->value, !g_value_get_boolean(renderer->value));
g_signal_emit(renderer, signals[CHANGED], 0, path, renderer->value);

return TRUE;
}

#if GTK_CHECK_VERSION(3, 98, 5)
static void browserCellRendererVariantCellRendererSnapshot(GtkCellRenderer *cell, GtkSnapshot *snapshot, GtkWidget *widget, const GdkRectangle *bgArea, const GdkRectangle *cellArea, GtkCellRendererState flags)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return;

GTK_CELL_RENDERER_GET_CLASS(renderer)->snapshot(renderer, snapshot, widget, bgArea, cellArea, flags);
}
#else
static void browserCellRendererVariantCellRendererRender(GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *bgArea, const GdkRectangle *cellArea, GtkCellRendererState flags)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return;

GTK_CELL_RENDERER_GET_CLASS(renderer)->render(renderer, cr, widget, bgArea, cellArea, flags);
}
#endif

static GtkCellEditable *browserCellRendererVariantCellRendererStartEditing(GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path, const GdkRectangle *bgArea, const GdkRectangle *cellArea, GtkCellRendererState flags)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return NULL;

if (!GTK_CELL_RENDERER_GET_CLASS(renderer)->start_editing)
return NULL;

return GTK_CELL_RENDERER_GET_CLASS(renderer)->start_editing(renderer, event, widget, path, bgArea, cellArea, flags);
}

static void browserCellRendererVariantCellRendererGetPreferredWidth(GtkCellRenderer *cell, GtkWidget *widget, gint *minimumWidth, gint *naturalWidth)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return;

GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_width(renderer, widget, minimumWidth, naturalWidth);
}

static void browserCellRendererVariantCellRendererGetPreferredHeight(GtkCellRenderer *cell, GtkWidget *widget, gint *minimumHeight, gint *naturalHeight)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return;

GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_height(renderer, widget, minimumHeight, naturalHeight);
}

static void browserCellRendererVariantCellRendererGetPreferredWidthForHeight(GtkCellRenderer *cell, GtkWidget *widget, gint height, gint *minimumWidth, gint *naturalWidth)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return;

GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_width_for_height(renderer, widget, height, minimumWidth, naturalWidth);
}

static void browserCellRendererVariantCellRendererGetPreferredHeightForWidth(GtkCellRenderer *cell, GtkWidget *widget, gint width, gint *minimumHeight, gint *naturalHeight)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return;

GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_height_for_width(renderer, widget, width, minimumHeight, naturalHeight);
}

static void browserCellRendererVariantCellRendererGetAlignedArea(GtkCellRenderer *cell, GtkWidget *widget, GtkCellRendererState flags, const GdkRectangle *cellArea, GdkRectangle *alignedArea)
{
GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell));
if (!renderer)
return;

GTK_CELL_RENDERER_GET_CLASS(renderer)->get_aligned_area(renderer, widget, flags, cellArea, alignedArea);
}

static void browser_cell_renderer_variant_init(BrowserCellRendererVariant *renderer)
{
g_object_set(renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);

renderer->toggleRenderer = gtk_cell_renderer_toggle_new();
g_object_set(G_OBJECT(renderer->toggleRenderer), "xalign", 0.0, NULL);
renderer->toggleRenderer = g_object_ref_sink(renderer->toggleRenderer);

renderer->textRenderer = gtk_cell_renderer_text_new();
g_signal_connect_swapped(renderer->textRenderer, "edited",
G_CALLBACK(browserCellRendererVariantCellRendererTextEdited), renderer);
g_object_set(G_OBJECT(renderer->textRenderer), "editable", TRUE, NULL);
renderer->textRenderer = g_object_ref_sink(renderer->textRenderer);

renderer->spinRenderer = gtk_cell_renderer_spin_new();
g_signal_connect_swapped(renderer->spinRenderer, "edited",
G_CALLBACK(browserCellRendererVariantCellRendererSpinEdited), renderer);
g_object_set(G_OBJECT(renderer->spinRenderer), "editable", TRUE, NULL);
}

static void browser_cell_renderer_variant_class_init(BrowserCellRendererVariantClass *klass)
{
GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
GtkCellRendererClass *cellRendererClass = GTK_CELL_RENDERER_CLASS(klass);

gobjectClass->get_property = browserCellRendererVariantGetProperty;
gobjectClass->set_property = browserCellRendererVariantSetProperty;
gobjectClass->finalize = browserCellRendererVariantFinalize;

cellRendererClass->activate = browserCellRendererVariantCellRendererActivate;
#if GTK_CHECK_VERSION(3, 98, 5)
cellRendererClass->snapshot = browserCellRendererVariantCellRendererSnapshot;
#else
cellRendererClass->render = browserCellRendererVariantCellRendererRender;
#endif
cellRendererClass->start_editing = browserCellRendererVariantCellRendererStartEditing;
cellRendererClass->get_preferred_width = browserCellRendererVariantCellRendererGetPreferredWidth;
cellRendererClass->get_preferred_height = browserCellRendererVariantCellRendererGetPreferredHeight;
cellRendererClass->get_preferred_width_for_height = browserCellRendererVariantCellRendererGetPreferredWidthForHeight;
cellRendererClass->get_preferred_height_for_width = browserCellRendererVariantCellRendererGetPreferredHeightForWidth;
cellRendererClass->get_aligned_area = browserCellRendererVariantCellRendererGetAlignedArea;

g_object_class_install_property(gobjectClass,
PROP_VALUE,
g_param_spec_boxed("value",
"Value",
"The cell renderer value",
G_TYPE_VALUE,
G_PARAM_READWRITE));
g_object_class_install_property(gobjectClass,
PROP_ADJUSTMENT,
g_param_spec_object("adjustment",
"Adjustment",
"The adjustment that holds the value of the spin button",
GTK_TYPE_ADJUSTMENT,
G_PARAM_READWRITE));

signals[CHANGED] =
g_signal_new("changed",
G_TYPE_FROM_CLASS(gobjectClass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
NULL,
G_TYPE_NONE, 2,
G_TYPE_STRING, G_TYPE_VALUE);
}

GtkCellRenderer *browser_cell_renderer_variant_new(void)
{
return GTK_CELL_RENDERER(g_object_new(BROWSER_TYPE_CELL_RENDERER_VARIANT, NULL));
}

Loading

0 comments on commit 0743c78

Please sign in to comment.