Skip to content

Commit

Permalink
core: Remove cog_platform_configure() function
Browse files Browse the repository at this point in the history
Remove the cog_platform_configure() utility function, because at this
point it does not do much else than calling cog_platform_new() and
cog_platform_setup(). Instead, make sure that the platform instance
is a global singleton and that it is created on-demand on the first
call of a the cog_platform_get() accessor.

In order to allow manually indicating which platform plug-in to use, a
new cog_init() function is added. While at it, make it unnecessary for
programs to always call cog_modules_add_directory() if they only need to
use the default module path.

The upside of these changes is that the API gets much more convenient
to use, and in the simplest of cases, it is enough to let the library
initialize the platform instance. The one-time configuration using
cog_platform_setup() is still needed, but now the following is enough
to properly use the library:

  CogShell *shell = cog_shell_new("my-program", FALSE);
  if (!cog_platform_setup(cog_platform_get(), shell, "", NULL))
      g_error("Cannot initialize Cog.");

Note that the COG_MODULEDIR and COG_PLATFORM_NAME environment variables
are still used when NULLs are passed to cog_init() or during implicit
initialization.
  • Loading branch information
aperezdc committed Nov 13, 2023
1 parent 0c3c7d2 commit ec558da
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 160 deletions.
195 changes: 78 additions & 117 deletions core/cog-platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,7 @@ 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);

if (cog_platform_get_default() == NULL)
cog_platform_set_default(platform);
}

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

if (cog_platform_get_default() == platform)
cog_platform_set_default(NULL);

G_OBJECT_CLASS(cog_platform_parent_class)->finalize(object);
}
static CogPlatform *platform_singleton = NULL; // (owned) (atomic)

static gboolean
cog_platform_is_supported(void)
Expand All @@ -44,10 +26,6 @@ cog_platform_is_supported(void)
static void
cog_platform_class_init(CogPlatformClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->constructed = cog_platform_constructed;
object_class->finalize = cog_platform_finalize;

klass->is_supported = cog_platform_is_supported;
}

Expand All @@ -56,41 +34,87 @@ cog_platform_init(CogPlatform *platform)
{
}

static CogPlatform *default_platform = NULL;

void
cog_platform_set_default(CogPlatform *platform)
static inline gboolean
cog_platform_ensure_singleton(const char *name)
{
default_platform = platform;
if (g_once_init_enter(&platform_singleton)) {
cog_modules_add_directory(NULL);

GType platform_type =
cog_modules_get_preferred(COG_MODULES_PLATFORM, name, G_STRUCT_OFFSET(CogPlatformClass, is_supported));

if (platform_type == G_TYPE_INVALID) {
if (name)
g_error("Requested platform '%s' not usable.", name);
else
g_error("Could not find an usable platform.");
}

g_debug("%s: %s requested, %s chosen.", G_STRFUNC, name ?: "None", g_type_name(platform_type));
g_once_init_leave(&platform_singleton, g_object_new(platform_type, NULL));
return FALSE;
}

return TRUE;
}

CogPlatform *
cog_platform_get_default(void)
/**
* cog_init:
* @platform_name: (nullable): The name of the platform module to use.
* @module_path: (nullable): The directory to scan for modules.
*
* Initialize the library, optionally indicating options.
*
* This function ensures the creation of the single [class@CogPlatform]
* instance, and optionally allows indicating which platform module to use
* and from which directory to load modules.
*
* If the @platform_name passed is %NULL, the value of the
* `COG_PLATFORM_NAME` environment variable will be used. If the environment
* variable is undefined, the most suitable platform module will be determined
* automatically.
*
* If the @module_path passed is %NULL, the value of the `COG_MODULEDIR`
* environment variable will be used. If the environment variable is
* undefined, the default module path chosen at build time will be used.
*
* Note that it is **not required** to use this function. It is possible
* to use [id@cog_platform_get] if the default behaviour of using the
* environment variables (if defined) and automatic detection as fallback
* with the default module path is acceptable.
*
* This function is thread-safe.
*
* Since: 0.20
*/
void
cog_init(const char *platform_name, const char *module_path)
{
return default_platform;
cog_modules_add_directory(module_path ?: g_getenv("COG_MODULEDIR"));
gboolean already_initialized = cog_platform_ensure_singleton(platform_name ?: g_getenv("COG_PLATFORM_NAME"));
g_return_if_fail(!already_initialized);
}

