gnome-control-center/shell/cc-window.c
Benjamin Berg cfc5fdb7c6 shell: Deactivate old panel before creating new one
We need to cancel internal operations before starting to create a new
panel, otherwise panels might be creating the same object for the cache
in parallel and this is not supported by the object cache.

The alternative to this would be to handle this inside the object
store to allow parallel creation of the same key.

Fixes: #1685
2022-06-20 03:18:30 +00:00

894 lines
26 KiB
C

/*
* Copyright (c) 2009, 2010 Intel, Inc.
* Copyright (c) 2010 Red Hat, Inc.
* Copyright (c) 2016 Endless, Inc.
*
* The Control Center 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 2 of the License, or (at your
* option) any later version.
*
* The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author: Thomas Wood <thos@gnome.org>
*/
#define G_LOG_DOMAIN "cc-window"
#include <config.h>
#include "cc-debug.h"
#include "cc-window.h"
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>
#include <gtk/gtk.h>
#include <string.h>
#include <time.h>
#include "cc-application.h"
#include "cc-panel-private.h"
#include "cc-shell.h"
#include "cc-shell-model.h"
#include "cc-panel-list.h"
#include "cc-panel-loader.h"
#include "cc-util.h"
#define MOUSE_BACK_BUTTON 8
#define DEFAULT_WINDOW_ICON_NAME "gnome-control-center"
struct _CcWindow
{
AdwApplicationWindow parent;
GtkMessageDialog *development_warning_dialog;
AdwHeaderBar *header;
AdwLeaflet *main_leaflet;
CcPanelList *panel_list;
GtkButton *previous_button;
GtkSearchBar *search_bar;
GtkToggleButton *search_button;
GtkSearchEntry *search_entry;
GtkBox *sidebar_box;
AdwWindowTitle *sidebar_title_widget;
GtkStack *stack;
GtkWidget *old_panel;
GtkWidget *current_panel;
char *current_panel_id;
GQueue *previous_panels;
GtkWidget *custom_titlebar;
CcShellModel *store;
CcPanel *active_panel;
GSettings *settings;
gboolean folded;
CcPanelListView previous_list_view;
};
static void cc_shell_iface_init (CcShellInterface *iface);
G_DEFINE_TYPE_WITH_CODE (CcWindow, cc_window, ADW_TYPE_APPLICATION_WINDOW,
G_IMPLEMENT_INTERFACE (CC_TYPE_SHELL, cc_shell_iface_init))
enum
{
PROP_0,
PROP_ACTIVE_PANEL,
PROP_MODEL,
PROP_FOLDED,
};
/* Auxiliary methods */
static void
load_window_state (CcWindow *self)
{
gint current_width = -1;
gint current_height = -1;
gboolean maximized = FALSE;
g_settings_get (self->settings,
"window-state",
"(iib)",
&current_width,
&current_height,
&maximized);
if (current_width != -1 && current_height != -1)
gtk_window_set_default_size (GTK_WINDOW (self), current_width, current_height);
if (maximized)
gtk_window_maximize (GTK_WINDOW (self));
}
static gboolean
in_flatpak_sandbox (void)
{
return g_strcmp0 (PROFILE, "development") == 0;
}
static void
on_sidebar_activated_cb (CcWindow *self)
{
adw_leaflet_navigate (self->main_leaflet, ADW_NAVIGATION_DIRECTION_FORWARD);
}
static gboolean
activate_panel (CcWindow *self,
const gchar *id,
GVariant *parameters,
const gchar *name,
GIcon *gicon,
CcPanelVisibility visibility)
{
g_autoptr(GTimer) timer = NULL;
GtkWidget *sidebar_widget;
gdouble ellapsed_time;
CC_ENTRY;
if (!id)
CC_RETURN (FALSE);
if (visibility == CC_PANEL_HIDDEN)
CC_RETURN (FALSE);
timer = g_timer_new ();
g_settings_set_string (self->settings, "last-panel", id);
/* Begin the profile */
g_timer_start (timer);
if (self->current_panel)
g_signal_handlers_disconnect_by_data (self->current_panel, self);
self->current_panel = GTK_WIDGET (cc_panel_loader_load_by_name (CC_SHELL (self), id, name, parameters));
cc_panel_set_folded (CC_PANEL (self->current_panel), adw_leaflet_get_folded (self->main_leaflet));
cc_shell_set_active_panel (CC_SHELL (self), CC_PANEL (self->current_panel));
gtk_stack_add_named (self->stack, self->current_panel, id);
/* switch to the new panel */
gtk_stack_set_visible_child_name (self->stack, id);
sidebar_widget = cc_panel_get_sidebar_widget (CC_PANEL (self->current_panel));
cc_panel_list_add_sidebar_widget (self->panel_list, sidebar_widget);
/* Ensure we show the panel when the leaflet is folded and a sidebar widget's
* row is activated.
*/
g_signal_connect_object (self->current_panel, "sidebar-activated", G_CALLBACK (on_sidebar_activated_cb), self, G_CONNECT_SWAPPED);
/* Finish profiling */
g_timer_stop (timer);
ellapsed_time = g_timer_elapsed (timer, NULL);
g_debug ("Time to open panel '%s': %lfs", name, ellapsed_time);
CC_RETURN (TRUE);
}
static void
add_current_panel_to_history (CcWindow *self,
const char *start_id)
{
g_return_if_fail (start_id != NULL);
if (!self->current_panel_id || g_strcmp0 (self->current_panel_id, start_id) == 0)
return;
g_queue_push_head (self->previous_panels, g_strdup (self->current_panel_id));
g_debug ("Added '%s' to the previous panels", self->current_panel_id);
}
static gboolean
find_iter_for_panel_id (CcWindow *self,
const gchar *panel_id,
GtkTreeIter *out_iter)
{
GtkTreeIter iter;
gboolean valid;
valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter);
while (valid)
{
g_autofree gchar *id = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (self->store),
&iter,
COL_ID, &id,
-1);
if (g_strcmp0 (id, panel_id) == 0)
break;
valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter);
}
g_assert (out_iter != NULL);
*out_iter = iter;
return valid;
}
static void
update_list_title (CcWindow *self)
{
CcPanelListView view;
GtkTreeIter iter;
g_autofree gchar *title = NULL;
CC_ENTRY;
view = cc_panel_list_get_view (self->panel_list);
title = NULL;
switch (view)
{
case CC_PANEL_LIST_PRIVACY:
title = g_strdup (_("Privacy"));
break;
case CC_PANEL_LIST_MAIN:
title = g_strdup (_("Settings"));
break;
case CC_PANEL_LIST_WIDGET:
find_iter_for_panel_id (self, self->current_panel_id, &iter);
gtk_tree_model_get (GTK_TREE_MODEL (self->store),
&iter,
COL_NAME, &title,
-1);
break;
case CC_PANEL_LIST_SEARCH:
title = NULL;
break;
}
if (title)
adw_window_title_set_title (self->sidebar_title_widget, title);
CC_EXIT;
}
static void
on_row_changed_cb (CcWindow *self,
GtkTreePath *path,
GtkTreeIter *iter,
GtkTreeModel *model)
{
g_autofree gchar *id = NULL;
CcPanelVisibility visibility;
gtk_tree_model_get (model, iter,
COL_ID, &id,
COL_VISIBILITY, &visibility,
-1);
cc_panel_list_set_panel_visibility (self->panel_list, id, visibility);
}
static void
setup_model (CcWindow *self)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean valid;
/* CcApplication must have a valid model at this point */
g_assert (self->store != NULL);
model = GTK_TREE_MODEL (self->store);
cc_panel_loader_fill_model (self->store);
/* Create a row for each panel */
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid)
{
CcPanelCategory category;
g_autoptr(GIcon) icon = NULL;
g_autofree gchar *name = NULL;
g_autofree gchar *description = NULL;
g_autofree gchar *id = NULL;
g_auto(GStrv) keywords = NULL;
CcPanelVisibility visibility;
gboolean has_sidebar;
const gchar *icon_name = NULL;
gtk_tree_model_get (model, &iter,
COL_CATEGORY, &category,
COL_DESCRIPTION, &description,
COL_GICON, &icon,
COL_ID, &id,
COL_NAME, &name,
COL_KEYWORDS, &keywords,
COL_VISIBILITY, &visibility,
COL_HAS_SIDEBAR, &has_sidebar,
-1);
if (G_IS_THEMED_ICON (icon))
icon_name = g_themed_icon_get_names (G_THEMED_ICON (icon))[0];
cc_panel_list_add_panel (self->panel_list,
category,
id,
name,
description,
keywords,
icon_name,
visibility,
has_sidebar);
valid = gtk_tree_model_iter_next (model, &iter);
}
/* React to visibility changes */
g_signal_connect_object (model, "row-changed", G_CALLBACK (on_row_changed_cb), self, G_CONNECT_SWAPPED);
}
static void
update_headerbar_buttons (CcWindow *self)
{
gboolean is_main_view;
CC_ENTRY;
is_main_view = cc_panel_list_get_view (self->panel_list) == CC_PANEL_LIST_MAIN;
gtk_widget_set_visible (GTK_WIDGET (self->previous_button), !is_main_view);
gtk_widget_set_visible (GTK_WIDGET (self->search_button), is_main_view);
gtk_search_bar_set_key_capture_widget (self->search_bar, is_main_view ? GTK_WIDGET (self) : NULL);
update_list_title (self);
CC_EXIT;
}
static gboolean
set_active_panel_from_id (CcWindow *self,
const gchar *start_id,
GVariant *parameters,
gboolean add_to_history,
gboolean force_moving_to_the_panel,
GError **error)
{
g_autoptr(GIcon) gicon = NULL;
g_autofree gchar *name = NULL;
CcPanelVisibility visibility;
GtkTreeIter iter;
CcPanelListView view;
gboolean activated;
gboolean found;
CC_ENTRY;
view = cc_panel_list_get_view (self->panel_list);
/* When loading the same panel again, just set its parameters */
if (g_strcmp0 (self->current_panel_id, start_id) == 0)
{
g_object_set (G_OBJECT (self->current_panel), "parameters", parameters, NULL);
if (force_moving_to_the_panel || self->previous_list_view == view)
adw_leaflet_navigate (self->main_leaflet, ADW_NAVIGATION_DIRECTION_FORWARD);
self->previous_list_view = view;
CC_RETURN (TRUE);
}
found = find_iter_for_panel_id (self, start_id, &iter);
if (!found)
{
g_warning ("Could not find settings panel \"%s\"", start_id);
CC_RETURN (TRUE);
}
if (self->old_panel)
gtk_stack_remove (self->stack, g_steal_pointer (&self->old_panel));
/* old_panel will be removed by the on_stack_transition_running_changed_cb
* callback - or, if panels changed before the transition ended, by the code
* just above.
*/
self->old_panel = self->current_panel;
if (self->old_panel)
cc_panel_deactivate (CC_PANEL (self->old_panel));
gtk_tree_model_get (GTK_TREE_MODEL (self->store),
&iter,
COL_NAME, &name,
COL_GICON, &gicon,
COL_VISIBILITY, &visibility,
-1);
/* Activate the panel */
activated = activate_panel (self, start_id, parameters, name, gicon, visibility);
/* Failed to activate the panel for some reason, let's keep the old
* panel around instead */
if (!activated)
{
g_debug ("Failed to activate panel");
CC_RETURN (TRUE);
}
if (add_to_history)
add_current_panel_to_history (self, start_id);
if (force_moving_to_the_panel)
adw_leaflet_navigate (self->main_leaflet, ADW_NAVIGATION_DIRECTION_FORWARD);
g_free (self->current_panel_id);
self->current_panel_id = g_strdup (start_id);
CC_TRACE_MSG ("Current panel id: %s", start_id);
cc_panel_list_set_active_panel (self->panel_list, start_id);
update_headerbar_buttons (self);
CC_RETURN (TRUE);
}
static void
set_active_panel (CcWindow *self,
CcPanel *panel)
{
g_return_if_fail (CC_IS_SHELL (self));
g_return_if_fail (panel == NULL || CC_IS_PANEL (panel));
if (panel != self->active_panel)
{
/* remove the old panel */
g_clear_object (&self->active_panel);
/* set the new panel */
if (panel)
self->active_panel = g_object_ref (panel);
g_object_notify (G_OBJECT (self), "active-panel");
}
}
static void
switch_to_previous_panel (CcWindow *self)
{
g_autofree gchar *previous_panel_id = NULL;
CC_ENTRY;
if (g_queue_get_length (self->previous_panels) == 0)
CC_RETURN ();
previous_panel_id = g_queue_pop_head (self->previous_panels);
g_debug ("Going to previous panel (%s)", previous_panel_id);
set_active_panel_from_id (self, previous_panel_id, NULL, FALSE, FALSE, NULL);
CC_EXIT;
}
/* Callbacks */
static void
navigate_action_cb (GtkWidget *widget,
const gchar *action_name,
GVariant *parameter)
{
CcWindow *self = CC_WINDOW (widget);
adw_leaflet_navigate (self->main_leaflet, g_variant_get_int32 (parameter));
}
static void
on_main_leaflet_folded_changed_cb (CcWindow *self)
{
GtkSelectionMode selection_mode;
gboolean folded;
g_assert (CC_IS_WINDOW (self));
folded = adw_leaflet_get_folded (self->main_leaflet);
selection_mode = folded ? GTK_SELECTION_NONE : GTK_SELECTION_SINGLE;
cc_panel_list_set_selection_mode (self->panel_list, selection_mode);
cc_panel_set_folded (CC_PANEL (self->current_panel), folded);
}
static void
show_panel_cb (CcWindow *self,
const gchar *panel_id)
{
if (!panel_id)
return;
set_active_panel_from_id (self, panel_id, NULL, TRUE, FALSE, NULL);
}
static void
search_entry_activate_cb (CcWindow *self)
{
gboolean changed;
changed = cc_panel_list_activate (self->panel_list);
gtk_search_bar_set_search_mode (self->search_bar, !changed);
}
static void
previous_button_clicked_cb (CcWindow *self)
{
g_debug ("Num previous panels? %d", g_queue_get_length (self->previous_panels));
/* When in search, simply unset the search mode */
if (gtk_search_bar_get_search_mode (self->search_bar))
gtk_search_bar_set_search_mode (self->search_bar, FALSE);
else
cc_panel_list_go_previous (self->panel_list);
update_headerbar_buttons (self);
}
static gboolean
go_back_shortcut_cb (GtkWidget *widget,
GVariant *args,
gpointer user_data)
{
g_debug ("Going to previous panel");
switch_to_previous_panel (CC_WINDOW (widget));
return GDK_EVENT_STOP;
}
static gboolean
search_shortcut_cb (GtkWidget *widget,
GVariant *args,
gpointer user_data)
{
CcPanelListView view;
CcWindow *self;
gboolean search;
self = CC_WINDOW (widget);
view = cc_panel_list_get_view (self->panel_list);
/* The search only happens when we're in the MAIN view */
if (view != CC_PANEL_LIST_MAIN && view != CC_PANEL_LIST_SEARCH)
return GDK_EVENT_PROPAGATE;
search = !gtk_search_bar_get_search_mode (self->search_bar);
gtk_search_bar_set_search_mode (self->search_bar, search);
if (search)
gtk_widget_grab_focus (GTK_WIDGET (self->search_entry));
return GDK_EVENT_STOP;
}
static void
on_development_warning_dialog_responded_cb (CcWindow *self)
{
g_debug ("Disabling development build warning dialog");
g_settings_set_boolean (self->settings, "show-development-warning", FALSE);
gtk_widget_hide (GTK_WIDGET (self->development_warning_dialog));
}
static void
on_stack_transition_running_changed_cb (GtkStack *stack,
GParamSpec *pspec,
CcWindow *self)
{
gboolean transition_running;
CC_ENTRY;
transition_running = gtk_stack_get_transition_running (stack);
if (!transition_running && self->old_panel)
gtk_stack_remove (self->stack, g_steal_pointer (&self->old_panel));
CC_EXIT;
}
/* CcShell implementation */
static gboolean
cc_window_set_active_panel_from_id (CcShell *shell,
const gchar *start_id,
GVariant *parameters,
GError **error)
{
return set_active_panel_from_id (CC_WINDOW (shell), start_id, parameters, TRUE, TRUE, error);
}
static GtkWidget *
cc_window_get_toplevel (CcShell *self)
{
return GTK_WIDGET (self);
}
static void
cc_shell_iface_init (CcShellInterface *iface)
{
iface->set_active_panel_from_id = cc_window_set_active_panel_from_id;
iface->get_toplevel = cc_window_get_toplevel;
}
/* GtkWidget overrides */
static void
cc_window_map (GtkWidget *widget)
{
CcWindow *self = (CcWindow *) widget;
GTK_WIDGET_CLASS (cc_window_parent_class)->map (widget);
/* Show a warning for Flatpak builds */
if (in_flatpak_sandbox () && g_settings_get_boolean (self->settings, "show-development-warning"))
gtk_window_present (GTK_WINDOW (self->development_warning_dialog));
}
static void
cc_window_unmap (GtkWidget *widget)
{
CcWindow *self = CC_WINDOW (widget);
gboolean maximized;
gint height;
gint width;
maximized = gtk_window_is_maximized (GTK_WINDOW (self));
gtk_window_get_default_size (GTK_WINDOW (self), &width, &height);
g_settings_set (self->settings,
"window-state",
"(iib)",
width,
height,
maximized);
GTK_WIDGET_CLASS (cc_window_parent_class)->unmap (widget);
}
/* GObject Implementation */
static void
cc_window_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
CcWindow *self = CC_WINDOW (object);
switch (property_id)
{
case PROP_ACTIVE_PANEL:
g_value_set_object (value, self->active_panel);
break;
case PROP_MODEL:
g_value_set_object (value, self->store);
break;
case PROP_FOLDED:
g_value_set_boolean (value, self->folded);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_window_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
CcWindow *self = CC_WINDOW (object);
switch (property_id)
{
case PROP_ACTIVE_PANEL:
set_active_panel (self, g_value_get_object (value));
break;
case PROP_MODEL:
g_assert (self->store == NULL);
self->store = g_value_dup_object (value);
break;
case PROP_FOLDED:
self->folded = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_window_constructed (GObject *object)
{
CcWindow *self = CC_WINDOW (object);
g_autofree char *id = NULL;
load_window_state (self);
/* Add the panels */
setup_model (self);
/* After everything is loaded, select the last used panel, if any,
* or the first visible panel */
id = g_settings_get_string (self->settings, "last-panel");
if (id != NULL && cc_shell_model_has_panel (self->store, id))
cc_panel_list_set_active_panel (self->panel_list, id);
else
cc_panel_list_activate (self->panel_list);
g_signal_connect_swapped (self->panel_list,
"notify::view",
G_CALLBACK (update_headerbar_buttons),
self);
update_headerbar_buttons (self);
adw_leaflet_set_visible_child (self->main_leaflet,
GTK_WIDGET (self->sidebar_box));
G_OBJECT_CLASS (cc_window_parent_class)->constructed (object);
}
static void
cc_window_dispose (GObject *object)
{
CcWindow *self = CC_WINDOW (object);
g_clear_pointer (&self->current_panel_id, g_free);
g_clear_object (&self->store);
g_clear_object (&self->active_panel);
G_OBJECT_CLASS (cc_window_parent_class)->dispose (object);
}
static void
cc_window_finalize (GObject *object)
{
CcWindow *self = CC_WINDOW (object);
if (self->previous_panels)
{
g_queue_free_full (self->previous_panels, g_free);
self->previous_panels = NULL;
}
g_clear_object (&self->settings);
G_OBJECT_CLASS (cc_window_parent_class)->finalize (object);
}
static void
cc_window_class_init (CcWindowClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = cc_window_get_property;
object_class->set_property = cc_window_set_property;
object_class->constructed = cc_window_constructed;
object_class->dispose = cc_window_dispose;
object_class->finalize = cc_window_finalize;
widget_class->map = cc_window_map;
widget_class->unmap = cc_window_unmap;
g_object_class_override_property (object_class, PROP_ACTIVE_PANEL, "active-panel");
g_object_class_install_property (object_class,
PROP_MODEL,
g_param_spec_object ("model",
"Model",
"The CcShellModel of this application",
CC_TYPE_SHELL_MODEL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_FOLDED,
g_param_spec_boolean ("folded",
"Folded",
"Whether the window is foled",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Settings/gtk/cc-window.ui");
gtk_widget_class_bind_template_child (widget_class, CcWindow, development_warning_dialog);
gtk_widget_class_bind_template_child (widget_class, CcWindow, header);
gtk_widget_class_bind_template_child (widget_class, CcWindow, main_leaflet);
gtk_widget_class_bind_template_child (widget_class, CcWindow, panel_list);
gtk_widget_class_bind_template_child (widget_class, CcWindow, previous_button);
gtk_widget_class_bind_template_child (widget_class, CcWindow, search_bar);
gtk_widget_class_bind_template_child (widget_class, CcWindow, search_button);
gtk_widget_class_bind_template_child (widget_class, CcWindow, search_entry);
gtk_widget_class_bind_template_child (widget_class, CcWindow, sidebar_box);
gtk_widget_class_bind_template_child (widget_class, CcWindow, sidebar_title_widget);
gtk_widget_class_bind_template_child (widget_class, CcWindow, stack);
gtk_widget_class_bind_template_callback (widget_class, on_main_leaflet_folded_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, on_development_warning_dialog_responded_cb);
gtk_widget_class_bind_template_callback (widget_class, on_stack_transition_running_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, previous_button_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, search_entry_activate_cb);
gtk_widget_class_bind_template_callback (widget_class, show_panel_cb);
gtk_widget_class_bind_template_callback (widget_class, update_list_title);
gtk_widget_class_add_binding (widget_class, GDK_KEY_Left, GDK_ALT_MASK, go_back_shortcut_cb, NULL);
gtk_widget_class_add_binding (widget_class, GDK_KEY_s, GDK_CONTROL_MASK, search_shortcut_cb, NULL);
gtk_widget_class_add_binding (widget_class, GDK_KEY_S, GDK_CONTROL_MASK, search_shortcut_cb, NULL);
gtk_widget_class_add_binding (widget_class, GDK_KEY_f, GDK_CONTROL_MASK, search_shortcut_cb, NULL);
gtk_widget_class_add_binding (widget_class, GDK_KEY_F, GDK_CONTROL_MASK, search_shortcut_cb, NULL);
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_q, GDK_CONTROL_MASK, "window.close", NULL);
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Q, GDK_CONTROL_MASK, "window.close", NULL);
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_w, GDK_CONTROL_MASK, "window.close", NULL);
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_W, GDK_CONTROL_MASK, "window.close", NULL);
gtk_widget_class_install_action (widget_class, "window.navigate", "i", navigate_action_cb);
g_type_ensure (CC_TYPE_PANEL_LIST);
}
static void
cc_window_init (CcWindow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->settings = g_settings_new ("org.gnome.Settings");
self->previous_panels = g_queue_new ();
self->previous_list_view = cc_panel_list_get_view (self->panel_list);
g_object_bind_property (self->main_leaflet,
"folded",
self,
"folded",
G_BINDING_SYNC_CREATE);
/* Add a custom CSS class on development builds */
if (in_flatpak_sandbox ())
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self)), "devel");
}
CcWindow *
cc_window_new (GtkApplication *application,
CcShellModel *model)
{
g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
return g_object_new (CC_TYPE_WINDOW,
"application", application,
"resizable", TRUE,
"title", _("Settings"),
"icon-name", DEFAULT_WINDOW_ICON_NAME,
"show-menubar", FALSE,
"model", model,
NULL);
}
void
cc_window_set_search_item (CcWindow *center,
const char *search)
{
gtk_search_bar_set_search_mode (center->search_bar, TRUE);
gtk_editable_set_text (GTK_EDITABLE (center->search_entry), search);
gtk_editable_set_position (GTK_EDITABLE (center->search_entry), -1);
}