Commit 36c3a4dd authored by Alberts Muktupāvels's avatar Alberts Muktupāvels
Browse files

input-sources: implement accelerator_activated_cb

parent 0a777f02
......@@ -4,6 +4,16 @@ GfPopupWindow
border: 1px solid rgba(0, 0, 0, 0.23);
}
GfInputSourcePopup #input-source
{
font-size: 22px;
}
GfInputSourcePopup #input-source:selected
{
border-radius: 10px;
}
FlashbackLabelWindow
{
font-size: 40px;
......
......@@ -4,6 +4,16 @@ GfPopupWindow
border: 1px solid rgba(0, 0, 0, 0.23);
}
GfInputSourcePopup #input-source
{
font-size: 22px;
}
GfInputSourcePopup #input-source:selected
{
border-radius: 10px;
}
FlashbackLabelWindow
{
font-size: 40px;
......
......@@ -25,6 +25,8 @@ libinput_sources_la_SOURCES = \
gf-input-sources.h \
gf-input-source-manager.c \
gf-input-source-manager.h \
gf-input-source-popup.c \
gf-input-source-popup.h \
gf-input-source-settings.c \
gf-input-source-settings.h \
gf-keyboard-manager.c \
......
......@@ -26,6 +26,7 @@
#include "gf-ibus-manager.h"
#include "gf-input-source.h"
#include "gf-input-source-manager.h"
#include "gf-input-source-popup.h"
#include "gf-input-source-settings.h"
#include "gf-keyboard-manager.h"
......@@ -70,6 +71,8 @@ struct _GfInputSourceManager
GList *mru_sources;
GList *mru_sources_backup;
GtkWidget *popup;
};
enum
......@@ -209,12 +212,54 @@ switch_input_backward_changed_cb (GSettings *settings,
manager->switch_source_backward_action = action;
}
static void
fade_finished_cb (GfInputSourcePopup *popup,
gpointer user_data)
{
GfInputSourceManager *manager;
GtkWidget *widget;
manager = GF_INPUT_SOURCE_MANAGER (user_data);
widget = GTK_WIDGET (popup);
gtk_widget_destroy (widget);
manager->popup = NULL;
}
static void
accelerator_activated_cb (GfKeybindings *keybindings,
guint action,
GVariant *parameters,
gpointer user_data)
{
GfInputSourceManager *manager;
gboolean backward;
guint keyval;
guint modifiers;
manager = GF_INPUT_SOURCE_MANAGER (user_data);
if (action != manager->switch_source_action &&
action != manager->switch_source_backward_action)
return;
if (g_list_length (manager->mru_sources) < 2)
return;
if (manager->popup != NULL)
return;
backward = action == manager->switch_source_backward_action;
keyval = gf_keybindings_get_keyval (manager->keybindings, action);
modifiers = gf_keybindings_get_modifiers (manager->keybindings, action);
manager->popup = gf_input_source_popup_new (manager->mru_sources, backward,
keyval, modifiers);
g_signal_connect (manager->popup, "fade-finished",
G_CALLBACK (fade_finished_cb), manager);
gtk_widget_show (manager->popup);
}
static void
......@@ -371,10 +416,47 @@ get_source_info_list (GfInputSourceManager *manager)
return list;
}
static gboolean
compare_sources (GfInputSource *source1,
GfInputSource *source2)
{
const gchar *type1;
const gchar *type2;
const gchar *id1;
const gchar *id2;
type1 = gf_input_source_get_source_type (source1);
type2 = gf_input_source_get_source_type (source2);
id1 = gf_input_source_get_id (source1);
id2 = gf_input_source_get_id (source2);
if (g_strcmp0 (type1, type2) == 0 && g_strcmp0 (id1, id2) == 0)
return TRUE;
return FALSE;
}
static void
current_input_source_changed (GfInputSourceManager *manager,
GfInputSource *new_source)
{
GList *l;
for (l = manager->mru_sources; l != NULL; l = g_list_next (l))
{
GfInputSource *source;
source = GF_INPUT_SOURCE (l->data);
if (compare_sources (source, new_source))
{
manager->mru_sources = g_list_remove_link (manager->mru_sources, l);
manager->mru_sources = g_list_concat (l, manager->mru_sources);
break;
}
}
}
static void
......@@ -532,27 +614,6 @@ sources_by_name_free (gpointer key,
return TRUE;
}
static gboolean
compare_sources (GfInputSource *source1,
GfInputSource *source2)
{
const gchar *type1;
const gchar *type2;
const gchar *id1;
const gchar *id2;
type1 = gf_input_source_get_source_type (source1);
type2 = gf_input_source_get_source_type (source2);
id1 = gf_input_source_get_id (source1);
id2 = gf_input_source_get_id (source2);
if (g_strcmp0 (type1, type2) == 0 && g_strcmp0 (id1, id2) == 0)
return TRUE;
return FALSE;
}
static void
update_mru_sources_list (GfInputSourceManager *manager)
{
......@@ -591,8 +652,6 @@ update_mru_sources_list (GfInputSourceManager *manager)
if (!compare_sources (source1, source2))
continue;
g_warning ("equal...");
source = g_list_remove_link (sources, l2);
mru_sources = g_list_concat (mru_sources, source);
......@@ -876,6 +935,12 @@ gf_input_source_manager_dispose (GObject *object)
manager->mru_sources_backup = NULL;
}
if (manager->popup != NULL)
{
gtk_widget_destroy (manager->popup);
manager->popup = NULL;
}
G_OBJECT_CLASS (gf_input_source_manager_parent_class)->dispose (object);
}
......
/*
* Copyright (C) 2015 Alberts Muktupāvels
*
* 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/>.
*/
#include "config.h"
#include <gdk/gdkx.h>
#include "gf-input-source.h"
#include "gf-input-source-popup.h"
struct _GfInputSourcePopup
{
GfPopupWindow parent;
GdkDevice *pointer;
GdkDevice *keyboard;
GList *mru_sources;
gboolean backward;
guint keyval;
guint modifiers;
GtkWidget *sources_box;
gint selected_index;
GtkWidget *selected_name;
};
enum
{
PROP_0,
PROP_MRU_SOURCES,
PROP_BACKWARD,
PROP_KEYVAL,
PROP_MODIFIERS,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP] = { NULL };
G_DEFINE_TYPE (GfInputSourcePopup, gf_input_source_popup, GF_TYPE_POPUP_WINDOW)
static gboolean
is_mouse_over_input_source (GfInputSourcePopup *popup,
gdouble x,
gdouble y,
gint *index)
{
gboolean mouse_over;
GList *sources;
GList *l;
mouse_over = FALSE;
sources = gtk_container_get_children (GTK_CONTAINER (popup->sources_box));
for (l = sources; l != NULL; l = g_list_next (l))
{
GtkWidget *widget;
GtkAllocation rect;
widget = GTK_WIDGET (l->data);
gtk_widget_get_allocation (widget, &rect);
if (x >= rect.x && x <= rect.x + rect.width &&
y >= rect.y && y <= rect.y + rect.height)
{
gpointer pointer;
pointer = g_object_get_data (G_OBJECT (widget), "index");
*index = GPOINTER_TO_INT (pointer);
mouse_over = TRUE;
break;
}
}
g_list_free (sources);
return mouse_over;
}
static void
selected_source_changed (GfInputSourcePopup *popup)
{
GtkWidget *widget;
GfInputSource *source;
const gchar *display_name;
widget = GTK_WIDGET (popup);
source = (GfInputSource *) g_list_nth_data (popup->mru_sources,
popup->selected_index);
display_name = gf_input_source_get_display_name (source);
gtk_label_set_text (GTK_LABEL (popup->selected_name), display_name);
gtk_widget_queue_draw (widget);
}
static gboolean
draw_cb (GtkWidget *widget,
cairo_t *cr,
gpointer user_data)
{
GfInputSourcePopup *popup;
GtkStyleContext *context;
gpointer index;
popup = GF_INPUT_SOURCE_POPUP (user_data);
context = gtk_widget_get_style_context (widget);
index = g_object_get_data (G_OBJECT (widget), "index");
if (popup->selected_index == GPOINTER_TO_INT (index))
gtk_style_context_set_state (context, GTK_STATE_FLAG_SELECTED);
else
gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL);
return FALSE;
}
static void
setup_popup_window (GfInputSourcePopup *popup)
{
GfInputSource *selected_source;
GtkWidget *vertical_box;
gint index;
GList *l;
const gchar *display_name;
selected_source = (GfInputSource *) g_list_nth_data (popup->mru_sources,
popup->selected_index);
gtk_container_set_border_width (GTK_CONTAINER (popup), 12);
vertical_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (popup), vertical_box);
popup->sources_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vertical_box), popup->sources_box, TRUE, TRUE, 0);
index = 0;
for (l = popup->mru_sources; l != NULL; l = g_list_next (l))
{
GfInputSource *source;
const gchar *short_name;
GtkWidget *label;
source = (GfInputSource *) l->data;
short_name = gf_input_source_get_short_name (source);
label = gtk_label_new (short_name);
g_object_set_data (G_OBJECT (label), "index", GINT_TO_POINTER (index));
g_signal_connect (label, "draw", G_CALLBACK (draw_cb), popup);
gtk_widget_set_name (label, "input-source");
gtk_widget_set_size_request (label, 120, 120);
gtk_box_pack_start (GTK_BOX (popup->sources_box), label, FALSE, FALSE, 0);
index++;
}
display_name = gf_input_source_get_display_name (selected_source);
popup->selected_name = gtk_label_new (display_name);
gtk_widget_set_halign (popup->selected_name, GTK_ALIGN_CENTER);
gtk_box_pack_start (GTK_BOX (vertical_box), popup->selected_name, FALSE,
FALSE, 0);
gtk_widget_show_all (vertical_box);
}
static void
ungrab (GfInputSourcePopup *popup)
{
if (popup->pointer != NULL)
{
gdk_device_ungrab (popup->pointer, GDK_CURRENT_TIME);
popup->pointer = NULL;
}
if (popup->keyboard != NULL)
{
gdk_device_ungrab (popup->keyboard, GDK_CURRENT_TIME);
popup->keyboard = NULL;
}
}
static void
activate_selected_input_source (GfInputSourcePopup *popup)
{
GfPopupWindow *popup_window;
GfInputSource *source;
popup_window = GF_POPUP_WINDOW (popup);
source = (GfInputSource *) g_list_nth_data (popup->mru_sources,
popup->selected_index);
ungrab (popup);
gf_popup_window_fade_start (popup_window);
gf_input_source_activate (source);
}
static void
gf_input_source_popup_constructed (GObject *object)
{
GfInputSourcePopup *popup;
popup = GF_INPUT_SOURCE_POPUP (object);
G_OBJECT_CLASS (gf_input_source_popup_parent_class)->constructed (object);
if (popup->backward)
popup->selected_index = g_list_length (popup->mru_sources) - 1;
else
popup->selected_index = 1;
setup_popup_window (popup);
}
static void
gf_input_source_popup_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GfInputSourcePopup *popup;
popup = GF_INPUT_SOURCE_POPUP (object);
switch (prop_id)
{
case PROP_MRU_SOURCES:
popup->mru_sources = g_value_get_pointer (value);
break;
case PROP_BACKWARD:
popup->backward = g_value_get_boolean (value);
break;
case PROP_KEYVAL:
popup->keyval = g_value_get_uint (value);
break;
case PROP_MODIFIERS:
popup->modifiers = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gf_input_source_popup_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
GfInputSourcePopup *popup;
GfPopupWindow *popup_window;
gint index;
popup = GF_INPUT_SOURCE_POPUP (widget);
popup_window = GF_POPUP_WINDOW (widget);
if (!is_mouse_over_input_source (popup, event->x, event->y, &index))
{
gf_popup_window_fade_start (popup_window);
return TRUE;
}
popup->selected_index = index;
selected_source_changed (popup);
activate_selected_input_source (popup);
return TRUE;
}
static gboolean
gf_input_source_popup_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
GfInputSourcePopup *popup;
gint index;
gint last_index;
popup = GF_INPUT_SOURCE_POPUP (widget);
index = popup->selected_index;
if (event->keyval == GDK_KEY_Left)
{
index--;
}
else if (event->keyval == GDK_KEY_Right)
{
index++;
}
else if (event->keyval == popup->keyval)
{
if (popup->backward)
index--;
else
index++;
}
last_index = g_list_length (popup->mru_sources) - 1;
if (index > last_index)
index = 0;
else if (index < 0)
index = last_index;
popup->selected_index = index;
selected_source_changed (popup);
return TRUE;
}
static gboolean
gf_input_source_popup_key_release_event (GtkWidget *widget,
GdkEventKey *event)
{
GfInputSourcePopup *popup;
GdkModifierType modifiers;
if (!event->is_modifier)
return TRUE;
popup = GF_INPUT_SOURCE_POPUP (widget);
modifiers = gtk_accelerator_get_default_mod_mask ();
if ((event->state & modifiers) != popup->modifiers)
return TRUE;
activate_selected_input_source (popup);
return TRUE;
}
static gboolean
gf_input_source_popup_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event)
{
GfInputSourcePopup *popup;
gint index;
popup = GF_INPUT_SOURCE_POPUP (widget);
if (!is_mouse_over_input_source (popup, event->x, event->y, &index))
return TRUE;
popup->selected_index = index;
selected_source_changed (popup);
return TRUE;
}
static void
gf_input_source_popup_show (GtkWidget *widget)
{
GfInputSourcePopup *popup;
GdkDisplay *display;
GdkDeviceManager *manager;
GdkWindow *window;
GdkGrabStatus status;
popup = GF_INPUT_SOURCE_POPUP (widget);
GTK_WIDGET_CLASS (gf_input_source_popup_parent_class)->show (widget);
display = gdk_display_get_default ();
manager = gdk_display_get_device_manager (display);
window = gtk_widget_get_window (widget);
popup->pointer = gdk_device_manager_get_client_pointer (manager);