00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #define _GNU_SOURCE
00027 #define _SVID_SOURCE
00028
00029 #include <config.h>
00030 #include "keybindings.h"
00031 #include "workspace.h"
00032 #include "errors.h"
00033 #include "edge-resistance.h"
00034 #include "ui.h"
00035 #include "frame-private.h"
00036 #include "place.h"
00037 #include "prefs.h"
00038 #include "effects.h"
00039
00040 #include <X11/keysym.h>
00041 #include <string.h>
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044
00045 #ifdef HAVE_XKB
00046 #include <X11/XKBlib.h>
00047 #endif
00048
00049 static gboolean all_bindings_disabled = FALSE;
00050
00051 typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
00052 MetaScreen *screen,
00053 MetaWindow *window,
00054 XEvent *event,
00055 MetaKeyBinding *binding);
00056
00057 static void handle_activate_workspace (MetaDisplay *display,
00058 MetaScreen *screen,
00059 MetaWindow *window,
00060 XEvent *event,
00061 MetaKeyBinding *binding);
00062 static void handle_activate_menu (MetaDisplay *display,
00063 MetaScreen *screen,
00064 MetaWindow *window,
00065 XEvent *event,
00066 MetaKeyBinding *binding);
00067 static void handle_tab_forward (MetaDisplay *display,
00068 MetaScreen *screen,
00069 MetaWindow *window,
00070 XEvent *event,
00071 MetaKeyBinding *binding);
00072 static void handle_tab_backward (MetaDisplay *display,
00073 MetaScreen *screen,
00074 MetaWindow *window,
00075 XEvent *event,
00076 MetaKeyBinding *binding);
00077 static void handle_cycle_forward (MetaDisplay *display,
00078 MetaScreen *screen,
00079 MetaWindow *window,
00080 XEvent *event,
00081 MetaKeyBinding *binding);
00082 static void handle_cycle_backward (MetaDisplay *display,
00083 MetaScreen *screen,
00084 MetaWindow *window,
00085 XEvent *event,
00086 MetaKeyBinding *binding);
00087 static void handle_toggle_fullscreen (MetaDisplay *display,
00088 MetaScreen *screen,
00089 MetaWindow *window,
00090 XEvent *event,
00091 MetaKeyBinding *binding);
00092 static void handle_toggle_desktop (MetaDisplay *display,
00093 MetaScreen *screen,
00094 MetaWindow *window,
00095 XEvent *event,
00096 MetaKeyBinding *binding);
00097 static void handle_panel_keybinding (MetaDisplay *display,
00098 MetaScreen *screen,
00099 MetaWindow *window,
00100 XEvent *event,
00101 MetaKeyBinding *binding);
00102 static void handle_toggle_above (MetaDisplay *display,
00103 MetaScreen *screen,
00104 MetaWindow *window,
00105 XEvent *event,
00106 MetaKeyBinding *binding);
00107 static void handle_toggle_maximize (MetaDisplay *display,
00108 MetaScreen *screen,
00109 MetaWindow *window,
00110 XEvent *event,
00111 MetaKeyBinding *binding);
00112 static void handle_maximize (MetaDisplay *display,
00113 MetaScreen *screen,
00114 MetaWindow *window,
00115 XEvent *event,
00116 MetaKeyBinding *binding);
00117 static void handle_unmaximize (MetaDisplay *display,
00118 MetaScreen *screen,
00119 MetaWindow *window,
00120 XEvent *event,
00121 MetaKeyBinding *binding);
00122 static void handle_toggle_shade (MetaDisplay *display,
00123 MetaScreen *screen,
00124 MetaWindow *window,
00125 XEvent *event,
00126 MetaKeyBinding *binding);
00127 static void handle_close_window (MetaDisplay *display,
00128 MetaScreen *screen,
00129 MetaWindow *window,
00130 XEvent *event,
00131 MetaKeyBinding *binding);
00132 static void handle_minimize_window (MetaDisplay *display,
00133 MetaScreen *screen,
00134 MetaWindow *window,
00135 XEvent *event,
00136 MetaKeyBinding *binding);
00137 static void handle_begin_move (MetaDisplay *display,
00138 MetaScreen *screen,
00139 MetaWindow *window,
00140 XEvent *event,
00141 MetaKeyBinding *binding);
00142 static void handle_begin_resize (MetaDisplay *display,
00143 MetaScreen *screen,
00144 MetaWindow *window,
00145 XEvent *event,
00146 MetaKeyBinding *binding);
00147 static void handle_toggle_sticky (MetaDisplay *display,
00148 MetaScreen *screen,
00149 MetaWindow *window,
00150 XEvent *event,
00151 MetaKeyBinding *binding);
00152 static void handle_move_to_workspace (MetaDisplay *display,
00153 MetaScreen *screen,
00154 MetaWindow *window,
00155 XEvent *event,
00156 MetaKeyBinding *binding);
00157 static void handle_move_to_workspace_flip (MetaDisplay *display,
00158 MetaScreen *screen,
00159 MetaWindow *window,
00160 XEvent *event,
00161 MetaKeyBinding *binding);
00162 static void handle_workspace_switch (MetaDisplay *display,
00163 MetaScreen *screen,
00164 MetaWindow *window,
00165 XEvent *event,
00166 MetaKeyBinding *binding);
00167 static void handle_raise_or_lower (MetaDisplay *display,
00168 MetaScreen *screen,
00169 MetaWindow *window,
00170 XEvent *event,
00171 MetaKeyBinding *binding);
00172 static void handle_raise (MetaDisplay *display,
00173 MetaScreen *screen,
00174 MetaWindow *window,
00175 XEvent *event,
00176 MetaKeyBinding *binding);
00177 static void handle_lower (MetaDisplay *display,
00178 MetaScreen *screen,
00179 MetaWindow *window,
00180 XEvent *event,
00181 MetaKeyBinding *binding);
00182 static void handle_run_command (MetaDisplay *display,
00183 MetaScreen *screen,
00184 MetaWindow *window,
00185 XEvent *event,
00186 MetaKeyBinding *binding);
00187 static void handle_maximize_vert (MetaDisplay *display,
00188 MetaScreen *screen,
00189 MetaWindow *window,
00190 XEvent *event,
00191 MetaKeyBinding *binding);
00192 static void handle_maximize_horiz (MetaDisplay *display,
00193 MetaScreen *screen,
00194 MetaWindow *window,
00195 XEvent *event,
00196 MetaKeyBinding *binding);
00197 static void handle_move_to_side_n (MetaDisplay *display,
00198 MetaScreen *screen,
00199 MetaWindow *window,
00200 XEvent *event,
00201 MetaKeyBinding *binding);
00202 static void handle_move_to_side_w (MetaDisplay *display,
00203 MetaScreen *screen,
00204 MetaWindow *window,
00205 XEvent *event,
00206 MetaKeyBinding *binding);
00207 static void handle_move_to_side_s (MetaDisplay *display,
00208 MetaScreen *screen,
00209 MetaWindow *window,
00210 XEvent *event,
00211 MetaKeyBinding *binding);
00212 static void handle_move_to_side_e (MetaDisplay *display,
00213 MetaScreen *screen,
00214 MetaWindow *window,
00215 XEvent *event,
00216 MetaKeyBinding *binding);
00217 static void handle_move_to_corner_nw (MetaDisplay *display,
00218 MetaScreen *screen,
00219 MetaWindow *window,
00220 XEvent *event,
00221 MetaKeyBinding *binding);
00222 static void handle_move_to_corner_ne (MetaDisplay *display,
00223 MetaScreen *screen,
00224 MetaWindow *window,
00225 XEvent *event,
00226 MetaKeyBinding *binding);
00227 static void handle_move_to_corner_sw (MetaDisplay *display,
00228 MetaScreen *screen,
00229 MetaWindow *window,
00230 XEvent *event,
00231 MetaKeyBinding *binding);
00232 static void handle_move_to_corner_se (MetaDisplay *display,
00233 MetaScreen *screen,
00234 MetaWindow *window,
00235 XEvent *event,
00236 MetaKeyBinding *binding);
00237 static void handle_spew_mark (MetaDisplay *display,
00238 MetaScreen *screen,
00239 MetaWindow *window,
00240 XEvent *event,
00241 MetaKeyBinding *binding);
00242 static void handle_run_terminal (MetaDisplay *display,
00243 MetaScreen *screen,
00244 MetaWindow *window,
00245 XEvent *event,
00246 MetaKeyBinding *binding);
00247
00248
00249 static gboolean process_mouse_move_resize_grab (MetaDisplay *display,
00250 MetaScreen *screen,
00251 MetaWindow *window,
00252 XEvent *event,
00253 KeySym keysym);
00254
00255 static gboolean process_keyboard_move_grab (MetaDisplay *display,
00256 MetaScreen *screen,
00257 MetaWindow *window,
00258 XEvent *event,
00259 KeySym keysym);
00260
00261 static gboolean process_keyboard_resize_grab (MetaDisplay *display,
00262 MetaScreen *screen,
00263 MetaWindow *window,
00264 XEvent *event,
00265 KeySym keysym);
00266
00267 static gboolean process_tab_grab (MetaDisplay *display,
00268 MetaScreen *screen,
00269 XEvent *event,
00270 KeySym keysym);
00271
00272 static gboolean process_workspace_switch_grab (MetaDisplay *display,
00273 MetaScreen *screen,
00274 XEvent *event,
00275 KeySym keysym);
00276
00277 static void regrab_screen_bindings (MetaDisplay *display);
00278 static void regrab_window_bindings (MetaDisplay *display);
00279
00280 typedef struct
00281 {
00282 const char *name;
00283 MetaKeyHandlerFunc func;
00284 void *data;
00285 } MetaKeyHandler;
00286
00287 struct _MetaKeyBinding
00288 {
00289 const char *name;
00290 KeySym keysym;
00291 KeyCode keycode;
00292 unsigned int mask;
00293 MetaVirtualModifier modifiers;
00294 const MetaKeyHandler *handler;
00295 };
00296
00297 static const MetaKeyHandler screen_handlers[] = {
00298 { META_KEYBINDING_WORKSPACE_1, handle_activate_workspace,
00299 GINT_TO_POINTER (0) },
00300 { META_KEYBINDING_WORKSPACE_2, handle_activate_workspace,
00301 GINT_TO_POINTER (1) },
00302 { META_KEYBINDING_WORKSPACE_3, handle_activate_workspace,
00303 GINT_TO_POINTER (2) },
00304 { META_KEYBINDING_WORKSPACE_4, handle_activate_workspace,
00305 GINT_TO_POINTER (3) },
00306 { META_KEYBINDING_WORKSPACE_5, handle_activate_workspace,
00307 GINT_TO_POINTER (4) },
00308 { META_KEYBINDING_WORKSPACE_6, handle_activate_workspace,
00309 GINT_TO_POINTER (5) },
00310 { META_KEYBINDING_WORKSPACE_7, handle_activate_workspace,
00311 GINT_TO_POINTER (6) },
00312 { META_KEYBINDING_WORKSPACE_8, handle_activate_workspace,
00313 GINT_TO_POINTER (7) },
00314 { META_KEYBINDING_WORKSPACE_9, handle_activate_workspace,
00315 GINT_TO_POINTER (8) },
00316 { META_KEYBINDING_WORKSPACE_10, handle_activate_workspace,
00317 GINT_TO_POINTER (9) },
00318 { META_KEYBINDING_WORKSPACE_11, handle_activate_workspace,
00319 GINT_TO_POINTER (10) },
00320 { META_KEYBINDING_WORKSPACE_12, handle_activate_workspace,
00321 GINT_TO_POINTER (11) },
00322 { META_KEYBINDING_WORKSPACE_LEFT, handle_workspace_switch,
00323 GINT_TO_POINTER (META_MOTION_LEFT) },
00324 { META_KEYBINDING_WORKSPACE_RIGHT, handle_workspace_switch,
00325 GINT_TO_POINTER (META_MOTION_RIGHT) },
00326 { META_KEYBINDING_WORKSPACE_UP, handle_workspace_switch,
00327 GINT_TO_POINTER (META_MOTION_UP) },
00328 { META_KEYBINDING_WORKSPACE_DOWN, handle_workspace_switch,
00329 GINT_TO_POINTER (META_MOTION_DOWN) },
00330 { META_KEYBINDING_SWITCH_WINDOWS, handle_tab_forward,
00331 GINT_TO_POINTER (META_TAB_LIST_NORMAL) },
00332 { META_KEYBINDING_SWITCH_WINDOWS_BACKWARD, handle_tab_backward,
00333 GINT_TO_POINTER (META_TAB_LIST_NORMAL) },
00334 { META_KEYBINDING_SWITCH_PANELS, handle_tab_forward,
00335 GINT_TO_POINTER (META_TAB_LIST_DOCKS) },
00336 { META_KEYBINDING_SWITCH_PANELS_BACKWARD, handle_tab_backward,
00337 GINT_TO_POINTER (META_TAB_LIST_DOCKS) },
00338 { META_KEYBINDING_SWITCH_GROUP, handle_tab_forward,
00339 GINT_TO_POINTER (META_TAB_LIST_GROUP) },
00340 { META_KEYBINDING_SWITCH_GROUP_BACKWARD, handle_tab_backward,
00341 GINT_TO_POINTER (META_TAB_LIST_GROUP) },
00342 { META_KEYBINDING_CYCLE_GROUP, handle_cycle_forward,
00343 GINT_TO_POINTER (META_TAB_LIST_GROUP) },
00344 { META_KEYBINDING_CYCLE_GROUP_BACKWARD, handle_cycle_backward,
00345 GINT_TO_POINTER (META_TAB_LIST_GROUP) },
00346 { META_KEYBINDING_CYCLE_WINDOWS, handle_cycle_forward,
00347 GINT_TO_POINTER (META_TAB_LIST_NORMAL) },
00348 { META_KEYBINDING_CYCLE_WINDOWS_BACKWARD, handle_cycle_backward,
00349 GINT_TO_POINTER (META_TAB_LIST_NORMAL) },
00350 { META_KEYBINDING_CYCLE_PANELS, handle_cycle_forward,
00351 GINT_TO_POINTER (META_TAB_LIST_DOCKS) },
00352 { META_KEYBINDING_CYCLE_PANELS_BACKWARD, handle_cycle_backward,
00353 GINT_TO_POINTER (META_TAB_LIST_DOCKS) },
00354 { META_KEYBINDING_SHOW_DESKTOP, handle_toggle_desktop,
00355 NULL },
00356 { META_KEYBINDING_PANEL_MAIN_MENU, handle_panel_keybinding,
00357 GINT_TO_POINTER (META_KEYBINDING_ACTION_PANEL_MAIN_MENU) },
00358 { META_KEYBINDING_PANEL_RUN_DIALOG, handle_panel_keybinding,
00359 GINT_TO_POINTER (META_KEYBINDING_ACTION_PANEL_RUN_DIALOG) },
00360 { META_KEYBINDING_COMMAND_1, handle_run_command,
00361 GINT_TO_POINTER (0) },
00362 { META_KEYBINDING_COMMAND_2, handle_run_command,
00363 GINT_TO_POINTER (1) },
00364 { META_KEYBINDING_COMMAND_3, handle_run_command,
00365 GINT_TO_POINTER (2) },
00366 { META_KEYBINDING_COMMAND_4, handle_run_command,
00367 GINT_TO_POINTER (3) },
00368 { META_KEYBINDING_COMMAND_5, handle_run_command,
00369 GINT_TO_POINTER (4) },
00370 { META_KEYBINDING_COMMAND_6, handle_run_command,
00371 GINT_TO_POINTER (5) },
00372 { META_KEYBINDING_COMMAND_7, handle_run_command,
00373 GINT_TO_POINTER (6) },
00374 { META_KEYBINDING_COMMAND_8, handle_run_command,
00375 GINT_TO_POINTER (7) },
00376 { META_KEYBINDING_COMMAND_9, handle_run_command,
00377 GINT_TO_POINTER (8) },
00378 { META_KEYBINDING_COMMAND_10, handle_run_command,
00379 GINT_TO_POINTER (9) },
00380 { META_KEYBINDING_COMMAND_11, handle_run_command,
00381 GINT_TO_POINTER (10) },
00382 { META_KEYBINDING_COMMAND_12, handle_run_command,
00383 GINT_TO_POINTER (11) },
00384 { META_KEYBINDING_COMMAND_13, handle_run_command,
00385 GINT_TO_POINTER (12) },
00386 { META_KEYBINDING_COMMAND_14, handle_run_command,
00387 GINT_TO_POINTER (13) },
00388 { META_KEYBINDING_COMMAND_15, handle_run_command,
00389 GINT_TO_POINTER (14) },
00390 { META_KEYBINDING_COMMAND_16, handle_run_command,
00391 GINT_TO_POINTER (15) },
00392 { META_KEYBINDING_COMMAND_17, handle_run_command,
00393 GINT_TO_POINTER (16) },
00394 { META_KEYBINDING_COMMAND_18, handle_run_command,
00395 GINT_TO_POINTER (17) },
00396 { META_KEYBINDING_COMMAND_19, handle_run_command,
00397 GINT_TO_POINTER (18) },
00398 { META_KEYBINDING_COMMAND_20, handle_run_command,
00399 GINT_TO_POINTER (19) },
00400 { META_KEYBINDING_COMMAND_21, handle_run_command,
00401 GINT_TO_POINTER (20) },
00402 { META_KEYBINDING_COMMAND_22, handle_run_command,
00403 GINT_TO_POINTER (21) },
00404 { META_KEYBINDING_COMMAND_23, handle_run_command,
00405 GINT_TO_POINTER (22) },
00406 { META_KEYBINDING_COMMAND_24, handle_run_command,
00407 GINT_TO_POINTER (23) },
00408 { META_KEYBINDING_COMMAND_25, handle_run_command,
00409 GINT_TO_POINTER (24) },
00410 { META_KEYBINDING_COMMAND_26, handle_run_command,
00411 GINT_TO_POINTER (25) },
00412 { META_KEYBINDING_COMMAND_27, handle_run_command,
00413 GINT_TO_POINTER (26) },
00414 { META_KEYBINDING_COMMAND_28, handle_run_command,
00415 GINT_TO_POINTER (27) },
00416 { META_KEYBINDING_COMMAND_29, handle_run_command,
00417 GINT_TO_POINTER (28) },
00418 { META_KEYBINDING_COMMAND_30, handle_run_command,
00419 GINT_TO_POINTER (29) },
00420 { META_KEYBINDING_COMMAND_31, handle_run_command,
00421 GINT_TO_POINTER (30) },
00422 { META_KEYBINDING_COMMAND_32, handle_run_command,
00423 GINT_TO_POINTER (31) },
00424 { META_KEYBINDING_COMMAND_SCREENSHOT, handle_run_command,
00425 GINT_TO_POINTER (32) },
00426 { META_KEYBINDING_COMMAND_WIN_SCREENSHOT, handle_run_command,
00427 GINT_TO_POINTER (33) },
00428 { META_KEYBINDING_RUN_COMMAND_TERMINAL, handle_run_terminal,
00429 NULL },
00430 { META_KEYBINDING_SET_SPEW_MARK, handle_spew_mark, NULL },
00431 { NULL, NULL, NULL }
00432 };
00433
00434 static const MetaKeyHandler window_handlers[] = {
00435 { META_KEYBINDING_WINDOW_MENU, handle_activate_menu, NULL },
00436 { META_KEYBINDING_TOGGLE_FULLSCREEN, handle_toggle_fullscreen, NULL },
00437 { META_KEYBINDING_TOGGLE_ABOVE, handle_toggle_above, NULL },
00438 { META_KEYBINDING_TOGGLE_MAXIMIZE, handle_toggle_maximize, NULL },
00439 { META_KEYBINDING_MAXIMIZE, handle_maximize, NULL },
00440 { META_KEYBINDING_UNMAXIMIZE, handle_unmaximize, NULL },
00441 { META_KEYBINDING_TOGGLE_SHADE, handle_toggle_shade, NULL },
00442 { META_KEYBINDING_CLOSE, handle_close_window, NULL },
00443 { META_KEYBINDING_MINIMIZE, handle_minimize_window, NULL },
00444 { META_KEYBINDING_BEGIN_MOVE, handle_begin_move, },
00445 { META_KEYBINDING_BEGIN_RESIZE, handle_begin_resize, },
00446 { META_KEYBINDING_TOGGLE_STICKY, handle_toggle_sticky, },
00447 { META_KEYBINDING_MOVE_WORKSPACE_1, handle_move_to_workspace,
00448 GINT_TO_POINTER (0) },
00449 { META_KEYBINDING_MOVE_WORKSPACE_2, handle_move_to_workspace,
00450 GINT_TO_POINTER (1) },
00451 { META_KEYBINDING_MOVE_WORKSPACE_3, handle_move_to_workspace,
00452 GINT_TO_POINTER (2) },
00453 { META_KEYBINDING_MOVE_WORKSPACE_4, handle_move_to_workspace,
00454 GINT_TO_POINTER (3) },
00455 { META_KEYBINDING_MOVE_WORKSPACE_5, handle_move_to_workspace,
00456 GINT_TO_POINTER (4) },
00457 { META_KEYBINDING_MOVE_WORKSPACE_6, handle_move_to_workspace,
00458 GINT_TO_POINTER (5) },
00459 { META_KEYBINDING_MOVE_WORKSPACE_7, handle_move_to_workspace,
00460 GINT_TO_POINTER (6) },
00461 { META_KEYBINDING_MOVE_WORKSPACE_8, handle_move_to_workspace,
00462 GINT_TO_POINTER (7) },
00463 { META_KEYBINDING_MOVE_WORKSPACE_9, handle_move_to_workspace,
00464 GINT_TO_POINTER (8) },
00465 { META_KEYBINDING_MOVE_WORKSPACE_10, handle_move_to_workspace,
00466 GINT_TO_POINTER (9) },
00467 { META_KEYBINDING_MOVE_WORKSPACE_11, handle_move_to_workspace,
00468 GINT_TO_POINTER (10) },
00469 { META_KEYBINDING_MOVE_WORKSPACE_12, handle_move_to_workspace,
00470 GINT_TO_POINTER (11) },
00471 { META_KEYBINDING_MOVE_WORKSPACE_LEFT, handle_move_to_workspace_flip,
00472 GINT_TO_POINTER (META_MOTION_LEFT) },
00473 { META_KEYBINDING_MOVE_WORKSPACE_RIGHT, handle_move_to_workspace_flip,
00474 GINT_TO_POINTER (META_MOTION_RIGHT) },
00475 { META_KEYBINDING_MOVE_WORKSPACE_UP, handle_move_to_workspace_flip,
00476 GINT_TO_POINTER (META_MOTION_UP) },
00477 { META_KEYBINDING_MOVE_WORKSPACE_DOWN, handle_move_to_workspace_flip,
00478 GINT_TO_POINTER (META_MOTION_DOWN) },
00479 { META_KEYBINDING_RAISE_OR_LOWER, handle_raise_or_lower, NULL},
00480 { META_KEYBINDING_RAISE, handle_raise, NULL},
00481 { META_KEYBINDING_LOWER, handle_lower, NULL},
00482 { META_KEYBINDING_MAXIMIZE_VERTICALLY, handle_maximize_vert, NULL },
00483 { META_KEYBINDING_MAXIMIZE_HORIZONTALLY, handle_maximize_horiz, NULL },
00484 { META_KEYBINDING_MOVE_TO_SIDE_N, handle_move_to_side_n, NULL },
00485 { META_KEYBINDING_MOVE_TO_SIDE_S, handle_move_to_side_s, NULL },
00486 { META_KEYBINDING_MOVE_TO_SIDE_E, handle_move_to_side_e, NULL },
00487 { META_KEYBINDING_MOVE_TO_SIDE_W, handle_move_to_side_w, NULL },
00488 { META_KEYBINDING_MOVE_TO_CORNER_NW, handle_move_to_corner_nw, NULL },
00489 { META_KEYBINDING_MOVE_TO_CORNER_NE, handle_move_to_corner_ne, NULL },
00490 { META_KEYBINDING_MOVE_TO_CORNER_SW, handle_move_to_corner_sw, NULL },
00491 { META_KEYBINDING_MOVE_TO_CORNER_SE, handle_move_to_corner_se, NULL },
00492 { NULL, NULL, NULL }
00493 };
00494
00495 static void
00496 reload_keymap (MetaDisplay *display)
00497 {
00498 if (display->keymap)
00499 meta_XFree (display->keymap);
00500
00501 display->keymap = XGetKeyboardMapping (display->xdisplay,
00502 display->min_keycode,
00503 display->max_keycode -
00504 display->min_keycode + 1,
00505 &display->keysyms_per_keycode);
00506 }
00507
00508 static void
00509 reload_modmap (MetaDisplay *display)
00510 {
00511 XModifierKeymap *modmap;
00512 int map_size;
00513 int i;
00514
00515 if (display->modmap)
00516 XFreeModifiermap (display->modmap);
00517
00518 modmap = XGetModifierMapping (display->xdisplay);
00519 display->modmap = modmap;
00520
00521 display->ignored_modifier_mask = 0;
00522
00523
00524 display->num_lock_mask = 0;
00525 display->scroll_lock_mask = 0;
00526 display->meta_mask = 0;
00527 display->hyper_mask = 0;
00528 display->super_mask = 0;
00529
00530
00531
00532
00533 map_size = 8 * modmap->max_keypermod;
00534 i = 3 * modmap->max_keypermod;
00535 while (i < map_size)
00536 {
00537
00538
00539
00540 int keycode = modmap->modifiermap[i];
00541
00542 if (keycode >= display->min_keycode &&
00543 keycode <= display->max_keycode)
00544 {
00545 int j = 0;
00546 KeySym *syms = display->keymap +
00547 (keycode - display->min_keycode) * display->keysyms_per_keycode;
00548
00549 while (j < display->keysyms_per_keycode)
00550 {
00551 if (syms[j] != 0)
00552 {
00553 const char *str;
00554
00555 str = XKeysymToString (syms[j]);
00556 meta_topic (META_DEBUG_KEYBINDINGS,
00557 "Keysym %s bound to modifier 0x%x\n",
00558 str ? str : "none",
00559 (1 << ( i / modmap->max_keypermod)));
00560 }
00561
00562 if (syms[j] == XK_Num_Lock)
00563 {
00564
00565
00566
00567
00568
00569 display->num_lock_mask |= (1 << ( i / modmap->max_keypermod));
00570 }
00571 else if (syms[j] == XK_Scroll_Lock)
00572 {
00573 display->scroll_lock_mask |= (1 << ( i / modmap->max_keypermod));
00574 }
00575 else if (syms[j] == XK_Super_L ||
00576 syms[j] == XK_Super_R)
00577 {
00578 display->super_mask |= (1 << ( i / modmap->max_keypermod));
00579 }
00580 else if (syms[j] == XK_Hyper_L ||
00581 syms[j] == XK_Hyper_R)
00582 {
00583 display->hyper_mask |= (1 << ( i / modmap->max_keypermod));
00584 }
00585 else if (syms[j] == XK_Meta_L ||
00586 syms[j] == XK_Meta_R)
00587 {
00588 display->meta_mask |= (1 << ( i / modmap->max_keypermod));
00589 }
00590
00591 ++j;
00592 }
00593 }
00594
00595 ++i;
00596 }
00597
00598 display->ignored_modifier_mask = (display->num_lock_mask |
00599 display->scroll_lock_mask |
00600 LockMask);
00601
00602 meta_topic (META_DEBUG_KEYBINDINGS,
00603 "Ignoring modmask 0x%x num lock 0x%x scroll lock 0x%x hyper 0x%x super 0x%x meta 0x%x\n",
00604 display->ignored_modifier_mask,
00605 display->num_lock_mask,
00606 display->scroll_lock_mask,
00607 display->hyper_mask,
00608 display->super_mask,
00609 display->meta_mask);
00610 }
00611
00612 static void
00613 reload_keycodes (MetaDisplay *display)
00614 {
00615 meta_topic (META_DEBUG_KEYBINDINGS,
00616 "Reloading keycodes for binding tables\n");
00617
00618 if (display->screen_bindings)
00619 {
00620 int i;
00621
00622 i = 0;
00623 while (i < display->n_screen_bindings)
00624 {
00625 if (display->screen_bindings[i].keycode == 0)
00626 display->screen_bindings[i].keycode = XKeysymToKeycode (
00627 display->xdisplay, display->screen_bindings[i].keysym);
00628
00629 ++i;
00630 }
00631 }
00632
00633 if (display->window_bindings)
00634 {
00635 int i;
00636
00637 i = 0;
00638 while (i < display->n_window_bindings)
00639 {
00640 if (display->window_bindings[i].keycode == 0)
00641 display->window_bindings[i].keycode = XKeysymToKeycode (
00642 display->xdisplay, display->window_bindings[i].keysym);
00643
00644 ++i;
00645 }
00646 }
00647 }
00648
00649 static void
00650 reload_modifiers (MetaDisplay *display)
00651 {
00652 meta_topic (META_DEBUG_KEYBINDINGS,
00653 "Reloading keycodes for binding tables\n");
00654
00655 if (display->screen_bindings)
00656 {
00657 int i;
00658
00659 i = 0;
00660 while (i < display->n_screen_bindings)
00661 {
00662 meta_display_devirtualize_modifiers (display,
00663 display->screen_bindings[i].modifiers,
00664 &display->screen_bindings[i].mask);
00665
00666 meta_topic (META_DEBUG_KEYBINDINGS,
00667 " Devirtualized mods 0x%x -> 0x%x (%s)\n",
00668 display->screen_bindings[i].modifiers,
00669 display->screen_bindings[i].mask,
00670 display->screen_bindings[i].name);
00671
00672 ++i;
00673 }
00674 }
00675
00676 if (display->window_bindings)
00677 {
00678 int i;
00679
00680 i = 0;
00681 while (i < display->n_window_bindings)
00682 {
00683 meta_display_devirtualize_modifiers (display,
00684 display->window_bindings[i].modifiers,
00685 &display->window_bindings[i].mask);
00686
00687 meta_topic (META_DEBUG_KEYBINDINGS,
00688 " Devirtualized mods 0x%x -> 0x%x (%s)\n",
00689 display->window_bindings[i].modifiers,
00690 display->window_bindings[i].mask,
00691 display->window_bindings[i].name);
00692
00693 ++i;
00694 }
00695 }
00696 }
00697
00698 static int
00699 count_bindings (const MetaKeyPref *prefs,
00700 int n_prefs)
00701 {
00702 int i;
00703 int count;
00704
00705 count = 0;
00706 i = 0;
00707 while (i < n_prefs)
00708 {
00709 GSList *tmp = prefs[i].bindings;
00710
00711 while (tmp)
00712 {
00713 MetaKeyCombo *combo = tmp->data;
00714
00715 if (combo && (combo->keysym != None || combo->keycode != 0))
00716 {
00717 count += 1;
00718
00719 if (prefs[i].add_shift &&
00720 (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
00721 count += 1;
00722 }
00723
00724 tmp = tmp->next;
00725 }
00726
00727 ++i;
00728 }
00729
00730 return count;
00731 }
00732
00733 static void
00734 rebuild_binding_table (MetaDisplay *display,
00735 MetaKeyBinding **bindings_p,
00736 int *n_bindings_p,
00737 const MetaKeyPref *prefs,
00738 int n_prefs)
00739 {
00740 int n_bindings;
00741 int src, dest;
00742
00743 n_bindings = count_bindings (prefs, n_prefs);
00744 g_free (*bindings_p);
00745 *bindings_p = g_new0 (MetaKeyBinding, n_bindings);
00746
00747 src = 0;
00748 dest = 0;
00749 while (src < n_prefs)
00750 {
00751 GSList *tmp = prefs[src].bindings;
00752
00753 while (tmp)
00754 {
00755 MetaKeyCombo *combo = tmp->data;
00756
00757 if (combo && (combo->keysym != None || combo->keycode != 0))
00758 {
00759 (*bindings_p)[dest].name = prefs[src].name;
00760 (*bindings_p)[dest].keysym = combo->keysym;
00761 (*bindings_p)[dest].keycode = combo->keycode;
00762 (*bindings_p)[dest].modifiers = combo->modifiers;
00763 (*bindings_p)[dest].mask = 0;
00764
00765 ++dest;
00766
00767 if (prefs[src].add_shift &&
00768 (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
00769 {
00770 meta_topic (META_DEBUG_KEYBINDINGS,
00771 "Binding %s also needs Shift grabbed\n",
00772 prefs[src].name);
00773
00774 (*bindings_p)[dest].name = prefs[src].name;
00775 (*bindings_p)[dest].keysym = combo->keysym;
00776 (*bindings_p)[dest].keycode = combo->keycode;
00777 (*bindings_p)[dest].modifiers = combo->modifiers |
00778 META_VIRTUAL_SHIFT_MASK;
00779 (*bindings_p)[dest].mask = 0;
00780
00781 ++dest;
00782 }
00783 }
00784
00785 tmp = tmp->next;
00786 }
00787
00788 ++src;
00789 }
00790
00791 g_assert (dest == n_bindings);
00792
00793 *n_bindings_p = dest;
00794
00795 meta_topic (META_DEBUG_KEYBINDINGS,
00796 " %d bindings in table\n",
00797 *n_bindings_p);
00798 }
00799
00800 static void
00801 rebuild_screen_binding_table (MetaDisplay *display)
00802 {
00803 const MetaKeyPref *prefs;
00804 int n_prefs;
00805
00806 meta_topic (META_DEBUG_KEYBINDINGS,
00807 "Rebuilding screen binding table from preferences\n");
00808
00809 meta_prefs_get_screen_bindings (&prefs, &n_prefs);
00810 rebuild_binding_table (display,
00811 &display->screen_bindings,
00812 &display->n_screen_bindings,
00813 prefs, n_prefs);
00814 }
00815
00816 static void
00817 rebuild_window_binding_table (MetaDisplay *display)
00818 {
00819 const MetaKeyPref *prefs;
00820 int n_prefs;
00821
00822 meta_topic (META_DEBUG_KEYBINDINGS,
00823 "Rebuilding window binding table from preferences\n");
00824
00825 meta_prefs_get_window_bindings (&prefs, &n_prefs);
00826 rebuild_binding_table (display,
00827 &display->window_bindings,
00828 &display->n_window_bindings,
00829 prefs, n_prefs);
00830 }
00831
00832 static void
00833 regrab_screen_bindings (MetaDisplay *display)
00834 {
00835 GSList *tmp;
00836
00837 meta_error_trap_push (display);
00838
00839 tmp = display->screens;
00840 while (tmp != NULL)
00841 {
00842 MetaScreen *screen = tmp->data;
00843
00844 meta_screen_ungrab_keys (screen);
00845 meta_screen_grab_keys (screen);
00846
00847 tmp = tmp->next;
00848 }
00849
00850 meta_error_trap_pop (display, FALSE);
00851 }
00852
00853 static void
00854 regrab_window_bindings (MetaDisplay *display)
00855 {
00856 GSList *windows;
00857 GSList *tmp;
00858
00859 windows = meta_display_list_windows (display);
00860
00861 meta_error_trap_push (display);
00862 tmp = windows;
00863 while (tmp != NULL)
00864 {
00865 MetaWindow *w = tmp->data;
00866
00867 meta_window_ungrab_keys (w);
00868 meta_window_grab_keys (w);
00869
00870 tmp = tmp->next;
00871 }
00872 meta_error_trap_pop (display, FALSE);
00873
00874 g_slist_free (windows);
00875 }
00876
00877 static MetaKeyBindingAction
00878 display_get_keybinding_action (MetaDisplay *display,
00879 unsigned int keysym,
00880 unsigned int keycode,
00881 unsigned long mask)
00882 {
00883 int i;
00884
00885 i = display->n_screen_bindings - 1;
00886 while (i >= 0)
00887 {
00888 if (display->screen_bindings[i].keysym == keysym &&
00889 display->screen_bindings[i].keycode == keycode &&
00890 display->screen_bindings[i].mask == mask)
00891 {
00892 return meta_prefs_get_keybinding_action (display->screen_bindings[i].name);
00893 }
00894
00895 --i;
00896 }
00897
00898 return META_KEYBINDING_ACTION_NONE;
00899 }
00900
00901 void
00902 meta_display_process_mapping_event (MetaDisplay *display,
00903 XEvent *event)
00904 {
00905 if (event->xmapping.request == MappingModifier)
00906 {
00907 meta_topic (META_DEBUG_KEYBINDINGS,
00908 "Received MappingModifier event, will reload modmap and redo keybindings\n");
00909
00910 reload_modmap (display);
00911
00912 reload_modifiers (display);
00913
00914 regrab_screen_bindings (display);
00915 regrab_window_bindings (display);
00916 }
00917 else if (event->xmapping.request == MappingKeyboard)
00918 {
00919 meta_topic (META_DEBUG_KEYBINDINGS,
00920 "Received MappingKeyboard event, will reload keycodes and redo keybindings\n");
00921
00922 reload_keymap (display);
00923 reload_modmap (display);
00924
00925 reload_keycodes (display);
00926
00927 regrab_screen_bindings (display);
00928 regrab_window_bindings (display);
00929 }
00930 }
00931
00932 static void
00933 bindings_changed_callback (MetaPreference pref,
00934 void *data)
00935 {
00936 MetaDisplay *display;
00937
00938 display = data;
00939
00940 switch (pref)
00941 {
00942 case META_PREF_SCREEN_KEYBINDINGS:
00943 rebuild_screen_binding_table (display);
00944 reload_keycodes (display);
00945 reload_modifiers (display);
00946 regrab_screen_bindings (display);
00947 break;
00948 case META_PREF_WINDOW_KEYBINDINGS:
00949 rebuild_window_binding_table (display);
00950 reload_keycodes (display);
00951 reload_modifiers (display);
00952 regrab_window_bindings (display);
00953 break;
00954 default:
00955 break;
00956 }
00957 }
00958
00959
00960 void
00961 meta_display_init_keys (MetaDisplay *display)
00962 {
00963
00964 display->keymap = NULL;
00965 display->keysyms_per_keycode = 0;
00966 display->modmap = NULL;
00967 display->min_keycode = 0;
00968 display->max_keycode = 0;
00969 display->ignored_modifier_mask = 0;
00970 display->num_lock_mask = 0;
00971 display->scroll_lock_mask = 0;
00972 display->hyper_mask = 0;
00973 display->super_mask = 0;
00974 display->meta_mask = 0;
00975 display->screen_bindings = NULL;
00976 display->n_screen_bindings = 0;
00977 display->window_bindings = NULL;
00978 display->n_window_bindings = 0;
00979
00980 XDisplayKeycodes (display->xdisplay,
00981 &display->min_keycode,
00982 &display->max_keycode);
00983
00984 meta_topic (META_DEBUG_KEYBINDINGS,
00985 "Display has keycode range %d to %d\n",
00986 display->min_keycode,
00987 display->max_keycode);
00988
00989 reload_keymap (display);
00990 reload_modmap (display);
00991
00992 rebuild_window_binding_table (display);
00993 rebuild_screen_binding_table (display);
00994
00995 reload_keycodes (display);
00996 reload_modifiers (display);
00997
00998
00999
01000 meta_prefs_add_listener (bindings_changed_callback, display);
01001 }
01002
01003 void
01004 meta_display_shutdown_keys (MetaDisplay *display)
01005 {
01006
01007
01008 meta_prefs_remove_listener (bindings_changed_callback, display);
01009
01010 if (display->keymap)
01011 meta_XFree (display->keymap);
01012
01013 if (display->modmap)
01014 XFreeModifiermap (display->modmap);
01015 g_free (display->screen_bindings);
01016 g_free (display->window_bindings);
01017 }
01018
01019 static const char*
01020 keysym_name (int keysym)
01021 {
01022 const char *name;
01023
01024 name = XKeysymToString (keysym);
01025 if (name == NULL)
01026 name = "(unknown)";
01027
01028 return name;
01029 }
01030
01031
01032 static void
01033 meta_change_keygrab (MetaDisplay *display,
01034 Window xwindow,
01035 gboolean grab,
01036 int keysym,
01037 unsigned int keycode,
01038 int modmask)
01039 {
01040 unsigned int ignored_mask;
01041
01042
01043
01044
01045
01046
01047 meta_topic (META_DEBUG_KEYBINDINGS,
01048 "%s keybinding %s keycode %d mask 0x%x on 0x%lx\n",
01049 grab ? "Grabbing" : "Ungrabbing",
01050 keysym_name (keysym), keycode,
01051 modmask, xwindow);
01052
01053
01054 meta_error_trap_push (display);
01055
01056 ignored_mask = 0;
01057 while (ignored_mask <= display->ignored_modifier_mask)
01058 {
01059 if (ignored_mask & ~(display->ignored_modifier_mask))
01060 {
01061
01062
01063
01064 ++ignored_mask;
01065 continue;
01066 }
01067
01068 if (meta_is_debugging ())
01069 meta_error_trap_push_with_return (display);
01070 if (grab)
01071 XGrabKey (display->xdisplay, keycode,
01072 modmask | ignored_mask,
01073 xwindow,
01074 True,
01075 GrabModeAsync, GrabModeSync);
01076 else
01077 XUngrabKey (display->xdisplay, keycode,
01078 modmask | ignored_mask,
01079 xwindow);
01080
01081 if (meta_is_debugging ())
01082 {
01083 int result;
01084
01085 result = meta_error_trap_pop_with_return (display, FALSE);
01086
01087 if (grab && result != Success)
01088 {
01089 if (result == BadAccess)
01090 meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), keysym_name (keysym), modmask | ignored_mask);
01091 else
01092 meta_topic (META_DEBUG_KEYBINDINGS,
01093 "Failed to grab key %s with modifiers %x\n",
01094 keysym_name (keysym), modmask | ignored_mask);
01095 }
01096 }
01097
01098 ++ignored_mask;
01099 }
01100
01101 meta_error_trap_pop (display, FALSE);
01102 }
01103
01104 static void
01105 meta_grab_key (MetaDisplay *display,
01106 Window xwindow,
01107 int keysym,
01108 unsigned int keycode,
01109 int modmask)
01110 {
01111 meta_change_keygrab (display, xwindow, TRUE, keysym, keycode, modmask);
01112 }
01113
01114 static void
01115 grab_keys (MetaKeyBinding *bindings,
01116 int n_bindings,
01117 MetaDisplay *display,
01118 Window xwindow)
01119 {
01120 int i;
01121
01122 g_assert (n_bindings == 0 || bindings != NULL);
01123
01124 meta_error_trap_push (display);
01125
01126 i = 0;
01127 while (i < n_bindings)
01128 {
01129 if (bindings[i].keycode != 0)
01130 {
01131 meta_grab_key (display, xwindow,
01132 bindings[i].keysym,
01133 bindings[i].keycode,
01134 bindings[i].mask);
01135 }
01136
01137 ++i;
01138 }
01139
01140 meta_error_trap_pop (display, FALSE);
01141 }
01142
01143 static void
01144 ungrab_all_keys (MetaDisplay *display,
01145 Window xwindow)
01146 {
01147 if (meta_is_debugging ())
01148 meta_error_trap_push_with_return (display);
01149 else
01150 meta_error_trap_push (display);
01151
01152 XUngrabKey (display->xdisplay, AnyKey, AnyModifier,
01153 xwindow);
01154
01155 if (meta_is_debugging ())
01156 {
01157 int result;
01158
01159 result = meta_error_trap_pop_with_return (display, FALSE);
01160
01161 if (result != Success)
01162 meta_topic (META_DEBUG_KEYBINDINGS,
01163 "Ungrabbing all keys on 0x%lx failed\n", xwindow);
01164 }
01165 else
01166 meta_error_trap_pop (display, FALSE);
01167 }
01168
01169 void
01170 meta_screen_grab_keys (MetaScreen *screen)
01171 {
01172 if (screen->all_keys_grabbed)
01173 return;
01174
01175 if (screen->keys_grabbed)
01176 return;
01177
01178 grab_keys (screen->display->screen_bindings,
01179 screen->display->n_screen_bindings,
01180 screen->display, screen->xroot);
01181
01182 screen->keys_grabbed = TRUE;
01183 }
01184
01185 void
01186 meta_screen_ungrab_keys (MetaScreen *screen)
01187 {
01188 if (screen->keys_grabbed)
01189 {
01190 ungrab_all_keys (screen->display, screen->xroot);
01191 screen->keys_grabbed = FALSE;
01192 }
01193 }
01194
01195 void
01196 meta_window_grab_keys (MetaWindow *window)
01197 {
01198 if (window->all_keys_grabbed)
01199 return;
01200
01201 if (window->type == META_WINDOW_DOCK)
01202 {
01203 if (window->keys_grabbed)
01204 ungrab_all_keys (window->display, window->xwindow);
01205 window->keys_grabbed = FALSE;
01206 return;
01207 }
01208
01209 if (window->keys_grabbed)
01210 {
01211 if (window->frame && !window->grab_on_frame)
01212 ungrab_all_keys (window->display, window->xwindow);
01213 else if (window->frame == NULL &&
01214 window->grab_on_frame)
01215 ;
01216 else
01217 return;
01218 }
01219
01220 grab_keys (window->display->window_bindings,
01221 window->display->n_window_bindings,
01222 window->display,
01223 window->frame ? window->frame->xwindow : window->xwindow);
01224
01225 window->keys_grabbed = TRUE;
01226 window->grab_on_frame = window->frame != NULL;
01227 }
01228
01229 void
01230 meta_window_ungrab_keys (MetaWindow *window)
01231 {
01232 if (window->keys_grabbed)
01233 {
01234 if (window->grab_on_frame &&
01235 window->frame != NULL)
01236 ungrab_all_keys (window->display,
01237 window->frame->xwindow);
01238 else if (!window->grab_on_frame)
01239 ungrab_all_keys (window->display,
01240 window->xwindow);
01241
01242 window->keys_grabbed = FALSE;
01243 }
01244 }
01245
01246 #ifdef WITH_VERBOSE_MODE
01247 static const char*
01248 grab_status_to_string (int status)
01249 {
01250 switch (status)
01251 {
01252 case AlreadyGrabbed:
01253 return "AlreadyGrabbed";
01254 case GrabSuccess:
01255 return "GrabSuccess";
01256 case GrabNotViewable:
01257 return "GrabNotViewable";
01258 case GrabFrozen:
01259 return "GrabFrozen";
01260 case GrabInvalidTime:
01261 return "GrabInvalidTime";
01262 default:
01263 return "(unknown)";
01264 }
01265 }
01266 #endif
01267
01268 static gboolean
01269 grab_keyboard (MetaDisplay *display,
01270 Window xwindow,
01271 guint32 timestamp)
01272 {
01273 int result;
01274 int grab_status;
01275
01276
01277
01278
01279 meta_error_trap_push_with_return (display);
01280
01281 grab_status = XGrabKeyboard (display->xdisplay,
01282 xwindow, True,
01283 GrabModeAsync, GrabModeAsync,
01284 timestamp);
01285
01286 if (grab_status != GrabSuccess)
01287 {
01288 meta_error_trap_pop_with_return (display, TRUE);
01289 meta_topic (META_DEBUG_KEYBINDINGS,
01290 "XGrabKeyboard() returned failure status %s time %u\n",
01291 grab_status_to_string (grab_status),
01292 timestamp);
01293 return FALSE;
01294 }
01295 else
01296 {
01297 result = meta_error_trap_pop_with_return (display, TRUE);
01298 if (result != Success)
01299 {
01300 meta_topic (META_DEBUG_KEYBINDINGS,
01301 "XGrabKeyboard() resulted in an error\n");
01302 return FALSE;
01303 }
01304 }
01305
01306 meta_topic (META_DEBUG_KEYBINDINGS, "Grabbed all keys\n");
01307
01308 return TRUE;
01309 }
01310
01311 static void
01312 ungrab_keyboard (MetaDisplay *display, guint32 timestamp)
01313 {
01314 meta_error_trap_push (display);
01315
01316 meta_topic (META_DEBUG_KEYBINDINGS,
01317 "Ungrabbing keyboard with timestamp %u\n",
01318 timestamp);
01319 XUngrabKeyboard (display->xdisplay, timestamp);
01320 meta_error_trap_pop (display, FALSE);
01321 }
01322
01323 gboolean
01324 meta_screen_grab_all_keys (MetaScreen *screen, guint32 timestamp)
01325 {
01326 gboolean retval;
01327
01328 if (screen->all_keys_grabbed)
01329 return FALSE;
01330
01331 if (screen->keys_grabbed)
01332 meta_screen_ungrab_keys (screen);
01333
01334 meta_topic (META_DEBUG_KEYBINDINGS,
01335 "Grabbing all keys on RootWindow\n");
01336 retval = grab_keyboard (screen->display, screen->xroot, timestamp);
01337 if (retval)
01338 screen->all_keys_grabbed = TRUE;
01339 else
01340 meta_screen_grab_keys (screen);
01341
01342 return retval;
01343 }
01344
01345 void
01346 meta_screen_ungrab_all_keys (MetaScreen *screen, guint32 timestamp)
01347 {
01348 if (screen->all_keys_grabbed)
01349 {
01350 ungrab_keyboard (screen->display, timestamp);
01351
01352 screen->all_keys_grabbed = FALSE;
01353 screen->keys_grabbed = FALSE;
01354
01355
01356 meta_screen_grab_keys (screen);
01357 }
01358 }
01359
01360 gboolean
01361 meta_window_grab_all_keys (MetaWindow *window,
01362 guint32 timestamp)
01363 {
01364 Window grabwindow;
01365 gboolean retval;
01366
01367 if (window->all_keys_grabbed)
01368 return FALSE;
01369
01370 if (window->keys_grabbed)
01371 meta_window_ungrab_keys (window);
01372
01373
01374
01375
01376 meta_topic (META_DEBUG_FOCUS,
01377 "Focusing %s because we're grabbing all its keys\n",
01378 window->desc);
01379 meta_window_focus (window, timestamp);
01380
01381 grabwindow = window->frame ? window->frame->xwindow : window->xwindow;
01382
01383 meta_topic (META_DEBUG_KEYBINDINGS,
01384 "Grabbing all keys on window %s\n", window->desc);
01385 retval = grab_keyboard (window->display, grabwindow, timestamp);
01386 if (retval)
01387 {
01388 window->keys_grabbed = FALSE;
01389 window->all_keys_grabbed = TRUE;
01390 window->grab_on_frame = window->frame != NULL;
01391 }
01392
01393 return retval;
01394 }
01395
01396 void
01397 meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
01398 {
01399 if (window->all_keys_grabbed)
01400 {
01401 ungrab_keyboard (window->display, timestamp);
01402
01403 window->grab_on_frame = FALSE;
01404 window->all_keys_grabbed = FALSE;
01405 window->keys_grabbed = FALSE;
01406
01407
01408 meta_window_grab_keys (window);
01409 }
01410 }
01411
01412 static gboolean
01413 is_modifier (MetaDisplay *display,
01414 unsigned int keycode)
01415 {
01416 int i;
01417 int map_size;
01418 gboolean retval = FALSE;
01419
01420 g_assert (display->modmap);
01421
01422 map_size = 8 * display->modmap->max_keypermod;
01423 i = 0;
01424 while (i < map_size)
01425 {
01426 if (keycode == display->modmap->modifiermap[i])
01427 {
01428 retval = TRUE;
01429 break;
01430 }
01431 ++i;
01432 }
01433
01434 return retval;
01435 }
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448 static gboolean
01449 is_specific_modifier (MetaDisplay *display,
01450 unsigned int keycode,
01451 unsigned int mask)
01452 {
01453 int i;
01454 int end;
01455 gboolean retval = FALSE;
01456 int mod_index;
01457
01458 g_assert (display->modmap);
01459
01460 meta_topic (META_DEBUG_KEYBINDINGS,
01461 "Checking whether code 0x%x is bound to modifier 0x%x\n",
01462 keycode, mask);
01463
01464 mod_index = 0;
01465 mask = mask >> 1;
01466 while (mask != 0)
01467 {
01468 mod_index += 1;
01469 mask = mask >> 1;
01470 }
01471
01472 meta_topic (META_DEBUG_KEYBINDINGS,
01473 "Modifier has index %d\n", mod_index);
01474
01475 end = (mod_index + 1) * display->modmap->max_keypermod;
01476 i = mod_index * display->modmap->max_keypermod;
01477 while (i < end)
01478 {
01479 if (keycode == display->modmap->modifiermap[i])
01480 {
01481 retval = TRUE;
01482 break;
01483 }
01484 ++i;
01485 }
01486
01487 return retval;
01488 }
01489
01490 static unsigned int
01491 get_primary_modifier (MetaDisplay *display,
01492 unsigned int entire_binding_mask)
01493 {
01494
01495
01496
01497
01498
01499
01500 unsigned int masks[] = { Mod5Mask, Mod4Mask, Mod3Mask,
01501 Mod2Mask, Mod1Mask, ControlMask,
01502 ShiftMask, LockMask };
01503
01504 int i;
01505
01506 i = 0;
01507 while (i < (int) G_N_ELEMENTS (masks))
01508 {
01509 if (entire_binding_mask & masks[i])
01510 return masks[i];
01511 ++i;
01512 }
01513
01514 return 0;
01515 }
01516
01517 static gboolean
01518 keycode_is_primary_modifier (MetaDisplay *display,
01519 unsigned int keycode,
01520 unsigned int entire_binding_mask)
01521 {
01522 unsigned int primary_modifier;
01523
01524 meta_topic (META_DEBUG_KEYBINDINGS,
01525 "Checking whether code 0x%x is the primary modifier of mask 0x%x\n",
01526 keycode, entire_binding_mask);
01527
01528 primary_modifier = get_primary_modifier (display, entire_binding_mask);
01529 if (primary_modifier != 0)
01530 return is_specific_modifier (display, keycode, primary_modifier);
01531 else
01532 return FALSE;
01533 }
01534
01535 static gboolean
01536 primary_modifier_still_pressed (MetaDisplay *display,
01537 unsigned int entire_binding_mask)
01538 {
01539 unsigned int primary_modifier;
01540 int x, y, root_x, root_y;
01541 Window root, child;
01542 guint mask;
01543 MetaScreen *random_screen;
01544 Window random_xwindow;
01545
01546 primary_modifier = get_primary_modifier (display, entire_binding_mask);
01547
01548 random_screen = display->screens->data;
01549 random_xwindow = random_screen->no_focus_window;
01550 XQueryPointer (display->xdisplay,
01551 random_xwindow,
01552 &root, &child,
01553 &root_x, &root_y,
01554 &x, &y,
01555 &mask);
01556
01557 meta_topic (META_DEBUG_KEYBINDINGS,
01558 "Primary modifier 0x%x full grab mask 0x%x current state 0x%x\n",
01559 primary_modifier, entire_binding_mask, mask);
01560
01561 if ((mask & primary_modifier) == 0)
01562 return FALSE;
01563 else
01564 return TRUE;
01565 }
01566
01567 static const MetaKeyHandler*
01568 find_handler (const MetaKeyHandler *handlers,
01569 const char *name)
01570 {
01571 const MetaKeyHandler *iter;
01572
01573 iter = handlers;
01574 while (iter->name)
01575 {
01576 if (strcmp (iter->name,
01577 name) == 0)
01578 return iter;
01579
01580 ++iter;
01581 }
01582
01583 return NULL;
01584 }
01585
01586 static gboolean
01587 process_event (MetaKeyBinding *bindings,
01588 int n_bindings,
01589 const MetaKeyHandler *handlers,
01590 MetaDisplay *display,
01591 MetaScreen *screen,
01592 MetaWindow *window,
01593 XEvent *event,
01594 KeySym keysym)
01595 {
01596 int i;
01597
01598
01599 if (event->type == KeyRelease)
01600 return FALSE;
01601
01602 i = 0;
01603 while (i < n_bindings)
01604 {
01605 if (bindings[i].keycode == event->xkey.keycode &&
01606 ((event->xkey.state & 0xff & ~(display->ignored_modifier_mask)) ==
01607 bindings[i].mask) &&
01608 event->type == KeyPress)
01609 {
01610 const MetaKeyHandler *handler;
01611
01612 meta_topic (META_DEBUG_KEYBINDINGS,
01613 "Binding keycode 0x%x mask 0x%x matches event 0x%x state 0x%x\n",
01614 bindings[i].keycode, bindings[i].mask,
01615 event->xkey.keycode, event->xkey.state);
01616
01617 if (bindings[i].handler)
01618 handler = bindings[i].handler;
01619 else
01620 {
01621 handler = find_handler (handlers, bindings[i].name);
01622 bindings[i].handler = handler;
01623 }
01624
01625 if (handler == NULL)
01626 meta_bug ("Binding %s has no handler\n", bindings[i].name);
01627 else
01628 meta_topic (META_DEBUG_KEYBINDINGS,
01629 "Running handler for %s\n",
01630 bindings[i].name);
01631
01632
01633
01634
01635
01636 display->allow_terminal_deactivation = TRUE;
01637
01638 (* handler->func) (display, screen, window, event,
01639 &bindings[i]);
01640 return TRUE;
01641 }
01642
01643 ++i;
01644 }
01645
01646 meta_topic (META_DEBUG_KEYBINDINGS,
01647 "No handler found for this event in this binding table\n");
01648 return FALSE;
01649 }
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662 void
01663 meta_display_process_key_event (MetaDisplay *display,
01664 MetaWindow *window,
01665 XEvent *event)
01666 {
01667 KeySym keysym;
01668 gboolean handled;
01669 gboolean keep_grab;
01670 gboolean all_keys_grabbed;
01671 const char *str;
01672 MetaScreen *screen;
01673
01674 XAllowEvents (display->xdisplay,
01675 all_bindings_disabled ? ReplayKeyboard : AsyncKeyboard,
01676 event->xkey.time);
01677 if (all_bindings_disabled)
01678 return;
01679
01680
01681 screen = meta_display_screen_for_root (display, event->xkey.window);
01682
01683
01684 if (screen == NULL)
01685 screen = meta_display_screen_for_xwindow (display,
01686 event->xany.window);
01687
01688 if (screen == NULL)
01689 return;
01690
01691
01692 if (window == NULL &&
01693 meta_ui_window_is_widget (screen->ui, event->xany.window))
01694 return;
01695
01696
01697
01698 keysym = XKeycodeToKeysym (display->xdisplay, event->xkey.keycode, 0);
01699
01700 str = XKeysymToString (keysym);
01701
01702 meta_topic (META_DEBUG_KEYBINDINGS,
01703 "Processing key %s event, keysym: %s state: 0x%x window: %s\n",
01704 event->type == KeyPress ? "press" : "release",
01705 str ? str : "none", event->xkey.state,
01706 window ? window->desc : "(no window)");
01707
01708 keep_grab = TRUE;
01709 all_keys_grabbed = window ? window->all_keys_grabbed : screen->all_keys_grabbed;
01710 if (all_keys_grabbed)
01711 {
01712 if (display->grab_op == META_GRAB_OP_NONE)
01713 return;
01714
01715
01716
01717
01718 if (window ? (window == display->grab_window) :
01719 (screen == display->grab_screen))
01720 {
01721 switch (display->grab_op)
01722 {
01723 case META_GRAB_OP_MOVING:
01724 case META_GRAB_OP_RESIZING_SE:
01725 case META_GRAB_OP_RESIZING_S:
01726 case META_GRAB_OP_RESIZING_SW:
01727 case META_GRAB_OP_RESIZING_N:
01728 case META_GRAB_OP_RESIZING_NE:
01729 case META_GRAB_OP_RESIZING_NW:
01730 case META_GRAB_OP_RESIZING_W:
01731 case META_GRAB_OP_RESIZING_E:
01732 meta_topic (META_DEBUG_KEYBINDINGS,
01733 "Processing event for mouse-only move/resize\n");
01734 g_assert (window != NULL);
01735 keep_grab = process_mouse_move_resize_grab (display, screen,
01736 window, event, keysym);
01737 break;
01738
01739 case META_GRAB_OP_KEYBOARD_MOVING:
01740 meta_topic (META_DEBUG_KEYBINDINGS,
01741 "Processing event for keyboard move\n");
01742 g_assert (window != NULL);
01743 keep_grab = process_keyboard_move_grab (display, screen,
01744 window, event, keysym);
01745 break;
01746
01747 case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
01748 case META_GRAB_OP_KEYBOARD_RESIZING_S:
01749 case META_GRAB_OP_KEYBOARD_RESIZING_N:
01750 case META_GRAB_OP_KEYBOARD_RESIZING_W:
01751 case META_GRAB_OP_KEYBOARD_RESIZING_E:
01752 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
01753 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
01754 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
01755 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
01756 meta_topic (META_DEBUG_KEYBINDINGS,
01757 "Processing event for keyboard resize\n");
01758 g_assert (window != NULL);
01759 keep_grab = process_keyboard_resize_grab (display, screen,
01760 window, event, keysym);
01761 break;
01762
01763 case META_GRAB_OP_KEYBOARD_TABBING_NORMAL:
01764 case META_GRAB_OP_KEYBOARD_TABBING_DOCK:
01765 case META_GRAB_OP_KEYBOARD_TABBING_GROUP:
01766 case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL:
01767 case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK:
01768 case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP:
01769 meta_topic (META_DEBUG_KEYBINDINGS,
01770 "Processing event for keyboard tabbing/cycling\n");
01771 keep_grab = process_tab_grab (display, screen, event, keysym);
01772 break;
01773
01774 case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING:
01775 meta_topic (META_DEBUG_KEYBINDINGS,
01776 "Processing event for keyboard workspace switching\n");
01777 keep_grab = process_workspace_switch_grab (display, screen, event, keysym);
01778 break;
01779
01780 default:
01781 break;
01782 }
01783 }
01784 if (!keep_grab)
01785 {
01786 meta_topic (META_DEBUG_KEYBINDINGS,
01787 "Ending grab op %u on key event sym %s\n",
01788 display->grab_op, XKeysymToString (keysym));
01789 meta_display_end_grab_op (display, event->xkey.time);
01790 return;
01791 }
01792 }
01793
01794 handled = process_event (display->screen_bindings,
01795 display->n_screen_bindings,
01796 screen_handlers,
01797 display, screen, NULL, event, keysym);
01798
01799 if (!all_keys_grabbed && !handled && window)
01800 handled = process_event (display->window_bindings,
01801 display->n_window_bindings,
01802 window_handlers,
01803 display, screen, window, event, keysym);
01804 }
01805
01806 static gboolean
01807 process_mouse_move_resize_grab (MetaDisplay *display,
01808 MetaScreen *screen,
01809 MetaWindow *window,
01810 XEvent *event,
01811 KeySym keysym)
01812 {
01813
01814 if (event->type == KeyRelease)
01815 return TRUE;
01816
01817 if (keysym == XK_Escape)
01818 {
01819
01820
01821
01822
01823
01824
01825
01826 if (window->shaken_loose)
01827 meta_window_maximize (window,
01828 META_MAXIMIZE_HORIZONTAL |
01829 META_MAXIMIZE_VERTICAL);
01830 else if (!display->grab_wireframe_active)
01831 meta_window_move_resize (display->grab_window,
01832 TRUE,
01833 display->grab_initial_window_pos.x,
01834 display->grab_initial_window_pos.y,
01835 display->grab_initial_window_pos.width,
01836 display->grab_initial_window_pos.height);
01837 else
01838 display->grab_was_cancelled = TRUE;
01839
01840
01841 return FALSE;
01842 }
01843
01844 return TRUE;
01845 }
01846
01847 static gboolean
01848 process_keyboard_move_grab (MetaDisplay *display,
01849 MetaScreen *screen,
01850 MetaWindow *window,
01851 XEvent *event,
01852 KeySym keysym)
01853 {
01854 gboolean handled;
01855 int x, y;
01856 int incr;
01857 gboolean smart_snap;
01858
01859 handled = FALSE;
01860
01861
01862 if (event->type == KeyRelease)
01863 return TRUE;
01864
01865
01866 if (is_modifier (display, event->xkey.keycode))
01867 return TRUE;
01868
01869 if (display->grab_wireframe_active)
01870 {
01871 x = display->grab_wireframe_rect.x;
01872 y = display->grab_wireframe_rect.y;
01873 }
01874 else
01875 {
01876 meta_window_get_position (window, &x, &y);
01877 }
01878
01879 smart_snap = (event->xkey.state & ShiftMask) != 0;
01880
01881 #define SMALL_INCREMENT 1
01882 #define NORMAL_INCREMENT 10
01883
01884 if (smart_snap)
01885 incr = 1;
01886 else if (event->xkey.state & ControlMask)
01887 incr = SMALL_INCREMENT;
01888 else
01889 incr = NORMAL_INCREMENT;
01890
01891 if (keysym == XK_Escape)
01892 {
01893
01894
01895
01896
01897
01898
01899
01900 if (window->shaken_loose)
01901 meta_window_maximize (window,
01902 META_MAXIMIZE_HORIZONTAL |
01903 META_MAXIMIZE_VERTICAL);
01904 else if (!display->grab_wireframe_active)
01905 meta_window_move_resize (display->grab_window,
01906 TRUE,
01907 display->grab_initial_window_pos.x,
01908 display->grab_initial_window_pos.y,
01909 display->grab_initial_window_pos.width,
01910 display->grab_initial_window_pos.height);
01911 else
01912 display->grab_was_cancelled = TRUE;
01913 }
01914
01915
01916
01917
01918
01919
01920 switch (keysym)
01921 {
01922 case XK_KP_Home:
01923 case XK_KP_Prior:
01924 case XK_Up:
01925 case XK_KP_Up:
01926 y -= incr;
01927 handled = TRUE;
01928 break;
01929 case XK_KP_End:
01930 case XK_KP_Next:
01931 case XK_Down:
01932 case XK_KP_Down:
01933 y += incr;
01934 handled = TRUE;
01935 break;
01936 }
01937
01938 switch (keysym)
01939 {
01940 case XK_KP_Home:
01941 case XK_KP_End:
01942 case XK_Left:
01943 case XK_KP_Left:
01944 x -= incr;
01945 handled = TRUE;
01946 break;
01947 case XK_KP_Prior:
01948 case XK_KP_Next:
01949 case XK_Right:
01950 case XK_KP_Right:
01951 x += incr;
01952 handled = TRUE;
01953 break;
01954 }
01955
01956 if (handled)
01957 {
01958 MetaRectangle old_rect;
01959 meta_topic (META_DEBUG_KEYBINDINGS,
01960 "Computed new window location %d,%d due to keypress\n",
01961 x, y);
01962
01963 if (display->grab_wireframe_active)
01964 old_rect = display->grab_wireframe_rect;
01965 else
01966 meta_window_get_client_root_coords (window, &old_rect);
01967
01968 meta_window_edge_resistance_for_move (window,
01969 old_rect.x,
01970 old_rect.y,
01971 &x,
01972 &y,
01973 NULL,
01974 smart_snap,
01975 TRUE);
01976
01977 if (display->grab_wireframe_active)
01978 {
01979 meta_window_update_wireframe (window, x, y,
01980 display->grab_wireframe_rect.width,
01981 display->grab_wireframe_rect.height);
01982 }
01983 else
01984 {
01985 meta_window_move (window, TRUE, x, y);
01986 }
01987
01988 meta_window_update_keyboard_move (window);
01989 }
01990
01991 return handled;
01992 }
01993
01994 static gboolean
01995 process_keyboard_resize_grab_op_change (MetaDisplay *display,
01996 MetaScreen *screen,
01997 MetaWindow *window,
01998 XEvent *event,
01999 KeySym keysym)
02000 {
02001 gboolean handled;
02002
02003 handled = FALSE;
02004 switch (display->grab_op)
02005 {
02006 case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
02007 switch (keysym)
02008 {
02009 case XK_Up:
02010 case XK_KP_Up:
02011 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
02012 handled = TRUE;
02013 break;
02014 case XK_Down:
02015 case XK_KP_Down:
02016 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
02017 handled = TRUE;
02018 break;
02019 case XK_Left:
02020 case XK_KP_Left:
02021 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
02022 handled = TRUE;
02023 break;
02024 case XK_Right:
02025 case XK_KP_Right:
02026 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
02027 handled = TRUE;
02028 break;
02029 }
02030 break;
02031
02032 case META_GRAB_OP_KEYBOARD_RESIZING_S:
02033 switch (keysym)
02034 {
02035 case XK_Left:
02036 case XK_KP_Left:
02037 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
02038 handled = TRUE;
02039 break;
02040 case XK_Right:
02041 case XK_KP_Right:
02042 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
02043 handled = TRUE;
02044 break;
02045 }
02046 break;
02047
02048 case META_GRAB_OP_KEYBOARD_RESIZING_N:
02049 switch (keysym)
02050 {
02051 case XK_Left:
02052 case XK_KP_Left:
02053 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
02054 handled = TRUE;
02055 break;
02056 case XK_Right:
02057 case XK_KP_Right:
02058 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
02059 handled = TRUE;
02060 break;
02061 }
02062 break;
02063
02064 case META_GRAB_OP_KEYBOARD_RESIZING_W:
02065 switch (keysym)
02066 {
02067 case XK_Up:
02068 case XK_KP_Up:
02069 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
02070 handled = TRUE;
02071 break;
02072 case XK_Down:
02073 case XK_KP_Down:
02074 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
02075 handled = TRUE;
02076 break;
02077 }
02078 break;
02079
02080 case META_GRAB_OP_KEYBOARD_RESIZING_E:
02081 switch (keysym)
02082 {
02083 case XK_Up:
02084 case XK_KP_Up:
02085 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
02086 handled = TRUE;
02087 break;
02088 case XK_Down:
02089 case XK_KP_Down:
02090 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
02091 handled = TRUE;
02092 break;
02093 }
02094 break;
02095
02096 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
02097 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
02098 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
02099 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
02100 break;
02101
02102 default:
02103 g_assert_not_reached ();
02104 break;
02105 }
02106
02107 if (handled)
02108 {
02109 meta_window_update_keyboard_resize (window, TRUE);
02110 return TRUE;
02111 }
02112
02113 return FALSE;
02114 }
02115
02116 static gboolean
02117 process_keyboard_resize_grab (MetaDisplay *display,
02118 MetaScreen *screen,
02119 MetaWindow *window,
02120 XEvent *event,
02121 KeySym keysym)
02122 {
02123 gboolean handled;
02124 int height_inc;
02125 int width_inc;
02126 int width, height;
02127 gboolean smart_snap;
02128 int gravity;
02129
02130 handled = FALSE;
02131
02132
02133 if (event->type == KeyRelease)
02134 return TRUE;
02135
02136
02137 if (is_modifier (display, event->xkey.keycode))
02138 return TRUE;
02139
02140 if (keysym == XK_Escape)
02141 {
02142
02143
02144
02145
02146
02147
02148 if (!display->grab_wireframe_active)
02149 meta_window_move_resize (display->grab_window,
02150 TRUE,
02151 display->grab_initial_window_pos.x,
02152 display->grab_initial_window_pos.y,
02153 display->grab_initial_window_pos.width,
02154 display->grab_initial_window_pos.height);
02155 else
02156 display->grab_was_cancelled = TRUE;
02157
02158 return FALSE;
02159 }
02160
02161 if (process_keyboard_resize_grab_op_change (display, screen, window,
02162 event, keysym))
02163 return TRUE;
02164
02165 if (display->grab_wireframe_active)
02166 {
02167 width = display->grab_wireframe_rect.width;
02168 height = display->grab_wireframe_rect.height;
02169 }
02170 else
02171 {
02172 width = window->rect.width;
02173 height = window->rect.height;
02174 }
02175
02176 gravity = meta_resize_gravity_from_grab_op (display->grab_op);
02177
02178 smart_snap = (event->xkey.state & ShiftMask) != 0;
02179
02180 #define SMALL_INCREMENT 1
02181 #define NORMAL_INCREMENT 10
02182
02183 if (smart_snap)
02184 {
02185 height_inc = 1;
02186 width_inc = 1;
02187 }
02188 else if (event->xkey.state & ControlMask)
02189 {
02190 width_inc = SMALL_INCREMENT;
02191 height_inc = SMALL_INCREMENT;
02192 }
02193 else
02194 {
02195 width_inc = NORMAL_INCREMENT;
02196 height_inc = NORMAL_INCREMENT;
02197 }
02198
02199
02200
02201
02202 if (window->size_hints.width_inc > 1)
02203 width_inc = window->size_hints.width_inc;
02204 if (window->size_hints.height_inc > 1)
02205 height_inc = window->size_hints.height_inc;
02206
02207 switch (keysym)
02208 {
02209 case XK_Up:
02210 case XK_KP_Up:
02211 switch (gravity)
02212 {
02213 case NorthGravity:
02214 case NorthWestGravity:
02215 case NorthEastGravity:
02216
02217 height -= height_inc;
02218 break;
02219
02220 case SouthGravity:
02221 case SouthWestGravity:
02222 case SouthEastGravity:
02223
02224 height += height_inc;
02225 break;
02226
02227 case EastGravity:
02228 case WestGravity:
02229 case CenterGravity:
02230 g_assert_not_reached ();
02231 break;
02232 }
02233
02234 handled = TRUE;
02235 break;
02236
02237 case XK_Down:
02238 case XK_KP_Down:
02239 switch (gravity)
02240 {
02241 case NorthGravity:
02242 case NorthWestGravity:
02243 case NorthEastGravity:
02244
02245 height += height_inc;
02246 break;
02247
02248 case SouthGravity:
02249 case SouthWestGravity:
02250 case SouthEastGravity:
02251
02252 height -= height_inc;
02253 break;
02254
02255 case EastGravity:
02256 case WestGravity:
02257 case CenterGravity:
02258 g_assert_not_reached ();
02259 break;
02260 }
02261
02262 handled = TRUE;
02263 break;
02264
02265 case XK_Left:
02266 case XK_KP_Left:
02267 switch (gravity)
02268 {
02269 case EastGravity:
02270 case SouthEastGravity:
02271 case NorthEastGravity:
02272
02273 width += width_inc;
02274 break;
02275
02276 case WestGravity:
02277 case SouthWestGravity:
02278 case NorthWestGravity:
02279
02280 width -= width_inc;
02281 break;
02282
02283 case NorthGravity:
02284 case SouthGravity:
02285 case CenterGravity:
02286 g_assert_not_reached ();
02287 break;
02288 }
02289
02290 handled = TRUE;
02291 break;
02292
02293 case XK_Right:
02294 case XK_KP_Right:
02295 switch (gravity)
02296 {
02297 case EastGravity:
02298 case SouthEastGravity:
02299 case NorthEastGravity:
02300
02301 width -= width_inc;
02302 break;
02303
02304 case WestGravity:
02305 case SouthWestGravity:
02306 case NorthWestGravity:
02307
02308 width += width_inc;
02309 break;
02310
02311 case NorthGravity:
02312 case SouthGravity:
02313 case CenterGravity:
02314 g_assert_not_reached ();
02315 break;
02316 }
02317
02318 handled = TRUE;
02319 break;
02320
02321 default:
02322 break;
02323 }
02324
02325
02326 if (height < 1)
02327 height = 1;
02328 if (width < 1)
02329 width = 1;
02330
02331 if (handled)
02332 {
02333 MetaRectangle old_rect;
02334 meta_topic (META_DEBUG_KEYBINDINGS,
02335 "Computed new window size due to keypress: "
02336 "%dx%d, gravity %s\n",
02337 width, height, meta_gravity_to_string (gravity));
02338
02339 if (display->grab_wireframe_active)
02340 old_rect = display->grab_wireframe_rect;
02341 else
02342 old_rect = window->rect;
02343
02344
02345 meta_window_edge_resistance_for_resize (window,
02346 old_rect.width,
02347 old_rect.height,
02348 &width,
02349 &height,
02350 gravity,
02351 NULL,
02352 smart_snap,
02353 TRUE);
02354
02355 if (display->grab_wireframe_active)
02356 {
02357 MetaRectangle new_position;
02358 meta_rectangle_resize_with_gravity (&display->grab_wireframe_rect,
02359 &new_position,
02360 gravity,
02361 width,
02362 height);
02363 meta_window_update_wireframe (window,
02364 new_position.x,
02365 new_position.y,
02366 new_position.width,
02367 new_position.height);
02368 }
02369 else
02370 {
02371
02372
02373
02374 if (window->rect.width != width || window->rect.height != height)
02375 meta_window_resize_with_gravity (window,
02376 TRUE,
02377 width,
02378 height,
02379 gravity);
02380 }
02381 meta_window_update_keyboard_resize (window, FALSE);
02382 }
02383
02384 return handled;
02385 }
02386
02387 static gboolean
02388 end_keyboard_grab (MetaDisplay *display,
02389 unsigned int keycode)
02390 {
02391 #ifdef HAVE_XKB
02392 if (display->xkb_base_event_type > 0)
02393 {
02394 unsigned int primary_modifier;
02395 XkbStateRec state;
02396
02397 primary_modifier = get_primary_modifier (display, display->grab_mask);
02398
02399 XkbGetState (display->xdisplay, XkbUseCoreKbd, &state);
02400
02401 if (!(primary_modifier & state.mods))
02402 return TRUE;
02403 }
02404 else
02405 #endif
02406 {
02407 if (keycode_is_primary_modifier (display, keycode, display->grab_mask))
02408 return TRUE;
02409 }
02410
02411 return FALSE;
02412 }
02413
02414 static gboolean
02415 process_tab_grab (MetaDisplay *display,
02416 MetaScreen *screen,
02417 XEvent *event,
02418 KeySym keysym)
02419 {
02420 MetaKeyBindingAction action;
02421 gboolean popup_not_showing;
02422 gboolean backward;
02423 gboolean key_used;
02424 Window prev_xwindow;
02425 MetaWindow *prev_window;
02426
02427 if (screen != display->grab_screen)
02428 return FALSE;
02429
02430 g_return_val_if_fail (screen->tab_popup != NULL, FALSE);
02431
02432 if (event->type == KeyRelease &&
02433 end_keyboard_grab (display, event->xkey.keycode))
02434 {
02435
02436 Window target_xwindow;
02437 MetaWindow *target_window;
02438
02439 target_xwindow =
02440 (Window) meta_ui_tab_popup_get_selected (screen->tab_popup);
02441 target_window =
02442 meta_display_lookup_x_window (display, target_xwindow);
02443
02444 meta_topic (META_DEBUG_KEYBINDINGS,
02445 "Ending tab operation, primary modifier released\n");
02446
02447 if (target_window)
02448 {
02449 target_window->tab_unminimized = FALSE;
02450
02451 meta_topic (META_DEBUG_KEYBINDINGS,
02452 "Activating target window\n");
02453
02454 meta_topic (META_DEBUG_FOCUS, "Activating %s due to tab popup "
02455 "selection and turning mouse_mode off\n",
02456 target_window->desc);
02457 display->mouse_mode = FALSE;
02458 meta_window_activate (target_window, event->xkey.time);
02459
02460 meta_topic (META_DEBUG_KEYBINDINGS,
02461 "Ending grab early so we can focus the target window\n");
02462 meta_display_end_grab_op (display, event->xkey.time);
02463
02464 return TRUE;
02465 }
02466
02467 return FALSE;
02468 }
02469
02470
02471 if (event->type == KeyRelease)
02472 return TRUE;
02473
02474
02475 if (is_modifier (display, event->xkey.keycode))
02476 return TRUE;
02477
02478 prev_xwindow = (Window) meta_ui_tab_popup_get_selected (screen->tab_popup);
02479 prev_window = meta_display_lookup_x_window (display, prev_xwindow);
02480 action = display_get_keybinding_action (display,
02481 keysym,
02482 event->xkey.keycode,
02483 display->grab_mask);
02484
02485
02486
02487
02488 switch (action)
02489 {
02490 case META_KEYBINDING_ACTION_CYCLE_PANELS:
02491 case META_KEYBINDING_ACTION_CYCLE_WINDOWS:
02492 case META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD:
02493 case META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD:
02494
02495
02496
02497 switch (display->grab_op)
02498 {
02499 case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL:
02500 case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK:
02501
02502 break;
02503 default:
02504 return FALSE;
02505 }
02506 break;
02507 case META_KEYBINDING_ACTION_SWITCH_PANELS:
02508 case META_KEYBINDING_ACTION_SWITCH_WINDOWS:
02509 case META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD:
02510 case META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD:
02511
02512
02513
02514 switch (display->grab_op)
02515 {
02516 case META_GRAB_OP_KEYBOARD_TABBING_NORMAL:
02517 case META_GRAB_OP_KEYBOARD_TABBING_DOCK:
02518
02519 break;
02520 default:
02521
02522
02523
02524 meta_stack_set_positions (screen->stack,
02525 screen->display->grab_old_window_stacking);
02526 if (prev_window && prev_window->tab_unminimized)
02527 {
02528 meta_window_minimize (prev_window);
02529 prev_window->tab_unminimized = FALSE;
02530 }
02531 return FALSE;
02532 }
02533 break;
02534 case META_KEYBINDING_ACTION_CYCLE_GROUP:
02535 case META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD:
02536 case META_KEYBINDING_ACTION_SWITCH_GROUP:
02537 case META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD:
02538 switch (display->grab_op)
02539 {
02540 case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP:
02541 case META_GRAB_OP_KEYBOARD_TABBING_GROUP:
02542
02543 break;
02544 default:
02545 return FALSE;
02546 }
02547
02548 break;
02549 default:
02550 break;
02551 }
02552
02553
02554
02555
02556
02557
02558
02559
02560 popup_not_showing = FALSE;
02561 key_used = FALSE;
02562 backward = FALSE;
02563
02564 switch (action)
02565 {
02566 case META_KEYBINDING_ACTION_CYCLE_PANELS:
02567 case META_KEYBINDING_ACTION_CYCLE_WINDOWS:
02568 case META_KEYBINDING_ACTION_CYCLE_GROUP:
02569 popup_not_showing = TRUE;
02570 key_used = TRUE;
02571 break;
02572 case META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD:
02573 case META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD:
02574 case META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD:
02575 popup_not_showing = TRUE;
02576 key_used = TRUE;
02577 backward = TRUE;
02578 break;
02579 case META_KEYBINDING_ACTION_SWITCH_PANELS:
02580 case META_KEYBINDING_ACTION_SWITCH_WINDOWS:
02581 case META_KEYBINDING_ACTION_SWITCH_GROUP:
02582 key_used = TRUE;
02583 break;
02584 case META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD:
02585 case META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD:
02586 case META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD:
02587 key_used = TRUE;
02588 backward = TRUE;
02589 break;
02590 default:
02591 break;
02592 }
02593
02594 if (key_used)
02595 {
02596 meta_topic (META_DEBUG_KEYBINDINGS,
02597 "Key pressed, moving tab focus in popup\n");
02598
02599 if (event->xkey.state & ShiftMask)
02600 backward = !backward;
02601
02602 if (backward)
02603 meta_ui_tab_popup_backward (screen->tab_popup);
02604 else
02605 meta_ui_tab_popup_forward (screen->tab_popup);
02606
02607 if (popup_not_showing)
02608 {
02609
02610
02611
02612 Window target_xwindow;
02613 MetaWindow *target_window;
02614
02615 meta_stack_set_positions (screen->stack,
02616 display->grab_old_window_stacking);
02617
02618 target_xwindow =
02619 (Window) meta_ui_tab_popup_get_selected (screen->tab_popup);
02620 target_window =
02621 meta_display_lookup_x_window (display, target_xwindow);
02622
02623 if (prev_window && prev_window->tab_unminimized)
02624 {
02625 prev_window->tab_unminimized = FALSE;
02626 meta_window_minimize (prev_window);
02627 }
02628
02629 if (target_window)
02630 {
02631 meta_window_raise (target_window);
02632 target_window->tab_unminimized = target_window->minimized;
02633 meta_window_unminimize (target_window);
02634 }
02635 }
02636 }
02637 else
02638 {
02639
02640 meta_topic (META_DEBUG_KEYBINDINGS,
02641 "Ending tabbing/cycling, uninteresting key pressed\n");
02642
02643 meta_topic (META_DEBUG_KEYBINDINGS,
02644 "Syncing to old stack positions.\n");
02645 meta_stack_set_positions (screen->stack,
02646 screen->display->grab_old_window_stacking);
02647
02648 if (prev_window && prev_window->tab_unminimized)
02649 {
02650 meta_window_minimize (prev_window);
02651 prev_window->tab_unminimized = FALSE;
02652 }
02653 }
02654
02655 return key_used;
02656 }
02657
02658 static void
02659 handle_activate_workspace (MetaDisplay *display,
02660 MetaScreen *screen,
02661 MetaWindow *event_window,
02662 XEvent *event,
02663 MetaKeyBinding *binding)
02664 {
02665 int which;
02666 MetaWorkspace *workspace;
02667
02668 which = GPOINTER_TO_INT (binding->handler->data);
02669
02670 workspace = NULL;
02671 if (which < 0)
02672 {
02673 workspace = meta_workspace_get_neighbor (screen->active_workspace,
02674 which);
02675 }
02676 else
02677 {
02678 workspace = meta_screen_get_workspace_by_index (screen, which);
02679 }
02680
02681 if (workspace)
02682 {
02683 meta_workspace_activate (workspace, event->xkey.time);
02684 }
02685 else
02686 {
02687
02688 }
02689 }
02690
02691 static void
02692 error_on_generic_command (const char *key,
02693 const char *command,
02694 const char *message,
02695 int screen_number,
02696 guint32 timestamp)
02697 {
02698 GError *err;
02699 char *argv[10];
02700 char numbuf[32];
02701 char timestampbuf[32];
02702
02703 sprintf (numbuf, "%d", screen_number);
02704 sprintf (timestampbuf, "%u", timestamp);
02705
02706 argv[0] = METACITY_LIBEXECDIR"/metacity-dialog";
02707 argv[1] = "--screen";
02708 argv[2] = numbuf;
02709 argv[3] = "--timestamp";
02710 argv[4] = timestampbuf;
02711 argv[5] = "--command-failed-error";
02712 argv[6] = (char *)key;
02713 argv[7] = (char*) (command ? command : "");
02714 argv[8] = (char*) message;
02715 argv[9] = NULL;
02716
02717 err = NULL;
02718 if (!g_spawn_async_with_pipes ("/",
02719 argv,
02720 NULL,
02721 0,
02722 NULL, NULL,
02723 NULL,
02724 NULL,
02725 NULL,
02726 NULL,
02727 &err))
02728 {
02729 meta_warning (_("Error launching metacity-dialog to print an error about a command: %s\n"),
02730 err->message);
02731 g_error_free (err);
02732 }
02733 }
02734
02735 static void
02736 error_on_command (int command_index,
02737 const char *command,
02738 const char *message,
02739 int screen_number,
02740 guint32 timestamp)
02741 {
02742 char *key;
02743
02744 meta_warning ("Error on command %d \"%s\": %s\n",
02745 command_index, command, message);
02746
02747 key = meta_prefs_get_gconf_key_for_command (command_index);
02748
02749 error_on_generic_command (key, command, message, screen_number, timestamp);
02750
02751 g_free (key);
02752 }
02753
02754 static void
02755 error_on_terminal_command (const char *command,
02756 const char *message,
02757 int screen_number,
02758 guint32 timestamp)
02759 {
02760 const char *key;
02761
02762 meta_warning ("Error on terminal command \"%s\": %s\n", command, message);
02763
02764 key = meta_prefs_get_gconf_key_for_terminal_command ();
02765
02766 error_on_generic_command (key, command, message, screen_number, timestamp);
02767 }
02768
02769 static void
02770 set_display_setup_func (void *data)
02771 {
02772 const char *screen_name = data;
02773 char *full;
02774
02775 full = g_strdup_printf ("DISPLAY=%s", screen_name);
02776
02777 putenv (full);
02778
02779
02780 }
02781
02782 static gboolean
02783 meta_spawn_command_line_async_on_screen (const gchar *command_line,
02784 MetaScreen *screen,
02785 GError **error)
02786 {
02787 gboolean retval;
02788 gchar **argv = NULL;
02789
02790 g_return_val_if_fail (command_line != NULL, FALSE);
02791
02792 if (!g_shell_parse_argv (command_line,
02793 NULL, &argv,
02794 error))
02795 return FALSE;
02796
02797 retval = g_spawn_async (NULL,
02798 argv,
02799 NULL,
02800 G_SPAWN_SEARCH_PATH,
02801 set_display_setup_func,
02802 screen->screen_name,
02803 NULL,
02804 error);
02805 g_strfreev (argv);
02806
02807 return retval;
02808 }
02809
02810
02811 static void
02812 handle_run_command (MetaDisplay *display,
02813 MetaScreen *screen,
02814 MetaWindow *window,
02815 XEvent *event,
02816 MetaKeyBinding *binding)
02817 {
02818 int which;
02819 const char *command;
02820 GError *err;
02821
02822 which = GPOINTER_TO_INT (binding->handler->data);
02823
02824 command = meta_prefs_get_command (which);
02825
02826 if (command == NULL)
02827 {
02828 char *s;
02829
02830 meta_topic (META_DEBUG_KEYBINDINGS,
02831 "No command %d to run in response to keybinding press\n",
02832 which);
02833
02834 s = g_strdup_printf (_("No command %d has been defined.\n"),
02835 which + 1);
02836 error_on_command (which, NULL, s, screen->number, event->xkey.time);
02837 g_free (s);
02838
02839 return;
02840 }
02841
02842 err = NULL;
02843 if (!meta_spawn_command_line_async_on_screen (command, screen, &err))
02844 {
02845 error_on_command (which, command, err->message, screen->number, event->xkey.time);
02846
02847 g_error_free (err);
02848 }
02849 }
02850
02851
02852 static void
02853 handle_maximize_vert (MetaDisplay *display,
02854 MetaScreen *screen,
02855 MetaWindow *window,
02856 XEvent *event,
02857 MetaKeyBinding *binding)
02858 {
02859 if (window && window->has_resize_func)
02860 {
02861 if (window->maximized_vertically)
02862 meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
02863 else
02864 meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
02865 }
02866 }
02867
02868 static void
02869 handle_maximize_horiz (MetaDisplay *display,
02870 MetaScreen *screen,
02871 MetaWindow *window,
02872 XEvent *event,
02873 MetaKeyBinding *binding)
02874 {
02875 if (window && window->has_resize_func)
02876 {
02877 if (window->maximized_horizontally)
02878 meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
02879 else
02880 meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
02881 }
02882 }
02883
02884
02885
02886
02887
02888
02889
02890 static void
02891 handle_move_to_corner_backend (MetaDisplay *display,
02892 MetaScreen *screen,
02893 MetaWindow *window,
02894 gboolean xchange,
02895 gboolean ychange,
02896 gboolean to_right,
02897 gboolean to_bottom)
02898 {
02899 MetaRectangle work_area;
02900 MetaRectangle outer;
02901 int orig_x, orig_y;
02902 int new_x, new_y;
02903 int frame_width, frame_height;
02904
02905 meta_window_get_work_area_all_xineramas (window, &work_area);
02906 meta_window_get_outer_rect (window, &outer);
02907 meta_window_get_position (window, &orig_x, &orig_y);
02908
02909 frame_width = (window->frame ? window->frame->child_x : 0);
02910 frame_height = (window->frame ? window->frame->child_y : 0);
02911
02912 if (xchange) {
02913 new_x = work_area.x + (to_right ?
02914 (work_area.width + frame_width) - outer.width :
02915 0);
02916 } else {
02917 new_x = orig_x;
02918 }
02919
02920 if (ychange) {
02921 new_y = work_area.y + (to_bottom ?
02922 (work_area.height + frame_height) - outer.height :
02923 0);
02924 } else {
02925 new_y = orig_y;
02926 }
02927
02928 meta_window_move_resize (window,
02929 FALSE,
02930 new_x,
02931 new_y,
02932 window->rect.width,
02933 window->rect.height);
02934 }
02935
02936 static void
02937 handle_move_to_corner_nw (MetaDisplay *display,
02938 MetaScreen *screen,
02939 MetaWindow *window,
02940 XEvent *event,
02941 MetaKeyBinding *binding)
02942 {
02943 if (window)
02944 {
02945 handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, FALSE);
02946 }
02947 }
02948
02949 static void
02950 handle_move_to_corner_ne (MetaDisplay *display,
02951 MetaScreen *screen,
02952 MetaWindow *window,
02953 XEvent *event,
02954 MetaKeyBinding *binding)
02955 {
02956 if (window)
02957 {
02958 handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, FALSE);
02959 }
02960 }
02961
02962 static void
02963 handle_move_to_corner_sw (MetaDisplay *display,
02964 MetaScreen *screen,
02965 MetaWindow *window,
02966 XEvent *event,
02967 MetaKeyBinding *binding)
02968 {
02969 if (window)
02970 {
02971 handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, TRUE);
02972 }
02973 }
02974
02975 static void
02976 handle_move_to_corner_se (MetaDisplay *display,
02977 MetaScreen *screen,
02978 MetaWindow *window,
02979 XEvent *event,
02980 MetaKeyBinding *binding)
02981 {
02982 if (window)
02983 {
02984 handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, TRUE);
02985 }
02986 }
02987
02988 static void
02989 handle_move_to_side_n (MetaDisplay *display,
02990 MetaScreen *screen,
02991 MetaWindow *window,
02992 XEvent *event,
02993 MetaKeyBinding *binding)
02994 {
02995 if (window)
02996 {
02997 handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, FALSE);
02998 }
02999 }
03000
03001 static void
03002 handle_move_to_side_s (MetaDisplay *display,
03003 MetaScreen *screen,
03004 MetaWindow *window,
03005 XEvent *event,
03006 MetaKeyBinding *binding)
03007 {
03008 if (window)
03009 {
03010 handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, TRUE);
03011 }
03012 }
03013
03014 static void
03015 handle_move_to_side_e (MetaDisplay *display,
03016 MetaScreen *screen,
03017 MetaWindow *window,
03018 XEvent *event,
03019 MetaKeyBinding *binding)
03020 {
03021 if (window)
03022 {
03023 handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, TRUE, FALSE);
03024 }
03025 }
03026
03027 static void
03028 handle_move_to_side_w (MetaDisplay *display,
03029 MetaScreen *screen,
03030 MetaWindow *window,
03031 XEvent *event,
03032 MetaKeyBinding *binding)
03033 {
03034 if (window)
03035 {
03036 handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, FALSE, FALSE);
03037 }
03038 }
03039
03040 static gboolean
03041 process_workspace_switch_grab (MetaDisplay *display,
03042 MetaScreen *screen,
03043 XEvent *event,
03044 KeySym keysym)
03045 {
03046 MetaWorkspace *workspace;
03047
03048 if (screen != display->grab_screen)
03049 return FALSE;
03050
03051 g_return_val_if_fail (screen->tab_popup != NULL, FALSE);
03052
03053 if (event->type == KeyRelease &&
03054 end_keyboard_grab (display, event->xkey.keycode))
03055 {
03056
03057 MetaWorkspace *target_workspace;
03058
03059 target_workspace =
03060 (MetaWorkspace *) meta_ui_tab_popup_get_selected (screen->tab_popup);
03061
03062 meta_topic (META_DEBUG_KEYBINDINGS,
03063 "Ending workspace tab operation, primary modifier released\n");
03064
03065 if (target_workspace == screen->active_workspace)
03066 {
03067 meta_topic (META_DEBUG_KEYBINDINGS,
03068 "Ending grab so we can focus on the target workspace\n");
03069 meta_display_end_grab_op (display, event->xkey.time);
03070
03071 meta_topic (META_DEBUG_KEYBINDINGS,
03072 "Focusing default window on target workspace\n");
03073
03074 meta_workspace_focus_default_window (target_workspace,
03075 NULL,
03076 event->xkey.time);
03077
03078 return TRUE;
03079 }
03080
03081
03082 meta_warning ("target_workspace != active_workspace. Some other event must have occurred.\n");
03083
03084 return FALSE;
03085 }
03086
03087
03088 if (event->type == KeyRelease)
03089 return TRUE;
03090
03091
03092 if (is_modifier (display, event->xkey.keycode))
03093 return TRUE;
03094
03095
03096 workspace =
03097 (MetaWorkspace *) meta_ui_tab_popup_get_selected (screen->tab_popup);
03098
03099 if (workspace)
03100 {
03101 MetaWorkspace *target_workspace;
03102 MetaKeyBindingAction action;
03103
03104 action = display_get_keybinding_action (display,
03105 keysym,
03106 event->xkey.keycode,
03107 display->grab_mask);
03108
03109 switch (action)
03110 {
03111 case META_KEYBINDING_ACTION_WORKSPACE_UP:
03112 target_workspace = meta_workspace_get_neighbor (workspace,
03113 META_MOTION_UP);
03114 break;
03115
03116 case META_KEYBINDING_ACTION_WORKSPACE_DOWN:
03117 target_workspace = meta_workspace_get_neighbor (workspace,
03118 META_MOTION_DOWN);
03119 break;
03120
03121 case META_KEYBINDING_ACTION_WORKSPACE_LEFT:
03122 target_workspace = meta_workspace_get_neighbor (workspace,
03123 META_MOTION_LEFT);
03124 break;
03125
03126 case META_KEYBINDING_ACTION_WORKSPACE_RIGHT:
03127 target_workspace = meta_workspace_get_neighbor (workspace,
03128 META_MOTION_RIGHT);
03129 break;
03130
03131 default:
03132 target_workspace = NULL;
03133 break;
03134 }
03135
03136 if (target_workspace)
03137 {
03138 meta_ui_tab_popup_select (screen->tab_popup,
03139 (MetaTabEntryKey) target_workspace);
03140 meta_topic (META_DEBUG_KEYBINDINGS,
03141 "Tab key pressed, moving tab focus in popup\n");
03142
03143 meta_topic (META_DEBUG_KEYBINDINGS,
03144 "Activating target workspace\n");
03145
03146 meta_workspace_activate (target_workspace, event->xkey.time);
03147
03148 return TRUE;
03149 }
03150 }
03151
03152
03153 meta_topic (META_DEBUG_KEYBINDINGS,
03154 "Ending workspace tabbing & focusing default window; uninteresting key pressed\n");
03155 workspace =
03156 (MetaWorkspace *) meta_ui_tab_popup_get_selected (screen->tab_popup);
03157 meta_workspace_focus_default_window (workspace, NULL, event->xkey.time);
03158 return FALSE;
03159 }
03160
03161 static void
03162 handle_toggle_desktop (MetaDisplay *display,
03163 MetaScreen *screen,
03164 MetaWindow *window,
03165 XEvent *event,
03166 MetaKeyBinding *binding)
03167 {
03168 if (screen->active_workspace->showing_desktop)
03169 {
03170 meta_screen_unshow_desktop (screen);
03171 meta_workspace_focus_default_window (screen->active_workspace,
03172 NULL,
03173 event->xkey.time);
03174 }
03175 else
03176 meta_screen_show_desktop (screen, event->xkey.time);
03177 }
03178
03179 static void
03180 handle_panel_keybinding (MetaDisplay *display,
03181 MetaScreen *screen,
03182 MetaWindow *window,
03183 XEvent *event,
03184 MetaKeyBinding *binding)
03185 {
03186 MetaKeyBindingAction action;
03187 Atom action_atom;
03188 XClientMessageEvent ev;
03189
03190 action = GPOINTER_TO_INT (binding->handler->data);
03191
03192 action_atom = None;
03193 switch (action)
03194 {
03195 case META_KEYBINDING_ACTION_PANEL_MAIN_MENU:
03196 action_atom = display->atom__GNOME_PANEL_ACTION_MAIN_MENU;
03197 break;
03198 case META_KEYBINDING_ACTION_PANEL_RUN_DIALOG:
03199 action_atom = display->atom__GNOME_PANEL_ACTION_RUN_DIALOG;
03200 break;
03201 default:
03202 return;
03203 }
03204
03205 ev.type = ClientMessage;
03206 ev.window = screen->xroot;
03207 ev.message_type = display->atom__GNOME_PANEL_ACTION;
03208 ev.format = 32;
03209 ev.data.l[0] = action_atom;
03210 ev.data.l[1] = event->xkey.time;
03211
03212 meta_topic (META_DEBUG_KEYBINDINGS,
03213 "Sending panel message with timestamp %lu, and turning mouse_mode "
03214 "off due to keybinding press\n", event->xkey.time);
03215 display->mouse_mode = FALSE;
03216
03217 meta_error_trap_push (display);
03218
03219
03220 XUngrabKeyboard (display->xdisplay, event->xkey.time);
03221
03222 XSendEvent (display->xdisplay,
03223 screen->xroot,
03224 False,
03225 StructureNotifyMask,
03226 (XEvent*) &ev);
03227
03228 meta_error_trap_pop (display, FALSE);
03229 }
03230
03231 static void
03232 handle_activate_menu (MetaDisplay *display,
03233 MetaScreen *screen,
03234 MetaWindow *event_window,
03235 XEvent *event,
03236 MetaKeyBinding *binding)
03237 {
03238 if (display->focus_window)
03239 {
03240 int x, y;
03241
03242 meta_window_get_position (display->focus_window,
03243 &x, &y);
03244
03245 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
03246 x += display->focus_window->rect.width;
03247
03248 meta_window_show_menu (display->focus_window,
03249 x, y,
03250 0,
03251 event->xkey.time);
03252 }
03253 }
03254
03255 static MetaGrabOp
03256 tab_op_from_tab_type (MetaTabList type)
03257 {
03258 switch (type)
03259 {
03260 case META_TAB_LIST_NORMAL:
03261 return META_GRAB_OP_KEYBOARD_TABBING_NORMAL;
03262 case META_TAB_LIST_DOCKS:
03263 return META_GRAB_OP_KEYBOARD_TABBING_DOCK;
03264 case META_TAB_LIST_GROUP:
03265 return META_GRAB_OP_KEYBOARD_TABBING_GROUP;
03266 }
03267
03268 g_assert_not_reached ();
03269
03270 return 0;
03271 }
03272
03273 static MetaGrabOp
03274 cycle_op_from_tab_type (MetaTabList type)
03275 {
03276 switch (type)
03277 {
03278 case META_TAB_LIST_NORMAL:
03279 return META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL;
03280 case META_TAB_LIST_DOCKS:
03281 return META_GRAB_OP_KEYBOARD_ESCAPING_DOCK;
03282 case META_TAB_LIST_GROUP:
03283 return META_GRAB_OP_KEYBOARD_ESCAPING_GROUP;
03284 }
03285
03286 g_assert_not_reached ();
03287
03288 return 0;
03289 }
03290
03291 static void
03292 do_choose_window (MetaDisplay *display,
03293 MetaScreen *screen,
03294 MetaWindow *event_window,
03295 XEvent *event,
03296 MetaKeyBinding *binding,
03297 gboolean backward,
03298 gboolean show_popup)
03299 {
03300 MetaTabList type;
03301 MetaWindow *initial_selection;
03302
03303 type = GPOINTER_TO_INT (binding->handler->data);
03304
03305 meta_topic (META_DEBUG_KEYBINDINGS,
03306 "Tab list = %u show_popup = %d\n", type, show_popup);
03307
03308
03309 if (event->xkey.state & ShiftMask)
03310 backward = !backward;
03311
03312 initial_selection = meta_display_get_tab_next (display,
03313 type,
03314 screen,
03315 screen->active_workspace,
03316 NULL,
03317 backward);
03318
03319
03320 if (initial_selection == NULL)
03321 initial_selection = meta_display_get_tab_current (display,
03322 type, screen,
03323 screen->active_workspace);
03324
03325 meta_topic (META_DEBUG_KEYBINDINGS,
03326 "Initially selecting window %s\n",
03327 initial_selection ? initial_selection->desc : "(none)");
03328
03329 if (initial_selection != NULL)
03330 {
03331 if (binding->mask == 0)
03332 {
03333
03334
03335
03336 meta_topic (META_DEBUG_FOCUS,
03337 "Activating %s and turning off mouse_mode due to "
03338 "switch/cycle windows with no modifiers\n",
03339 initial_selection->desc);
03340 display->mouse_mode = FALSE;
03341 meta_window_activate (initial_selection, event->xkey.time);
03342 }
03343 else if (meta_display_begin_grab_op (display,
03344 screen,
03345 NULL,
03346 show_popup ?
03347 tab_op_from_tab_type (type) :
03348 cycle_op_from_tab_type (type),
03349 FALSE,
03350 FALSE,
03351 0,
03352 binding->mask,
03353 event->xkey.time,
03354 0, 0))
03355 {
03356 if (!primary_modifier_still_pressed (display,
03357 binding->mask))
03358 {
03359
03360
03361
03362
03363 meta_topic (META_DEBUG_FOCUS,
03364 "Ending grab, activating %s, and turning off "
03365 "mouse_mode due to switch/cycle windows where "
03366 "modifier was released prior to grab\n",
03367 initial_selection->desc);
03368 meta_display_end_grab_op (display, event->xkey.time);
03369 display->mouse_mode = FALSE;
03370 meta_window_activate (initial_selection, event->xkey.time);
03371 }
03372 else
03373 {
03374 meta_ui_tab_popup_select (screen->tab_popup,
03375 (MetaTabEntryKey) initial_selection->xwindow);
03376
03377 if (show_popup)
03378 meta_ui_tab_popup_set_showing (screen->tab_popup,
03379 TRUE);
03380 else
03381 {
03382 meta_window_raise (initial_selection);
03383 initial_selection->tab_unminimized =
03384 initial_selection->minimized;
03385 meta_window_unminimize (initial_selection);
03386 }
03387 }
03388 }
03389 }
03390 }
03391
03392 static void
03393 handle_tab_forward (MetaDisplay *display,
03394 MetaScreen *screen,
03395 MetaWindow *event_window,
03396 XEvent *event,
03397 MetaKeyBinding *binding)
03398 {
03399 do_choose_window (display, screen,
03400 event_window, event, binding, FALSE, TRUE);
03401 }
03402
03403 static void
03404 handle_tab_backward (MetaDisplay *display,
03405 MetaScreen *screen,
03406 MetaWindow *event_window,
03407 XEvent *event,
03408 MetaKeyBinding *binding)
03409 {
03410 do_choose_window (display, screen,
03411 event_window, event, binding, TRUE, TRUE);
03412 }
03413
03414 static void
03415 handle_cycle_forward (MetaDisplay *display,
03416 MetaScreen *screen,
03417 MetaWindow *event_window,
03418 XEvent *event,
03419 MetaKeyBinding *binding)
03420 {
03421 do_choose_window (display, screen,
03422 event_window, event, binding, FALSE, FALSE);
03423 }
03424
03425 static void
03426 handle_cycle_backward (MetaDisplay *display,
03427 MetaScreen *screen,
03428 MetaWindow *event_window,
03429 XEvent *event,
03430 MetaKeyBinding *binding)
03431 {
03432 do_choose_window (display, screen,
03433 event_window, event, binding, TRUE, FALSE);
03434 }
03435
03436 static void
03437 handle_toggle_fullscreen (MetaDisplay *display,
03438 MetaScreen *screen,
03439 MetaWindow *window,
03440 XEvent *event,
03441 MetaKeyBinding *binding)
03442 {
03443 if (window)
03444 {
03445 if (window->fullscreen)
03446 meta_window_unmake_fullscreen (window);
03447 else if (window->has_fullscreen_func)
03448 meta_window_make_fullscreen (window);
03449 }
03450 }
03451
03452 static void
03453 handle_toggle_above (MetaDisplay *display,
03454 MetaScreen *screen,
03455 MetaWindow *window,
03456 XEvent *event,
03457 MetaKeyBinding *binding)
03458 {
03459 if (window)
03460 {
03461 if (window->wm_state_above)
03462 meta_window_unmake_above (window);
03463 else
03464 meta_window_make_above (window);
03465 }
03466 }
03467
03468 static void
03469 handle_toggle_maximize (MetaDisplay *display,
03470 MetaScreen *screen,
03471 MetaWindow *window,
03472 XEvent *event,
03473 MetaKeyBinding *binding)
03474 {
03475 if (window)
03476 {
03477 if (META_WINDOW_MAXIMIZED (window))
03478 meta_window_unmaximize (window,
03479 META_MAXIMIZE_HORIZONTAL |
03480 META_MAXIMIZE_VERTICAL);
03481 else if (window->has_maximize_func)
03482 meta_window_maximize (window,
03483 META_MAXIMIZE_HORIZONTAL |
03484 META_MAXIMIZE_VERTICAL);
03485 }
03486 }
03487
03488 static void
03489 handle_maximize (MetaDisplay *display,
03490 MetaScreen *screen,
03491 MetaWindow *window,
03492 XEvent *event,
03493 MetaKeyBinding *binding)
03494 {
03495 if (window)
03496 {
03497 if (window->has_maximize_func)
03498 meta_window_maximize (window,
03499 META_MAXIMIZE_HORIZONTAL |
03500 META_MAXIMIZE_VERTICAL);
03501 }
03502 }
03503
03504 static void
03505 handle_unmaximize (MetaDisplay *display,
03506 MetaScreen *screen,
03507 MetaWindow *window,
03508 XEvent *event,
03509 MetaKeyBinding *binding)
03510 {
03511 if (window)
03512 {
03513 if (window->maximized_vertically || window->maximized_horizontally)
03514 meta_window_unmaximize (window,
03515 META_MAXIMIZE_HORIZONTAL |
03516 META_MAXIMIZE_VERTICAL);
03517 }
03518 }
03519
03520 static void
03521 handle_toggle_shade (MetaDisplay *display,
03522 MetaScreen *screen,
03523 MetaWindow *window,
03524 XEvent *event,
03525 MetaKeyBinding *binding)
03526 {
03527 if (window)
03528 {
03529 if (window->shaded)
03530 meta_window_unshade (window, event->xkey.time);
03531 else if (window->has_shade_func)
03532 meta_window_shade (window, event->xkey.time);
03533 }
03534 }
03535
03536 static void
03537 handle_close_window (MetaDisplay *display,
03538 MetaScreen *screen,
03539 MetaWindow *window,
03540 XEvent *event,
03541 MetaKeyBinding *binding)
03542 {
03543 if (window)
03544 if (window->has_close_func)
03545 meta_window_delete (window, event->xkey.time);
03546 }
03547
03548 static void
03549 handle_minimize_window (MetaDisplay *display,
03550 MetaScreen *screen,
03551 MetaWindow *window,
03552 XEvent *event,
03553 MetaKeyBinding *binding)
03554 {
03555 if (window)
03556 if (window->has_minimize_func)
03557 meta_window_minimize (window);
03558 }
03559
03560 static void
03561 handle_begin_move (MetaDisplay *display,
03562 MetaScreen *screen,
03563 MetaWindow *window,
03564 XEvent *event,
03565 MetaKeyBinding *binding)
03566 {
03567 if (window && window->has_move_func)
03568 {
03569 meta_window_begin_grab_op (window,
03570 META_GRAB_OP_KEYBOARD_MOVING,
03571 FALSE,
03572 event->xkey.time);
03573 }
03574 }
03575
03576 static void
03577 handle_begin_resize (MetaDisplay *display,
03578 MetaScreen *screen,
03579 MetaWindow *window,
03580 XEvent *event,
03581 MetaKeyBinding *binding)
03582 {
03583 if (window && window->has_resize_func)
03584 {
03585 meta_window_begin_grab_op (window,
03586 META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
03587 FALSE,
03588 event->xkey.time);
03589 }
03590 }
03591
03592 static void
03593 handle_toggle_sticky (MetaDisplay *display,
03594 MetaScreen *screen,
03595 MetaWindow *window,
03596 XEvent *event,
03597 MetaKeyBinding *binding)
03598 {
03599 if (window)
03600 {
03601 if (window->on_all_workspaces)
03602 meta_window_unstick (window);
03603 else
03604 meta_window_stick (window);
03605 }
03606 }
03607
03608 static void
03609 do_handle_move_to_workspace (MetaDisplay *display,
03610 MetaScreen *screen,
03611 MetaWindow *window,
03612 XEvent *event,
03613 MetaKeyBinding *binding,
03614 gboolean flip)
03615 {
03616 int which;
03617 MetaWorkspace *workspace;
03618
03619 which = GPOINTER_TO_INT (binding->handler->data);
03620
03621 if (window == NULL || window->always_sticky)
03622 return;
03623
03624 workspace = NULL;
03625 if (which < 0)
03626 {
03627 workspace = meta_workspace_get_neighbor (screen->active_workspace,
03628 which);
03629 }
03630 else
03631 {
03632 workspace = meta_screen_get_workspace_by_index (screen, which);
03633 }
03634
03635 if (workspace)
03636 {
03637
03638 meta_window_change_workspace (window, workspace);
03639 if (flip)
03640 {
03641 meta_topic (META_DEBUG_FOCUS,
03642 "Resetting mouse_mode to FALSE due to "
03643 "do_handle_move_to_workspace() call with flip set.\n");
03644 workspace->screen->display->mouse_mode = FALSE;
03645 meta_workspace_activate_with_focus (workspace,
03646 window,
03647 event->xkey.time);
03648 }
03649 }
03650 else
03651 {
03652
03653 }
03654 }
03655
03656 static void
03657 handle_move_to_workspace (MetaDisplay *display,
03658 MetaScreen *screen,
03659 MetaWindow *window,
03660 XEvent *event,
03661 MetaKeyBinding *binding)
03662 {
03663 do_handle_move_to_workspace (display,
03664 screen,
03665 window,
03666 event,
03667 binding,
03668 FALSE);
03669 }
03670 static void
03671 handle_move_to_workspace_flip (MetaDisplay *display,
03672 MetaScreen *screen,
03673 MetaWindow *window,
03674 XEvent *event,
03675 MetaKeyBinding *binding)
03676 {
03677 do_handle_move_to_workspace (display,
03678 screen,
03679 window,
03680 event,
03681 binding,
03682 TRUE);
03683 }
03684
03685 static void
03686 handle_raise_or_lower (MetaDisplay *display,
03687 MetaScreen *screen,
03688 MetaWindow *window,
03689 XEvent *event,
03690 MetaKeyBinding *binding)
03691 {
03692
03693
03694 if (window)
03695 {
03696 MetaWindow *above = NULL;
03697
03698
03699 if (meta_stack_get_top (window->screen->stack) == window)
03700 {
03701 meta_window_lower (window);
03702 return;
03703 }
03704
03705
03706
03707 above = meta_stack_get_above (window->screen->stack, window, TRUE);
03708
03709 while (above)
03710 {
03711 MetaRectangle tmp, win_rect, above_rect;
03712
03713 if (above->mapped)
03714 {
03715 meta_window_get_outer_rect (window, &win_rect);
03716 meta_window_get_outer_rect (above, &above_rect);
03717
03718
03719 if (meta_rectangle_intersect (&win_rect, &above_rect, &tmp))
03720 {
03721 meta_window_raise (window);
03722 return;
03723 }
03724 }
03725
03726 above = meta_stack_get_above (window->screen->stack, above, TRUE);
03727 }
03728
03729
03730 meta_window_lower (window);
03731 }
03732 }
03733
03734 static void
03735 handle_raise (MetaDisplay *display,
03736 MetaScreen *screen,
03737 MetaWindow *window,
03738 XEvent *event,
03739 MetaKeyBinding *binding)
03740 {
03741 if (window)
03742 {
03743 meta_window_raise (window);
03744 }
03745 }
03746
03747 static void
03748 handle_lower (MetaDisplay *display,
03749 MetaScreen *screen,
03750 MetaWindow *window,
03751 XEvent *event,
03752 MetaKeyBinding *binding)
03753 {
03754 if (window)
03755 {
03756 meta_window_lower (window);
03757 }
03758 }
03759
03760 static void
03761 handle_workspace_switch (MetaDisplay *display,
03762 MetaScreen *screen,
03763 MetaWindow *window,
03764 XEvent *event,
03765 MetaKeyBinding *binding)
03766 {
03767 int motion;
03768 unsigned int grab_mask;
03769
03770 motion = GPOINTER_TO_INT (binding->handler->data);
03771
03772 g_assert (motion < 0);
03773
03774 meta_topic (META_DEBUG_KEYBINDINGS,
03775 "Starting tab between workspaces, showing popup\n");
03776
03777
03778 grab_mask = event->xkey.state & ~(display->ignored_modifier_mask);
03779
03780 if (meta_display_begin_grab_op (display,
03781 screen,
03782 NULL,
03783 META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING,
03784 FALSE,
03785 FALSE,
03786 0,
03787 grab_mask,
03788 event->xkey.time,
03789 0, 0))
03790 {
03791 MetaWorkspace *next;
03792 gboolean grabbed_before_release;
03793
03794 next = meta_workspace_get_neighbor (screen->active_workspace, motion);
03795 g_assert (next);
03796
03797 grabbed_before_release = primary_modifier_still_pressed (display, grab_mask);
03798
03799 meta_topic (META_DEBUG_KEYBINDINGS,
03800 "Activating target workspace\n");
03801
03802 if (!grabbed_before_release)
03803 {
03804
03805
03806
03807
03808
03809 meta_display_end_grab_op (display, event->xkey.time);
03810 }
03811
03812 meta_workspace_activate (next, event->xkey.time);
03813
03814 if (grabbed_before_release)
03815 {
03816 meta_ui_tab_popup_select (screen->tab_popup, (MetaTabEntryKey) next);
03817
03818
03819 meta_ui_tab_popup_set_showing (screen->tab_popup, TRUE);
03820 }
03821 }
03822 }
03823
03824 static void
03825 handle_spew_mark (MetaDisplay *display,
03826 MetaScreen *screen,
03827 MetaWindow *window,
03828 XEvent *event,
03829 MetaKeyBinding *binding)
03830 {
03831 meta_verbose ("-- MARK MARK MARK MARK --\n");
03832 }
03833
03834 void
03835 meta_set_keybindings_disabled (gboolean setting)
03836 {
03837 all_bindings_disabled = setting;
03838 meta_topic (META_DEBUG_KEYBINDINGS,
03839 "Keybindings %s\n", all_bindings_disabled ? "disabled" : "enabled");
03840 }
03841
03842 static void
03843 handle_run_terminal (MetaDisplay *display,
03844 MetaScreen *screen,
03845 MetaWindow *window,
03846 XEvent *event,
03847 MetaKeyBinding *binding)
03848 {
03849 const char *command;
03850 GError *err;
03851
03852 command = meta_prefs_get_terminal_command ();
03853
03854 if (command == NULL)
03855 {
03856 char *s;
03857
03858 meta_topic (META_DEBUG_KEYBINDINGS,
03859 "No terminal command to run in response to "
03860 "keybinding press\n");
03861
03862 s = g_strdup_printf (_("No terminal command has been defined.\n"));
03863 error_on_terminal_command (NULL, s, screen->number, event->xkey.time);
03864 g_free (s);
03865
03866 return;
03867 }
03868
03869 err = NULL;
03870 if (!meta_spawn_command_line_async_on_screen (command, screen, &err))
03871 {
03872 error_on_terminal_command (command, err->message, screen->number,
03873 event->xkey.time);
03874
03875 g_error_free (err);
03876 }
03877 }