search: add a panel to configure search providers
The panel lists all the search providers registered on the system, and allows to reoder or disable them, or disable the search providers feature entirely. The panel will also allow configuration, for which a first implementation will be added in a separate commit. https://live.gnome.org/Design/SystemSettings/Search https://bugzilla.gnome.org/show_bug.cgi?id=687490
This commit is contained in:
parent
f1812b2707
commit
7ab2d5073d
8 changed files with 924 additions and 2 deletions
|
@ -103,7 +103,7 @@ NETWORK_MANAGER_REQUIRED_VERSION=0.8.995
|
|||
NETWORK_MANAGER_APPLET_REQUIRED_VERSION=0.9.7
|
||||
LIBNOTIFY_REQUIRED_VERSION=0.7.3
|
||||
GNOME_DESKTOP_REQUIRED_VERSION=3.5.91
|
||||
SCHEMAS_REQUIRED_VERSION=3.5.91
|
||||
SCHEMAS_REQUIRED_VERSION=3.7.0
|
||||
LIBWACOM_REQUIRED_VERSION=0.6
|
||||
CLUTTER_REQUIRED_VERSION=1.11.3
|
||||
GOA_REQUIRED_VERSION=3.5.90
|
||||
|
@ -148,6 +148,7 @@ PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES
|
|||
gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION
|
||||
$IBUS_MODULE)
|
||||
PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES)
|
||||
PKG_CHECK_MODULES(SEARCH_PANEL, $COMMON_MODULES)
|
||||
PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0
|
||||
libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION
|
||||
libpulse >= $PA_REQUIRED_VERSION
|
||||
|
@ -428,6 +429,8 @@ panels/online-accounts/icons/24x24/Makefile
|
|||
panels/online-accounts/icons/32x32/Makefile
|
||||
panels/online-accounts/icons/48x48/Makefile
|
||||
panels/online-accounts/icons/256x256/Makefile
|
||||
panels/search/Makefile
|
||||
panels/search/gnome-search-panel.desktop.in
|
||||
panels/sound/Makefile
|
||||
panels/sound/gvc/Makefile
|
||||
panels/sound/data/Makefile
|
||||
|
|
|
@ -13,7 +13,8 @@ SUBDIRS= \
|
|||
keyboard \
|
||||
universal-access \
|
||||
user-accounts \
|
||||
datetime
|
||||
datetime \
|
||||
search
|
||||
|
||||
if BUILD_WACOM
|
||||
SUBDIRS += wacom
|
||||
|
|
35
panels/search/Makefile.am
Normal file
35
panels/search/Makefile.am
Normal file
|
@ -0,0 +1,35 @@
|
|||
cappletname = search
|
||||
|
||||
INCLUDES = \
|
||||
$(PANEL_CFLAGS) \
|
||||
$(SEARCH_PANEL_CFLAGS) \
|
||||
-DGNOMECC_UI_DIR="\"$(uidir)\"" \
|
||||
-DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
|
||||
-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" \
|
||||
-DDATADIR="\"$(datadir)\"" \
|
||||
-I$(top_srcdir)/panels/common/ \
|
||||
$(NULL)
|
||||
|
||||
ccpanelsdir = $(PANELS_DIR)
|
||||
ccpanels_LTLIBRARIES = libsearch.la
|
||||
|
||||
libsearch_la_SOURCES = \
|
||||
search-module.c \
|
||||
cc-search-panel.c \
|
||||
cc-search-panel.h
|
||||
|
||||
libsearch_la_LIBADD = $(PANEL_LIBS) $(SEARCH_PANEL_LIBS)
|
||||
libsearch_la_LDFLAGS = $(PANEL_LDFLAGS)
|
||||
|
||||
uidir = $(pkgdatadir)/ui
|
||||
dist_ui_DATA = search.ui
|
||||
|
||||
@INTLTOOL_DESKTOP_RULE@
|
||||
|
||||
desktopdir = $(datadir)/applications
|
||||
desktop_in_files = gnome-search-panel.desktop.in
|
||||
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
|
||||
|
||||
CLEANFILES = $(desktop_in_files) $(desktop_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
625
panels/search/cc-search-panel.c
Normal file
625
panels/search/cc-search-panel.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: Cosimo Cecchi <cosimoc@gnome.org>
|
||||
*/
|
||||
|
||||
#include "cc-search-panel.h"
|
||||
|
||||
#include <egg-list-box/egg-list-box.h>
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
CC_PANEL_REGISTER (CcSearchPanel, cc_search_panel)
|
||||
|
||||
#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s))
|
||||
|
||||
struct _CcSearchPanelPrivate
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *list_box;
|
||||
GtkWidget *up_button;
|
||||
GtkWidget *down_button;
|
||||
|
||||
GSettings *search_settings;
|
||||
GHashTable *sort_order;
|
||||
};
|
||||
|
||||
#define SHELL_PROVIDER_GROUP "Shell Search Provider"
|
||||
|
||||
static gint
|
||||
list_sort_func (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer user_data)
|
||||
{
|
||||
CcSearchPanel *self = user_data;
|
||||
GtkWidget *widget_a, *widget_b;
|
||||
GAppInfo *app_a, *app_b;
|
||||
const gchar *id_a, *id_b;
|
||||
gint idx_a, idx_b, num_sorted;
|
||||
gpointer lookup;
|
||||
|
||||
widget_a = GTK_WIDGET (a);
|
||||
widget_b = GTK_WIDGET (b);
|
||||
|
||||
app_a = g_object_get_data (G_OBJECT (widget_a), "app-info");
|
||||
app_b = g_object_get_data (G_OBJECT (widget_b), "app-info");
|
||||
|
||||
id_a = g_app_info_get_id (app_a);
|
||||
id_b = g_app_info_get_id (app_b);
|
||||
|
||||
/* find the index of the application in the GSettings preferences */
|
||||
idx_a = -1;
|
||||
idx_b = -1;
|
||||
|
||||
lookup = g_hash_table_lookup (self->priv->sort_order, id_a);
|
||||
if (lookup)
|
||||
idx_a = GPOINTER_TO_INT (lookup) - 1;
|
||||
|
||||
lookup = g_hash_table_lookup (self->priv->sort_order, id_b);
|
||||
if (lookup)
|
||||
idx_b = GPOINTER_TO_INT (lookup) - 1;
|
||||
|
||||
/* if neither app is found, use alphabetical order */
|
||||
if ((idx_a == -1) && (idx_b == -1))
|
||||
return g_utf8_collate (g_app_info_get_name (app_a), g_app_info_get_name (app_b));
|
||||
|
||||
num_sorted = g_hash_table_size (self->priv->sort_order) - 1;
|
||||
if (num_sorted > 1)
|
||||
{
|
||||
/* if app_a is the last, it goes after everything */
|
||||
if (idx_a == num_sorted)
|
||||
return 1;
|
||||
/* if app_b is the last, it goes after everything */
|
||||
else if (idx_b == num_sorted)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if app_a isn't found, it's sorted after app_b */
|
||||
if (idx_a == -1)
|
||||
return 1;
|
||||
|
||||
/* if app_b isn't found, it's sorted after app_a */
|
||||
if (idx_b == -1)
|
||||
return -1;
|
||||
|
||||
/* finally, if both apps are found, return their order in the list */
|
||||
return (idx_a - idx_b);
|
||||
}
|
||||
|
||||
static void
|
||||
search_panel_invalidate_button_state (CcSearchPanel *self)
|
||||
{
|
||||
GList *children;
|
||||
gboolean is_first, is_last;
|
||||
GtkWidget *child;
|
||||
|
||||
child = egg_list_box_get_selected_child (EGG_LIST_BOX (self->priv->list_box));
|
||||
children = gtk_container_get_children (GTK_CONTAINER (self->priv->list_box));
|
||||
|
||||
if (!child || !children)
|
||||
return;
|
||||
|
||||
is_first = (child == g_list_first (children)->data);
|
||||
is_last = (child == g_list_last (children)->data);
|
||||
|
||||
gtk_widget_set_sensitive (self->priv->up_button, !is_first);
|
||||
gtk_widget_set_sensitive (self->priv->down_button, !is_last);
|
||||
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
search_panel_invalidate_sort_order (CcSearchPanel *self)
|
||||
{
|
||||
gchar **sort_order;
|
||||
gint idx;
|
||||
|
||||
g_hash_table_remove_all (self->priv->sort_order);
|
||||
sort_order = g_settings_get_strv (self->priv->search_settings, "sort-order");
|
||||
|
||||
for (idx = 0; sort_order[idx] != NULL; idx++)
|
||||
g_hash_table_insert (self->priv->sort_order, g_strdup (sort_order[idx]), GINT_TO_POINTER (idx + 1));
|
||||
|
||||
egg_list_box_resort (EGG_LIST_BOX (self->priv->list_box));
|
||||
g_strfreev (sort_order);
|
||||
|
||||
search_panel_invalidate_button_state (self);
|
||||
}
|
||||
|
||||
static gint
|
||||
propagate_compare_func (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer user_data)
|
||||
{
|
||||
CcSearchPanel *self = user_data;
|
||||
const gchar *key_a = a, *key_b = b;
|
||||
gint idx_a, idx_b;
|
||||
|
||||
idx_a = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->sort_order, key_a));
|
||||
idx_b = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->sort_order, key_b));
|
||||
|
||||
return (idx_a - idx_b);
|
||||
}
|
||||
|
||||
static void
|
||||
search_panel_propagate_sort_order (CcSearchPanel *self)
|
||||
{
|
||||
GList *keys, *l;
|
||||
GPtrArray *sort_order;
|
||||
|
||||
sort_order = g_ptr_array_new ();
|
||||
keys = g_hash_table_get_keys (self->priv->sort_order);
|
||||
keys = g_list_sort_with_data (keys, propagate_compare_func, self);
|
||||
|
||||
for (l = keys; l != NULL; l = l->next)
|
||||
g_ptr_array_add (sort_order, l->data);
|
||||
|
||||
g_ptr_array_add (sort_order, NULL);
|
||||
g_settings_set_strv (self->priv->search_settings, "sort-order",
|
||||
(const gchar **) sort_order->pdata);
|
||||
|
||||
g_ptr_array_unref (sort_order);
|
||||
g_list_free (keys);
|
||||
}
|
||||
|
||||
static void
|
||||
search_panel_set_no_providers (CcSearchPanel *self)
|
||||
{
|
||||
GtkWidget *w;
|
||||
|
||||
/* center the list box in the scrolled window */
|
||||
gtk_widget_set_valign (self->priv->list_box, GTK_ALIGN_CENTER);
|
||||
|
||||
w = gtk_label_new (_("No applications found"));
|
||||
gtk_widget_show (w);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (self->priv->list_box), w);
|
||||
}
|
||||
|
||||
static void
|
||||
search_panel_move_selected (CcSearchPanel *self,
|
||||
gboolean down)
|
||||
{
|
||||
GtkWidget *box, *other_box;
|
||||
GAppInfo *app_info, *other_app_info;
|
||||
const gchar *app_id, *other_app_id;
|
||||
gint idx, other_idx;
|
||||
GList *children, *l;
|
||||
|
||||
box = egg_list_box_get_selected_child (EGG_LIST_BOX (self->priv->list_box));
|
||||
app_info = g_object_get_data (G_OBJECT (box), "app-info");
|
||||
app_id = g_app_info_get_id (app_info);
|
||||
|
||||
other_app_id = NULL;
|
||||
children = gtk_container_get_children (GTK_CONTAINER (self->priv->list_box));
|
||||
l = g_list_find (children, box);
|
||||
|
||||
if (l != NULL)
|
||||
{
|
||||
other_box = down ? g_list_next (l)->data : g_list_previous (l)->data;
|
||||
other_app_info = g_object_get_data (G_OBJECT (other_box), "app-info");
|
||||
other_app_id = g_app_info_get_id (other_app_info);
|
||||
}
|
||||
|
||||
other_idx = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->sort_order, app_id));
|
||||
idx = down ? (other_idx + 1) : (other_idx - 1);
|
||||
|
||||
if (other_app_id != NULL)
|
||||
g_hash_table_replace (self->priv->sort_order, g_strdup (other_app_id), GINT_TO_POINTER (other_idx));
|
||||
|
||||
g_hash_table_replace (self->priv->sort_order, g_strdup (app_id), GINT_TO_POINTER (idx));
|
||||
|
||||
search_panel_propagate_sort_order (self);
|
||||
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
down_button_clicked (GtkWidget *widget,
|
||||
CcSearchPanel *self)
|
||||
{
|
||||
search_panel_move_selected (self, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
up_button_clicked (GtkWidget *widget,
|
||||
CcSearchPanel *self)
|
||||
{
|
||||
search_panel_move_selected (self, FALSE);
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
switch_settings_mapping_set (const GValue *value,
|
||||
const GVariantType *expected_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *box = user_data;
|
||||
CcSearchPanel *self = g_object_get_data (G_OBJECT (box), "self");
|
||||
GAppInfo *app_info = g_object_get_data (G_OBJECT (box), "app-info");
|
||||
gchar **disabled;
|
||||
GPtrArray *new_disabled;
|
||||
gint idx;
|
||||
gboolean remove, found;
|
||||
GVariant *variant;
|
||||
|
||||
remove = g_value_get_boolean (value);
|
||||
found = FALSE;
|
||||
new_disabled = g_ptr_array_new_with_free_func (g_free);
|
||||
disabled = g_settings_get_strv (self->priv->search_settings, "disabled");
|
||||
|
||||
for (idx = 0; disabled[idx] != NULL; idx++)
|
||||
{
|
||||
if (g_strcmp0 (disabled[idx], g_app_info_get_id (app_info)) == 0)
|
||||
{
|
||||
found = TRUE;
|
||||
|
||||
if (remove)
|
||||
continue;
|
||||
}
|
||||
|
||||
g_ptr_array_add (new_disabled, g_strdup (disabled[idx]));
|
||||
}
|
||||
|
||||
if (!found && !remove)
|
||||
g_ptr_array_add (new_disabled, g_strdup (g_app_info_get_id (app_info)));
|
||||
|
||||
g_ptr_array_add (new_disabled, NULL);
|
||||
|
||||
variant = g_variant_new_strv ((const gchar **) new_disabled->pdata, -1);
|
||||
g_ptr_array_unref (new_disabled);
|
||||
g_strfreev (disabled);
|
||||
|
||||
return variant;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
switch_settings_mapping_get (GValue *value,
|
||||
GVariant *variant,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *box = user_data;
|
||||
GAppInfo *app_info = g_object_get_data (G_OBJECT (box), "app-info");
|
||||
const gchar **disabled;
|
||||
gint idx;
|
||||
gboolean found;
|
||||
|
||||
found = FALSE;
|
||||
disabled = g_variant_get_strv (variant, NULL);
|
||||
|
||||
for (idx = 0; disabled[idx] != NULL; idx++)
|
||||
{
|
||||
if (g_strcmp0 (disabled[idx], g_app_info_get_id (app_info)) == 0)
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_value_set_boolean (value, !found);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
search_panel_add_one_app_info (CcSearchPanel *self,
|
||||
GAppInfo *app_info)
|
||||
{
|
||||
GtkWidget *box, *w;
|
||||
GIcon *icon;
|
||||
|
||||
/* reset valignment of the list box */
|
||||
gtk_widget_set_valign (self->priv->list_box, GTK_ALIGN_FILL);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_widget_set_hexpand (box, TRUE);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (box), 6);
|
||||
g_object_set_data_full (G_OBJECT (box), "app-info",
|
||||
g_object_ref (app_info), g_object_unref);
|
||||
g_object_set_data (G_OBJECT (box), "self", self);
|
||||
gtk_container_add (GTK_CONTAINER (self->priv->list_box), box);
|
||||
|
||||
icon = g_app_info_get_icon (app_info);
|
||||
if (icon == NULL)
|
||||
icon = g_themed_icon_new ("application-x-executable");
|
||||
else
|
||||
g_object_ref (icon);
|
||||
|
||||
w = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
|
||||
gtk_container_add (GTK_CONTAINER (box), w);
|
||||
g_object_unref (icon);
|
||||
|
||||
w = gtk_label_new (g_app_info_get_name (app_info));
|
||||
gtk_container_add (GTK_CONTAINER (box), w);
|
||||
|
||||
w = gtk_switch_new ();
|
||||
gtk_widget_set_valign (w, GTK_ALIGN_CENTER);
|
||||
gtk_box_pack_end (GTK_BOX (box), w, FALSE, FALSE, 0);
|
||||
|
||||
g_settings_bind_with_mapping (self->priv->search_settings, "disabled",
|
||||
w, "active",
|
||||
G_SETTINGS_BIND_DEFAULT,
|
||||
switch_settings_mapping_get,
|
||||
switch_settings_mapping_set,
|
||||
box, NULL);
|
||||
|
||||
gtk_widget_show_all (box);
|
||||
}
|
||||
|
||||
static void
|
||||
search_panel_add_one_provider (CcSearchPanel *self,
|
||||
GFile *provider)
|
||||
{
|
||||
gchar *path, *desktop_id;
|
||||
GKeyFile *keyfile;
|
||||
GAppInfo *app_info;
|
||||
GError *error = NULL;
|
||||
|
||||
path = g_file_get_path (provider);
|
||||
keyfile = g_key_file_new ();
|
||||
g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Error loading %s: %s - search provider will be ignored",
|
||||
path, error->message);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_key_file_has_group (keyfile, SHELL_PROVIDER_GROUP))
|
||||
goto out;
|
||||
|
||||
desktop_id = g_key_file_get_string (keyfile, SHELL_PROVIDER_GROUP,
|
||||
"DesktopId", &error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Unable to read desktop ID from %s: %s - search provider will be ignored",
|
||||
path, error->message);
|
||||
goto out;
|
||||
}
|
||||
|
||||
app_info = G_APP_INFO (g_desktop_app_info_new (desktop_id));
|
||||
g_free (desktop_id);
|
||||
|
||||
if (app_info == NULL)
|
||||
goto out;
|
||||
|
||||
search_panel_add_one_app_info (self, app_info);
|
||||
g_object_unref (app_info);
|
||||
|
||||
out:
|
||||
g_free (path);
|
||||
g_clear_error (&error);
|
||||
g_key_file_unref (keyfile);
|
||||
}
|
||||
|
||||
static void
|
||||
next_search_provider_ready (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
CcSearchPanel *self = user_data;
|
||||
GFile *providers_location, *provider;
|
||||
GList *files;
|
||||
GError *error = NULL;
|
||||
gchar *path;
|
||||
|
||||
files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source),
|
||||
res, &error);
|
||||
providers_location = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source));
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
path = g_file_get_path (providers_location);
|
||||
|
||||
g_warning ("Error reading from %s: %s - search providers might be missing from the panel",
|
||||
path, error->message);
|
||||
|
||||
g_error_free (error);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
if (files != NULL)
|
||||
{
|
||||
provider = g_file_get_child (providers_location, g_file_info_get_name (files->data));
|
||||
search_panel_add_one_provider (self, provider);
|
||||
g_object_unref (provider);
|
||||
|
||||
g_file_enumerator_next_files_async (G_FILE_ENUMERATOR (source), 1,
|
||||
G_PRIORITY_DEFAULT, NULL,
|
||||
next_search_provider_ready, self);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* propagate a write to GSettings, to make sure we always have
|
||||
* all the providers in the list.
|
||||
*/
|
||||
search_panel_propagate_sort_order (self);
|
||||
}
|
||||
|
||||
g_list_free_full (files, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
enumerate_search_providers_ready (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
CcSearchPanel *self = user_data;
|
||||
GFileEnumerator *enumerator;
|
||||
GError *error = NULL;
|
||||
gchar *path;
|
||||
|
||||
enumerator = g_file_enumerate_children_finish (G_FILE (source), res, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
path = g_file_get_path (G_FILE (source));
|
||||
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
g_warning ("Error opening %s: %s - search provider configuration won't be possible",
|
||||
path, error->message);
|
||||
|
||||
search_panel_set_no_providers (self);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_file_enumerator_next_files_async (enumerator, 1,
|
||||
G_PRIORITY_DEFAULT, NULL,
|
||||
next_search_provider_ready, self);
|
||||
g_object_unref (enumerator);
|
||||
}
|
||||
|
||||
static void
|
||||
populate_search_providers (CcSearchPanel *self)
|
||||
{
|
||||
GFile *providers_location;
|
||||
|
||||
providers_location = g_file_new_for_path (DATADIR "/gnome-shell/search-providers");
|
||||
g_file_enumerate_children_async (providers_location,
|
||||
"standard::type,standard::name,standard::content-type",
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
enumerate_search_providers_ready, self);
|
||||
g_object_unref (providers_location);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_search_panel_finalize (GObject *object)
|
||||
{
|
||||
CcSearchPanelPrivate *priv = CC_SEARCH_PANEL (object)->priv;
|
||||
|
||||
g_clear_object (&priv->builder);
|
||||
g_clear_object (&priv->search_settings);
|
||||
g_hash_table_destroy (priv->sort_order);
|
||||
|
||||
G_OBJECT_CLASS (cc_search_panel_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_search_panel_constructed (GObject *object)
|
||||
{
|
||||
CcSearchPanel *self = CC_SEARCH_PANEL (object);
|
||||
GtkWidget *box, *widget, *search_box;
|
||||
|
||||
G_OBJECT_CLASS (cc_search_panel_parent_class)->constructed (object);
|
||||
|
||||
/* add the disable all switch */
|
||||
search_box = WID ("search_vbox");
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
|
||||
widget = gtk_label_new (_("Enabled"));
|
||||
gtk_container_add (GTK_CONTAINER (box), widget);
|
||||
|
||||
widget = gtk_switch_new ();
|
||||
gtk_container_add (GTK_CONTAINER (box), widget);
|
||||
|
||||
g_settings_bind (self->priv->search_settings, "disable-external",
|
||||
widget, "active",
|
||||
G_SETTINGS_BIND_DEFAULT |
|
||||
G_SETTINGS_BIND_INVERT_BOOLEAN);
|
||||
|
||||
g_object_bind_property (widget, "active",
|
||||
search_box, "sensitive",
|
||||
G_BINDING_DEFAULT |
|
||||
G_BINDING_SYNC_CREATE);
|
||||
|
||||
gtk_widget_show_all (box);
|
||||
cc_shell_embed_widget_in_header (cc_panel_get_shell (CC_PANEL (self)), box);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_search_panel_init (CcSearchPanel *self)
|
||||
{
|
||||
GError *error;
|
||||
GtkWidget *widget;
|
||||
GtkWidget *scrolled_window;
|
||||
guint res;
|
||||
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CC_TYPE_SEARCH_PANEL, CcSearchPanelPrivate);
|
||||
|
||||
self->priv->builder = gtk_builder_new ();
|
||||
|
||||
error = NULL;
|
||||
res = gtk_builder_add_from_file (self->priv->builder,
|
||||
GNOMECC_UI_DIR "/search.ui",
|
||||
&error);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
g_warning ("Could not load interface file: %s",
|
||||
(error != NULL) ? error->message : "unknown error");
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
scrolled_window = WID ("scrolled_window");
|
||||
widget = GTK_WIDGET (egg_list_box_new ());
|
||||
egg_list_box_set_sort_func (EGG_LIST_BOX (widget),
|
||||
list_sort_func, self, NULL);
|
||||
egg_list_box_add_to_scrolled (EGG_LIST_BOX (widget), GTK_SCROLLED_WINDOW (scrolled_window));
|
||||
self->priv->list_box = widget;
|
||||
gtk_widget_show (widget);
|
||||
|
||||
g_signal_connect_swapped (widget, "child-selected",
|
||||
G_CALLBACK (search_panel_invalidate_button_state), self);
|
||||
|
||||
self->priv->up_button = WID ("up_button");
|
||||
g_signal_connect (self->priv->up_button, "clicked",
|
||||
G_CALLBACK (up_button_clicked), self);
|
||||
gtk_widget_set_sensitive (self->priv->up_button, FALSE);
|
||||
|
||||
self->priv->down_button = WID ("down_button");
|
||||
g_signal_connect (self->priv->down_button, "clicked",
|
||||
G_CALLBACK (down_button_clicked), self);
|
||||
gtk_widget_set_sensitive (self->priv->down_button, FALSE);
|
||||
|
||||
self->priv->search_settings = g_settings_new ("org.gnome.desktop.search-providers");
|
||||
self->priv->sort_order = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
g_signal_connect_swapped (self->priv->search_settings, "changed::sort-order",
|
||||
G_CALLBACK (search_panel_invalidate_sort_order), self);
|
||||
search_panel_invalidate_sort_order (self);
|
||||
|
||||
populate_search_providers (self);
|
||||
|
||||
widget = WID ("search_vbox");
|
||||
gtk_widget_reparent (widget, (GtkWidget *) self);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_search_panel_class_init (CcSearchPanelClass *klass)
|
||||
{
|
||||
GObjectClass *oclass = G_OBJECT_CLASS (klass);
|
||||
|
||||
oclass->constructed = cc_search_panel_constructed;
|
||||
oclass->finalize = cc_search_panel_finalize;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (CcSearchPanelPrivate));
|
||||
}
|
||||
|
||||
void
|
||||
cc_search_panel_register (GIOModule *module)
|
||||
{
|
||||
cc_search_panel_register_type (G_TYPE_MODULE (module));
|
||||
g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
|
||||
CC_TYPE_SEARCH_PANEL,
|
||||
"search", 0);
|
||||
}
|
73
panels/search/cc-search-panel.h
Normal file
73
panels/search/cc-search-panel.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: Cosimo Cecchi <cosimoc@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef _CC_SEARCH_PANEL_H
|
||||
#define _CC_SEARCH_PANEL_H
|
||||
|
||||
#include <shell/cc-panel.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CC_TYPE_SEARCH_PANEL cc_search_panel_get_type()
|
||||
|
||||
#define CC_SEARCH_PANEL(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||
CC_TYPE_SEARCH_PANEL, CcSearchPanel))
|
||||
|
||||
#define CC_SEARCH_PANEL_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
||||
CC_TYPE_SEARCH_PANEL, CcSearchPanelClass))
|
||||
|
||||
#define CC_IS_SEARCH_PANEL(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
||||
CC_TYPE_SEARCH_PANEL))
|
||||
|
||||
#define CC_IS_SEARCH_PANEL_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
CC_TYPE_SEARCH_PANEL))
|
||||
|
||||
#define CC_SEARCH_PANEL_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||
CC_TYPE_SEARCH_PANEL, CcSearchPanelClass))
|
||||
|
||||
typedef struct _CcSearchPanel CcSearchPanel;
|
||||
typedef struct _CcSearchPanelClass CcSearchPanelClass;
|
||||
typedef struct _CcSearchPanelPrivate CcSearchPanelPrivate;
|
||||
|
||||
struct _CcSearchPanel
|
||||
{
|
||||
CcPanel parent;
|
||||
|
||||
CcSearchPanelPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CcSearchPanelClass
|
||||
{
|
||||
CcPanelClass parent_class;
|
||||
};
|
||||
|
||||
GType cc_search_panel_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void cc_search_panel_register (GIOModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _CC_SEARCH_PANEL_H */
|
17
panels/search/gnome-search-panel.desktop.in.in
Normal file
17
panels/search/gnome-search-panel.desktop.in.in
Normal file
|
@ -0,0 +1,17 @@
|
|||
[Desktop Entry]
|
||||
_Name=Search
|
||||
_Comment=Search settings
|
||||
Exec=gnome-control-center search
|
||||
Icon=find
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings
|
||||
OnlyShowIn=GNOME;Unity;
|
||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||
X-GNOME-Bugzilla-Product=gnome-control-center
|
||||
X-GNOME-Bugzilla-Component=search
|
||||
X-GNOME-Bugzilla-Version=@VERSION@
|
||||
X-GNOME-Settings-Panel=search
|
||||
# Translators: those are keywords for the search control-center panel
|
||||
_Keywords=Search;Find;Index;Hide;Privacy;Results;
|
41
panels/search/search-module.c
Normal file
41
panels/search/search-module.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: Cosimo Cecchi <cosimoc@gnome.org>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "cc-search-panel.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
void
|
||||
g_io_module_load (GIOModule *module)
|
||||
{
|
||||
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
|
||||
/* register the panel */
|
||||
cc_search_panel_register (module);
|
||||
}
|
||||
|
||||
void
|
||||
g_io_module_unload (GIOModule *module)
|
||||
{
|
||||
}
|
127
panels/search/search.ui
Normal file
127
panels/search/search.ui
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.0 -->
|
||||
<object class="GtkWindow" id="window1">
|
||||
<child>
|
||||
<object class="GtkBox" id="search_vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin-left">128</property>
|
||||
<property name="margin-right">128</property>
|
||||
<property name="margin-top">16</property>
|
||||
<property name="margin-bottom">16</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="width-request">400</property>
|
||||
<property name="height-request">350</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToolbar" id="search_toolbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="toolbar_style">icons</property>
|
||||
<property name="show_arrow">False</property>
|
||||
<property name="icon_size">1</property>
|
||||
<style>
|
||||
<class name="inline-toolbar"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToolItem" id="up_down_item">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="up_down_box">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="up_button">
|
||||
<property name="visible">True</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="up_button_a11y">
|
||||
<property name="accessible-name" translatable="yes">Move Up</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="up_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="icon-name">go-up-symbolic</property>
|
||||
<property name="icon-size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="down_button">
|
||||
<property name="visible">True</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="down_button_a11y">
|
||||
<property name="accessible-name" translatable="yes">Move Down</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="down_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="icon-name">go-down-symbolic</property>
|
||||
<property name="icon-size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorToolItem" id="sep1">
|
||||
<property name="visible">True</property>
|
||||
<property name="draw">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToolItem" id="settings_item">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="i_s_ud_box">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="settings_button">
|
||||
<property name="visible">True</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="settings_button_a11y">
|
||||
<property name="accessible-name" translatable="yes">Preferences</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="settings_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="icon-name">emblem-system-symbolic</property>
|
||||
<property name="icon-size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
Loading…
Add table
Add a link
Reference in a new issue