WIP implement engine switcher popup ui
authorPeng Huang <shawn.p.huang@gmail.com>
Sun, 27 Nov 2011 05:21:02 +0000 (00:21 -0500)
committerPeng Huang <shawn.p.huang@gmail.com>
Tue, 21 Feb 2012 16:50:21 +0000 (11:50 -0500)
src/ibusbus.c
src/ibusbus.h
ui/gtk3/Makefile.am
ui/gtk3/candidatepanel.vala
ui/gtk3/grabkeycode.c
ui/gtk3/keybindingmanager.vala
ui/gtk3/panel.vala
ui/gtk3/switcher.vala
ui/gtk3/switchertest.vala

index 6137441..d013745 100644 (file)
@@ -1480,7 +1480,7 @@ ibus_bus_list_active_engines_async_finish (IBusBus      *bus,
 
 IBusEngineDesc **
 ibus_bus_get_engines_by_names (IBusBus             *bus,
-                               const gchar * const *names)
+                               gchar              **names)
 {
     g_return_val_if_fail (IBUS_IS_BUS (bus), NULL);
 
index abcf2c4..efa7902 100644 (file)
@@ -722,7 +722,7 @@ GList       *ibus_bus_list_active_engines_async_finish
 IBusEngineDesc **
              ibus_bus_get_engines_by_names
                                         (IBusBus             *bus,
-                                         const gchar * const *names);
+                                         gchar              **names);
 /**
  * ibus_bus_get_use_sys_layout:
  * @bus: An #IBusBus.
index 7eccb03..330d55b 100644 (file)
@@ -35,12 +35,15 @@ AM_CFLAGS = \
        @GTHREAD2_CFLAGS@ \
        @GTK3_CFLAGS@ \
        @X11_CFLAGS@ \
+       $(INCLUDES) \
        -DG_LOG_DOMAIN=\"IBUS\" \
        -DPKGDATADIR=\"$(pkgdatadir)\" \
        -DLIBEXECDIR=\"$(libexecdir)\" \
        -DBINDIR=\"@bindir@\" \
     -DIBUS_DISABLE_DEPRECATED \
-       $(INCLUDES) \
+       -Wno-unused-variable \
+       -Wno-unused-but-set-variable \
+       -Wno-unused-function \
        $(NULL)
 
 AM_LDADD = \
@@ -85,7 +88,7 @@ TESTS = \
        test-switcher \
        $(NULL)
 
-noinst_PROGRAMS = $(TESTS)
+noinst_PROGRAMS = $(TESTS)
 
 test_switcher_SOURCES = \
        iconwidget.vala \
index b31913e..06cceb3 100644 (file)
@@ -23,7 +23,7 @@
 using Gtk;
 using Pango;
 
-class CandidatePanel : Gtk.HBox{
+public class CandidatePanel : Gtk.HBox{
     private bool m_vertical = true;
     private Gtk.Window m_toplevel;
     private Gtk.VBox m_vbox;
index 0af0f1c..200f956 100644 (file)
@@ -37,7 +37,7 @@ gboolean grab_keycode (GdkDisplay *display,
     XIEventMask mask;
     mask.deviceid = XIAllMasterDevices;
     mask.mask_len = XIMaskLen(XI_RawMotion);
-    mask.mask = g_new0 (char, mask.mask_len);
+    mask.mask = g_new0 (unsigned char, mask.mask_len);
     XISetMask (mask.mask, XI_KeyPress);
     XISetMask (mask.mask, XI_KeyRelease);
 
index 3aa40c4..ebb9d64 100644 (file)
@@ -23,12 +23,12 @@ extern bool ungrab_keycode (Gdk.Display display,
                             uint keyval,
                             uint modifiers);
 
-class KeybindingManager : GLib.Object {
+public class KeybindingManager : GLib.Object {
     /**
      * list of binded keybindings
      */
     private GLib.List<Keybinding> m_bindings = new GLib.List<Keybinding>();
