Skip to content

Commit

Permalink
Make platform plug-ins implement an extension point
Browse files Browse the repository at this point in the history
Instead of using dlopen/dlsym manually, turn existing platform modules
into implementations of the platform extension point. This is mostly
mechanical work to apply the following changes to each platform
plug-in:

- Add a subclass of CogPlatform e.g. CogFdoPlatform.
- Make callback functions private to the platform plug-ins and install
  them as vfuncs of the CogPlatform class.
- Support automatic selection of platform plug-ins by adding a new
  "is_suported" static vfunc.

Note than other than the "is_supported" bit, no attempt is done at
changing the architecture of the platform plug-ins.
  • Loading branch information
aperezdc committed Jun 23, 2021
1 parent 42e2214 commit a3815bb
Show file tree
Hide file tree
Showing 15 changed files with 517 additions and 177 deletions.
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ option(USE_SOUP2 "Build with libsoup2 instead of libsoup3" ON)
set(COG_APPID "" CACHE STRING "Default GApplication unique identifier")
set(COG_HOME_URI "" CACHE STRING "Default home URI")

set(COG_MODULEDIR "${CMAKE_INSTALL_PREFIX}/lib/cog/modules"
CACHE STRING "Default search path for loadable modules")

if (NOT COG_APPID OR COG_APPID STREQUAL "")
set(COG_DEFAULT_APPID com.igalia.Cog)
else ()
Expand Down Expand Up @@ -157,7 +160,7 @@ set_target_properties(cogcore PROPERTIES
VERSION ${COGCORE_VERSION}
SOVERSION ${COGCORE_VERSION_MAJOR}
)
target_link_libraries(cogcore PkgConfig::WebKit PkgConfig::SOUP)
target_link_libraries(cogcore PkgConfig::GIO PkgConfig::WebKit PkgConfig::SOUP)
target_compile_definitions(cogcore PRIVATE G_LOG_DOMAIN=\"Cog-Core\")
if (HAS_WALL)
target_compile_options(cogcore PUBLIC -Wall)
Expand Down
39 changes: 22 additions & 17 deletions cog.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,31 +289,23 @@ platform_setup (CogShell *shell)

g_debug ("%s: Platform name: %s", __func__, s_options.platform_name);

if (!s_options.platform_name)
return FALSE;

g_autofree char *platform_soname =
g_strdup_printf ("libcogplatform-%s.so", s_options.platform_name);
g_clear_pointer (&s_options.platform_name, g_free);

g_debug ("%s: Platform plugin: %s", __func__, platform_soname);

g_autoptr(CogPlatform) platform = cog_platform_new ();
if (!cog_platform_try_load (platform, platform_soname)) {
g_warning ("Could not load: %s (possible cause: %s).\n",
platform_soname, strerror (errno));
g_autoptr(GError) error = NULL;
CogPlatform *platform = cog_platform_new(s_options.platform_name, &error);
if (!platform) {
g_warning("Cannot create platform: %s", error->message);
return FALSE;
}

g_autoptr(GError) error = NULL;
if (!cog_platform_setup (platform, shell, "", &error)) {
g_clear_pointer(&s_options.platform_name, g_free);

if (!cog_platform_setup(platform, shell, "", &error)) {
g_warning ("Platform setup failed: %s", error->message);
return FALSE;
}

s_options.platform = g_steal_pointer (&platform);

g_debug ("%s: Platform = %p", __func__, s_options.platform);
g_debug("%s: Selected %s @ %p", __func__, g_type_name(G_OBJECT_TYPE(s_options.platform)), s_options.platform);
return TRUE;
}

Expand All @@ -325,7 +317,7 @@ on_shutdown (CogLauncher *launcher G_GNUC_UNUSED, void *user_data G_GNUC_UNUSED)

if (s_options.platform) {
cog_platform_teardown (s_options.platform);
g_clear_pointer (&s_options.platform, cog_platform_free);
g_clear_object(&s_options.platform);
g_debug ("%s: Platform teardown completed.", __func__);
}
}
Expand Down Expand Up @@ -429,6 +421,14 @@ on_create_view (CogShell *shell, void *user_data G_GNUC_UNUSED)
return g_steal_pointer (&web_view);
}

static void
print_module_info(GIOExtension *extension, void *userdata G_GNUC_UNUSED)
{
g_info(" %s - %d/%s",
g_io_extension_get_name(extension),
g_io_extension_get_priority(extension),
g_type_name(g_io_extension_get_type(extension)));
}

int
main (int argc, char *argv[])
Expand All @@ -442,6 +442,11 @@ main (int argc, char *argv[])
g_set_application_name ("Cog");
}

cog_modules_add_directory(g_getenv("COG_MODULEDIR") ?: COG_MODULEDIR);

g_info("%s:", COG_MODULES_PLATFORM_EXTENSION_POINT);
cog_modules_foreach(COG_MODULES_PLATFORM, print_module_info, NULL);