/**
* cog_platform_get:
*
* Gets the platform instance.
*
* The platform module instance is a singleton. The instance will be created
* if needed, but [id@cog_init] can be used to control at which point it shall
* be created and which particular module to use.
*
* This function is thread-safe.
*
* Returns: (transfer none): The platform instance.
*
* Since: 0.20
*/
CogPlatform *
cog_platform_new(const char *name, GError **error)
cog_platform_get(void)
{
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 a 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);
cog_platform_ensure_singleton(NULL);
return platform_singleton;
}

gboolean
Expand All @@ -100,7 +124,10 @@ cog_platform_setup (CogPlatform *platform,
GError **error)
{
g_return_val_if_fail(COG_IS_PLATFORM(platform), FALSE);
g_return_val_if_fail (COG_IS_SHELL (shell), FALSE);
g_return_val_if_fail(COG_IS_SHELL(shell), FALSE);

if (G_IS_INITABLE(platform) && !g_initable_init(G_INITABLE(platform), NULL /* cancellable */, error))
return FALSE;

return COG_PLATFORM_GET_CLASS(platform)->setup(platform, shell, params, error);
}
Expand Down Expand Up @@ -156,69 +183,3 @@ cog_platform_create_im_context(CogPlatform *platform)

return NULL;
}

/**
* cog_platform_configure: (constructor)
* @name: (nullable): Name of the platform implementation to use.
* @params: (nullable): Parameters passed to the platform implementation.
* @env_prefix: (nullable): Prefix for environment variables to check.
* @shell: The shell that the platform will be configured for.
* @error: Location where to store errors, if any.
*
* Creates and configures a platform implementation.
*
* Search and create a platform implementation with the given @name,
* configuring it with the passed @params for use with a @shell.
*
* If the @env_prefix is non-%NULL, then the environment variable
* `<env_prefix>_PLATFORM_NAME` can be used to set the platform name
* when @name is %NULL, and the variable `<env_prefix>_PLATFORM_PARAMS`
* can be used to set the configuration parameters when @params is %NULL.
* Environment variables will *not* be used if %NULL is passed as the
* prefix.
*
* If both @name is %NULL and the `<env_prefix>_PLATFORM_NAME` variable
* not defined, then the platform implementation will be chosen automatically
* among the available ones.
*
* Note that [id@cog_modules_add_directory] may be used beforehand to
* configure where to search for available platform plug-ins.
*
* Returns: (transfer full): The configured platform.
*
* Since: 0.18
*/
CogPlatform *
cog_platform_configure(const char *name, const char *params, const char *env_prefix, CogShell *shell, GError **error)
{
g_return_val_if_fail(!default_platform, default_platform);

g_autofree char *platform_name = g_strdup(name);
g_autofree char *platform_params = g_strdup(params);

if (env_prefix) {
if (!platform_name) {
g_autofree char *name_var = g_strconcat(env_prefix, "_PLATFORM_NAME", NULL);
platform_name = g_strdup(g_getenv(name_var));
}
if (!params) {
g_autofree char *params_var = g_strconcat(env_prefix, "_PLATFORM_PARAMS", NULL);
platform_params = g_strdup(g_getenv(params_var));
}
}
g_debug("%s: name '%s', params '%s'", G_STRFUNC, platform_name, platform_params);

CogPlatform *platform = cog_platform_new(platform_name, error);
if (!platform)
return NULL;

if (!cog_platform_setup(platform, shell, platform_params ?: "", error)) {
g_object_unref(platform);
g_assert(!default_platform);
return NULL;
}
g_debug("%s: Configured %s @ %p", G_STRFUNC, G_OBJECT_TYPE_NAME(platform), platform);

g_assert(platform == default_platform);
return platform;
}
8 changes: 2 additions & 6 deletions core/cog-platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ struct _CogPlatformClass {
GType (*get_view_type)(void);
};

COG_API void cog_platform_set_default(CogPlatform *);
COG_API CogPlatform *cog_platform_get_default(void);
COG_API CogPlatform *cog_platform_new(const char *name, GError **);
COG_API void cog_init(const char *platform_name, const char *module_path);
COG_API CogPlatform *cog_platform_get(void);

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

