gnome-shell r83 - in trunk: js/ui src



Author: otaylor
Date: Mon Nov 24 19:07:18 2008
New Revision: 83
URL: http://svn.gnome.org/viewvc/gnome-shell?rev=83&view=rev

Log:
Add a concept of "going modal" by grabbing the keyboard

shell-global.[ch]: Replace shell_global_focus_stage()
  with shell_global_grab_keyboard()/shell_global_ungrab_keyboard()
main.js: Add startModal()/endModal() functions to go modal and
  undo that.
run_dialog.js overlay.js main.js: Use startModal() for the overlay
  and for the run dialog.

http://bugzilla.gnome.org/show_bug.cgi?id=561880

Modified:
   trunk/js/ui/main.js
   trunk/js/ui/overlay.js
   trunk/js/ui/run_dialog.js
   trunk/src/shell-global.c
   trunk/src/shell-global.h

Modified: trunk/js/ui/main.js
==============================================================================
--- trunk/js/ui/main.js	(original)
+++ trunk/js/ui/main.js	Mon Nov 24 19:07:18 2008
@@ -103,13 +103,14 @@
         // Make sure not more than one run dialog is shown.
         if (!run_dialog) {
             run_dialog = new RunDialog.RunDialog();
-	    let handler = function() {
+	    let end_handler = function() {
                 run_dialog.destroy();
                 run_dialog = null;
             };
-            run_dialog.connect('run', handler);
-            run_dialog.connect('cancel', handler);
-            run_dialog.show();
+            run_dialog.connect('run', end_handler);
+            run_dialog.connect('cancel', end_handler);
+            if (!run_dialog.show())
+		end_handler();
         }
     });
 
@@ -120,17 +121,33 @@
     wm = new WindowManager.WindowManager();
 }
 
-function show_overlay() {
+// Used to go into a mode where all keyboard and mouse input goes to
+// the stage. Returns true if we successfully grabbed the keyboard and
+// went modal, false otherwise
+function startModal() {
     let global = Shell.global_get();
 
-    overlay.show();
+    if (!global.grab_keyboard())
+	return false;
+
     global.set_stage_input_area(0, 0, global.screen_width, global.screen_height);
+
+    return true;
 }
 
-function hide_overlay() {
+function endModal() {
     let global = Shell.global_get();
 
-    overlay.hide();
-    panel.overlayHidden();
+    global.ungrab_keyboard();
     global.set_stage_input_area(0, 0, global.screen_width, Panel.PANEL_HEIGHT);
 }
+
+function show_overlay() {
+    if (startModal())
+	overlay.show();
+}
+
+function hide_overlay() {
+    overlay.hide();
+    endModal();
+}

Modified: trunk/js/ui/overlay.js
==============================================================================
--- trunk/js/ui/overlay.js	(original)
+++ trunk/js/ui/overlay.js	Mon Nov 24 19:07:18 2008
@@ -178,8 +178,6 @@
 
 	    let global = Shell.global_get();
 
-	    global.focus_stage();
-
 	    let windows = global.get_windows();
 	    let desktopWindow = null;
 

Modified: trunk/js/ui/run_dialog.js
==============================================================================
--- trunk/js/ui/run_dialog.js	(original)
+++ trunk/js/ui/run_dialog.js	Mon Nov 24 19:07:18 2008
@@ -26,8 +26,9 @@
     _init : function() {
         let global = Shell.global_get();
 
-        // All actors are inside _group.
-        this._group = new Clutter.Group();
+        // All actors are inside _group. We create it initially
+	// hidden then show it in show()
+        this._group = new Clutter.Group({ visible: false });
         global.stage.add_actor(this._group);
 
         this._overlay = new Clutter.Rectangle({ color: OVERLAY_COLOR,
@@ -74,19 +75,6 @@
             return false;
         });
 
-        // TODO: Detect escape key and make it cancel the operation.
-        //       Use me.on_cancel() if it exists. Something like this:
-        // this._entry.connect('key-press-event', function(o, e) {
-        //     if (the pressed key is the escape key) {
-        //         me.hide();
-        //         me.emit('cancel');
-        //         return false;
-        //     } else
-        //         return true;
-        // });
-
-        global.focus_stage();
-        global.stage.set_key_focus(this._entry);
     },
 
     _run : function(command) {
@@ -104,14 +92,41 @@
     },
 
     show : function() {
+	if (this._group.visible) // Already shown
+	    return false;
+
+	if (!Main.startModal())
+	    return false;
+
         this._group.show_all();
+
+        // TODO: Detect escape key and make it cancel the operation.
+        //       Use me.on_cancel() if it exists. Something like this:
+        // this._entry.connect('key-press-event', function(o, e) {
+        //     if (the pressed key is the escape key) {
+        //         me.hide();
+        //         me.emit('cancel');
+        //         return false;
+        //     } else
+        //         return true;
+        // });
+
+	let global = Shell.global_get();
+        global.stage.set_key_focus(this._entry);
+
+	return true;
     },
 
     hide : function() {
-        this._group.hide();
+	if (!this._group.visible)
+	    return;
+
+	this._group.hide();
+	Main.endModal();
     },
 
     destroy : function(){
+	this.hide();
         this._group.destroy();
     }
 };

Modified: trunk/src/shell-global.c
==============================================================================
--- trunk/src/shell-global.c	(original)
+++ trunk/src/shell-global.c	Mon Nov 24 19:07:18 2008
@@ -11,6 +11,7 @@
 
   MutterPlugin *plugin;
   ShellWM *wm;
+  gboolean keyboard_grabbed;
 };
 
 enum {
@@ -273,19 +274,64 @@
 }
 
 /**
- * shell_global_focus_stage:
+ * shell_global_grab_keyboard:
+ * @global: a #ShellGlobal
  *
- * Set the keyboard focus to the Clutter stage window.  This function
- * is best used in combination with some sort of visual notification
- * that the shell has taken over input.
+ * Grab the keyboard to the stage window. The stage will receive
+ * all keyboard events until shell_global_ungrab_keyboard() is called.
+ * This is appropriate to do when the desktop goes into a special
+ * mode where no normal global key shortcuts or application keyboard
+ * processing should happen.
  */