g_autoptr(GApplication) app = G_APPLICATION (cog_launcher_get_default ());
g_application_add_main_option_entries (app, s_cli_options);
cog_launcher_add_web_settings_option_entries (COG_LAUNCHER (app));
Expand Down
1 change: 1 addition & 0 deletions core/cog-config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef COG_CONFIG_H_IN
#define COG_CONFIG_H_IN

#define COG_MODULEDIR "@COG_MODULEDIR@"
#define COG_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define COG_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define COG_VERSION_PATCH @PROJECT_VERSION_PATCH@
Expand Down
158 changes: 86 additions & 72 deletions core/cog-platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,101 @@
* Distributed under terms of the MIT license.
*/

#include <dlfcn.h>
#include "cog-platform.h"
#include "cog-modules.h"

G_DEFINE_QUARK(COG_PLATFORM_ERROR, cog_platform_error)
G_DEFINE_QUARK(COG_PLATFORM_EGL_ERROR, cog_platform_egl_error)
G_DEFINE_QUARK(COG_PLATFORM_WPE_ERROR, cog_platform_wpe_error)

G_DEFINE_QUARK (COG_PLATFORM_EGL_ERROR, cog_platform_egl_error)
G_DEFINE_QUARK (COG_PLATFORM_WPE_ERROR, cog_platform_wpe_error)
G_DEFINE_ABSTRACT_TYPE(CogPlatform, cog_platform, G_TYPE_OBJECT)

