/* gtd-window.c * * Copyright (C) 2015-2020 Georges Basile Stavracas Neto * * 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 . */ #define G_LOG_DOMAIN "GtdWindow" #include "config.h" #include "gtd-activatable.h" #include "gtd-application.h" #include "gtd-debug.h" #include "gtd-task-list-view.h" #include "gtd-manager.h" #include "gtd-manager-protected.h" #include "gtd-menu-button.h" #include "gtd-notification.h" #include "gtd-omni-area.h" #include "gtd-plugin-manager.h" #include "gtd-provider.h" #include "gtd-panel.h" #include "gtd-task.h" #include "gtd-task-list.h" #include "gtd-window.h" #include "gtd-workspace.h" #include #include /** * SECTION:gtd-window * @short_description:main window * @title:GtdWindow * @stability:Unstable * * The #GtdWindow is the main application window of Endeavour. Objects should * use this class to change between selection and normal mode and * fine-tune the headerbar. */ struct _GtdWindow { AdwApplicationWindow application; GtkStack *stack; GtdWorkspace *current_workspace; GListStore *workspaces; GVariant *parameters; PeasExtensionSet *workspaces_set; }; enum { PROP_0, PROP_CURRENT_WORKSPACE, N_PROPS, }; static GParamSpec *properties[N_PROPS] = { NULL, }; G_DEFINE_TYPE (GtdWindow, gtd_window, ADW_TYPE_APPLICATION_WINDOW) static gint compare_workspaced_func (gconstpointer a, gconstpointer b, gpointer user_data); static void setup_development_build (GtdWindow *self) { g_message (_("This is a development build of Endeavour. You may experience errors, wrong behaviors, " "and data loss.")); gtk_widget_add_css_class (GTK_WIDGET (self), "devel"); } static gboolean is_development_build (void) { #ifdef DEVELOPMENT_BUILD return TRUE; #else return FALSE; #endif } static void load_geometry (GtdWindow *self) { GSettings *settings; GtkWindow *window; gboolean maximized; gint height; gint width; window = GTK_WINDOW (self); settings = gtd_manager_get_settings (gtd_manager_get_default ()); maximized = g_settings_get_boolean (settings, "window-maximized"); g_settings_get (settings, "window-size", "(ii)", &width, &height); gtk_window_set_default_size (window, width, height); if (maximized) gtk_window_maximize (window); } static void add_workspace (GtdWindow *self, GtdWorkspace *workspace) { const gchar *workspace_id; workspace_id = gtd_workspace_get_id (workspace); gtk_stack_add_named (self->stack, GTK_WIDGET (workspace), workspace_id); g_list_store_insert_sorted (self->workspaces, workspace, compare_workspaced_func, self); } static void remove_workspace (GtdWindow *self, GtdWorkspace *workspace) { guint position; if (!g_list_store_find (self->workspaces, workspace, &position)) return; gtk_stack_remove (self->stack, GTK_WIDGET (workspace)); g_list_store_remove (self->workspaces, position); } /* * Callbacks */ static void on_action_activate_workspace_activated_cb (GSimpleAction *simple, GVariant *state, gpointer user_data) { g_autofree gchar *workspace_id = NULL; GtdWindow *self; self = GTD_WINDOW (user_data); g_variant_get (state, "(sv)", &workspace_id, &self->parameters, NULL); gtk_stack_set_visible_child_name (self->stack, workspace_id); } static gint compare_workspaced_func (gconstpointer a, gconstpointer b, gpointer user_data) { gint a_priority; gint b_priority; a_priority = gtd_workspace_get_priority ((GtdWorkspace *)a); b_priority = gtd_workspace_get_priority ((GtdWorkspace *)b); return b_priority - a_priority; } static void on_stack_visible_child_cb (GtkStack *stack, GParamSpec *pspec, GtdWindow *self) { g_autoptr (GVariant) parameters = NULL; g_autoptr (GIcon) workspace_icon = NULL; GtdWorkspace *new_workspace; GTD_ENTRY; if (self->current_workspace) gtd_workspace_deactivate (self->current_workspace); new_workspace = GTD_WORKSPACE (gtk_stack_get_visible_child (stack)); self->current_workspace = new_workspace; if (!new_workspace) GTD_GOTO (out); parameters = g_steal_pointer (&self->parameters); gtd_workspace_activate (new_workspace, parameters); out: g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CURRENT_WORKSPACE]); GTD_EXIT; } static void on_workspace_added_cb (PeasExtensionSet *extension_set, PeasPluginInfo *plugin_info, GtdWorkspace *workspace, GtdWindow *self) { GTD_ENTRY; add_workspace (self, g_object_ref_sink (workspace)); GTD_EXIT; } static void on_workspace_removed_cb (PeasExtensionSet *extension_set, PeasPluginInfo *plugin_info, GtdWorkspace *workspace, GtdWindow *self) { GTD_ENTRY; remove_workspace (self, workspace); GTD_EXIT; } /* * GtkWindow overrides */ static void gtd_window_unmap (GtkWidget *widget) { GSettings *settings; GtkWindow *window; gboolean maximized; window = GTK_WINDOW (widget); settings = gtd_manager_get_settings (gtd_manager_get_default ()); maximized = gtk_window_is_maximized (window); g_settings_set_boolean (settings, "window-maximized", maximized); if (!maximized) { gint height; gint width; gtk_window_get_default_size (window, &width, &height); g_settings_set (settings, "window-size", "(ii)", width, height); } GTK_WIDGET_CLASS (gtd_window_parent_class)->unmap (widget); } /* * GObject overrides */ static void gtd_window_dispose (GObject *object) { GtdWindow *self = GTD_WINDOW (object); g_clear_object (&self->workspaces_set); G_OBJECT_CLASS (gtd_window_parent_class)->dispose (object); } static void gtd_window_finalize (GObject *object) { GtdWindow *self = GTD_WINDOW (object); g_clear_object (&self->workspaces); G_OBJECT_CLASS (gtd_window_parent_class)->finalize (object); } static void gtd_window_constructed (GObject *object) { GtdWindow *self; self = GTD_WINDOW (object); G_OBJECT_CLASS (gtd_window_parent_class)->constructed (object); /* Load stored size */ load_geometry (GTD_WINDOW (object)); /* Workspaces */ self->workspaces_set = peas_extension_set_new (peas_engine_get_default (), GTD_TYPE_WORKSPACE, NULL); peas_extension_set_foreach (self->workspaces_set, (PeasExtensionSetForeachFunc) on_workspace_added_cb, self); g_object_connect (self->workspaces_set, "signal::extension-added", G_CALLBACK (on_workspace_added_cb), self, "signal::extension-removed", G_CALLBACK (on_workspace_removed_cb), self, NULL); } static void gtd_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GtdWindow *self = (GtdWindow *) object; switch (prop_id) { case PROP_CURRENT_WORKSPACE: g_value_set_object (value, self->current_workspace); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void gtd_window_class_init (GtdWindowClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = gtd_window_dispose; object_class->finalize = gtd_window_finalize; object_class->constructed = gtd_window_constructed; object_class->get_property = gtd_window_get_property; widget_class->unmap = gtd_window_unmap; properties[PROP_CURRENT_WORKSPACE] = g_param_spec_object ("current-workspace", "Current workspace", "Current workspace", GTD_TYPE_WORKSPACE, G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); g_type_ensure (GTD_TYPE_MENU_BUTTON); g_type_ensure (GTD_TYPE_OMNI_AREA); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/todo/ui/gtd-window.ui"); gtk_widget_class_bind_template_child (widget_class, GtdWindow, stack); gtk_widget_class_bind_template_callback (widget_class, on_stack_visible_child_cb); } static void gtd_window_init (GtdWindow *self) { static const GActionEntry entries[] = { { "activate-workspace", on_action_activate_workspace_activated_cb, "(sv)" }, }; g_action_map_add_action_entries (G_ACTION_MAP (self), entries, G_N_ELEMENTS (entries), self); self->workspaces = g_list_store_new (GTD_TYPE_WORKSPACE); gtk_widget_init_template (GTK_WIDGET (self)); /* Development build */ if (is_development_build ()) setup_development_build (self); } GtkWidget* gtd_window_new (GtdApplication *application) { return g_object_new (GTD_TYPE_WINDOW, "application", application, NULL); } /** * gtd_window_get_current_workspace: * @self: a #GtdWindow * * Retrieves the currently active workspace * * Returns: (transfer full): a #GtdWorkspace */ GtdWorkspace* gtd_window_get_current_workspace (GtdWindow *self) { g_return_val_if_fail (GTD_IS_WINDOW (self), NULL); return self->current_workspace; }