Expand All @@ -70,9 +69,6 @@ void cog_platform_init_web_view (CogPlatform *platfor
COG_API
WebKitInputMethodContext *cog_platform_create_im_context (CogPlatform *platform);

COG_API CogPlatform *
cog_platform_configure(const char *name, const char *params, const char *env_prefix, CogShell *shell, GError **error);

G_END_DECLS

#endif /* !COG_PLATFORM_H */
4 changes: 2 additions & 2 deletions core/cog-view.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ _cog_view_get_impl_type_init(GType *type)
{
*type = cog_core_view_get_type();

CogPlatform *platform = cog_platform_get_default();
CogPlatform *platform = cog_platform_get();
if (platform) {
CogPlatformClass *platform_class = COG_PLATFORM_GET_CLASS(platform);
if (platform_class->get_view_type) {
Expand Down Expand Up @@ -216,7 +216,7 @@ cog_core_view_create_backend(CogView *view G_GNUC_UNUSED)
{
g_autoptr(GError) error = NULL;

WebKitWebViewBackend *backend = cog_platform_get_view_backend(cog_platform_get_default(), NULL, &error);
WebKitWebViewBackend *backend = cog_platform_get_view_backend(cog_platform_get(), NULL, &error);
if (!backend)
g_error("%s: Could not create view backend, %s", G_STRFUNC, error->message);

Expand Down
1 change: 1 addition & 0 deletions docs/cog.toml.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ base_url = "https://github.com/Igalia/cog/blob/master/"
[extra]
content_files = [
"overview.md",
"running.md",
"contributing.md",
"platform-wl.md",
"platform-drm.md",
Expand Down
10 changes: 5 additions & 5 deletions examples/viewport.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ main(int argc, char *argv[])
}

g_set_prgname("view-stack");
cog_modules_add_directory(g_getenv("COG_MODULEDIR") ?: COG_MODULEDIR);

g_autoptr(GError) error = NULL;
g_autoptr(CogShell) shell = cog_shell_new(g_get_prgname(), FALSE);
g_autoptr(CogPlatform) platform = cog_platform_configure(NULL, NULL, "COG", shell, &error);
if (!platform)
g_autoptr(CogShell) shell = cog_shell_new(g_get_prgname(), FALSE);
g_autoptr(GError) error = NULL;

CogPlatform *platform = cog_platform_get();
if (!cog_platform_setup(platform, shell, g_getenv("COG_PLATFORM_PARAMS") ?: "", &error))
g_error("Cannot configure platform: %s", error->message);

g_autoptr(GMainLoop) loop = g_main_loop_new(NULL, FALSE);
Expand Down
13 changes: 7 additions & 6 deletions launcher/cog-launcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,12 @@ cog_launcher_create_view(CogLauncher *self, CogShell *shell)
webkit_web_context_set_cache_model(web_context, WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
}

CogPlatform *platform = cog_platform_get();

g_autoptr(GError) error = NULL;
CogPlatform *platform =
cog_platform_configure(s_options.platform_name, s_options.platform_params, "COG", shell, &error);
if (!platform)
g_error("Cannot instantiate a platform: %s", error->message);
if (!cog_platform_setup(platform, shell, s_options.platform_params ?: (g_getenv("COG_PLATFORM_PARAMS") ?: ""),
&error))
g_error("Cannot configure platform: %s", error->message);

#if HAVE_WEBKIT_AUTOPLAY
WebKitWebsitePolicies *website_policies =
Expand Down Expand Up @@ -330,6 +331,8 @@ cog_launcher_startup(GApplication *application)
*/
g_application_hold(application);

cog_init(s_options.platform_name, NULL);

CogLauncher *self = COG_LAUNCHER(application);
self->shell = g_object_new(
COG_TYPE_SHELL, "name", g_get_prgname(), "automated", self->automated, "web-settings", self->web_settings,
Expand Down Expand Up @@ -435,8 +438,6 @@ cog_launcher_dispose(GObject *object)
g_clear_pointer(&launcher->net_mem_settings, webkit_memory_pressure_settings_free);
#endif /* COG_HAVE_MEM_PRESSURE */

g_object_unref(cog_platform_get_default());

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

Expand Down
1 change: 0 additions & 1 deletion launcher/cog.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ int
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);
Expand Down
Loading

0 comments on commit ec558da

Please sign in to comment.