static void
cog_platform_constructed(GObject *object)
{
CogPlatform *platform = COG_PLATFORM(object);

/* @FIXME: Move this implementation to use a GIO extension point. */

struct _CogPlatform {
void *so;

gboolean (*setup) (CogPlatform *platform,
CogShell *shell,
const char *params,
GError **error);
if (cog_platform_get_default() == NULL)
cog_platform_set_default(platform);
}

void (*teardown) (CogPlatform *platform);
static void
cog_platform_finalize(GObject *object)
{
CogPlatform *platform = COG_PLATFORM(object);

WebKitWebViewBackend* (*get_view_backend) (CogPlatform *platform,
WebKitWebView *related_view,
GError **error);
void (*init_web_view) (CogPlatform *platform,
WebKitWebView *view);
WebKitInputMethodContext* (*create_im_context) (CogPlatform *platform);
};
if (cog_platform_get_default() == platform)
cog_platform_set_default(NULL);

CogPlatform*
cog_platform_new (void)
{
return g_slice_new0 (CogPlatform);
G_OBJECT_CLASS(cog_platform_parent_class)->finalize(object);
}

void
cog_platform_free (CogPlatform *platform)
static gboolean
cog_platform_is_supported(void)
{
g_clear_pointer (&platform->so, dlclose);
g_slice_free (CogPlatform, platform);
return TRUE;
}

void
cog_platform_teardown (CogPlatform *platform)
static void
cog_platform_class_init(CogPlatformClass *klass)
{
g_return_if_fail (platform != NULL);
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->constructed = cog_platform_constructed;
object_class->finalize = cog_platform_finalize;

platform->teardown (platform);
klass->is_supported = cog_platform_is_supported;
}

gboolean
cog_platform_try_load (CogPlatform *platform,
const gchar *soname)
static void
cog_platform_init(CogPlatform *platform)
{
g_return_val_if_fail (platform != NULL, FALSE);
g_return_val_if_fail (soname != NULL, FALSE);

g_assert (!platform->so);
platform->so = dlopen (soname, RTLD_LAZY);
if (!platform->so)
return FALSE;
}

platform->setup = dlsym (platform->so, "cog_platform_plugin_setup");
if (!platform->setup)
goto err_out;
static CogPlatform *default_platform = NULL;

platform->teardown = dlsym (platform->so, "cog_platform_plugin_teardown");
if (!platform->teardown)
goto err_out;
void
cog_platform_set_default(CogPlatform *platform)
{
default_platform = platform;
}

platform->get_view_backend = dlsym (platform->so,
"cog_platform_plugin_get_view_backend");
if (!platform->get_view_backend)
goto err_out;
CogPlatform *
cog_platform_get_default(void)
{
return default_platform;
}

platform->init_web_view = dlsym (platform->so,
"cog_platform_plugin_init_web_view");
platform->create_im_context = dlsym (platform->so,
"cog_platform_plugin_create_im_context");
CogPlatform *
cog_platform_new(const char *name, GError **error)
{
GType platform_type =
cog_modules_get_preferred(COG_MODULES_PLATFORM, name, G_STRUCT_OFFSET(CogPlatformClass, is_supported));

if (platform_type == G_TYPE_INVALID) {
g_set_error_literal(error, COG_PLATFORM_ERROR, COG_PLATFORM_ERROR_NO_MODULE,
"Could not find an usable platform module");
return NULL;
}

g_autoptr(CogPlatform) self = g_object_new(platform_type, NULL);
if (G_IS_INITABLE(self)) {
if (!g_initable_init(G_INITABLE(self),
NULL, /* cancellable */
error))
return NULL;
}

return g_steal_pointer(&self);
}

return TRUE;
void
cog_platform_teardown(CogPlatform *platform)
{
g_return_if_fail(COG_IS_PLATFORM(platform));

err_out:
g_clear_pointer (&platform->so, dlclose);
return FALSE;
CogPlatformClass *klass = COG_PLATFORM_GET_CLASS(platform);
if (klass->teardown)
klass->teardown(platform);
}

gboolean
Expand All @@ -98,39 +109,42 @@ cog_platform_setup (CogPlatform *platform,
const char *params,
GError **error)
{
g_return_val_if_fail (platform != NULL, FALSE);
g_return_val_if_fail(COG_IS_PLATFORM(platform), FALSE);
g_return_val_if_fail (COG_IS_SHELL (shell), FALSE);

return platform->setup (platform, shell, params, error);
return COG_PLATFORM_GET_CLASS(platform)->setup(platform, shell, params, error);
}

WebKitWebViewBackend*
cog_platform_get_view_backend (CogPlatform *platform,
WebKitWebView *related_view,
GError **error)
{
g_return_val_if_fail (platform != NULL, NULL);
g_return_val_if_fail(COG_IS_PLATFORM(platform), NULL);

return platform->get_view_backend (platform, related_view, error);
CogPlatformClass *klass = COG_PLATFORM_GET_CLASS(platform);
return klass->get_view_backend(platform, related_view, error);
}

void
cog_platform_init_web_view (CogPlatform *platform,
WebKitWebView *view)
{
g_return_if_fail (platform != NULL);
g_return_if_fail(COG_IS_PLATFORM(platform));

if (platform->init_web_view)
platform->init_web_view (platform, view);
CogPlatformClass *klass = COG_PLATFORM_GET_CLASS(platform);
if (klass->init_web_view)
klass->init_web_view(platform, view);
}

WebKitInputMethodContext*
cog_platform_create_im_context (CogPlatform *platform)
WebKitInputMethodContext *
cog_platform_create_im_context(CogPlatform *platform)
{
g_return_val_if_fail (platform != NULL, NULL);
g_return_val_if_fail(COG_IS_PLATFORM(platform), NULL);

if (platform->create_im_context)
return platform->create_im_context (platform);
CogPlatformClass *klass = COG_PLATFORM_GET_CLASS(platform);
if (klass->create_im_context)
return klass->create_im_context(platform);

return NULL;
}
40 changes: 26 additions & 14 deletions core/cog-platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,51 @@
# error "Do not include this header directly, use <cog.h> instead"
#endif

#include <glib.h>
#include "cog-shell.h"
#include <glib-object.h>

G_BEGIN_DECLS

#define COG_PLATFORM_ERROR (cog_platform_error_quark())

typedef enum {
COG_PLATFORM_ERROR_NO_MODULE,
} CogPlatformError;

#define COG_PLATFORM_EGL_ERROR (cog_platform_egl_error_quark ())
GQuark cog_platform_egl_error_quark (void);

#define COG_PLATFORM_WPE_ERROR (cog_platform_wpe_error_quark ())
GQuark cog_platform_wpe_error_quark (void);

typedef struct _WebKitInputMethodContext WebKitInputMethodContext;
typedef struct _WebKitWebViewBackend WebKitWebViewBackend;

typedef enum {
COG_PLATFORM_WPE_ERROR_INIT,
} CogPlatformWpeError;

#define COG_TYPE_PLATFORM (cog_platform_get_type())

/* @FIXME: Eventually move this interface to GObject. */
typedef struct _CogPlatform CogPlatform;
typedef struct _WebKitInputMethodContext WebKitInputMethodContext;
G_DECLARE_DERIVABLE_TYPE(CogPlatform, cog_platform, COG, PLATFORM, GObject)

CogPlatform *cog_platform_new (void);
void cog_platform_free (CogPlatform *platform);
struct _CogPlatformClass {
GObjectClass parent_class;

gboolean cog_platform_try_load (CogPlatform *platform,
const gchar *soname);
/*< public >*/
gboolean (*is_supported)(void);
gboolean (*setup)(CogPlatform *, CogShell *shell, const char *params, GError **);
void (*teardown)(CogPlatform *);
WebKitWebViewBackend *(*get_view_backend)(CogPlatform *, WebKitWebView *related_view, GError **);
void (*init_web_view)(CogPlatform *, WebKitWebView *);
WebKitInputMethodContext *(*create_im_context)(CogPlatform *);
};

gboolean cog_platform_setup (CogPlatform *platform,
CogShell *shell,
const char *params,
GError **error);
void cog_platform_set_default(CogPlatform *);
CogPlatform *cog_platform_get_default(void);
CogPlatform *cog_platform_new(const char *name, GError **);

gboolean cog_platform_setup(CogPlatform *platform, CogShell *shell, const char *params, GError **error);

void cog_platform_teardown (CogPlatform *platform);

Expand All @@ -56,8 +70,6 @@ void cog_platform_init_web_view (CogPlatform *platfor

WebKitInputMethodContext *cog_platform_create_im_context (CogPlatform *platform);

G_DEFINE_AUTOPTR_CLEANUP_FUNC (CogPlatform, cog_platform_free)

G_END_DECLS

#endif /* !COG_PLATFORM_H */
Loading

0 comments on commit a3815bb

Please sign in to comment.