[gnome-builder] libide-gui: port IdeApplication to GTK 4
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] libide-gui: port IdeApplication to GTK 4
- Date: Tue, 12 Jul 2022 06:39:12 +0000 (UTC)
commit 71608e8d2e423f2df3f0132b5fa38cbd570422f5
Author: Christian Hergert <chergert redhat com>
Date: Mon Jul 11 21:45:36 2022 -0700
libide-gui: port IdeApplication to GTK 4
This bridges in the support for recoloring, fixes plugin loading, handles
a number of actions that needed to be redone, improves open support, and
cleans up availability macros.
src/libide/gui/ide-application-color.c | 83 ++-
src/libide/gui/ide-application-command-line.c | 6 -
src/libide/gui/ide-application-open.c | 2 -
src/libide/gui/ide-application-plugins.c | 78 +--
src/libide/gui/ide-application-private.h | 56 +-
src/libide/gui/ide-application-settings.c | 209 ++++++++
src/libide/gui/ide-application.c | 715 ++++++++++++++++----------
src/libide/gui/ide-application.h | 68 ++-
8 files changed, 826 insertions(+), 391 deletions(-)
---
diff --git a/src/libide/gui/ide-application-color.c b/src/libide/gui/ide-application-color.c
index ff5e8c1d5..de2e8a487 100644
--- a/src/libide/gui/ide-application-color.c
+++ b/src/libide/gui/ide-application-color.c
@@ -23,10 +23,10 @@
#include "config.h"
#include <gtksourceview/gtksource.h>
-#include <handy.h>
#include "ide-application.h"
#include "ide-application-private.h"
+#include "ide-recoloring-private.h"
static void
add_style_name (GPtrArray *ar,
@@ -93,7 +93,7 @@ static void
_ide_application_update_color (IdeApplication *self)
{
static gboolean ignore_reentrant = FALSE;
- HdyStyleManager *manager;
+ AdwStyleManager *manager;
g_autofree char *style_variant = NULL;
g_assert (IDE_IS_APPLICATION (self));
@@ -109,14 +109,16 @@ _ide_application_update_color (IdeApplication *self)
g_assert (G_IS_SETTINGS (self->settings));
style_variant = g_settings_get_string (self->settings, "style-variant");
- manager = hdy_style_manager_get_default ();
+ manager = adw_style_manager_get_default ();
- if (!g_strcmp0 (style_variant, "follow"))
- hdy_style_manager_set_color_scheme (manager, HDY_COLOR_SCHEME_PREFER_LIGHT);
- else if (!g_strcmp0 (style_variant, "dark"))
- hdy_style_manager_set_color_scheme (manager, HDY_COLOR_SCHEME_FORCE_DARK);
+ g_debug ("Style variant changed to %s", style_variant);
+
+ if (g_strcmp0 (style_variant, "follow") == 0)
+ adw_style_manager_set_color_scheme (manager, ADW_COLOR_SCHEME_PREFER_LIGHT);
+ else if (g_strcmp0 (style_variant, "dark") == 0)
+ adw_style_manager_set_color_scheme (manager, ADW_COLOR_SCHEME_FORCE_DARK);
else
- hdy_style_manager_set_color_scheme (manager, HDY_COLOR_SCHEME_FORCE_LIGHT);
+ adw_style_manager_set_color_scheme (manager, ADW_COLOR_SCHEME_FORCE_LIGHT);
ignore_reentrant = FALSE;
}
@@ -124,12 +126,14 @@ _ide_application_update_color (IdeApplication *self)
static void
_ide_application_update_style_scheme (IdeApplication *self)
{
- HdyStyleManager *manager;
+ AdwStyleManager *manager;
g_autoptr(GSettings) editor_settings = NULL;
g_autofree gchar *old_name = NULL;
g_autofree gchar *new_name = NULL;
- manager = hdy_style_manager_get_default ();
+ g_assert (IDE_IS_APPLICATION (self));
+
+ manager = adw_style_manager_get_default ();
/*
* Now that we have our color up to date, we need to possibly update the
@@ -143,32 +147,87 @@ _ide_application_update_style_scheme (IdeApplication *self)
editor_settings = g_settings_new ("org.gnome.builder.editor");
old_name = g_settings_get_string (editor_settings, "style-scheme-name");
- new_name = find_similar_style_scheme (old_name, hdy_style_manager_get_dark (manager));
+ new_name = find_similar_style_scheme (old_name, adw_style_manager_get_dark (manager));
if (new_name != NULL)
g_settings_set_string (editor_settings, "style-scheme-name", new_name);
}
+static void
+ide_application_color_style_scheme_changed_cb (IdeApplication *self,
+ const char *key,
+ GSettings *editor_settings)
+{
+ GtkSourceStyleSchemeManager *manager;
+ GtkSourceStyleScheme *scheme;
+ g_autofree char *style_scheme_name = NULL;
+ g_autofree char *css = NULL;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (g_strcmp0 (key, "style-scheme-name") == 0);
+ g_assert (G_IS_SETTINGS (editor_settings));
+
+ style_scheme_name = g_settings_get_string (editor_settings, key);
+ g_debug ("Style scheme changed to %s", style_scheme_name);
+
+ manager = gtk_source_style_scheme_manager_get_default ();
+ scheme = gtk_source_style_scheme_manager_get_scheme (manager, style_scheme_name);
+
+ if (scheme == NULL)
+ return;
+
+ css = _ide_recoloring_generate_css (scheme);
+ gtk_css_provider_load_from_data (self->recoloring, css ? css : "", -1);
+}
+
void
_ide_application_init_color (IdeApplication *self)
{
+ g_autofree char *style_scheme_name = NULL;
+
g_return_if_fail (IDE_IS_APPLICATION (self));
g_return_if_fail (G_IS_SETTINGS (self->settings));
if (g_getenv ("GTK_THEME") == NULL)
{
+ g_autofree char *style_variant = NULL;
+
+ /* We must read "style-variant" to get changed notifications */
+ style_variant = g_settings_get_string (self->settings, "style-variant");
+ g_debug ("Initialized with style-variant %s", style_variant);
+
g_signal_connect_object (self->settings,
"changed::style-variant",
G_CALLBACK (_ide_application_update_color),
self,
G_CONNECT_SWAPPED);
- g_signal_connect_object (hdy_style_manager_get_default (),
+ g_signal_connect_object (adw_style_manager_get_default (),
"notify::dark",
G_CALLBACK (_ide_application_update_style_scheme),
self,
G_CONNECT_SWAPPED);
}
+ style_scheme_name = g_settings_get_string (self->editor_settings, "style-scheme-name");
+ g_debug ("Initialized with style scheme %s", style_scheme_name);
+ g_signal_connect_object (self->editor_settings,
+ "changed::style-scheme-name",
+ G_CALLBACK (ide_application_color_style_scheme_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+ GTK_STYLE_PROVIDER (self->recoloring),
+ GTK_STYLE_PROVIDER_PRIORITY_THEME+1);
+
_ide_application_update_color (self);
_ide_application_update_style_scheme (self);
+ ide_application_color_style_scheme_changed_cb (self, "style-scheme-name", self->editor_settings);
+}
+
+gboolean
+ide_application_get_dark (IdeApplication *self)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), FALSE);
+
+ return adw_style_manager_get_dark (adw_style_manager_get_default ());
}
diff --git a/src/libide/gui/ide-application-command-line.c b/src/libide/gui/ide-application-command-line.c
index 9899137fd..155762904 100644
--- a/src/libide/gui/ide-application-command-line.c
+++ b/src/libide/gui/ide-application-command-line.c
@@ -54,8 +54,6 @@ add_option_entries_foreach_cb (PeasExtensionSet *set,
*
* Inflate all early stage plugins asking them to let us know about what
* command-line options they support.
- *
- * Since: 3.32
*/
void
_ide_application_add_option_entries (IdeApplication *self)
@@ -130,8 +128,6 @@ ide_application_command_line_open_project_cb (GObject *object,
* plugins who have elected to handle command-line options. Some
* of them, like the greeter, may create an initial workbench
* and workspace window in response.
- *
- * Since: 3.32
*/
void
_ide_application_command_line (IdeApplication *self,
@@ -230,8 +226,6 @@ _ide_application_command_line (IdeApplication *self,
*
* Returns: (transfer full) (nullable) (array zero-terminated=1): an
* array of strings or %NULL
- *
- * Since: 3.32
*/
gchar **
ide_application_get_argv (IdeApplication *self,
diff --git a/src/libide/gui/ide-application-open.c b/src/libide/gui/ide-application-open.c
index 721bb0664..4624089b5 100644
--- a/src/libide/gui/ide-application-open.c
+++ b/src/libide/gui/ide-application-open.c
@@ -147,8 +147,6 @@ ide_application_open_project_async (IdeApplication *self,
*
* Returns: (transfer full): an #IdeWorkbench or %NULL on failure and @error
* is set.
- *
- * Since: 3.32
*/
IdeWorkbench *
ide_application_open_project_finish (IdeApplication *self,
diff --git a/src/libide/gui/ide-application-plugins.c b/src/libide/gui/ide-application-plugins.c
index ff27b1aa7..7c066d584 100644
--- a/src/libide/gui/ide-application-plugins.c
+++ b/src/libide/gui/ide-application-plugins.c
@@ -106,10 +106,6 @@ ide_application_can_load_plugin (IdeApplication *self,
module_dir = peas_plugin_info_get_module_dir (plugin_info);
module_name = peas_plugin_info_get_module_name (plugin_info);
- /* Short-circuit for single-plugin mode */
- if (self->plugin != NULL)
- return ide_str_equal0 (module_name, self->plugin);
-
if (g_hash_table_contains (circular, module_name))
{
g_warning ("Circular dependency found in module %s", module_name);
@@ -123,14 +119,6 @@ ide_application_can_load_plugin (IdeApplication *self,
if (!g_settings_get_boolean (settings, "enabled"))
return FALSE;
-#if 0
- if (self->mode == IDE_APPLICATION_MODE_WORKER)
- {
- if (self->worker != plugin_info)
- return FALSE;
- }
-#endif
-
/*
* If the plugin is not bundled within the Builder executable, then we
* require that an X-Builder-ABI=major.minor style extended data be
@@ -216,7 +204,7 @@ ide_application_load_plugin_resources (IdeApplication *self,
g_resources_register (resource);
resource_path = g_strdup_printf ("resource:///plugins/%s", module_name);
- dzl_application_add_resources (DZL_APPLICATION (self), resource_path);
+ _ide_application_add_resources (self, resource_path);
}
}
@@ -238,9 +226,9 @@ _ide_application_load_plugin (IdeApplication *self,
}
static void
-ide_application_plugins_load_plugin_cb (IdeApplication *self,
- PeasPluginInfo *plugin_info,
- PeasEngine *engine)
+ide_application_plugins_load_plugin_after_cb (IdeApplication *self,
+ PeasPluginInfo *plugin_info,
+ PeasEngine *engine)
{
const gchar *data_dir;
const gchar *module_dir;
@@ -273,19 +261,29 @@ ide_application_plugins_load_plugin_cb (IdeApplication *self,
*/
if (g_str_has_prefix (data_dir, "resource://") ||
!peas_plugin_info_is_builtin (plugin_info))
- dzl_application_add_resources (DZL_APPLICATION (self), data_dir);
+ _ide_application_add_resources (self, data_dir);
}
static void
-ide_application_plugins_unload_plugin_cb (IdeApplication *self,
- PeasPluginInfo *plugin_info,
- PeasEngine *engine)
+ide_application_plugins_unload_plugin_after_cb (IdeApplication *self,
+ PeasPluginInfo *plugin_info,
+ PeasEngine *engine)
{
+ const gchar *module_dir;
+ const gchar *module_name;
+
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_APPLICATION (self));
g_assert (plugin_info != NULL);
g_assert (PEAS_IS_ENGINE (engine));
+ module_dir = peas_plugin_info_get_module_dir (plugin_info);
+ module_name = peas_plugin_info_get_module_name (plugin_info);
+
+ _ide_application_remove_resources (self, module_dir);
+
+ g_debug ("Unloaded plugin \"%s\" with module-dir \"%s\"",
+ module_name, module_dir);
}
/**
@@ -295,8 +293,6 @@ ide_application_plugins_unload_plugin_cb (IdeApplication *self,
* early-stage initialization. Usually, that is any plugin that has a
* command-line handler and uses "X-At-Startup=true" in their .plugin
* manifest.
- *
- * Since: 3.32
*/
void
_ide_application_load_plugins_for_startup (IdeApplication *self)
@@ -308,15 +304,15 @@ _ide_application_load_plugins_for_startup (IdeApplication *self)
g_signal_connect_object (engine,
"load-plugin",
- G_CALLBACK (ide_application_plugins_load_plugin_cb),
+ G_CALLBACK (ide_application_plugins_load_plugin_after_cb),
self,
- G_CONNECT_SWAPPED);
+ G_CONNECT_SWAPPED | G_CONNECT_AFTER);
g_signal_connect_object (engine,
"unload-plugin",
- G_CALLBACK (ide_application_plugins_unload_plugin_cb),
+ G_CALLBACK (ide_application_plugins_unload_plugin_after_cb),
self,
- G_CONNECT_SWAPPED);
+ G_CONNECT_SWAPPED | G_CONNECT_AFTER);
/* Ensure that our embedded plugins are allowed early access to
* start loading (before we ever look at anything on disk). This
@@ -355,14 +351,11 @@ _ide_application_load_plugins_for_startup (IdeApplication *self)
*
* This function loads any additional plugins that have not yet been
* loaded during early startup.
- *
- * Since: 3.32
*/
void
_ide_application_load_plugins (IdeApplication *self)
{
g_autofree gchar *user_plugins_dir = NULL;
- g_autoptr(GError) error = NULL;
const GList *plugins;
PeasEngine *engine;
@@ -406,28 +399,7 @@ _ide_application_load_plugins (IdeApplication *self)
NULL);
peas_engine_prepend_search_path (engine, user_plugins_dir, NULL);
- /* Ensure that we have all our required GObject Introspection packages
- * loaded so that plugins don't need to require_version() as that is
- * tedious and annoying to keep up to date.
- *
- * If we can't load any of our dependent packages, then fail to load
- * python3 plugins altogether to avoid loading anything improper into
- * the process space.
- */
- g_irepository_prepend_search_path (PACKAGE_LIBDIR"/gnome-builder/girepository-1.0");
- if (!g_irepository_require (NULL, "GtkSource", "4", 0, &error) ||
- !g_irepository_require (NULL, "Gio", "2.0", 0, &error) ||
- !g_irepository_require (NULL, "GLib", "2.0", 0, &error) ||
- !g_irepository_require (NULL, "Gtk", "3.0", 0, &error) ||
- !g_irepository_require (NULL, "Dazzle", "1.0", 0, &error) ||
- !g_irepository_require (NULL, "Jsonrpc", "1.0", 0, &error) ||
- !g_irepository_require (NULL, "Template", "1.0", 0, &error) ||
-#ifdef HAVE_WEBKIT
- !g_irepository_require (NULL, "WebKit2", "4.0", 0, &error) ||
-#endif
- !g_irepository_require (NULL, "Ide", PACKAGE_ABI_S, 0, &error))
- g_critical ("Cannot enable Python 3 plugins: %s", error->message);
- else
+ if (self->loaded_typelibs)
peas_engine_enable_loader (engine, "python3");
peas_engine_rescan_plugins (engine);
@@ -484,8 +456,6 @@ ide_application_addin_removed_cb (PeasExtensionSet *set,
* @self: a #IdeApplication
*
* Loads the #IdeApplicationAddin's for this application.
- *
- * Since: 3.32
*/
void
_ide_application_load_addins (IdeApplication *self)
@@ -518,8 +488,6 @@ _ide_application_load_addins (IdeApplication *self)
* @self: a #IdeApplication
*
* Unloads all of the previously loaded #IdeApplicationAddin.
- *
- * Since: 3.32
*/
void
_ide_application_unload_addins (IdeApplication *self)
diff --git a/src/libide/gui/ide-application-private.h b/src/libide/gui/ide-application-private.h
index c710549ad..51c0e5908 100644
--- a/src/libide/gui/ide-application-private.h
+++ b/src/libide/gui/ide-application-private.h
@@ -20,18 +20,22 @@
#pragma once
-#include <dazzle.h>
+#include <libide-core.h>
+#include <libide-gtk.h>
+
#include <libpeas/peas.h>
#include "ide-application.h"
-#include "ide-keybindings.h"
-#include "ide-worker-manager.h"
G_BEGIN_DECLS
struct _IdeApplication
{
- DzlApplication parent_instance;
+ AdwApplication parent_instance;
+
+ /* Our helper to merge menus together */
+ IdeMenuManager *menu_manager;
+ GHashTable *menu_merge_ids;
/* Array of all of our IdeWorkebench instances (loaded projects and
* their application windows).
@@ -55,11 +59,7 @@ struct _IdeApplication
* for various keys.
*/
GSettings *settings;
-
- /* Tracks changes to plugins and updates the available keybindings
- * to ensure they are loaded correctly (including .css files).
- */
- IdeKeybindings *keybindings;
+ GSettings *editor_settings;
/* We need to track the GResource files that were manually loaded for
* plugins on disk (generally Python plugins that need resources). That
@@ -67,6 +67,18 @@ struct _IdeApplication
*/
GHashTable *plugin_gresources;
+ /* CSS providers for each plugin that is loaded, indexed by the resource
+ * path for the plugin/internal library.
+ */
+ GHashTable *css_providers;
+
+ /* The CSS provider to recolor all of the widgetry based on style schemes */
+ GtkCssProvider *recoloring;
+
+ /* A D-Bus proxy to settings portal */
+ GDBusProxy *settings_portal;
+ char *system_font_name;
+
/* We need to stash the unmodified argv for the application somewhere
* so that we can pass it to a remote instance. Otherwise we lose
* the ability by cmdline-addins to determine if any options were
@@ -77,18 +89,6 @@ struct _IdeApplication
/* The time the application was started */
GDateTime *started_at;
- /* Multi-process worker manager */
- IdeWorkerManager *worker_manager;
-
- /* Our type of process (optionally set to "worker" */
- gchar *type;
-
- /* The single plugin to load within a worker */
- gchar *plugin;
-
- /* The dbus-address for worker mode */
- gchar *dbus_address;
-
/* Sets the type of workspace to create when creating the next workspace
* (such as when processing command line arguments).
*/
@@ -97,15 +97,15 @@ struct _IdeApplication
/* If we've detected we lost network access */
GNetworkMonitor *network_monitor;
guint has_network : 1;
+
+ /* If all our typelibs were loaded successfully */
+ guint loaded_typelibs : 1;
};
-IdeApplication *_ide_application_new (gboolean standalone,
- const gchar *type,
- const gchar *plugin,
- const gchar *dbus_address);
+IdeApplication *_ide_application_new (gboolean standalone);
void _ide_application_init_color (IdeApplication *self);
void _ide_application_init_actions (IdeApplication *self);
-void _ide_application_init_shortcuts (IdeApplication *self);
+void _ide_application_init_settings (IdeApplication *self);
void _ide_application_load_addins (IdeApplication *self);
void _ide_application_unload_addins (IdeApplication *self);
void _ide_application_load_plugin (IdeApplication *self,
@@ -115,5 +115,9 @@ void _ide_application_load_plugins_for_startup (IdeApplication
void _ide_application_load_plugins (IdeApplication *self);
void _ide_application_command_line (IdeApplication *self,
GApplicationCommandLine *cmdline);
+void _ide_application_add_resources (IdeApplication *self,
+ const char *path);
+void _ide_application_remove_resources (IdeApplication *self,
+ const char *path);
G_END_DECLS
diff --git a/src/libide/gui/ide-application-settings.c b/src/libide/gui/ide-application-settings.c
new file mode 100644
index 000000000..d24a71698
--- /dev/null
+++ b/src/libide/gui/ide-application-settings.c
@@ -0,0 +1,209 @@
+/* ide-application-settings.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-application-settings"
+
+#include "config.h"
+
+#include <libide-sourceview.h>
+
+#include "ide-application-private.h"
+#include "ide-recoloring-private.h"
+
+#define PORTAL_BUS_NAME "org.freedesktop.portal.Desktop"
+#define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop"
+#define PORTAL_SETTINGS_INTERFACE "org.freedesktop.portal.Settings"
+
+static void
+on_portal_settings_changed_cb (IdeApplication *self,
+ const char *sender_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ g_autoptr(GVariant) value = NULL;
+ const char *schema_id;
+ const char *key;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (sender_name != NULL);
+ g_assert (signal_name != NULL);
+
+ if (g_strcmp0 (signal_name, "SettingChanged") != 0)
+ return;
+
+ g_variant_get (parameters, "(&s&sv)", &schema_id, &key, &value);
+
+ if (g_strcmp0 (schema_id, "org.gnome.desktop.interface") == 0 &&
+ g_strcmp0 (key, "monospace-font-name") == 0 &&
+ g_strcmp0 (g_variant_get_string (value, NULL), "") != 0)
+ {
+ g_free (self->system_font_name);
+ self->system_font_name = g_strdup (g_variant_get_string (value, NULL));
+ g_object_notify (G_OBJECT (self), "system-font-name");
+ g_object_notify (G_OBJECT (self), "system-font");
+ }
+}
+
+static void
+parse_portal_settings (IdeApplication *self,
+ GVariant *parameters)
+{
+ GVariantIter *iter = NULL;
+ const char *schema_str;
+ GVariant *val;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ if (parameters == NULL)
+ return;
+
+ g_variant_get (parameters, "(a{sa{sv}})", &iter);
+
+ while (g_variant_iter_loop (iter, "{s@a{sv}}", &schema_str, &val))
+ {
+ GVariantIter *iter2 = g_variant_iter_new (val);
+ const char *key;
+ GVariant *v;
+
+ while (g_variant_iter_loop (iter2, "{sv}", &key, &v))
+ {
+ if (g_strcmp0 (schema_str, "org.gnome.desktop.interface") == 0 &&
+ g_strcmp0 (key, "monospace-font-name") == 0 &&
+ g_strcmp0 (g_variant_get_string (v, NULL), "") != 0)
+ {
+ g_free (self->system_font_name);
+ self->system_font_name = g_strdup (g_variant_get_string (v, NULL));
+ }
+ }
+
+ g_variant_iter_free (iter2);
+ }
+
+ g_variant_iter_free (iter);
+}
+
+static void
+ide_application_settings_style_scheme_changed_cb (IdeApplication *self,
+ const char *key,
+ GSettings *settings)
+{
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (G_IS_SETTINGS (settings));
+
+ g_object_notify (G_OBJECT (self), "style-scheme");
+
+ IDE_EXIT;
+}
+
+void
+_ide_application_init_settings (IdeApplication *self)
+{
+ static const char *patterns[] = { "org.gnome.*", NULL };
+ g_autoptr(GVariant) all = NULL;
+ g_autofree char *style_scheme_name = NULL;
+
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+ g_return_if_fail (self->settings_portal == NULL);
+
+ /* We must query the key to get changed notifications */
+ style_scheme_name = g_settings_get_string (self->editor_settings, "style-scheme-name");
+ g_debug ("Initial style scheme set to %s", style_scheme_name);
+ g_signal_connect_object (self->editor_settings,
+ "changed::style-scheme-name",
+ G_CALLBACK (ide_application_settings_style_scheme_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ self->settings_portal = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ PORTAL_BUS_NAME,
+ PORTAL_OBJECT_PATH,
+ PORTAL_SETTINGS_INTERFACE,
+ NULL,
+ NULL);
+
+ if (self->settings_portal != NULL)
+ {
+ g_signal_connect_object (self->settings_portal,
+ "g-signal",
+ G_CALLBACK (on_portal_settings_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ all = g_dbus_proxy_call_sync (self->settings_portal,
+ "ReadAll",
+ g_variant_new ("(^as)", patterns),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ NULL);
+ parse_portal_settings (self, all);
+ }
+}
+
+void
+ide_application_set_style_scheme (IdeApplication *self,
+ const char *style_scheme)
+{
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+
+ if (style_scheme == NULL)
+ style_scheme = "Adwaita";
+
+ g_object_freeze_notify (G_OBJECT (self));
+ g_settings_set_string (self->editor_settings, "style-scheme-name", style_scheme);
+ g_object_thaw_notify (G_OBJECT (self));
+}
+
+const char *
+ide_application_get_style_scheme (IdeApplication *self)
+{
+ GtkSourceStyleSchemeManager *style_scheme_manager;
+ GtkSourceStyleScheme *style_scheme;
+ AdwStyleManager *style_manager;
+ g_autofree char *style_scheme_id = NULL;
+ const char *variant;
+
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+
+ style_manager = adw_style_manager_get_default ();
+ style_scheme_manager = gtk_source_style_scheme_manager_get_default ();
+ style_scheme_id = g_settings_get_string (self->editor_settings, "style-scheme-name");
+
+ /* Fallback to Adwaita if we don't find a match */
+ if (gtk_source_style_scheme_manager_get_scheme (style_scheme_manager, style_scheme_id) == NULL)
+ {
+ g_free (style_scheme_id);
+ style_scheme_id = g_strdup ("Adwaita");
+ }
+
+ if (adw_style_manager_get_dark (style_manager))
+ variant = "dark";
+ else
+ variant = "light";
+
+ style_scheme = gtk_source_style_scheme_manager_get_scheme (style_scheme_manager, style_scheme_id);
+ style_scheme = ide_source_style_scheme_get_variant (style_scheme, variant);
+
+ return gtk_source_style_scheme_get_id (style_scheme);
+}
diff --git a/src/libide/gui/ide-application.c b/src/libide/gui/ide-application.c
index ab0b6c390..90e8f277f 100644
--- a/src/libide/gui/ide-application.c
+++ b/src/libide/gui/ide-application.c
@@ -27,9 +27,8 @@
#endif
#include <glib/gi18n.h>
-#include <handy.h>
+
#include <libpeas/peas-autocleanups.h>
-#include <libide-themes.h>
#include "ide-language-defaults.h"
@@ -38,11 +37,7 @@
#include "ide-application-private.h"
#include "ide-gui-global.h"
#include "ide-primary-workspace.h"
-#include "ide-worker.h"
-
-G_DEFINE_FINAL_TYPE (IdeApplication, ide_application, DZL_TYPE_APPLICATION)
-
-#define IS_UI_PROCESS(app) ((app)->type == NULL)
+#include "ide-shortcut-manager-private.h"
typedef struct
{
@@ -52,6 +47,18 @@ typedef struct
const gchar *hint;
} OpenData;
+G_DEFINE_FINAL_TYPE (IdeApplication, ide_application, ADW_TYPE_APPLICATION)
+
+enum {
+ PROP_0,
+ PROP_STYLE_SCHEME,
+ PROP_SYSTEM_FONT,
+ PROP_SYSTEM_FONT_NAME,
+ N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS];
+
static void
ide_application_add_platform_data (GApplication *app,
GVariantBuilder *builder)
@@ -106,113 +113,122 @@ ide_application_local_command_line (GApplication *app,
return G_APPLICATION_CLASS (ide_application_parent_class)->local_command_line (app, arguments,
exit_status);
}
-static void
-ide_application_register_keybindings (IdeApplication *self)
+G_GNUC_NULL_TERMINATED
+static gboolean
+ide_application_load_all_typelibs (GError **error, ...)
{
- g_autoptr(GSettings) settings = NULL;
- g_autofree gchar *name = NULL;
+ g_autoptr(GString) msg = g_string_new (NULL);
+ const char *typelib;
+ gboolean had_failure = FALSE;
+ va_list args;
- g_assert (IDE_IS_APPLICATION (self));
+ va_start (args, error);
+ while ((typelib = va_arg (args, const char *)))
+ {
+ const char *version = va_arg (args, const char *);
+ g_autoptr(GError) local_error = NULL;
+
+ if (!g_irepository_require (NULL, typelib, version, 0, &local_error))
+ {
+ if (msg->len)
+ g_string_append (msg, "; ");
+ g_string_append (msg, local_error->message);
+ had_failure = TRUE;
+ }
+ }
+ va_end (args);
- settings = g_settings_new ("org.gnome.builder.editor");
- name = g_settings_get_string (settings, "keybindings");
- self->keybindings = ide_keybindings_new (name);
- g_settings_bind (settings, "keybindings", self->keybindings, "mode", G_SETTINGS_BIND_GET);
+ if (had_failure)
+ {
+ g_set_error_literal (error,
+ G_IREPOSITORY_ERROR,
+ G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
+ msg->str);
+ return FALSE;
+ }
+
+ return TRUE;
}
-static int
-keybinding_key_snooper (GtkWidget *grab_widget,
- GdkEventKey *key,
- gpointer func_data)
+static void
+ide_application_load_typelibs (IdeApplication *self)
{
- IdeApplication *self = func_data;
-
- g_assert (IDE_IS_APPLICATION (self));
+ g_autoptr(GError) error = NULL;
- /* We need to hijack <Ctrl>period because ibus is messing it up. However,
- * we only get a release event since it gets hijacked from the compositor
- * so we never see the event. Instead, we catch the release and then change
- * the focus to what we want (clearlying the state created in the compositor
- * ibus bits).
- */
- if (key->type == GDK_KEY_RELEASE &&
- key->keyval == GDK_KEY_period &&
- (key->state & GDK_CONTROL_MASK) != 0)
- {
- if (IDE_IS_WORKSPACE (grab_widget))
- {
- DzlShortcutManager *shortcuts = dzl_shortcut_manager_get_default ();
+ IDE_ENTRY;
- g_clear_object (&key->window);
- key->window = g_object_ref (gtk_widget_get_window (grab_widget));
- key->type = GDK_KEY_PRESS;
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_APPLICATION (self));
- dzl_shortcut_manager_handle_event (shortcuts, key, grab_widget);
+ g_irepository_prepend_search_path (PACKAGE_LIBDIR"/gnome-builder/girepository-1.0");
- return TRUE;
- }
- }
+ /* Ensure that we have all our required GObject Introspection packages
+ * loaded so that plugins don't need to require_version() as that is
+ * tedious and annoying to keep up to date.
+ *
+ * If we can't load any of our dependent packages, then fail to load
+ * python3 plugins altogether to avoid loading anything improper into
+ * the process space.
+ */
+ if (!ide_application_load_all_typelibs (&error,
+ "Gio", "2.0",
+ "GLib", "2.0",
+ "Gtk", "4.0",
+ "GtkSource", "5",
+ "Jsonrpc", "1.0",
+ "Template", "1.0",
+ "Vte", "3.91",
+#ifdef HAVE_WEBKIT
+ "WebKit2", "5.0",
+#endif
+ "Ide", PACKAGE_ABI_S,
+ NULL))
+ g_critical ("Cannot enable Python 3 plugins: %s", error->message);
+ else
+ self->loaded_typelibs = TRUE;
- return FALSE;
+ IDE_EXIT;
}
static void
ide_application_startup (GApplication *app)
{
IdeApplication *self = (IdeApplication *)app;
+ g_autofree gchar *style_path = NULL;
+ GtkSourceStyleSchemeManager *styles;
+ GtkSourceLanguageManager *langs;
+ GtkIconTheme *icon_theme;
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_APPLICATION (self));
- /*
- * We require a desktop session that provides a properly working
- * D-Bus environment. Bail if for some reason that is not the case.
- */
- if (g_getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)
- g_warning ("%s",
- _("GNOME Builder requires a session with D-Bus which was not found. Please set
DBUS_SESSION_BUS_ADDRESS. Some features may not be available."));
-
G_APPLICATION_CLASS (ide_application_parent_class)->startup (app);
- if (IS_UI_PROCESS (self))
- {
- g_autofree gchar *style_path = NULL;
- GtkSourceStyleSchemeManager *styles;
-
- /* Setup key snoopers */
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- gtk_key_snooper_install (keybinding_key_snooper, self);
- G_GNUC_END_IGNORE_DEPRECATIONS
+ /* Setup access to private icons dir */
+ icon_theme = gtk_icon_theme_get_for_display (gdk_display_get_default ());
+ gtk_icon_theme_add_search_path (icon_theme, PACKAGE_ICONDIR);
- /* Setup access to private icons dir */
- gtk_icon_theme_prepend_search_path (gtk_icon_theme_get_default (), PACKAGE_ICONDIR);
+ /* Add custom style locations for gtksourceview schemes */
+ styles = gtk_source_style_scheme_manager_get_default ();
+ style_path = g_build_filename (g_get_home_dir (), ".local", "share", "gtksourceview-5", "styles", NULL);
+ gtk_source_style_scheme_manager_append_search_path (styles, style_path);
+ gtk_source_style_scheme_manager_append_search_path (styles, PACKAGE_DATADIR"/gnome-builder/styles/");
- /* Add custom style locations for gtksourceview schemes */
- styles = gtk_source_style_scheme_manager_get_default ();
- style_path = g_build_filename (g_get_home_dir (), ".local", "share", "gtksourceview-4", "styles",
NULL);
- gtk_source_style_scheme_manager_append_search_path (styles, style_path);
- gtk_source_style_scheme_manager_append_search_path (styles, PACKAGE_DATADIR"/gtksourceview-4/styles/");
+ /* Add custom locations for language specs */
+ langs = gtk_source_language_manager_get_default ();
+ gtk_source_language_manager_append_search_path (langs,
"resource:///org/gnome/builder/gtksourceview/language-specs");
- hdy_init ();
+ /* Setup access to portal settings */
+ _ide_application_init_settings (self);
- /* Load color settings (Night Light, Dark Mode, etc) */
- _ide_application_init_color (self);
- }
+ /* Load color settings (Night Light, Dark Mode, etc) */
+ _ide_application_init_color (self);
/* And now we can load the rest of our plugins for startup. */
_ide_application_load_plugins (self);
- if (IS_UI_PROCESS (self))
- {
- /* Make sure our shorcuts are registered */
- _ide_application_init_shortcuts (self);
-
- /* Load keybindings from plugins and what not */
- ide_application_register_keybindings (self);
-
- /* Load language defaults into gsettings */
- ide_language_defaults_init_async (NULL, NULL, NULL);
- }
+ /* Load language defaults into gsettings */
+ ide_language_defaults_init_async (NULL, NULL, NULL);
}
static void
@@ -228,66 +244,10 @@ ide_application_shutdown (GApplication *app)
g_clear_pointer (&self->plugin_settings, g_hash_table_unref);
g_clear_object (&self->addins);
g_clear_object (&self->settings);
- g_clear_object (&self->keybindings);
G_APPLICATION_CLASS (ide_application_parent_class)->shutdown (app);
}
-static void
-ide_application_activate_worker (IdeApplication *self)
-{
- g_autoptr(GDBusConnection) connection = NULL;
- g_autoptr(GError) error = NULL;
- PeasPluginInfo *plugin_info;
- PeasExtension *extension;
- PeasEngine *engine;
-
- IDE_ENTRY;
-
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (IDE_IS_APPLICATION (self));
- g_assert (ide_str_equal0 (self->type, "worker"));
- g_assert (self->dbus_address != NULL);
- g_assert (self->plugin != NULL);
-
-#ifdef __linux__
- prctl (PR_SET_PDEATHSIG, SIGKILL);
-#endif
-
- IDE_TRACE_MSG ("Connecting to %s", self->dbus_address);
-
- connection = g_dbus_connection_new_for_address_sync (self->dbus_address,
- (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
- G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING),
- NULL, NULL, &error);
-
- if (error != NULL)
- {
- g_error ("D-Bus failure: %s", error->message);
- IDE_EXIT;
- }
-
- engine = peas_engine_get_default ();
-
- if (!(plugin_info = peas_engine_get_plugin_info (engine, self->plugin)))
- {
- g_error ("No such plugin \"%s\"", self->plugin);
- IDE_EXIT;
- }
-
- if (!(extension = peas_engine_create_extension (engine, plugin_info, IDE_TYPE_WORKER, NULL)))
- {
- g_error ("Failed to create \"%s\" worker", self->plugin);
- IDE_EXIT;
- }
-
- ide_worker_register_service (IDE_WORKER (extension), connection);
- g_application_hold (G_APPLICATION (self));
- g_dbus_connection_start_message_processing (connection);
-
- IDE_EXIT;
-}
-
static void
ide_application_activate_cb (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
@@ -313,14 +273,8 @@ ide_application_activate (GApplication *app)
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_APPLICATION (self));
- if (ide_str_equal0 (self->type, "worker"))
- {
- ide_application_activate_worker (self);
- IDE_EXIT;
- }
-
if ((window = gtk_application_get_active_window (GTK_APPLICATION (self))))
- ide_gtk_window_present (window);
+ gtk_window_present (GTK_WINDOW (window));
if (self->addins != NULL)
peas_extension_set_foreach (self->addins,
@@ -377,6 +331,148 @@ ide_application_open (GApplication *app,
IDE_EXIT;
}
+static GtkCssProvider *
+get_css_provider (IdeApplication *self,
+ const char *key)
+{
+ GtkCssProvider *ret;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (key != NULL);
+
+ if (!(ret = g_hash_table_lookup (self->css_providers, key)))
+ {
+ ret = gtk_css_provider_new ();
+ gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+ GTK_STYLE_PROVIDER (ret),
+ GTK_STYLE_PROVIDER_PRIORITY_USER-1);
+ g_hash_table_insert (self->css_providers, g_strdup (key), ret);
+ }
+
+ return ret;
+}
+
+void
+_ide_application_add_resources (IdeApplication *self,
+ const char *resource_path)
+{
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *menu_path = NULL;
+ g_autofree gchar *css_path = NULL;
+ guint merge_id;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (resource_path != NULL);
+
+ /* We use interned strings for hash table keys */
+ resource_path = g_intern_string (resource_path);
+
+ /*
+ * If the resource path has a gtk/menus.ui file, we want to auto-load and
+ * merge the menus.
+ */
+ menu_path = g_build_filename (resource_path, "gtk", "menus.ui", NULL);
+
+ if (g_str_has_prefix (menu_path, "resource://"))
+ merge_id = ide_menu_manager_add_resource (self->menu_manager, menu_path, &error);
+ else
+ merge_id = ide_menu_manager_add_filename (self->menu_manager, menu_path, &error);
+
+ if (merge_id != 0)
+ g_hash_table_insert (self->menu_merge_ids, (gchar *)resource_path, GUINT_TO_POINTER (merge_id));
+
+ if (error != NULL &&
+ !(g_error_matches (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND) ||
+ g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)))
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+
+ if (g_str_has_prefix (resource_path, "resource://"))
+ {
+ g_autoptr(GBytes) bytes = NULL;
+
+ css_path = g_build_filename (resource_path + strlen ("resource://"), "style.css", NULL);
+ bytes = g_resources_lookup_data (css_path, 0, NULL);
+
+ if (bytes != NULL)
+ {
+ GtkCssProvider *provider = get_css_provider (self, resource_path);
+ gtk_css_provider_load_from_resource (provider, css_path);
+ }
+ }
+ else
+ {
+ css_path = g_build_filename (resource_path, "style.css", NULL);
+
+ if (g_file_test (css_path, G_FILE_TEST_IS_REGULAR))
+ {
+ GtkCssProvider *provider = get_css_provider (self, resource_path);
+ gtk_css_provider_load_from_path (provider, css_path);
+ }
+ }
+
+ ide_shortcut_manager_add_resources (resource_path);
+}
+
+void
+_ide_application_remove_resources (IdeApplication *self,
+ const char *resource_path)
+{
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+ g_return_if_fail (resource_path != NULL);
+
+ /* Unmerge menus, keybindings, etc */
+ g_warning ("TODO: implement resource unloading for plugins: %s", resource_path);
+}
+
+static void
+ide_application_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeApplication *self = IDE_APPLICATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_STYLE_SCHEME:
+ g_value_set_string (value, ide_application_get_style_scheme (self));
+ break;
+
+ case PROP_SYSTEM_FONT_NAME:
+ g_value_set_string (value, ide_application_get_system_font_name (self));
+ break;
+
+ case PROP_SYSTEM_FONT: {
+ const char *system_font_name = ide_application_get_system_font_name (self);
+ g_value_take_boxed (value, pango_font_description_from_string (system_font_name));
+ break;
+ }
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_application_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeApplication *self = IDE_APPLICATION (object);
+
+ switch (prop_id)
+ {
+ case PROP_STYLE_SCHEME:
+ ide_application_set_style_scheme (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
static void
ide_application_dispose (GObject *object)
{
@@ -390,14 +486,16 @@ ide_application_dispose (GObject *object)
g_clear_pointer (&self->workbenches, g_ptr_array_unref);
g_clear_pointer (&self->plugin_settings, g_hash_table_unref);
g_clear_pointer (&self->plugin_gresources, g_hash_table_unref);
+ g_clear_pointer (&self->css_providers, g_hash_table_unref);
g_clear_pointer (&self->argv, g_strfreev);
- g_clear_pointer (&self->plugin, g_free);
- g_clear_pointer (&self->type, g_free);
- g_clear_pointer (&self->dbus_address, g_free);
+ g_clear_pointer (&self->menu_merge_ids, g_hash_table_unref);
+ g_clear_pointer (&self->system_font_name, g_free);
+ g_clear_object (&self->recoloring);
g_clear_object (&self->addins);
+ g_clear_object (&self->editor_settings);
g_clear_object (&self->settings);
g_clear_object (&self->network_monitor);
- g_clear_object (&self->worker_manager);
+ g_clear_object (&self->menu_manager);
G_OBJECT_CLASS (ide_application_parent_class)->dispose (object);
}
@@ -409,6 +507,8 @@ ide_application_class_init (IdeApplicationClass *klass)
GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
object_class->dispose = ide_application_dispose;
+ object_class->get_property = ide_application_get_property;
+ object_class->set_property = ide_application_set_property;
app_class->activate = ide_application_activate;
app_class->open = ide_application_open;
@@ -417,41 +517,71 @@ ide_application_class_init (IdeApplicationClass *klass)
app_class->local_command_line = ide_application_local_command_line;
app_class->startup = ide_application_startup;
app_class->shutdown = ide_application_shutdown;
+
+ properties[PROP_STYLE_SCHEME] =
+ g_param_spec_string ("style-scheme",
+ "Style Scheme",
+ "The style scheme for the editor",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_SYSTEM_FONT] =
+ g_param_spec_boxed ("system-font",
+ "System Font",
+ "System Font",
+ PANGO_TYPE_FONT_DESCRIPTION,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_SYSTEM_FONT_NAME] =
+ g_param_spec_string ("system-font-name",
+ "System Font Name",
+ "System Font Name",
+ "Monospace 11",
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
ide_application_init (IdeApplication *self)
{
+ self->system_font_name = g_strdup ("Monospace 11");
+ self->menu_merge_ids = g_hash_table_new (g_str_hash, g_str_equal);
+ self->menu_manager = ide_menu_manager_new ();
self->started_at = g_date_time_new_now_local ();
self->workspace_type = IDE_TYPE_PRIMARY_WORKSPACE;
self->workbenches = g_ptr_array_new_with_free_func (g_object_unref);
self->settings = g_settings_new ("org.gnome.builder");
+ self->editor_settings = g_settings_new ("org.gnome.builder.editor");
self->plugin_gresources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify)g_resource_unref);
+ self->css_providers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref );
+ self->recoloring = gtk_css_provider_new ();
g_application_set_default (G_APPLICATION (self));
gtk_window_set_default_icon_name (ide_get_application_id ());
- ide_themes_init ();
+
+ /* Make sure we've loaded typelibs into process for early access */
+ ide_application_load_typelibs (self);
/* Ensure our core data is loaded early. */
- dzl_application_add_resources (DZL_APPLICATION (self), "resource:///org/gnome/libide-sourceview/");
- dzl_application_add_resources (DZL_APPLICATION (self), "resource:///org/gnome/libide-gui/");
- dzl_application_add_resources (DZL_APPLICATION (self), "resource:///org/gnome/libide-terminal/");
+ _ide_application_add_resources (self, "resource:///org/gnome/libide-sourceview/");
+ _ide_application_add_resources (self, "resource:///org/gnome/libide-gui/");
+ _ide_application_add_resources (self, "resource:///org/gnome/libide-greeter/");
+ _ide_application_add_resources (self, "resource:///org/gnome/libide-editor/");
+ _ide_application_add_resources (self, "resource:///org/gnome/libide-terminal/");
/* Make sure our GAction are available */
_ide_application_init_actions (self);
}
IdeApplication *
-_ide_application_new (gboolean standalone,
- const gchar *type,
- const gchar *plugin,
- const gchar *dbus_address)
+_ide_application_new (gboolean standalone)
{
GApplicationFlags flags = G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN;
IdeApplication *self;
- if (standalone || ide_str_equal0 (type, "worker"))
+ if (standalone)
flags |= G_APPLICATION_NON_UNIQUE;
self = g_object_new (IDE_TYPE_APPLICATION,
@@ -460,10 +590,6 @@ _ide_application_new (gboolean standalone,
"resource-base-path", "/org/gnome/builder",
NULL);
- self->type = g_strdup (type);
- self->plugin = g_strdup (plugin);
- self->dbus_address = g_strdup (dbus_address);
-
/* Load plugins indicating they support startup features */
_ide_application_load_plugins_for_startup (self);
@@ -541,8 +667,6 @@ ide_application_remove_workbench (IdeApplication *self,
* @user_data: user data for @callback
*
* Calls @callback for each of the registered workbenches.
- *
- * Since: 3.32
*/
void
ide_application_foreach_workbench (IdeApplication *self,
@@ -568,8 +692,6 @@ ide_application_foreach_workbench (IdeApplication *self,
* next workspace upon handling files from command-line arguments. This is
* reset after the files are opened and is generally only useful from
* #IdeApplicationAddin's who need to alter the default workspace.
- *
- * Since: 3.32
*/
void
ide_application_set_workspace_type (IdeApplication *self,
@@ -601,8 +723,6 @@ ide_application_network_changed_cb (IdeApplication *self,
* the wild that make determining if we have network access difficult.
*
* Returns: %TRUE if we think there is network access.
- *
- * Since: 3.32
*/
gboolean
ide_application_has_network (IdeApplication *self)
@@ -646,8 +766,6 @@ ide_application_has_network (IdeApplication *self)
* Gets the time the application was started.
*
* Returns: (transfer none): a #GDateTime
- *
- * Since: 3.32
*/
GDateTime *
ide_application_get_started_at (IdeApplication *self)
@@ -657,94 +775,6 @@ ide_application_get_started_at (IdeApplication *self)
return self->started_at;
}
-static void
-ide_application_get_worker_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeWorkerManager *worker_manager = (IdeWorkerManager *)object;
- g_autoptr(IdeTask) task = user_data;
- g_autoptr(GError) error = NULL;
- GDBusProxy *proxy;
-
- g_assert (IDE_IS_WORKER_MANAGER (worker_manager));
-
- if (!(proxy = ide_worker_manager_get_worker_finish (worker_manager, result, &error)))
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_task_return_pointer (task, g_steal_pointer (&proxy), g_object_unref);
-}
-
-/**
- * ide_application_get_worker_async:
- * @self: an #IdeApplication
- * @plugin_name: The name of the plugin.
- * @cancellable: (allow-none): a #GCancellable or %NULL.
- * @callback: a #GAsyncReadyCallback or %NULL.
- * @user_data: user data for @callback.
- *
- * Asynchronously requests a #GDBusProxy to a service provided in a worker
- * process. The worker should be an #IdeWorker implemented by the plugin named
- * @plugin_name. The #IdeWorker is responsible for created both the service
- * registered on the bus and the proxy to it.
- *
- * The #IdeApplication is responsible for spawning a subprocess for the worker.
- *
- * @callback should call ide_application_get_worker_finish() with the result
- * provided to retrieve the result.
- *
- * Since: 3.32
- */
-void
-ide_application_get_worker_async (IdeApplication *self,
- const gchar *plugin_name,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr(IdeTask) task = NULL;
-
- g_return_if_fail (IDE_IS_APPLICATION (self));
- g_return_if_fail (plugin_name != NULL);
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- if (self->worker_manager == NULL)
- self->worker_manager = ide_worker_manager_new ();
-
- task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_source_tag (task, ide_application_get_worker_async);
-
- ide_worker_manager_get_worker_async (self->worker_manager,
- plugin_name,
- cancellable,
- ide_application_get_worker_cb,
- g_steal_pointer (&task));
-}
-
-/**
- * ide_application_get_worker_finish:
- * @self: an #IdeApplication.
- * @result: a #GAsyncResult
- * @error: a location for a #GError, or %NULL.
- *
- * Completes an asynchronous request to get a proxy to a worker process.
- *
- * Returns: (transfer full): a #GDBusProxy or %NULL.
- *
- * Since: 3.32
- */
-GDBusProxy *
-ide_application_get_worker_finish (IdeApplication *self,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
- g_return_val_if_fail (IDE_IS_TASK (result), NULL);
-
- return ide_task_propagate_pointer (IDE_TASK (result), error);
-}
-
/**
* ide_application_find_workbench_for_file:
* @self: a #IdeApplication
@@ -755,8 +785,6 @@ ide_application_get_worker_finish (IdeApplication *self,
* If no workbench is the root of @file, then %NULL is returned.
*
* Returns: (transfer none) (nullable): an #IdeWorkbench or %NULL
- *
- * Since: 3.32
*/
IdeWorkbench *
ide_application_find_workbench_for_file (IdeApplication *self,
@@ -833,8 +861,6 @@ ide_application_get_command_line_handled (IdeApplication *self,
*
* Returns: (transfer none) (type IdeApplicationAddin) (nullable): an
* #IdeApplicationAddin or %NULL.
- *
- * Since: 3.34
*/
gpointer
ide_application_find_addin_by_module_name (IdeApplication *self,
@@ -860,3 +886,166 @@ ide_application_find_addin_by_module_name (IdeApplication *self,
return peas_extension_set_get_extension (self->addins, plugin_info);
}
+
+/**
+ * ide_application_get_menu_by_id:
+ * @self: a #IdeApplication
+ * @menu_id: (nullable): the menu identifier
+ *
+ * Gets the merged menu by it's identifier.
+ *
+ * Returns: (transfer none) (nullable): a #GMenu or %NULL if @menu_id is %NULL
+ */
+GMenu *
+ide_application_get_menu_by_id (IdeApplication *self,
+ const char *menu_id)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+
+ if (menu_id == NULL)
+ return NULL;
+
+ return ide_menu_manager_get_menu_by_id (self->menu_manager, menu_id);
+}
+
+const char *
+ide_application_get_system_font_name (IdeApplication *self)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+
+ return self->system_font_name;
+}
+
+static GFile *
+get_user_style_file (GFile *file)
+{
+ static GFile *style_dir;
+ g_autofree char *basename = NULL;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+ if G_UNLIKELY (style_dir == NULL)
+ {
+ if (ide_is_flatpak ())
+ style_dir = g_file_new_build_filename (g_get_home_dir (),
+ ".local",
+ "share",
+ "gtksourceview-5",
+ "styles",
+ NULL);
+ else
+ style_dir = g_file_new_build_filename (g_get_user_data_dir (),
+ "gtksourceview-5",
+ "styles",
+ NULL);
+ }
+
+ basename = g_file_get_basename (file);
+
+ return g_file_get_child (style_dir, basename);
+}
+
+static void
+ide_application_install_schemes_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file = (GFile *)object;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = user_data;
+ g_autoptr(GFile) dst = NULL;
+ GPtrArray *ar;
+ GFile *src;
+
+ g_assert (G_IS_FILE (file));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (G_IS_TASK (task));
+
+ ar = g_task_get_task_data (task);
+
+ g_assert (ar != NULL);
+ g_assert (ar->len > 0);
+ g_assert (G_IS_FILE (g_ptr_array_index (ar, ar->len-1)));
+
+ g_ptr_array_remove_index (ar, ar->len-1);
+
+ if (!g_file_copy_finish (file, result, &error))
+ g_warning ("Failed to copy file: %s", error->message);
+
+ if (ar->len == 0)
+ {
+ g_task_return_boolean (task, TRUE);
+ return;
+ }
+
+ src = g_ptr_array_index (ar, ar->len-1);
+ dst = get_user_style_file (src);
+
+ g_file_copy_async (src, dst,
+ G_FILE_COPY_OVERWRITE | G_FILE_COPY_BACKUP,
+ G_PRIORITY_LOW,
+ g_task_get_cancellable (task),
+ NULL, NULL,
+ ide_application_install_schemes_cb,
+ g_object_ref (task));
+}
+
+void
+ide_application_install_schemes_async (IdeApplication *self,
+ GFile **files,
+ guint n_files,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GPtrArray) ar = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GFile) dst = NULL;
+ g_autoptr(GFile) dir = NULL;
+ GFile *src;
+
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+ g_return_if_fail (files != NULL);
+ g_return_if_fail (n_files > 0);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ ar = g_ptr_array_new_with_free_func (g_object_unref);
+ for (guint i = 0; i < n_files; i++)
+ g_ptr_array_add (ar, g_object_ref (files[i]));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, ide_application_install_schemes_async);
+ g_task_set_task_data (task, g_ptr_array_ref (ar), (GDestroyNotify) g_ptr_array_unref);
+
+ src = g_ptr_array_index (ar, ar->len-1);
+ dst = get_user_style_file (src);
+ dir = g_file_get_parent (dst);
+
+ if (!g_file_query_exists (dir, NULL) &&
+ !g_file_make_directory_with_parents (dir, cancellable, &error))
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ g_file_copy_async (src, dst,
+ G_FILE_COPY_OVERWRITE | G_FILE_COPY_BACKUP,
+ G_PRIORITY_LOW,
+ cancellable,
+ NULL, NULL,
+ ide_application_install_schemes_cb,
+ g_steal_pointer (&task));
+}
+
+gboolean
+ide_application_install_schemes_finish (IdeApplication *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/src/libide/gui/ide-application.h b/src/libide/gui/ide-application.h
index 446f9aa7d..69c18a9f4 100644
--- a/src/libide/gui/ide-application.h
+++ b/src/libide/gui/ide-application.h
@@ -24,7 +24,8 @@
# error "Only <libide-gui.h> can be included directly."
#endif
-#include <dazzle.h>
+#include <adwaita.h>
+
#include <libide-core.h>
#include <libide-projects.h>
@@ -35,65 +36,78 @@ G_BEGIN_DECLS
#define IDE_TYPE_APPLICATION (ide_application_get_type())
#define IDE_APPLICATION_DEFAULT IDE_APPLICATION(g_application_get_default())
-IDE_AVAILABLE_IN_3_32
-G_DECLARE_FINAL_TYPE (IdeApplication, ide_application, IDE, APPLICATION, DzlApplication)
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (IdeApplication, ide_application, IDE, APPLICATION, AdwApplication)
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
gboolean ide_application_has_network (IdeApplication *self);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
gchar **ide_application_get_argv (IdeApplication *self,
GApplicationCommandLine *cmdline);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
GDateTime *ide_application_get_started_at (IdeApplication *self);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
gboolean ide_application_get_command_line_handled (IdeApplication *self,
GApplicationCommandLine *cmdline);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_application_set_command_line_handled (IdeApplication *self,
GApplicationCommandLine *cmdline,
gboolean handled);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_application_open_project_async (IdeApplication *self,
IdeProjectInfo *project_info,
GType workspace_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
IdeWorkbench *ide_application_open_project_finish (IdeApplication *self,
GAsyncResult *result,
GError **error);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_application_set_workspace_type (IdeApplication *self,
GType workspace_type);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_application_add_workbench (IdeApplication *self,
IdeWorkbench *workbench);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_application_remove_workbench (IdeApplication *self,
IdeWorkbench *workbench);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_application_foreach_workbench (IdeApplication *self,
GFunc callback,
gpointer user_data);
-IDE_AVAILABLE_IN_3_32
-void ide_application_get_worker_async (IdeApplication *self,
- const gchar *plugin_name,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-IDE_AVAILABLE_IN_3_32
-GDBusProxy *ide_application_get_worker_finish (IdeApplication *self,
- GAsyncResult *result,
- GError **error);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
IdeWorkbench *ide_application_find_workbench_for_file (IdeApplication *self,
GFile *file);
-IDE_AVAILABLE_IN_3_34
+IDE_AVAILABLE_IN_ALL
gpointer ide_application_find_addin_by_module_name (IdeApplication *self,
const gchar *module_name);
-IDE_AVAILABLE_IN_41
+IDE_AVAILABLE_IN_ALL
char *ide_application_create_cancel_action (IdeApplication *self,
GCancellable *cancellable);
+IDE_AVAILABLE_IN_ALL
+GMenu *ide_application_get_menu_by_id (IdeApplication *self,
+ const char *menu_id);
+IDE_AVAILABLE_IN_ALL
+const char *ide_application_get_system_font_name (IdeApplication *self);
+IDE_AVAILABLE_IN_ALL
+const char *ide_application_get_style_scheme (IdeApplication *self);
+IDE_AVAILABLE_IN_ALL
+void ide_application_set_style_scheme (IdeApplication *self,
+ const char *style_scheme);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_application_get_dark (IdeApplication *self);
+IDE_AVAILABLE_IN_ALL
+void ide_application_install_schemes_async (IdeApplication *self,
+ GFile **files,
+ guint n_files,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_application_install_schemes_finish (IdeApplication *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]