-    
+
     private static KeybindingManager m_instance = null;
 
     /**
@@ -111,9 +111,9 @@ class KeybindingManager : GLib.Object {
         GLib.List<Keybinding> remove_bindings = new GLib.List<Keybinding>();
         foreach(Keybinding binding in m_bindings) {
             if(str_equal(accelerator, binding.accelerator)) {
-                grab_keycode (Gdk.Display.get_default(),
-                              binding.keysym,
-                              binding.modifiers);
+                ungrab_keycode (Gdk.Display.get_default(),
+                                binding.keysym,
+                                binding.modifiers);
                 remove_bindings.append(binding);
             }
         }
@@ -147,6 +147,54 @@ class KeybindingManager : GLib.Object {
         return 0;
     }
 
+    public static bool primary_modifier_still_pressed(Gdk.Event event) {
+        Gdk.EventKey keyevent = event.key;
+        uint primary_modifier = get_primary_modifier(keyevent.state);
+        if (primary_modifier == 0)
+            return false;
+
+        Gdk.Device device = event.get_device();
+        Gdk.Device pointer;
+        if (device.get_source() == Gdk.InputSource.KEYBOARD)
+            pointer = device.get_associated_device();
+        else
+            pointer = device;
+
+        uint modifier = 0;
+        pointer.get_state(keyevent.window, null, out modifier);
+        if ((primary_modifier & modifier) == primary_modifier)
+            return true;
+
+        return false;
+    }
+
+    public static uint keyval_to_modifier (uint keyval) {
+        switch(keyval) {
+            case 0xffe3: /* Control_L */
+            case 0xffe4: /* Control_R */
+                return Gdk.ModifierType.CONTROL_MASK;
+            case 0xffe1: /* Shift_L */
+            case 0xffe2: /* Shift_R */
+                return Gdk.ModifierType.SHIFT_MASK;
+            case 0xffe5: /* Caps_Lock */
+                return Gdk.ModifierType.LOCK_MASK;
+            case 0xffe9: /* Alt_L */
+            case 0xffea: /* Alt_R */
+                return Gdk.ModifierType.MOD1_MASK;
+            case 0xffe7: /* Meta_L */
+            case 0xffe8: /* Meta_R */
+                return Gdk.ModifierType.META_MASK;
+            case 0xffeb: /* Super_L */
+            case 0xffec: /* Super_R */
+                return Gdk.ModifierType.SUPER_MASK;
+            case 0xffed: /* Hyper_L */
+            case 0xffee: /* Hyper_R */
+                return Gdk.ModifierType.HYPER_MASK;
+            default:
+                return 0;
+        }
+    }
+
     private void event_handler(Gdk.Event event) {
         do {
             if (event.any.window != Gdk.get_default_root_window())
index b33804d..b460d1e 100644 (file)
@@ -70,26 +70,8 @@ class Panel : IBus.PanelService {
 
     }
 
-    private bool primary_modifier_still_pressed(Gdk.Event event) {
-        Gdk.EventKey keyevent = event.key;
-        uint primary_modifier =
-            KeybindingManager.get_primary_modifier (keyevent.state);
-        if (primary_modifier == 0)
-            return false;
-
-        Gdk.Window window = keyevent.window;
-        Gdk.Display display = window.get_display();
-        Gdk.Device device = display.get_device_manager().get_client_pointer();
-
-        uint modifier = 0;
-        device.get_state(window, null, out modifier);
-        if ((primary_modifier & modifier) == primary_modifier)
-            return true;
-        return false;
-    }
-
     private void handle_engine_switch(Gdk.Event event, bool revert) {
-        if (!primary_modifier_still_pressed(event)) {
+        if (!KeybindingManager.primary_modifier_still_pressed(event)) {
             /*
                 Switch engine and change the engines order.
             */
@@ -99,8 +81,7 @@ class Panel : IBus.PanelService {
             /*
                 TODO 
             */
-            m_switcher.update_engines(m_engines);
-            m_switcher.start_switch(event);
+            m_switcher.run(event, m_engines, 0);
         }
         
 
@@ -122,9 +103,6 @@ class Panel : IBus.PanelService {
         */
     }
 
-    private void switch_engine () {
-    }
-
     private void update_engines() {
         Variant variant = m_config.get_value("general", "preload_engines");
         if (variant != null)
index af2d782..09b49a1 100644 (file)
@@ -28,34 +28,53 @@ class Switcher : Gtk.Window {
     private Gtk.Box m_box;
     private Gtk.Button[] m_buttons = {};
     private IBus.EngineDesc[] m_engines;
+    private uint m_selected_engine;
+    private uint m_primary_modifier;
+    private GLib.MainLoop m_loop;
+    private int m_result;
 
     public Switcher() {
         GLib.Object(type : Gtk.WindowType.POPUP);
-        set_can_focus(true);
+        set_accept_focus(true);
         set_decorated(false);
         set_position(Gtk.WindowPosition.CENTER);
         add_events(Gdk.EventMask.KEY_PRESS_MASK);
         add_events(Gdk.EventMask.KEY_RELEASE_MASK);
 
-        key_press_event.connect((e) => {
-            debug ("press");
-            if (e.keyval == 0xff1b /* Escape */)
-                hide();
-            return true;
-        });
-
-        key_release_event.connect((e) => {
-            debug ("release");
-            return true;
-        });
-
         m_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
         add(m_box);
 
         grab_focus();
     }
 
-    public void update_engines(IBus.EngineDesc[] engines) {
+    public int run(Gdk.Event event, IBus.EngineDesc[] engines, int index) {
+        assert (m_loop == null);
+        assert (index < engines.length);
+
+        m_selected_engine = index;
+        update_engines(engines);
+
+        show_all();
+        Gdk.Device device = event.get_device();
+        device.grab(get_window(),
+                    Gdk.GrabOwnership.NONE,
+                    true,
+                    Gdk.EventMask.KEY_PRESS_MASK |
+                    Gdk.EventMask.KEY_RELEASE_MASK,
+                    null,
+                    Gdk.CURRENT_TIME);
+        m_primary_modifier =
+            KeybindingManager.get_primary_modifier(event.key.state);
+
+        m_loop = new GLib.MainLoop();
+        m_loop.run();
+        m_loop = null;
+        hide();
+        debug("run over");
+        return m_result;
+    }
+
+    private void update_engines(IBus.EngineDesc[] engines) {
         foreach (var button in m_buttons) {
             button.destroy();
         }
@@ -72,26 +91,85 @@ class Switcher : Gtk.Window {
         foreach (var engine in m_engines) {
             var button = new Gtk.Button.with_label(engine.get_longname());
             button.set_image(new IconWidget(engine.get_icon(), width));
+            button.set_relief(Gtk.ReliefStyle.NONE);
             button.show();
             m_box.pack_start(button, true, true);
             m_buttons += button;
         }
     }
 
-    public void start_switch(Gdk.Event event) {
-        show_all();
-        Gdk.Device device = event.get_device();
-        device.grab(get_window(),
-                    Gdk.GrabOwnership.NONE,
-                    true,
-                    Gdk.EventMask.KEY_PRESS_MASK |
-                    Gdk.EventMask.KEY_RELEASE_MASK,
-                    null,
-                    Gdk.CURRENT_TIME);
+    private void next_engine() {
+        if (m_selected_engine == m_engines.length - 1)
+            m_selected_engine = 0;
+        else
+            m_selected_engine ++;
+        set_focus(m_buttons[m_selected_engine]);
+        m_buttons[m_selected_engine].set_state_flags(Gtk.StateFlags.FOCUSED, true);
+        debug("next engine");
     }
 
+    private void previous_engine() {
+        if (m_selected_engine == 0)
+            m_selected_engine = m_engines.length - 1;
+        else
+            m_selected_engine --;
+        set_focus(m_buttons[m_selected_engine]);
+        debug("previous engine");
+    }
+
+    /* override virtual functions */
     public override void show() {
         base.show();
-        get_window().focus(Gdk.CURRENT_TIME);
+        debug("is_active = %d", (int)this.is_active);
+    }
+
+    public override void grab_focus() {
+        base.grab_focus();
+        debug("grab_focus");
+        set_focus(m_buttons[m_selected_engine]);
+    }
+
+    public override bool key_press_event(Gdk.EventKey e) {
+        Gdk.EventKey *pe = &e;
+        switch (pe->keyval) {
+            case 0x0020: /* space */
+            case 0xff80: /* KP_Space */
+                if ((pe->state & Gdk.ModifierType.SHIFT_MASK) == 0)
+                    next_engine();
+                else
+                    previous_engine();
+                break;
+            case 0x08fb: /* leftarrow */
+            case 0xff51: /* Down */
+                break;
+            case 0x08fc: /* uparrow */
+            case 0xff52: /* Up */
+                previous_engine();
+                break;
+            case 0x08fd: /* rightarrow */
+            case 0xff53: /* Right */
+                break;
+            case 0x08fe: /* downarrow */
+            case 0xff54: /* Down */
+                next_engine();
+                break;
+            default:
+                debug("0x%04x", pe->keyval);
+                break;
+        }
+        return true;
+    }
+
+    public override bool key_release_event(Gdk.EventKey e) {
+        Gdk.EventKey *pe = &e;
+        if (m_primary_modifier != KeybindingManager.keyval_to_modifier(pe->keyval))
+            return true;
+
+        if (KeybindingManager.primary_modifier_still_pressed((Gdk.Event *)pe))
+            return true;
+
+        m_loop.quit();
+        m_result = (int)m_selected_engine;
+        return true;
     }
 }
index ab90a03..2a237de 100644 (file)
@@ -44,7 +44,8 @@ public void main(string[] argv) {
     Gtk.init(ref argv);
     IBus.init();
     var bus = new IBus.Bus();
-    var engines = bus.get_engines_by_names({"xkb:us:eng", "pinyin", "anthy"});
+    string[] names = { "xkb:us:eng", "pinyin", "anthy" };
+    var engines = bus.get_engines_by_names(names);
     Switcher switcher = new Switcher();
 
     switcher.update_engines(engines);