Commit bfaeb6a4 authored by Rui Matos's avatar Rui Matos Committed by Bastien Nocera
Browse files

region: Add an initial input sources tab

This is just the scaffolding according to
https://live.gnome.org/Design/SystemSettings/RegionAndLanguage
No code behind it yet.

Original code from Matthias Clasen.

https://bugzilla.gnome.org/show_bug.cgi?id=662489
parent e59dc8de
......@@ -23,6 +23,8 @@ libregion_la_SOURCES = \
gnome-region-panel-lang.h \
gnome-region-panel-system.c \
gnome-region-panel-system.h \
gnome-region-panel-input.c \
gnome-region-panel-input.h \
gnome-region-panel-xkb.c \
gnome-region-panel-xkblt.c \
gnome-region-panel-xkbltadd.c \
......@@ -40,6 +42,7 @@ uidir = $(pkgdatadir)/ui
ui_DATA = \
gnome-region-panel.ui \
gnome-region-panel-layout-chooser.ui \
gnome-region-panel-input-chooser.ui \
gnome-region-panel-options-dialog.ui
desktopdir = $(datadir)/applications
......
......@@ -23,6 +23,7 @@
#include <gtk/gtk.h>
#include "gnome-region-panel-xkb.h"
#include "gnome-region-panel-input.h"
#include "gnome-region-panel-lang.h"
#include "gnome-region-panel-formats.h"
#include "gnome-region-panel-system.h"
......@@ -161,6 +162,7 @@ cc_region_panel_init (CcRegionPanel * self)
gtk_widget_reparent (prefs_widget, GTK_WIDGET (self));
setup_xkb_tabs (priv->builder);
setup_input_tabs (priv->builder, self);
setup_language (priv->builder);
setup_formats (priv->builder);
setup_system (priv->builder);
......
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<object class="GtkListStore" id="input_source_model">
<columns>
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeModelFilter" id="filtered_input_source_model">
<property name="child_model">input_source_model</property>
</object>
<object class="GtkDialog" id="input_source_chooser">
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Choose an input source</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="hbtnBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel-button">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ok-button">
<property name="label">gtk-add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkVBox" id="vbox40">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="spacing">6</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Select an input source to add</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">etched-in</property>
<property name="min_content_width">450</property>
<property name="min_content_height">250</property>
<child>
<object class="GtkTreeView" id="filtered_input_source_list">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">filtered_input_source_model</property>
<property name="headers_visible">False</property>
<property name="search_column">0</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="input_source_filter">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="secondary-icon-name">edit-find-symbolic</property>
<property name="secondary-icon-activatable">False</property>
<property name="secondary-icon-sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-5">ok-button</action-widget>
<action-widget response="-6">cancel-button</action-widget>
</action-widgets>
</object>
</interface>
/*
* Copyright (C) 2011 Red Hat, Inc.
*
* Written by: Matthias Clasen <mclasen@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 2, 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.
*/
#include <config.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "gnome-region-panel-input.h"
#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s))
static GtkWidget *input_chooser_new (GtkWindow *main_window);
static gboolean input_chooser_get_selected (GtkWidget *chooser,
GtkTreeModel **model,
GtkTreeIter *iter);
static gboolean
get_selected_iter (GtkBuilder *builder,
GtkTreeModel **model,
GtkTreeIter *iter)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources")));
return gtk_tree_selection_get_selected (selection, model, iter);
}
static gint
find_selected_layout_idx (GtkBuilder *builder)
{
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreePath *path;
gint idx;
if (!get_selected_iter (builder, &model, &iter))
return -1;
path = gtk_tree_model_get_path (model, &iter);
if (path == NULL)
return -1;
idx = gtk_tree_path_get_indices (path)[0];
gtk_tree_path_free (path);
return idx;
}
static void
update_button_sensitivity (GtkBuilder *builder)
{
GtkWidget *remove_button;
GtkWidget *up_button;
GtkWidget *down_button;
GtkWidget *show_button;
GtkTreeView *tv;
gint n_active;
gint index;
remove_button = WID("input_source_remove");
show_button = WID("input_source_show");
up_button = WID("input_source_move_up");
down_button = WID("input_source_move_down");
tv = GTK_TREE_VIEW (WID ("active_input_sources"));
n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL);
index = find_selected_layout_idx (builder);
gtk_widget_set_sensitive (remove_button, index >= 0 && n_active > 1);
gtk_widget_set_sensitive (show_button, index >= 0);
gtk_widget_set_sensitive (up_button, index > 0);
gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1);
}
static void
set_selected_path (GtkBuilder *builder,
GtkTreePath *path)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources")));
gtk_tree_selection_select_path (selection, path);
}
static void
chooser_response (GtkWidget *chooser, gint response_id, gpointer data)
{
GtkBuilder *builder = data;
if (response_id == GTK_RESPONSE_OK)
{
GtkTreeModel *model;
GtkTreeIter iter;
if (input_chooser_get_selected (chooser, &model, &iter))
{
GtkTreeView *my_tv;
GtkListStore *my_model;
GtkTreeIter my_iter;
gchar *name;
gtk_tree_model_get (model, &iter,
0, &name,
-1);
my_tv = GTK_TREE_VIEW (WID ("active_input_sources"));
my_model = GTK_LIST_STORE (gtk_tree_view_get_model (my_tv));
gtk_list_store_append (my_model, &my_iter);
gtk_list_store_set (my_model, &my_iter,
0, name,
-1);
g_free (name);
gtk_tree_selection_select_iter (gtk_tree_view_get_selection (my_tv), &my_iter);
update_button_sensitivity (builder);
}
else
{
g_debug ("nothing selected, nothing added");
}
}
gtk_widget_destroy (GTK_WIDGET (chooser));
}
static void
add_input (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkWidget *chooser;
GtkWidget *toplevel;
g_debug ("add an input source");
toplevel = gtk_widget_get_toplevel (WID ("region_notebook"));
chooser = input_chooser_new (GTK_WINDOW (toplevel));
g_signal_connect (chooser, "response",
G_CALLBACK (chooser_response), builder);
}
static void
remove_selected_input (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreePath *path;
g_debug ("remove selected input source");
if (get_selected_iter (builder, &model, &iter) == FALSE)
return;
path = gtk_tree_model_get_path (model, &iter);
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
if (!gtk_tree_model_get_iter (model, &iter, path))
gtk_tree_path_prev (path);
set_selected_path (builder, path);
gtk_tree_path_free (path);
update_button_sensitivity (builder);
}
static void
move_selected_input_up (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter, prev;
GtkTreePath *path;
g_debug ("move selected input source up");
if (!get_selected_iter (builder, &model, &iter))
return;
prev = iter;
if (!gtk_tree_model_iter_previous (model, &prev))
return;
path = gtk_tree_model_get_path (model, &prev);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &prev);
set_selected_path (builder, path);
gtk_tree_path_free (path);
update_button_sensitivity (builder);
}
static void
move_selected_input_down (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter, next;
GtkTreePath *path;
g_debug ("move selected input source down");
if (!get_selected_iter (builder, &model, &iter))
return;
next = iter;
if (!gtk_tree_model_iter_next (model, &next))
return;
path = gtk_tree_model_get_path (model, &next);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &next);
set_selected_path (builder, path);
gtk_tree_path_free (path);
update_button_sensitivity (builder);
}
static void
show_selected_layout (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter;
gchar *layout;
gchar *kbd_viewer_args;
g_debug ("show selected layout");
if (!get_selected_iter (builder, &model, &iter))
return;
gtk_tree_model_get (model, &iter,
0, &layout,
-1);
kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s", layout);
g_spawn_command_line_async (kbd_viewer_args, NULL);
g_free (kbd_viewer_args);
g_free (layout);
}
static gboolean
go_to_shortcuts (GtkLinkButton *button,
CcRegionPanel *panel)
{
CcShell *shell;
const gchar *argv[] = { "shortcuts", NULL };
GError *error = NULL;
shell = cc_panel_get_shell (CC_PANEL (panel));
if (!cc_shell_set_active_panel_from_id (shell, "keyboard", argv, &error))
{
g_warning ("Failed to activate Keyboard panel: %s", error->message);
g_error_free (error);
}
return TRUE;
}
void
setup_input_tabs (GtkBuilder *builder,
CcRegionPanel *panel)
{
GtkWidget *treeview;
GtkTreeViewColumn *column;
GtkCellRenderer *cell;
GtkListStore *store;
GtkTreeSelection *selection;
gchar *previous = NULL;
gchar *next = NULL;
GtkWidget *label;
/* set up the list of active inputs */
treeview = WID("active_input_sources");
column = gtk_tree_view_column_new ();
cell = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, cell, TRUE);
gtk_tree_view_column_add_attribute (column, cell, "text", 0);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
store = gtk_list_store_new (1, G_TYPE_STRING);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
g_signal_connect_swapped (selection, "changed",
G_CALLBACK (update_button_sensitivity), builder);
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
/* set up the buttons */
g_signal_connect (WID("input_source_add"), "clicked",
G_CALLBACK (add_input), builder);
g_signal_connect (WID("input_source_remove"), "clicked",
G_CALLBACK (remove_selected_input), builder);
g_signal_connect (WID("input_source_move_up"), "clicked",
G_CALLBACK (move_selected_input_up), builder);
g_signal_connect (WID("input_source_move_down"), "clicked",
G_CALLBACK (move_selected_input_down), builder);
g_signal_connect (WID("input_source_show"), "clicked",
G_CALLBACK (show_selected_layout), builder);
/* use an em dash is no shortcut */
if (!previous)
previous = g_strdup ("\342\200\224");
if (!next)
next = g_strdup ("\342\200\224");
label = WID("prev-source-shortcut-label");
gtk_label_set_label (GTK_LABEL (label), previous);
label = WID("next-source-shortcut-label");
gtk_label_set_label (GTK_LABEL (label), next);
g_free (previous);
g_free (next);
g_signal_connect (WID("jump-to-shortcuts"), "activate-link",
G_CALLBACK (go_to_shortcuts), panel);
}
static void
filter_clear (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
gpointer user_data)
{
gtk_entry_set_text (entry, "");
}
static gchar **search_pattern_list;
static void
filter_changed (GtkBuilder *builder)
{
GtkTreeModelFilter *filtered_model;
GtkWidget *filter_entry;
const gchar *pattern;
gchar *upattern;
filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder,
"filtered_input_source_model"));
filter_entry = WID ("input_source_filter");
pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry));
upattern = g_utf8_strup (pattern, -1);
if (!g_strcmp0 (pattern, ""))
g_object_set (G_OBJECT (filter_entry),
"secondary-icon-name", "edit-find-symbolic",
"secondary-icon-activatable", FALSE,
"secondary-icon-sensitive", FALSE,
NULL);
else
g_object_set (G_OBJECT (filter_entry),
"secondary-icon-name", "edit-clear-symbolic",
"secondary-icon-activatable", TRUE,
"secondary-icon-sensitive", TRUE,
NULL);
if (search_pattern_list != NULL)
g_strfreev (search_pattern_list);
search_pattern_list = g_strsplit (upattern, " ", -1);
g_free (upattern);
gtk_tree_model_filter_refilter (filtered_model);
}
static void
selection_changed (GtkTreeSelection *selection,
GtkBuilder *builder)
{
gtk_widget_set_sensitive (WID ("ok-button"),
gtk_tree_selection_get_selected (selection, NULL, NULL));
}
static void
row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
GtkBuilder *builder)
{
GtkWidget *add_button;
GtkWidget *dialog;
add_button = WID ("ok-button");
dialog = WID ("input_source_chooser");
if (gtk_widget_is_sensitive (add_button))
gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
}
static gboolean
filter_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{