-void
-shell_global_focus_stage (ShellGlobal *global)
+gboolean
+shell_global_grab_keyboard (ShellGlobal *global)
 {
   MetaScreen *screen = mutter_plugin_get_screen (global->plugin);
   MetaDisplay *display = meta_screen_get_display (screen);
   Display *xdisplay = meta_display_get_xdisplay (display);
   ClutterStage *stage = CLUTTER_STAGE (mutter_plugin_get_stage (global->plugin));
   Window stagewin = clutter_x11_get_stage_window (stage);
-  XSetInputFocus (xdisplay, stagewin, RevertToParent, CurrentTime);
+
+  /* FIXME: we need to coordinate with the rest of Metacity or we
+   * may grab the keyboard away from other portions of Metacity
+   * and leave Metacity in a confused state. An X client is allowed
+   * to overgrab itself, though not allowed to grab they keyboard
+   * away from another applications.
+   */
+  if (global->keyboard_grabbed)
+    return FALSE;
+
+  if (XGrabKeyboard (xdisplay, stagewin,
+                     False, /* owner_events - steal events from the rest of metacity */
+                     GrabModeAsync, GrabModeAsync,
+                     CurrentTime) != Success)
+    return FALSE; /* probably AlreadyGrabbed, some other app has a keyboard grab */
+
+  global->keyboard_grabbed = TRUE;
+
+  return TRUE;
+}
+
+/**
+ * shell_global_ungrab_keyboard:
+ * @global: a #ShellGlobal
+ *
+ * Undoes the effect of shell_global_grab_keyboard
+ */
+void
+shell_global_ungrab_keyboard (ShellGlobal *global)
+{
+  MetaScreen *screen;
+  MetaDisplay *display;
+  Display *xdisplay;
+
+  g_return_if_fail (global->keyboard_grabbed);
+
+  screen = mutter_plugin_get_screen (global->plugin);
+  display = meta_screen_get_display (screen);
+  xdisplay = meta_display_get_xdisplay (display);
+
+  XUngrabKeyboard (xdisplay, CurrentTime);
+
+  global->keyboard_grabbed = FALSE;
 }

Modified: trunk/src/shell-global.h
==============================================================================
--- trunk/src/shell-global.h	(original)
+++ trunk/src/shell-global.h	Mon Nov 24 19:07:18 2008
@@ -49,7 +49,8 @@
 
 MetaScreen * shell_global_get_screen (ShellGlobal *global);
 
-void shell_global_focus_stage (ShellGlobal *global);
+gboolean shell_global_grab_keyboard   (ShellGlobal *global);
+void     shell_global_ungrab_keyboard (ShellGlobal *global);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]