LEFT | RIGHT |
1 /* vim:set et sts=4 sw=4: | 1 /* vim:set et sts=4 sw=4: |
2 * | 2 * |
3 * ibus - The Input Bus | 3 * ibus - The Input Bus |
4 * | 4 * |
5 * Copyright (c) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com> | 5 * Copyright (c) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com> |
6 * | 6 * |
7 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Lesser General Public | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
10 * version 2.1 of the License, or (at your option) any later version. | 10 * version 2.1 of the License, or (at your option) any later version. |
(...skipping 21 matching lines...) Expand all Loading... |
32 ); | 32 ); |
33 } | 33 } |
34 } | 34 } |
35 private class EListBox : Gtk.ListBox { | 35 private class EListBox : Gtk.ListBox { |
36 public EListBox() { | 36 public EListBox() { |
37 GLib.Object( | 37 GLib.Object( |
38 vexpand : true, | 38 vexpand : true, |
39 halign : Gtk.Align.FILL, | 39 halign : Gtk.Align.FILL, |
40 valign : Gtk.Align.FILL | 40 valign : Gtk.Align.FILL |
41 ); | 41 ); |
| 42 this.motion_notify_event.connect((e) => { |
| 43 #if VALA_0_24 |
| 44 Gdk.EventMotion pe = e; |
| 45 #else |
| 46 Gdk.EventMotion *pe = &e; |
| 47 #endif |
| 48 if (m_mouse_x == pe.x_root && m_mouse_y == pe.y_root) |
| 49 return false; |
| 50 m_mouse_x = pe.x_root; |
| 51 m_mouse_y = pe.y_root; |
| 52 var row = this.get_row_at_y((int)e.y); |
| 53 if (row != null) |
| 54 this.select_row(row); |
| 55 return false; |
| 56 }); |
| 57 this.enter_notify_event.connect((e) => { |
| 58 // avoid gtk_button_update_state() |
| 59 return true; |
| 60 }); |
42 } | 61 } |
43 } | 62 } |
44 private class EBoxRow : Gtk.ListBoxRow { | 63 private class EBoxRow : Gtk.ListBoxRow { |
45 public EBoxRow(string text) { | 64 public EBoxRow(string text) { |
46 this.text = text; | 65 this.text = text; |
47 } | 66 } |
48 | 67 |
49 public string text { get; set; } | 68 public string text { get; set; } |
50 } | 69 } |
51 private class EScrolledWindow : Gtk.ScrolledWindow { | 70 private class EScrolledWindow : Gtk.ScrolledWindow { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 public override void get_preferred_height(out int minimum_height, | 140 public override void get_preferred_height(out int minimum_height, |
122 out int natural_height) { | 141 out int natural_height) { |
123 get_preferred_size_with_hb(null, null, | 142 get_preferred_size_with_hb(null, null, |
124 out minimum_height, | 143 out minimum_height, |
125 out natural_height); | 144 out natural_height); |
126 } | 145 } |
127 public override bool draw(Cairo.Context cr) { | 146 public override bool draw(Cairo.Context cr) { |
128 if (m_fontset == null) | 147 if (m_fontset == null) |
129 return true; | 148 return true; |
130 if (m_requisition == null) | 149 if (m_requisition == null) |
131 return true; | 150 return true; |
132 if (m_requisition.cairo_lines == null) | 151 if (m_requisition.cairo_lines == null) |
133 return true; | 152 return true; |
134 var style_context = get_style_context(); | 153 var style_context = get_style_context(); |
135 Gtk.Allocation allocation; | 154 Gtk.Allocation allocation; |
136 get_allocation(out allocation); | 155 get_allocation(out allocation); |
137 style_context.render_background(cr, | 156 style_context.render_background(cr, |
138 0, 0, | 157 0, 0, |
139 allocation.width, | 158 allocation.width, |
140 allocation.height); | 159 allocation.height); |
141 Gdk.RGBA *normal_fg = null; | 160 Gdk.RGBA *normal_fg = null; |
142 style_context.get(Gtk.StateFlags.NORMAL, | 161 style_context.get(Gtk.StateFlags.NORMAL, |
143 "color", | 162 "color", |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 private GLib.MainLoop? m_loop; | 321 private GLib.MainLoop? m_loop; |
303 private string? m_result; | 322 private string? m_result; |
304 private string? m_unicode_point = null; | 323 private string? m_unicode_point = null; |
305 private bool m_candidate_panel_is_visible; | 324 private bool m_candidate_panel_is_visible; |
306 private int m_category_active_index; | 325 private int m_category_active_index; |
307 private IBus.LookupTable m_lookup_table; | 326 private IBus.LookupTable m_lookup_table; |
308 private Gtk.Label[] m_candidates; | 327 private Gtk.Label[] m_candidates; |
309 private bool m_enter_notify_enable = true; | 328 private bool m_enter_notify_enable = true; |
310 private uint m_entry_notify_show_id; | 329 private uint m_entry_notify_show_id; |
311 private uint m_entry_notify_disable_id; | 330 private uint m_entry_notify_disable_id; |
| 331 protected static double m_mouse_x; |
| 332 protected static double m_mouse_y; |
312 | 333 |
313 public signal void candidate_clicked(uint index, uint button, uint state); | 334 public signal void candidate_clicked(uint index, uint button, uint state); |
314 | 335 |
315 public IBusEmojier() { | 336 public IBusEmojier() { |
316 GLib.Object( | 337 GLib.Object( |
317 type : Gtk.WindowType.TOPLEVEL, | 338 type : Gtk.WindowType.TOPLEVEL, |
318 events : Gdk.EventMask.KEY_PRESS_MASK | | 339 events : Gdk.EventMask.KEY_PRESS_MASK | |
319 Gdk.EventMask.KEY_RELEASE_MASK | | 340 Gdk.EventMask.KEY_RELEASE_MASK | |
320 Gdk.EventMask.BUTTON_PRESS_MASK | | 341 Gdk.EventMask.BUTTON_PRESS_MASK | |
321 Gdk.EventMask.BUTTON_RELEASE_MASK, | 342 Gdk.EventMask.BUTTON_RELEASE_MASK, |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 | 665 |
645 private static void update_category_to_emojis_dict(IBus.EmojiData data, | 666 private static void update_category_to_emojis_dict(IBus.EmojiData data, |
646 string lang) { | 667 string lang) { |
647 string emoji = data.get_emoji(); | 668 string emoji = data.get_emoji(); |
648 string category = data.get_category(); | 669 string category = data.get_category(); |
649 if (category == "") | 670 if (category == "") |
650 category = EMOJI_CATEGORY_OTHERS; | 671 category = EMOJI_CATEGORY_OTHERS; |
651 if (lang == "en") { | 672 if (lang == "en") { |
652 bool has_variant = false; | 673 bool has_variant = false; |
653 foreach (unichar ch in EMOJI_VARIANT_LIST) { | 674 foreach (unichar ch in EMOJI_VARIANT_LIST) { |
654 if (emoji.chr(-1, ch) != null) { | 675 if (emoji.index_of_char(ch) >= 0) { |
655 has_variant = true; | 676 has_variant = true; |
656 break; | 677 break; |
657 } | 678 } |
658 } | 679 } |
659 // If emoji includes variants (skin colors and items), | 680 // If emoji includes variants (skin colors and items), |
660 // it's escaped in m_emoji_to_emoji_variants_dict and | 681 // it's escaped in m_emoji_to_emoji_variants_dict and |
661 // not shown by default. | 682 // not shown by default. |
662 if (has_variant) { | 683 if (has_variant) { |
663 unichar base_ch = emoji.get_char(); | 684 unichar base_ch = emoji.get_char(); |
664 string base_emoji = base_ch.to_string(); | 685 string base_emoji = base_ch.to_string(); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 buttons_hbox.pack_start(prev_button, false, false, 0); | 872 buttons_hbox.pack_start(prev_button, false, false, 0); |
852 buttons_hbox.pack_start(next_button, false, false, 0); | 873 buttons_hbox.pack_start(next_button, false, false, 0); |
853 m_vbox.pack_start(buttons_hbox, false, false, 0); | 874 m_vbox.pack_start(buttons_hbox, false, false, 0); |
854 buttons_hbox.show_all(); | 875 buttons_hbox.show_all(); |
855 } | 876 } |
856 | 877 |
857 | 878 |
858 private bool check_unicode_point() { | 879 private bool check_unicode_point() { |
859 string annotation = m_entry.get_text(); | 880 string annotation = m_entry.get_text(); |
860 m_unicode_point = null; | 881 m_unicode_point = null; |
861 var buff = new GLib.StringBuilder(); | 882 // Add "0x" because uint64.ascii_strtoull() is not accessible |
| 883 // and need to use uint64.parse() |
| 884 var buff = new GLib.StringBuilder("0x"); |
862 var retval = new GLib.StringBuilder(); | 885 var retval = new GLib.StringBuilder(); |
863 for (int i = 0; i < annotation.char_count(); i++) { | 886 for (int i = 0; i < annotation.char_count(); i++) { |
864 unichar ch = annotation.get_char(i); | 887 unichar ch = annotation.get_char(i); |
865 if (ch == 0) | 888 if (ch == 0) |
866 return false; | 889 return false; |
867 if (ch.isspace()) { | 890 if (ch.isspace()) { |
868 unichar code = (unichar)buff.str.to_ulong(null, 16); | 891 unichar code = (unichar)uint64.parse(buff.str); |
869 buff.erase(); | 892 buff.assign("0x"); |
870 if (!code.validate()) | 893 if (!code.validate()) |
871 return false; | 894 return false; |
872 retval.append(code.to_string()); | 895 retval.append(code.to_string()); |
873 continue; | 896 continue; |
874 } | 897 } |
875 if (!ch.isxdigit()) | 898 if (!ch.isxdigit()) |
876 return false; | 899 return false; |
877 buff.append_unichar(ch); | 900 buff.append_unichar(ch); |
878 } | 901 } |
879 unichar code = (unichar)buff.str.to_ulong(null, 16); | 902 unichar code = (unichar)uint64.parse(buff.str); |
880 if (!code.validate()) | 903 if (!code.validate()) |
881 return false; | 904 return false; |
882 retval.append(code.to_string()); | 905 retval.append(code.to_string()); |
883 m_unicode_point = retval.str; | 906 m_unicode_point = retval.str; |
884 if (m_unicode_point == null) | 907 if (m_unicode_point == null) |
885 return true; | 908 return true; |
886 IBus.Text text = new IBus.Text.from_string(m_unicode_point); | 909 IBus.Text text = new IBus.Text.from_string(m_unicode_point); |
887 m_lookup_table.append_candidate(text); | 910 m_lookup_table.append_candidate(text); |
888 return true; | 911 return true; |
889 } | 912 } |
(...skipping 13 matching lines...) Expand all Loading... |
903 switch(m_partial_match_condition) { | 926 switch(m_partial_match_condition) { |
904 case 0: | 927 case 0: |
905 if (key.has_prefix(annotation)) | 928 if (key.has_prefix(annotation)) |
906 matched = true; | 929 matched = true; |
907 break; | 930 break; |
908 case 1: | 931 case 1: |
909 if (key.has_suffix(annotation)) | 932 if (key.has_suffix(annotation)) |
910 matched = true; | 933 matched = true; |
911 break; | 934 break; |
912 case 2: | 935 case 2: |
913 if (key.str(annotation) != null) | 936 if (key.index_of(annotation) >= 0) |
914 matched = true; | 937 matched = true; |
915 break; | 938 break; |
916 default: | 939 default: |
917 break; | 940 break; |
918 } | 941 } |
919 if (!matched) | 942 if (!matched) |
920 continue; | 943 continue; |
921 sub_emojis = m_annotation_to_emojis_dict.lookup(key); | 944 sub_emojis = m_annotation_to_emojis_dict.lookup(key); |
922 foreach (unowned string emoji in sub_emojis) { | 945 foreach (unowned string emoji in sub_emojis) { |
923 if (total_emojis.find_custom(emoji, GLib.strcmp) == null) { | 946 if (total_emojis.find_custom(emoji, GLib.strcmp) == null) { |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1041 string font_family = m_emoji_font_family; | 1064 string font_family = m_emoji_font_family; |
1042 int font_size = m_emoji_font_size - 2; | 1065 int font_size = m_emoji_font_size - 2; |
1043 string emoji_font = "%s %d".printf(font_family, font_size); | 1066 string emoji_font = "%s %d".printf(font_family, font_size); |
1044 string markup = "<span font=\"%s\">%s</span>". | 1067 string markup = "<span font=\"%s\">%s</span>". |
1045 printf(emoji_font, utf8_entity(text)); | 1068 printf(emoji_font, utf8_entity(text)); |
1046 label.set_markup(markup); | 1069 label.set_markup(markup); |
1047 } | 1070 } |
1048 label.set_halign(Gtk.Align.FILL); | 1071 label.set_halign(Gtk.Align.FILL); |
1049 label.set_valign(Gtk.Align.FILL); | 1072 label.set_valign(Gtk.Align.FILL); |
1050 Gtk.EventBox candidate_ebox = new Gtk.EventBox(); | 1073 Gtk.EventBox candidate_ebox = new Gtk.EventBox(); |
| 1074 candidate_ebox.add_events(Gdk.EventMask.POINTER_MOTION_MASK); |
1051 candidate_ebox.add(label); | 1075 candidate_ebox.add(label); |
1052 // Make a copy of i to workaround a bug in vala. | 1076 // Make a copy of i to workaround a bug in vala. |
1053 // https://bugzilla.gnome.org/show_bug.cgi?id=628336 | 1077 // https://bugzilla.gnome.org/show_bug.cgi?id=628336 |
1054 uint index = i; | 1078 uint index = i; |
1055 candidate_ebox.button_press_event.connect((w, e) => { | 1079 candidate_ebox.button_press_event.connect((w, e) => { |
1056 candidate_clicked(index, e.button, e.state); | 1080 candidate_clicked(index, e.button, e.state); |
1057 return true; | 1081 return true; |
1058 }); | 1082 }); |
1059 candidate_ebox.enter_notify_event.connect((e) => { | 1083 candidate_ebox.motion_notify_event.connect((e) => { |
1060 // m_enter_notify_enable is added because | 1084 // m_enter_notify_enable is added because |
1061 // enter_notify_event conflicts with keyboard operations. | 1085 // enter_notify_event conflicts with keyboard operations. |
1062 if (!m_enter_notify_enable) | 1086 if (!m_enter_notify_enable) |
1063 return true; | 1087 return false; |
1064 if (m_lookup_table.get_cursor_pos() == index) | 1088 if (m_lookup_table.get_cursor_pos() == index) |
1065 return true; | 1089 return false; |
| 1090 #if VALA_0_24 |
| 1091 Gdk.EventMotion pe = e; |
| 1092 #else |
| 1093 Gdk.EventMotion *pe = &e; |
| 1094 #endif |
| 1095 if (m_mouse_x == pe.x_root && m_mouse_y == pe.y_root) |
| 1096 return false; |
| 1097 m_mouse_x = pe.x_root; |
| 1098 m_mouse_y = pe.y_root; |
| 1099 |
1066 m_lookup_table.set_cursor_pos(index); | 1100 m_lookup_table.set_cursor_pos(index); |
1067 if (m_entry_notify_show_id > 0) { | 1101 if (m_entry_notify_show_id > 0 && |
| 1102 GLib.MainContext.default().find_source_by_id( |
| 1103 m_entry_notify_show_id) != null) { |
1068 GLib.Source.remove(m_entry_notify_show_id); | 1104 GLib.Source.remove(m_entry_notify_show_id); |
1069 } | 1105 } |
1070 // If timeout is not added, memory leak happens and | 1106 // If timeout is not added, memory leak happens and |
1071 // button_press_event signal does not work above. | 1107 // button_press_event signal does not work above. |
1072 m_entry_notify_show_id = GLib.Timeout.add(100, () => { | 1108 m_entry_notify_show_id = GLib.Timeout.add(100, () => { |
1073 show_candidate_panel(); | 1109 show_candidate_panel(); |
1074 return false; | 1110 return false; |
1075 }); | 1111 }); |
1076 return true; | 1112 return false; |
1077 }); | 1113 }); |
1078 grid.attach(candidate_ebox, | 1114 grid.attach(candidate_ebox, |
1079 n % (int)EMOJI_GRID_PAGE, n / (int)EMOJI_GRID_PAGE, | 1115 n % (int)EMOJI_GRID_PAGE, n / (int)EMOJI_GRID_PAGE, |
1080 1, 1); | 1116 1, 1); |
1081 n++; | 1117 n++; |
1082 | 1118 |
1083 m_candidates += label; | 1119 m_candidates += label; |
1084 } | 1120 } |
1085 if (n > 0) { | 1121 if (n > 0) { |
1086 m_candidate_panel_is_visible = true; | 1122 m_candidate_panel_is_visible = true; |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1434 * does not give the keyboard focus when Emojier is lauched | 1470 * does not give the keyboard focus when Emojier is lauched |
1435 * twice with Ctrl-Shift-e via XIEvent, if present_with_time() | 1471 * twice with Ctrl-Shift-e via XIEvent, if present_with_time() |
1436 * is not applied. | 1472 * is not applied. |
1437 * But XFCE4 desktop does not effect this bug. | 1473 * But XFCE4 desktop does not effect this bug. |
1438 * Seems this is caused by the window manager's focus stealing | 1474 * Seems this is caused by the window manager's focus stealing |
1439 * prevention logic: | 1475 * prevention logic: |
1440 * https://mail.gnome.org/archives/gtk-devel-list/2017-May/msg00026.html | 1476 * https://mail.gnome.org/archives/gtk-devel-list/2017-May/msg00026.html |
1441 */ | 1477 */ |
1442 uint32 timestamp = event.get_time(); | 1478 uint32 timestamp = event.get_time(); |
1443 present_with_time(timestamp); | 1479 present_with_time(timestamp); |
| 1480 |
| 1481 Gdk.Device pointer; |
| 1482 #if VALA_0_34 |
| 1483 Gdk.Seat seat = event.get_seat(); |
| 1484 if (seat == null) { |
| 1485 var display = get_display(); |
| 1486 seat = display.get_default_seat(); |
| 1487 } |
| 1488 pointer = seat.get_pointer(); |
| 1489 #else |
| 1490 Gdk.Device device = event.get_device(); |
| 1491 if (device == null) { |
| 1492 var display = get_display(); |
| 1493 device = display.list_devices().data; |
| 1494 } |
| 1495 if (device.get_source() == Gdk.InputSource.KEYBOARD) |
| 1496 pointer = device.get_associated_device(); |
| 1497 else |
| 1498 pointer = device; |
| 1499 #endif |
| 1500 pointer.get_position_double(null, |
| 1501 out m_mouse_x, |
| 1502 out m_mouse_y); |
1444 | 1503 |
1445 m_loop = new GLib.MainLoop(); | 1504 m_loop = new GLib.MainLoop(); |
1446 m_loop.run(); | 1505 m_loop.run(); |
1447 m_loop = null; | 1506 m_loop = null; |
1448 | 1507 |
1449 // Need focus-out on Gtk.Entry to send the emoji to applications. | 1508 // Need focus-out on Gtk.Entry to send the emoji to applications. |
1450 Gdk.Event fevent = new Gdk.Event(Gdk.EventType.FOCUS_CHANGE); | 1509 Gdk.Event fevent = new Gdk.Event(Gdk.EventType.FOCUS_CHANGE); |
1451 fevent.focus_change.in = 0; | 1510 fevent.focus_change.in = 0; |
1452 fevent.focus_change.window = get_window(); | 1511 fevent.focus_change.window = get_window(); |
1453 m_entry.send_focus_change(fevent); | 1512 m_entry.send_focus_change(fevent); |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1655 | 1714 |
1656 public void reset() { | 1715 public void reset() { |
1657 m_input_context_path = ""; | 1716 m_input_context_path = ""; |
1658 m_result = null; | 1717 m_result = null; |
1659 } | 1718 } |
1660 | 1719 |
1661 | 1720 |
1662 public void present_centralize(Gdk.Event event) { | 1721 public void present_centralize(Gdk.Event event) { |
1663 Gtk.Allocation allocation; | 1722 Gtk.Allocation allocation; |
1664 get_allocation(out allocation); | 1723 get_allocation(out allocation); |
| 1724 Gdk.Rectangle monitor_area; |
| 1725 #if VALA_0_34 |
| 1726 Gdk.Display display = Gdk.Display.get_default(); |
| 1727 Gdk.Monitor monitor = display.get_monitor_at_window(this.get_window()); |
| 1728 monitor_area = monitor.get_geometry(); |
| 1729 #else |
1665 Gdk.Screen screen = Gdk.Screen.get_default(); | 1730 Gdk.Screen screen = Gdk.Screen.get_default(); |
1666 int monitor_num = screen.get_monitor_at_window(get_window()); | 1731 int monitor_num = screen.get_monitor_at_window(this.get_window()); |
1667 Gdk.Rectangle monitor_area; | |
1668 screen.get_monitor_geometry(monitor_num, out monitor_area); | 1732 screen.get_monitor_geometry(monitor_num, out monitor_area); |
| 1733 #endif |
1669 int x = (monitor_area.x + monitor_area.width - allocation.width)/2; | 1734 int x = (monitor_area.x + monitor_area.width - allocation.width)/2; |
1670 int y = (monitor_area.y + monitor_area.height | 1735 int y = (monitor_area.y + monitor_area.height |
1671 - allocation.height)/2; | 1736 - allocation.height)/2; |
1672 move(x, y); | 1737 move(x, y); |
1673 | 1738 |
1674 uint32 timestamp = event.get_time(); | 1739 uint32 timestamp = event.get_time(); |
1675 present_with_time(timestamp); | 1740 present_with_time(timestamp); |
1676 m_entry.set_activates_default(true); | 1741 m_entry.set_activates_default(true); |
1677 } | 1742 } |
1678 | 1743 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1758 m_favorites += favorite; | 1823 m_favorites += favorite; |
1759 } | 1824 } |
1760 for(int i = 0; i < unowned_favorite_annotations.length; i++) { | 1825 for(int i = 0; i < unowned_favorite_annotations.length; i++) { |
1761 string? favorite_annotation = unowned_favorite_annotations[i]; | 1826 string? favorite_annotation = unowned_favorite_annotations[i]; |
1762 GLib.return_if_fail(favorite_annotation != null); | 1827 GLib.return_if_fail(favorite_annotation != null); |
1763 m_favorite_annotations += favorite_annotation; | 1828 m_favorite_annotations += favorite_annotation; |
1764 } | 1829 } |
1765 update_favorite_emoji_dict(); | 1830 update_favorite_emoji_dict(); |
1766 } | 1831 } |
1767 } | 1832 } |
LEFT | RIGHT |