1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
namespace Caribou {
[DBus(name = "org.gnome.Caribou.Keyboard")]
interface Keyboard : Object {
public abstract void set_cursor_location (int x, int y, int w, int h)
throws IOError;
public abstract void set_entry_location (int x, int y, int w, int h)
throws IOError;
public abstract void show (uint32 timestamp) throws IOError;
public abstract void hide (uint32 timestamp) throws IOError;
}
class GtkModule {
private GLib.HashTable<Gtk.Window, bool> windows;
private Keyboard keyboard;
private Gdk.Display display;
public GtkModule () {
windows = new GLib.HashTable<Gtk.Window, bool> (null, null);
try {
display = Gdk.Display.get_default ();
keyboard = Bus.get_proxy_sync (BusType.SESSION,
"org.gnome.Caribou.Keyboard",
"/org/gnome/Caribou/Keyboard");
Gdk.window_add_filter (null, event_filter);
} catch (Error e) {
stderr.printf ("%s\n", e.message);
}
}
private Gdk.FilterReturn event_filter (Gdk.XEvent xevent, Gdk.Event evt) {
void* data;
Gtk.Window window;
if (evt.any.window == null ||
evt.any.window.get_window_type () != Gdk.WindowType.TOPLEVEL)
return Gdk.FilterReturn.CONTINUE;
Gdk.window_get_user_data (evt.any.window, out data);
if (data == null || !(data is Gtk.Window))
return Gdk.FilterReturn.CONTINUE;
window = (Gtk.Window *) data;
if (!windows.lookup (window)) {
windows.insert (window, true);
window.notify["has-toplevel-focus"].connect (toplevel_focus_changed);
window.set_focus.connect (window_focus_changed);
window.destroy.connect (() => { windows.remove (window); });
}
return Gdk.FilterReturn.CONTINUE;
}
private void toplevel_focus_changed (Object obj, ParamSpec prop) {
Gtk.Window window = (Gtk.Window) obj;
if (window.has_toplevel_focus)
do_focus_change (window.get_focus ());
}
private void window_focus_changed (Gtk.Window window,
Gtk.Widget? widget) {
do_focus_change (widget);
}
private void do_focus_change (Gtk.Widget? widget) {
#if GTK2
uint32 timestamp = Gdk.x11_display_get_user_time (display);
#else
uint32 timestamp = Gdk.X11Display.get_user_time (display);
#endif
if ((widget is Gtk.Editable &&
((Gtk.Editable) widget).get_editable ()) ||
(widget is Gtk.TextView &&
((Gtk.TextView) widget).get_editable ())) {
Gdk.Window current_window = widget.get_window ();
int x = 0, y = 0, w = 0, h = 0;
if (current_window != null)
get_origin_geometry (current_window, out x, out y, out w, out h);
try {
keyboard.show (timestamp);
keyboard.set_entry_location (x, y, w, h);
} catch (IOError e) {
stderr.printf ("%s\n", e.message);
}
} else {
try {
keyboard.hide (timestamp);
} catch (IOError e) {
stderr.printf ("%s\n", e.message);
}
}
}
private void get_origin_geometry (Gdk.Window window,
out int x, out int y,
out int w, out int h) {
window.get_origin (out x, out y);
#if GTK2
window.get_geometry (null, null, out w, out h, null);
#else
window.get_geometry (null, null, out w, out h);
#endif
}
}
}
|