Implement shortcut keys on emoji dialog

- Implemented Ctrl-[f|b|n|p|h|e|a|u] for cursor operations on emoji dialog
- Added XSetIOErrorHandler() for GNOME3 desktop
This commit is contained in:
Takao Fujiwara 2017-03-15 12:41:29 +09:00
parent 4b04cc4195
commit 6a3b677013
2 changed files with 550 additions and 1 deletions

View File

@ -1223,3 +1223,548 @@ index 8cecea8..5e126e9 100644
--
2.9.3
From ab6c38c192cdf22356cbf254b98fb5b3d9d9a680 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Wed, 15 Mar 2017 11:48:24 +0900
Subject: [PATCH] client/x11: Add XSetIOErrorHandler() for GNOME3 desktop
When log into GNOME3 desktop immediately after the system is booted,
ibus-daemon is sometimes alive but ibus-x11 is dead after log out
the session. Because gdk_x_io_error() is called as the callback of
XSetIOErrorHandler() in gtk/gdk/x11/gdkmain-x11.c in ibus-x11.
Now I assume the callback is called in logout.
BUG=https://github.com/ibus/ibus/issues/1907
Review URL: https://codereview.appspot.com/319490043
---
client/x11/main.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/client/x11/main.c b/client/x11/main.c
index a717a2c..159f430 100644
--- a/client/x11/main.c
+++ b/client/x11/main.c
@@ -2,6 +2,7 @@
/* vim:set et sts=4: */
/* ibus
* Copyright (C) 2007-2015 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
* Copyright (C) 2007-2015 Red Hat, Inc.
*
* main.c:
@@ -1131,6 +1132,20 @@ _xerror_handler (Display *dpy, XErrorEvent *e)
return 1;
}
+/* When log into GNOME3 desktop immediately after the system is booted,
+ * ibus-daemon is sometimes alive but ibus-x11 is dead after log out
+ * the session. Because gdk_x_io_error() is called as the callback of
+ * XSetIOErrorHandler() in gtk/gdk/x11/gdkmain-x11.c in ibus-x11.
+ * Now I assume the callback is called in logout.
+ */
+static int
+_xerror_io_handler (Display *dpy)
+{
+ if (_kill_daemon)
+ _atexit_cb ();
+ return 0;
+}
+
int
main (int argc, char **argv)
{
@@ -1146,6 +1161,7 @@ main (int argc, char **argv)
gtk_init (&argc, &argv);
XSetErrorHandler (_xerror_handler);
+ XSetIOErrorHandler (_xerror_io_handler);
while (1) {
static struct option long_options [] = {
--
2.9.3
From 58f6140f427815adc947a5bb5c7dea4f3e315ae8 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Wed, 15 Mar 2017 11:52:39 +0900
Subject: [PATCH] ui/gtk3: Implement shortcut keys on emoji dialog
- Implement Ctrl-f, Ctrl-b, Ctrl-n, Ctrl-p, Ctrl-h, Ctrh-e for
cursor movements; forward, back, next, previous, head, end
on emoji grid.
- Implement Ctrl-a and Shift+arrow for text selection on emoji annotation.
- Implement Ctrl-u to delete text on emoji annotation.
- Implement to delete a selected text on emoji annotation.
- Change to show page indices to candidate indices on emoji.
- Sorted emoji categories.
- Added timeout of m_enter_notify_enable = false to bring back mouse.
R=Shawn.P.Huang@gmail.com
Review URL: https://codereview.appspot.com/315700043
---
ui/gtk3/emojier.vala | 311 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 215 insertions(+), 96 deletions(-)
diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
index 5e126e9..7da96c7 100644
--- a/ui/gtk3/emojier.vala
+++ b/ui/gtk3/emojier.vala
@@ -214,6 +214,7 @@ class IBusEmojier : Gtk.Window {
private string[] m_favorites = {};
private bool m_enter_notify_enable = true;
private uint m_entry_notify_show_id;
+ private uint m_entry_notify_disable_id;
public signal void candidate_clicked(uint index, uint button, uint state);
public signal void loaded_emoji_dict();
@@ -525,6 +526,18 @@ class IBusEmojier : Gtk.Window {
show_category_list();
}
+ private string get_title_string(string orig) {
+ StringBuilder buff = new StringBuilder();
+ for (int i = 0; i < orig.char_count(); i++) {
+ unichar ch = orig.get_char(i);
+ if (i == 0)
+ buff.append_unichar(ch.toupper());
+ else
+ buff.append_unichar(ch);
+ }
+ return buff.str;
+ }
+
private void show_category_list() {
remove_all_children();
m_scrolled_window = new EScrolledWindow();
@@ -586,19 +599,14 @@ class IBusEmojier : Gtk.Window {
}
GLib.List<unowned string> categories =
m_category_to_emojis_dict.get_keys();
+ categories.sort((a, b) => {
+ return GLib.strcmp(_(a), _(b));
+ });
foreach (unowned string category in categories) {
EBoxRow row = new EBoxRow(category);
string locale_category = _(category);
- StringBuilder capital_category = new StringBuilder();
- for (int i = 0; i < locale_category.char_count(); i++) {
- unichar ch = locale_category.get_char(i);
- if (i == 0)
- capital_category.append_unichar(ch.toupper());
- else
- capital_category.append_unichar(ch);
- }
EPaddedLabel widget =
- new EPaddedLabel(capital_category.str,
+ new EPaddedLabel(get_title_string(locale_category),
Gtk.Align.CENTER);
row.add(widget);
m_list_box.add(row);
@@ -650,7 +658,7 @@ class IBusEmojier : Gtk.Window {
IBus.Text text = new IBus.Text.from_string(emoji);
m_lookup_table.append_candidate(text);
}
- m_backward = row.text;
+ m_backward = get_title_string(row.text);
}
show_candidate_panel();
}
@@ -759,9 +767,7 @@ class IBusEmojier : Gtk.Window {
uint page_end_pos = uint.min(page_start_pos + page_size, ncandidates);
if (m_backward != null) {
string backward_desc =
- "%s (%u / %u)".printf(m_backward,
- cursor / page_size + 1,
- ncandidates / page_size + 1);
+ "%s (%u / %u)".printf(m_backward, cursor, ncandidates - 1);
EPaddedLabel label = new EPaddedLabel(backward_desc,
Gtk.Align.CENTER,
TravelDirection.BACKWARD);
@@ -805,23 +811,23 @@ class IBusEmojier : Gtk.Window {
candidate_clicked(index, e.button, e.state);
return true;
});
- // m_enter_notify_enable is added because
- // enter_notify_event conflicts with keyboard operations.
- if (m_enter_notify_enable) {
- candidate_ebox.enter_notify_event.connect((e) => {
- m_lookup_table.set_cursor_pos(index);
- if (m_entry_notify_show_id > 0) {
+ candidate_ebox.enter_notify_event.connect((e) => {
+ // m_enter_notify_enable is added because
+ // enter_notify_event conflicts with keyboard operations.
+ if (!m_enter_notify_enable)
+ return true;
+ m_lookup_table.set_cursor_pos(index);
+ if (m_entry_notify_show_id > 0) {
GLib.Source.remove(m_entry_notify_show_id);
- }
- // If timeout is not added, memory leak happens and
- // button_press_event signal does not work above.
- m_entry_notify_show_id = GLib.Timeout.add(100, () => {
+ }
+ // If timeout is not added, memory leak happens and
+ // button_press_event signal does not work above.
+ m_entry_notify_show_id = GLib.Timeout.add(100, () => {
show_candidate_panel();
return false;
- });
- return true;
});
- }
+ return true;
+ });
grid.attach(candidate_ebox,
n % (int)EMOJI_GRID_PAGE, n / (int)EMOJI_GRID_PAGE,
1, 1);
@@ -844,16 +850,23 @@ class IBusEmojier : Gtk.Window {
widget.show_all();
return;
}
- unowned IBus.EmojiData data =
+ unowned IBus.EmojiData? data =
m_emoji_to_data_dict.lookup(candidate.text);
- unowned string description = data.get_description();
- if (description != "") {
+ if (data == null) {
+ // TODO: Provide a description for the favorite emojis.
EPaddedLabel widget = new EPaddedLabel(
- _("Description: %s").printf(description),
+ _("Description: %s").printf(_("None")),
Gtk.Align.START);
m_vbox.add(widget);
widget.show_all();
+ return;
}
+ unowned string description = data.get_description();
+ EPaddedLabel desc_widget = new EPaddedLabel(
+ _("Description: %s").printf(description),
+ Gtk.Align.START);
+ m_vbox.add(desc_widget);
+ desc_widget.show_all();
unowned GLib.SList<unowned string>? annotations =
data.get_annotations();
GLib.StringBuilder buff = new GLib.StringBuilder();
@@ -922,8 +935,21 @@ class IBusEmojier : Gtk.Window {
m_result = text.text;
}
- private void candidate_panel_cursor_down() {
+ private void enter_notify_disable_with_timer() {
+ // Enable keyboard operation and disable mouse operation.
m_enter_notify_enable = false;
+ if (m_entry_notify_disable_id > 0) {
+ GLib.Source.remove(m_entry_notify_disable_id);
+ }
+ // Bring back the mouse operation after a timeout.
+ m_entry_notify_show_id = GLib.Timeout.add(100, () => {
+ m_enter_notify_enable = true;
+ return false;
+ });
+ }
+
+ private void candidate_panel_cursor_down() {
+ enter_notify_disable_with_timer();
uint ncandidates = m_lookup_table.get_number_of_candidates();
uint cursor = m_lookup_table.get_cursor_pos();
if ((cursor + EMOJI_GRID_PAGE) < ncandidates) {
@@ -937,11 +963,11 @@ class IBusEmojier : Gtk.Window {
}
private void candidate_panel_cursor_up() {
- m_enter_notify_enable = false;
+ enter_notify_disable_with_timer();
int ncandidates = (int)m_lookup_table.get_number_of_candidates();
int cursor = (int)m_lookup_table.get_cursor_pos();
int highest_pos =
- (ncandidates / (int)EMOJI_GRID_PAGE * (int)EMOJI_GRID_PAGE)
+ ((ncandidates - 1)/ (int)EMOJI_GRID_PAGE * (int)EMOJI_GRID_PAGE)
+ (cursor % (int)EMOJI_GRID_PAGE);
if ((cursor - (int)EMOJI_GRID_PAGE) >= 0) {
m_lookup_table.set_cursor_pos(cursor - (int)EMOJI_GRID_PAGE);
@@ -967,13 +993,119 @@ class IBusEmojier : Gtk.Window {
show_category_list();
}
+ private bool key_press_cursor_horizontal(uint keyval,
+ uint modifiers) {
+ assert (keyval == Gdk.Key.Left || keyval == Gdk.Key.Right);
+
+ if (m_candidate_panel_is_visible) {
+ enter_notify_disable_with_timer();
+ if (keyval == Gdk.Key.Left)
+ m_lookup_table.cursor_up();
+ else if (keyval == Gdk.Key.Right)
+ m_lookup_table.cursor_down();
+ show_candidate_panel();
+ } else if (m_entry.get_text().len() > 0) {
+ int step = 0;
+ if (keyval == Gdk.Key.Left)
+ step = -1;
+ else if (keyval == Gdk.Key.Right)
+ step = 1;
+ GLib.Signal.emit_by_name(
+ m_entry, "move-cursor",
+ Gtk.MovementStep.VISUAL_POSITIONS,
+ step,
+ (modifiers & Gdk.ModifierType.SHIFT_MASK) != 0
+ ? true : false);
+ } else {
+ // For Gdk.Key.f and Gdk.Key.b
+ if (keyval == Gdk.Key.Left)
+ keyval = Gdk.Key.Up;
+ else if (keyval == Gdk.Key.Right)
+ keyval = Gdk.Key.Down;
+ category_list_cursor_move(keyval);
+ }
+ return true;
+ }
+
+ private bool key_press_cursor_vertical(uint keyval) {
+ assert (keyval == Gdk.Key.Down || keyval == Gdk.Key.Up);
+
+ if (m_candidate_panel_is_visible) {
+ if (keyval == Gdk.Key.Down)
+ candidate_panel_cursor_down();
+ else if (keyval == Gdk.Key.Up)
+ candidate_panel_cursor_up();
+ } else {
+ category_list_cursor_move(keyval);
+ }
+ return true;
+ }
+
+ private bool key_press_cursor_home_end(uint keyval,
+ uint modifiers) {
+ assert (keyval == Gdk.Key.Home || keyval == Gdk.Key.End);
+
+ if (m_candidate_panel_is_visible) {
+ enter_notify_disable_with_timer();
+ if (keyval == Gdk.Key.Home) {
+ m_lookup_table.set_cursor_pos(0);
+ } else if (keyval == Gdk.Key.End) {
+ uint ncandidates = m_lookup_table.get_number_of_candidates();
+ m_lookup_table.set_cursor_pos(ncandidates - 1);
+ }
+ show_candidate_panel();
+ return true;
+ }
+ if (m_entry.get_text().len() > 0) {
+ int step = 0;
+ if (keyval == Gdk.Key.Home)
+ step = -1;
+ else if (keyval == Gdk.Key.End)
+ step = 1;
+ GLib.Signal.emit_by_name(
+ m_entry, "move-cursor",
+ Gtk.MovementStep.DISPLAY_LINE_ENDS,
+ step,
+ (modifiers & Gdk.ModifierType.SHIFT_MASK) != 0
+ ? true : false);
+ return true;
+ }
+ return false;
+ }
+
+ private bool key_press_cursor_escape() {
+ if (m_candidate_panel_is_visible) {
+ hide_candidate_panel();
+ return true;
+ } else if (m_current_category_type == CategoryType.LANG) {
+ m_current_category_type = CategoryType.EMOJI;
+ show_candidate_panel();
+ return true;
+ } else if (m_entry.get_text().length == 0) {
+ m_loop.quit();
+ hide_candidate_panel();
+ return true;
+ }
+ m_entry.delete_text(0, -1);
+ return true;
+ }
+
private void entry_enter_keyval(uint keyval) {
unichar ch = IBus.keyval_to_unicode(keyval);
- if (!ch.isgraph())
+ if (ch.iscntrl())
return;
string str = ch.to_string();
// what gtk_entry_commit_cb() do
+ if (m_entry.get_selection_bounds(null, null)) {
+ m_entry.delete_selection();
+ } else {
+ if (m_entry.get_overwrite_mode()) {
+ uint text_length = m_entry.get_buffer().get_length();
+ if (m_entry.cursor_position < text_length)
+ m_entry.delete_from_cursor(Gtk.DeleteType.CHARS, 1);
+ }
+ }
int pos = m_entry.get_position();
m_entry.insert_text(str, -1, ref pos);
m_entry.set_position(pos);
@@ -1084,19 +1216,8 @@ class IBusEmojier : Gtk.Window {
}
switch (keyval) {
case Gdk.Key.Escape:
- if (m_candidate_panel_is_visible) {
- hide_candidate_panel();
- return true;
- } else if (m_current_category_type == CategoryType.LANG) {
- m_current_category_type = CategoryType.EMOJI;
- show_candidate_panel();
+ if (key_press_cursor_escape())
return true;
- } else if (m_entry.get_text().length == 0) {
- m_loop.quit();
- hide_candidate_panel();
- return true;
- }
- m_entry.delete_text(0, -1);
break;
case Gdk.Key.Return:
if (m_candidate_panel_is_visible) {
@@ -1126,7 +1247,7 @@ class IBusEmojier : Gtk.Window {
break;
}
if (m_candidate_panel_is_visible) {
- m_enter_notify_enable = false;
+ enter_notify_disable_with_timer();
m_lookup_table.cursor_down();
show_candidate_panel();
}
@@ -1135,48 +1256,20 @@ class IBusEmojier : Gtk.Window {
}
return true;
case Gdk.Key.Right:
- if (m_candidate_panel_is_visible) {
- m_enter_notify_enable = false;
- m_lookup_table.cursor_down();
- show_candidate_panel();
- return true;
- }
- if (m_entry.get_text().len() > 0) {
- GLib.Signal.emit_by_name(m_entry, "move-cursor",
- Gtk.MovementStep.VISUAL_POSITIONS,
- 1, false);
- return true;
- }
- break;
+ key_press_cursor_horizontal(keyval, modifiers);
+ return true;
case Gdk.Key.Left:
- if (m_candidate_panel_is_visible) {
- m_enter_notify_enable = false;
- m_lookup_table.cursor_up();
- show_candidate_panel();
- return true;
- }
- if (m_entry.get_text().len() > 0) {
- GLib.Signal.emit_by_name(m_entry, "move-cursor",
- Gtk.MovementStep.VISUAL_POSITIONS,
- -1, false);
- return true;
- }
- break;
+ key_press_cursor_horizontal(keyval, modifiers);
+ return true;
case Gdk.Key.Down:
- if (m_candidate_panel_is_visible)
- candidate_panel_cursor_down();
- else
- category_list_cursor_move(Gdk.Key.Down);
+ key_press_cursor_vertical(keyval);
return true;
case Gdk.Key.Up:
- if (m_candidate_panel_is_visible)
- candidate_panel_cursor_up();
- else
- category_list_cursor_move(Gdk.Key.Up);
+ key_press_cursor_vertical(keyval);
return true;
case Gdk.Key.Page_Down:
if (m_candidate_panel_is_visible) {
- m_enter_notify_enable = false;
+ enter_notify_disable_with_timer();
m_lookup_table.page_down();
show_candidate_panel();
return true;
@@ -1184,33 +1277,59 @@ class IBusEmojier : Gtk.Window {
break;
case Gdk.Key.Page_Up:
if (m_candidate_panel_is_visible) {
- m_enter_notify_enable = false;
+ enter_notify_disable_with_timer();
m_lookup_table.page_up();
show_candidate_panel();
return true;
}
break;
case Gdk.Key.Home:
- if (m_entry.get_text().len() > 0) {
- GLib.Signal.emit_by_name(m_entry, "move-cursor",
- Gtk.MovementStep.DISPLAY_LINE_ENDS,
- -1, false);
+ if (key_press_cursor_home_end(keyval, modifiers))
return true;
- }
break;
case Gdk.Key.End:
- if (m_entry.get_text().len() > 0) {
- GLib.Signal.emit_by_name(m_entry, "move-cursor",
- Gtk.MovementStep.DISPLAY_LINE_ENDS,
- 1, false);
+ if (key_press_cursor_home_end(keyval, modifiers))
return true;
- }
- break;
- default:
- entry_enter_keyval(keyval);
break;
}
+ if ((modifiers & Gdk.ModifierType.CONTROL_MASK) != 0) {
+ switch (keyval) {
+ case Gdk.Key.f:
+ key_press_cursor_horizontal(Gdk.Key.Right, modifiers);
+ return true;
+ case Gdk.Key.b:
+ key_press_cursor_horizontal(Gdk.Key.Left, modifiers);
+ return true;
+ case Gdk.Key.n:
+ key_press_cursor_vertical(Gdk.Key.Down);
+ return true;
+ case Gdk.Key.p:
+ key_press_cursor_vertical(Gdk.Key.Up);
+ return true;
+ case Gdk.Key.h:
+ if (key_press_cursor_home_end(Gdk.Key.Home, modifiers))
+ return true;
+ break;
+ case Gdk.Key.e:
+ if (key_press_cursor_home_end(Gdk.Key.End, modifiers))
+ return true;
+ break;
+ case Gdk.Key.u:
+ if (key_press_cursor_escape())
+ return true;
+ break;
+ case Gdk.Key.a:
+ if (m_entry.get_text().len() > 0) {
+ m_entry.select_region(0, -1);
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ entry_enter_keyval(keyval);
return true;
}
--
2.9.3

View File

@ -28,7 +28,7 @@
Name: ibus
Version: 1.5.15
Release: 3%{?dist}
Release: 4%{?dist}
Summary: Intelligent Input Bus for Linux OS
License: LGPLv2+
Group: System Environment/Libraries
@ -426,6 +426,10 @@ gtk-query-immodules-3.0-%{__isa_bits} --update-cache &> /dev/null || :
%{_datadir}/gtk-doc/html/*
%changelog
* Wed Mar 15 2017 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.15-4
- Implemented Ctrl-[f|b|n|p|h|e|a|u] for cursor operations on emoji dialog
- Added XSetIOErrorHandler() for GNOME3 desktop
* Mon Mar 13 2017 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.15-3
- Emoji dialog enhancements and bug fixes
Fixed ibus_emoji_dict_load() API.