keybindings.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity Keybindings */ 
00004 /* 
00005  * Copyright (C) 2001 Havoc Pennington
00006  * Copyright (C) 2002 Red Hat Inc.
00007  * Copyright (C) 2003 Rob Adams
00008  * Copyright (C) 2004-2006 Elijah Newren
00009  * 
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License as
00012  * published by the Free Software Foundation; either version 2 of the
00013  * License, or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  * 
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00023  * 02111-1307, USA.
00024  */
00025 
00026 #define _GNU_SOURCE
00027 #define _SVID_SOURCE /* for putenv() */
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 /* debug */
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   /* Multiple bits may get set in each of these */
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   /* there are 8 modifiers, and the first 3 are shift, shift lock,
00531    * and control
00532    */
00533   map_size = 8 * modmap->max_keypermod;
00534   i = 3 * modmap->max_keypermod;
00535   while (i < map_size)
00536     {
00537       /* get the key code at this point in the map,
00538        * see if its keysym is one we're interested in
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                   /* Mod1Mask is 1 << 3 for example, i.e. the
00565                    * fourth modifier, i / keyspermod is the modifier
00566                    * index
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); /* for efficiency push outer trap */
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); /* for efficiency push outer trap */
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   /* Keybindings */
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   /* Keys are actually grabbed in meta_screen_grab_keys() */
00999   
01000   meta_prefs_add_listener (bindings_changed_callback, display);
01001 }
01002 
01003 void
01004 meta_display_shutdown_keys (MetaDisplay *display)
01005 {
01006   /* Note that display->xdisplay is invalid in this function */
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 /* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */
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   /* Grab keycode/modmask, together with
01043    * all combinations of ignored modifiers.
01044    * X provides no better way to do this.
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   /* efficiency, avoid so many XSync() */
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           /* Not a combination of ignored modifiers
01062            * (it contains some non-ignored modifiers)
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         ; /* continue to regrab on client window */
01216       else
01217         return; /* already all good */
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 /* WITH_VERBOSE_MODE */
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   /* Grab the keyboard, so we get key releases and all key
01277    * presses
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       /* Re-establish our standard bindings */
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   /* Make sure the window is focused, otherwise the grab
01374    * won't do a lot of good.
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       /* Re-establish our standard bindings */
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 /* Indexes:
01438  * shift = 0
01439  * lock = 1
01440  * control = 2
01441  * mod1 = 3
01442  * mod2 = 4
01443  * mod3 = 5
01444  * mod4 = 6
01445  * mod5 = 7
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   /* The idea here is to see if the "main" modifier
01495    * for Alt+Tab has been pressed/released. So if the binding
01496    * is Alt+Shift+Tab then releasing Alt is the thing that
01497    * ends the operation. It's pretty random how we order
01498    * these.
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, /* some random window */
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   /* we used to have release-based bindings but no longer. */
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; /* cache */
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           /* Global keybindings count as a let-the-terminal-lose-focus
01633            * due to new window mapping until the user starts
01634            * interacting with the terminal again.
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 /* Handle a key event. May be called recursively: some key events cause
01652  * grabs to be ended and then need to be processed again in their own
01653  * right. This cannot cause infinite recursion because we never call
01654  * ourselves when there wasn't a grab, and we always clear the grab
01655  * first; the invariant is enforced using an assertion. See #112560.
01656  * FIXME: We need to prove there are no race conditions here.
01657  * FIXME: Does it correctly handle alt-Tab being followed by another
01658  * grabbing keypress without letting go of alt?
01659  * FIXME: An iterative solution would probably be simpler to understand
01660  * (and help us solve the other fixmes).
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   /* if key event was on root window, we have a shortcut */
01681   screen = meta_display_screen_for_root (display, event->xkey.window);
01682   
01683   /* else round-trip to server */
01684   if (screen == NULL)
01685     screen = meta_display_screen_for_xwindow (display,
01686                                               event->xany.window);
01687 
01688   if (screen == NULL)
01689     return; /* event window is destroyed */
01690   
01691   /* ignore key events on popup menus and such. */
01692   if (window == NULL &&
01693       meta_ui_window_is_widget (screen->ui, event->xany.window))
01694     return;
01695   
01696   /* window may be NULL */
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       /* If we get here we have a global grab, because
01715         * we're in some special keyboard mode such as window move
01716         * mode.
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   /* Do the normal keybindings */
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   /* don't care about releases, but eat them, don't end grab */
01814   if (event->type == KeyRelease)
01815     return TRUE;
01816 
01817   if (keysym == XK_Escape)
01818     {
01819       /* End move or resize and restore to original state.  If the
01820        * window was a maximized window that had been "shaken loose" we
01821        * need to remaximize it.  In normal cases, we need to do a
01822        * moveresize now to get the position back to the original.  In
01823        * wireframe mode, we just need to set grab_was_cancelled to tru
01824        * to avoid avoid moveresizing to the position of the wireframe.
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       /* End grab */
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   /* don't care about releases, but eat them, don't end grab */
01862   if (event->type == KeyRelease)
01863     return TRUE;
01864 
01865   /* don't end grab on modifier key presses */
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       /* End move and restore to original state.  If the window was a
01894        * maximized window that had been "shaken loose" we need to
01895        * remaximize it.  In normal cases, we need to do a moveresize
01896        * now to get the position back to the original.  In wireframe
01897        * mode, we just need to set grab_was_cancelled to tru to avoid
01898        * avoid moveresizing to the position of the wireframe.
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   /* When moving by increments, we still snap to edges if the move
01916    * to the edge is smaller than the increment. This is because
01917    * Shift + arrow to snap is sort of a hidden feature. This way
01918    * people using just arrows shouldn't get too frustrated.
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   /* don't care about releases, but eat them, don't end grab */
02133   if (event->type == KeyRelease)
02134     return TRUE;
02135 
02136   /* don't end grab on modifier key presses */
02137   if (is_modifier (display, event->xkey.keycode))
02138     return TRUE;
02139 
02140   if (keysym == XK_Escape)
02141     {
02142       /* End resize and restore to original state.  If not in
02143        * wireframe mode, we need to do a moveresize now to get the
02144        * position back to the original.  If we are in wireframe mode,
02145        * we need to avoid moveresizing to the position of the
02146        * wireframe.
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   /* If this is a resize increment window, make the amount we resize
02200    * the window by match that amount (well, unless snap resizing...)
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           /* Move bottom edge up */
02217           height -= height_inc;
02218           break;
02219 
02220         case SouthGravity:
02221         case SouthWestGravity:
02222         case SouthEastGravity:
02223           /* Move top edge up */
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           /* Move bottom edge down */
02245           height += height_inc;
02246           break;
02247 
02248         case SouthGravity:
02249         case SouthWestGravity:
02250         case SouthEastGravity:
02251           /* Move top edge down */
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           /* Move left edge left */
02273           width += width_inc;
02274           break;
02275 
02276         case WestGravity:
02277         case SouthWestGravity:
02278         case NorthWestGravity:
02279           /* Move right edge left */
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           /* Move left edge right */
02301           width -= width_inc;
02302           break;
02303 
02304         case WestGravity:
02305         case SouthWestGravity:
02306         case NorthWestGravity:
02307           /* Move right edge right */
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   /* fixup hack (just paranoia, not sure it's required) */
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;  /* Don't actually care about x,y */
02343 
02344       /* Do any edge resistance/snapping */
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           /* We don't need to update unless the specified width and height
02372            * are actually different from what we had before.
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       /* We're done, move to the new window. */
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; /* we already ended the grab */
02465         }
02466       
02467       return FALSE; /* end grab */
02468     }
02469   
02470   /* don't care about other releases, but eat them, don't end grab */
02471   if (event->type == KeyRelease)
02472     return TRUE;
02473 
02474   /* don't end grab on modifier key presses */
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   /* Cancel when alt-Escape is pressed during using alt-Tab, and vice
02486    * versa.
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       /* CYCLE_* are traditionally Escape-based actions,
02495        * and should cancel traditionally Tab-based ones.
02496        */
02497        switch (display->grab_op)
02498         {
02499         case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL:
02500         case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK:
02501          /* carry on */
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       /* SWITCH_* are traditionally Tab-based actions,
02512        * and should cancel traditionally Escape-based ones.
02513        */
02514       switch (display->grab_op)
02515         {
02516         case META_GRAB_OP_KEYBOARD_TABBING_NORMAL:
02517         case META_GRAB_OP_KEYBOARD_TABBING_DOCK:
02518           /* carry on */
02519           break;
02520         default:
02521           /* Also, we must re-lower and re-minimize whatever window
02522            * we'd previously raised and unminimized.
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           /* carry on */
02543              break;
02544         default:
02545              return FALSE;
02546         }
02547  
02548       break;
02549     default:
02550       break;
02551     }
02552 
02553   /* !! TO HERE !!
02554    * alt-f6 during alt-{Tab,Escape} does not end the grab
02555    * but does change the grab op (and redraws the window,
02556    * of course).
02557    * See _{SWITCH,CYCLE}_GROUP.@@@
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           /* We can't actually change window focus, due to the grab.
02610            * but raise the window.
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       /* end grab */
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       /* We could offer to create it I suppose */
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   /* do not free full, because putenv is lame */
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 /* Move a window to a corner; to_bottom/to_right are FALSE for the
02885  * top or left edge, or TRUE for the bottom/right edge.  xchange/ychange
02886  * are FALSE if that dimension is not to be changed, TRUE otherwise.
02887  * Together they describe which of the four corners, or four sides,
02888  * is desired.
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       /* We're done, move to the new workspace. */
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; /* we already ended the grab */
03079         }
03080 
03081       /* Workspace switching should have already occurred on KeyPress */
03082       meta_warning ("target_workspace != active_workspace.  Some other event must have occurred.\n");
03083       
03084       return FALSE; /* end grab */
03085     }
03086   
03087   /* don't care about other releases, but eat them, don't end grab */
03088   if (event->type == KeyRelease)
03089     return TRUE;
03090 
03091   /* don't end grab on modifier key presses */
03092   if (is_modifier (display, event->xkey.keycode))
03093     return TRUE;
03094 
03095   /* select the next workspace in the tabpopup */
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; /* we already ended the grab */
03149         }
03150     }
03151 
03152   /* end grab */
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   /* Release the grab for the panel before sending the event */
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   /* reverse direction if shift is down */
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   /* Note that focus_window may not be in the tab chain, but it's OK */
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           /* If no modifiers, we can't do the "hold down modifier to keep
03334            * moving" thing, so we just instaswitch by one window.
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               /* This handles a race where modifier might be released
03360                * before we establish the grab. must end grab
03361                * prior to trying to focus a window.
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       /* Activate second, so the window is never unmapped */
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       /* We could offer to create it I suppose */
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   /* Get window at pointer */
03693   
03694   if (window)
03695     {
03696       MetaWindow *above = NULL;
03697       
03698       /* Check if top */
03699       if (meta_stack_get_top (window->screen->stack) == window)
03700         {
03701           meta_window_lower (window);
03702           return;
03703         }
03704       
03705       /* else check if windows in same layer are intersecting it */
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               /* Check if obscured */
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       /* window is not obscured */
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   /* FIXME should we use binding->mask ? */
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           /* end the grab right away, modifier possibly released
03805            * before we could establish the grab and receive the
03806            * release event. Must end grab before we can switch
03807            * spaces.
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           /* only after selecting proper space */
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 }

Generated on Sat Aug 23 22:04:17 2008 for metacity by  doxygen 1.5.5