1 /*
2 * Copyright (C) 2002-2006 Sergey V. Udaltsov <svu@gnome.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include <time.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <X11/Xmd.h>
25 #include <X11/Xatom.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/keysym.h>
29
30 #include "config.h"
31
32 #include "xklavier_private.h"
33 #include "xklavier_private_xmm.h"
34
35 #define SHORTCUT_OPTION_PREFIX "grp:"
36
37 const gchar **
xkl_xmm_get_groups_names(XklEngine * engine)38 xkl_xmm_get_groups_names(XklEngine * engine)
39 {
40 return (const gchar **) xkl_engine_backend(engine, XklXmm,
41 current_config).layouts;
42 }
43
44 const gchar **
xkl_xmm_get_indicators_names(XklEngine * engine)45 xkl_xmm_get_indicators_names(XklEngine * engine)
46 {
47 return NULL;
48 }
49
50 void
xkl_xmm_shortcuts_grab(XklEngine * engine)51 xkl_xmm_shortcuts_grab(XklEngine * engine)
52 {
53 const XmmShortcut *shortcut;
54 const XmmSwitchOption *option =
55 xkl_xmm_shortcut_get_current(engine);
56
57 xkl_debug(150, "Found shortcut option: %p\n", option);
58 if (option == NULL)
59 return;
60
61 shortcut = option->shortcuts;
62 while (shortcut->keysym != XK_VoidSymbol) {
63 int keycode =
64 XKeysymToKeycode(xkl_engine_get_display(engine),
65 shortcut->keysym);
66 xkl_xmm_grab_ignoring_indicators(engine, keycode,
67 shortcut->modifiers);
68 shortcut++;
69 }
70 }
71
72 void
xkl_xmm_shortcuts_ungrab(XklEngine * engine)73 xkl_xmm_shortcuts_ungrab(XklEngine * engine)
74 {
75 const XmmShortcut *shortcut;
76 const XmmSwitchOption *option =
77 xkl_xmm_shortcut_get_current(engine);
78
79 if (option == NULL)
80 return;
81
82 shortcut = option->shortcuts;
83 while (shortcut->keysym != XK_VoidSymbol) {
84 int keycode =
85 XKeysymToKeycode(xkl_engine_get_display(engine),
86 shortcut->keysym);
87 xkl_xmm_ungrab_ignoring_indicators(engine, keycode,
88 shortcut->modifiers);
89 shortcut++;
90 }
91 }
92
93 XmmSwitchOption *
xkl_xmm_shortcut_get_current(XklEngine * engine)94 xkl_xmm_shortcut_get_current(XklEngine * engine)
95 {
96 const gchar *option_name =
97 xkl_xmm_shortcut_get_current_option_name(engine);
98
99 xkl_debug(150, "Configured switch option: [%s]\n", option_name);
100
101 if (option_name == NULL)
102 return NULL;
103
104 return (XmmSwitchOption *)
105 g_hash_table_lookup(xkl_engine_backend
106 (engine, XklXmm, switch_options),
107 (gconstpointer) option_name);
108 }
109
110 const gchar *
xkl_xmm_shortcut_get_current_option_name(XklEngine * engine)111 xkl_xmm_shortcut_get_current_option_name(XklEngine * engine)
112 {
113 gchar **option =
114 xkl_engine_backend(engine, XklXmm, current_config).options;
115 if (option == NULL)
116 return NULL;
117
118 while (*option != NULL) {
119 /* starts with "grp:" */
120 if (strstr(*option, SHORTCUT_OPTION_PREFIX) != NULL) {
121 return *option + sizeof SHORTCUT_OPTION_PREFIX - 1;
122 }
123 option++;
124 }
125 return NULL;
126 }
127
128 const XmmSwitchOption *
xkl_xmm_find_switch_option(XklEngine * engine,gint keycode,guint state,gint * current_shortcut_rv)129 xkl_xmm_find_switch_option(XklEngine * engine, gint keycode,
130 guint state, gint * current_shortcut_rv)
131 {
132 const XmmSwitchOption *rv = xkl_xmm_shortcut_get_current(engine);
133
134 if (rv != NULL) {
135 const XmmShortcut *sc = rv->shortcuts;
136 while (sc->keysym != XK_VoidSymbol) {
137 if ((XKeysymToKeycode
138 (xkl_engine_get_display(engine),
139 sc->keysym) == keycode)
140 && ((state & sc->modifiers) == sc->modifiers)) {
141 return rv;
142 }
143 sc++;
144 }
145 }
146 return NULL;
147 }
148
149 gint
xkl_xmm_resume_listen(XklEngine * engine)150 xkl_xmm_resume_listen(XklEngine * engine)
151 {
152 if (xkl_engine_is_listening_for(engine, XKLL_MANAGE_LAYOUTS))
153 xkl_xmm_shortcuts_grab(engine);
154 return 0;
155 }
156
157 gint
xkl_xmm_pause_listen(XklEngine * engine)158 xkl_xmm_pause_listen(XklEngine * engine)
159 {
160 if (xkl_engine_is_listening_for(engine, XKLL_MANAGE_LAYOUTS))
161 xkl_xmm_shortcuts_ungrab(engine);
162 return 0;
163 }
164
165 guint
xkl_xmm_get_max_num_groups(XklEngine * engine)166 xkl_xmm_get_max_num_groups(XklEngine * engine)
167 {
168 return 0;
169 }
170
171 guint
xkl_xmm_get_num_groups(XklEngine * engine)172 xkl_xmm_get_num_groups(XklEngine * engine)
173 {
174 gint rv = 0;
175 gchar **p =
176 xkl_engine_backend(engine, XklXmm, current_config).layouts;
177 if (p != NULL)
178 while (*p++ != NULL)
179 rv++;
180 return rv;
181 }
182
183 void
xkl_xmm_free_all_info(XklEngine * engine)184 xkl_xmm_free_all_info(XklEngine * engine)
185 {
186 gchar *current_rules =
187 xkl_engine_backend(engine, XklXmm, current_rules);
188 if (current_rules != NULL) {
189 g_free(current_rules);
190 current_rules = NULL;
191 xkl_engine_backend(engine, XklXmm, current_rules) = NULL;
192 }
193 xkl_config_rec_reset(&xkl_engine_backend
194 (engine, XklXmm, current_config));
195 }
196
197 gboolean
xkl_xmm_if_cached_info_equals_actual(XklEngine * engine)198 xkl_xmm_if_cached_info_equals_actual(XklEngine * engine)
199 {
200 return FALSE;
201 }
202
203 gboolean
xkl_xmm_load_all_info(XklEngine * engine)204 xkl_xmm_load_all_info(XklEngine * engine)
205 {
206 return
207 xkl_config_rec_get_full_from_server(&xkl_engine_backend
208 (engine, XklXmm,
209 current_rules),
210 &xkl_engine_backend(engine,
211 XklXmm,
212 current_config),
213 engine);
214 }
215
216 void
xkl_xmm_get_server_state(XklEngine * engine,XklState * state)217 xkl_xmm_get_server_state(XklEngine * engine, XklState * state)
218 {
219 unsigned char *propval = NULL;
220 Atom actual_type;
221 int actual_format;
222 unsigned long bytes_remaining;
223 unsigned long actual_items;
224 int result;
225
226 memset(state, 0, sizeof(*state));
227
228 result =
229 XGetWindowProperty(xkl_engine_get_display(engine),
230 xkl_engine_priv(engine, root_window),
231 xkl_engine_backend(engine, XklXmm,
232 state_atom), 0L, 1L,
233 False, XA_INTEGER, &actual_type,
234 &actual_format, &actual_items,
235 &bytes_remaining, &propval);
236
237 if (Success == result) {
238 if (actual_format == 32 || actual_items == 1) {
239 state->group = *(CARD32 *) propval;
240 } else {
241 xkl_debug(160,
242 "Could not get the xmodmap current group\n");
243 }
244 XFree(propval);
245 } else {
246 xkl_debug(160,
247 "Could not get the xmodmap current group: %d\n",
248 result);
249 }
250 }
251
252 void
xkl_xmm_actualize_group(XklEngine * engine,gint group)253 xkl_xmm_actualize_group(XklEngine * engine, gint group)
254 {
255 char cmd[1024];
256 int res;
257 const gchar *layout_name = NULL;
258
259 if (xkl_xmm_get_num_groups(engine) < group)
260 return;
261
262 layout_name =
263 xkl_engine_backend(engine, XklXmm,
264 current_config).layouts[group];
265
266 g_snprintf(cmd, sizeof cmd,
267 "xmodmap %s/xmodmap.%s", XMODMAP_BASE, layout_name);
268
269 res = system(cmd);
270 if (res > 0) {
271 xkl_debug(0, "xmodmap error %d\n", res);
272 } else if (res < 0) {
273 xkl_debug(0, "Could not execute xmodmap: %d\n", res);
274 }
275 XSync(xkl_engine_get_display(engine), False);
276 }
277
278 void
xkl_xmm_lock_group(XklEngine * engine,gint group)279 xkl_xmm_lock_group(XklEngine * engine, gint group)
280 {
281 CARD32 propval;
282 Display *display;
283
284 if (xkl_xmm_get_num_groups(engine) < group)
285 return;
286
287 /* updating the status property */
288 propval = group;
289 display = xkl_engine_get_display(engine);
290 XChangeProperty(display, xkl_engine_priv(engine, root_window),
291 xkl_engine_backend(engine, XklXmm, state_atom),
292 XA_INTEGER, 32, PropModeReplace,
293 (unsigned char *) &propval, 1);
294 XSync(display, False);
295 }
296
297 void
xkl_xmm_set_indicators(XklEngine * engine,const XklState * window_state)298 xkl_xmm_set_indicators(XklEngine * engine, const XklState * window_state)
299 {
300 }
301
302
303 gint
xkl_xmm_init(XklEngine * engine)304 xkl_xmm_init(XklEngine * engine)
305 {
306 Display *display;
307
308 xkl_engine_priv(engine, backend_id) = "xmodmap";
309 xkl_engine_priv(engine, features) =
310 XKLF_MULTIPLE_LAYOUTS_SUPPORTED |
311 XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT;
312 xkl_engine_priv(engine, activate_config_rec) =
313 xkl_xmm_activate_config_rec;
314 xkl_engine_priv(engine, init_config_registry) =
315 xkl_xmm_init_config_registry;
316 xkl_engine_priv(engine, load_config_registry) =
317 xkl_xmm_load_config_registry;
318 xkl_engine_priv(engine, write_config_rec_to_file) = NULL;
319
320 xkl_engine_priv(engine, get_groups_names) =
321 xkl_xmm_get_groups_names;
322 xkl_engine_priv(engine, get_indicators_names) =
323 xkl_xmm_get_indicators_names;
324 xkl_engine_priv(engine, get_max_num_groups) =
325 xkl_xmm_get_max_num_groups;
326 xkl_engine_priv(engine, get_num_groups) = xkl_xmm_get_num_groups;
327 xkl_engine_priv(engine, lock_group) = xkl_xmm_lock_group;
328
329 xkl_engine_priv(engine, process_x_event) = xkl_xmm_process_x_event;
330 xkl_engine_priv(engine, process_x_error) = NULL;
331 xkl_engine_priv(engine, free_all_info) = xkl_xmm_free_all_info;
332 xkl_engine_priv(engine, if_cached_info_equals_actual) =
333 xkl_xmm_if_cached_info_equals_actual;
334 xkl_engine_priv(engine, load_all_info) = xkl_xmm_load_all_info;
335 xkl_engine_priv(engine, get_server_state) =
336 xkl_xmm_get_server_state;
337 xkl_engine_priv(engine, pause_listen) = xkl_xmm_pause_listen;
338 xkl_engine_priv(engine, resume_listen) = xkl_xmm_resume_listen;
339 xkl_engine_priv(engine, set_indicators) = xkl_xmm_set_indicators;
340 xkl_engine_priv(engine, finalize) = xkl_xmm_term;
341
342 if (getenv("XKL_XMODMAP_DISABLE") != NULL)
343 return -1;
344
345 display = xkl_engine_get_display(engine);
346 xkl_engine_priv(engine, base_config_atom) =
347 XInternAtom(display, "_XMM_NAMES", False);
348 xkl_engine_priv(engine, backup_config_atom) =
349 XInternAtom(display, "_XMM_NAMES_BACKUP", False);
350
351 xkl_engine_priv(engine, backend) = g_new0(XklXmm, 1);
352
353 xkl_engine_backend(engine, XklXmm, state_atom) =
354 XInternAtom(display, "_XMM_STATE", False);
355
356 xkl_engine_priv(engine, default_model) = "generic";
357 xkl_engine_priv(engine, default_layout) = "us";
358
359 xkl_xmm_init_switch_options((XklXmm *)
360 xkl_engine_priv(engine, backend));
361
362 return 0;
363 }
364
365 void
xkl_xmm_term(XklEngine * engine)366 xkl_xmm_term(XklEngine * engine)
367 {
368 xkl_xmm_term_switch_options((XklXmm *)
369 xkl_engine_priv(engine, backend));
370 }
371