Index: metacity/src/common.h
===================================================================
RCS file: /export/cvs/gnome-2.0/metacity/src/common.h,v
retrieving revision 1.33
diff -p -u -5 -r1.33 common.h
--- metacity/src/common.h	2003/12/21 06:31:40	1.33
+++ metacity/src/common.h	2004/03/19 10:28:36
@@ -113,10 +113,12 @@ typedef enum
   /* Alt+Esc */
   META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL,
   META_GRAB_OP_KEYBOARD_ESCAPING_DOCK,
   
   META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING,
+
+  META_GRAB_OP_KEYBOARD_SCREEN_SWITCHING,
   
   /* Frame button ops */
   META_GRAB_OP_CLICKING_MINIMIZE,
   META_GRAB_OP_CLICKING_MAXIMIZE,
   META_GRAB_OP_CLICKING_UNMAXIMIZE,

Index: metacity/src/display.c
===================================================================
RCS file: /export/cvs/gnome-2.0/metacity/src/display.c,v
retrieving revision 1.214
diff -p -u -5 -r1.214 display.c
--- metacity/src/display.c	2004/02/23 01:48:29	1.214
+++ metacity/src/display.c	2004/03/19 10:28:36
@@ -983,10 +983,11 @@ grab_op_is_keyboard (MetaGrabOp op)
     case META_GRAB_OP_KEYBOARD_TABBING_NORMAL:
     case META_GRAB_OP_KEYBOARD_TABBING_DOCK:
     case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL:
     case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK:
     case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING:
+    case META_GRAB_OP_KEYBOARD_SCREEN_SWITCHING:
       return TRUE;
       break;
 
     default:
       return FALSE;
@@ -3070,10 +3071,14 @@ meta_display_begin_grab_op (MetaDisplay 
       
     case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING:
       meta_screen_ensure_workspace_popup (screen);
       break;
 
+    case META_GRAB_OP_KEYBOARD_SCREEN_SWITCHING:
+      meta_screen_ensure_screen_popup (screen);
+      break;
+
     default:
       break;
     }
 
   if (display->grab_window)
@@ -3106,11 +3111,12 @@ meta_display_end_grab_op (MetaDisplay *d
   
   if (display->grab_op == META_GRAB_OP_KEYBOARD_TABBING_NORMAL ||
       display->grab_op == META_GRAB_OP_KEYBOARD_TABBING_DOCK ||
       display->grab_op == META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL ||
       display->grab_op == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK ||
-      display->grab_op == META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING)
+      display->grab_op == META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING ||
+      display->grab_op == META_GRAB_OP_KEYBOARD_SCREEN_SWITCHING)
     {
       meta_ui_tab_popup_free (display->grab_screen->tab_popup);
       display->grab_screen->tab_popup = NULL;
 
       /* If the ungrab here causes an EnterNotify, ignore it for

Index: metacity/src/keybindings.c
===================================================================
RCS file: /export/cvs/gnome-2.0/metacity/src/keybindings.c,v
retrieving revision 1.97
diff -p -u -5 -r1.97 keybindings.c
--- metacity/src/keybindings.c	2004/02/23 01:48:29	1.97
+++ metacity/src/keybindings.c	2004/03/19 10:28:36
@@ -42,10 +42,14 @@ typedef void (* MetaKeyHandlerFunc) (Met
                                      MetaScreen     *screen,
                                      MetaWindow     *window,
                                      XEvent         *event,
                                      MetaKeyBinding *binding);
 
+int find_screen_neighbor (MetaDisplay    *display,
+                          MetaScreen     *screen,
+                          int             backward);
+
 static void handle_activate_workspace (MetaDisplay    *display,
                                        MetaScreen     *screen,
                                        MetaWindow     *window,
                                        XEvent         *event,
                                        MetaKeyBinding *binding);
@@ -82,10 +86,15 @@ static void handle_toggle_fullscreen  (M
 static void handle_toggle_desktop     (MetaDisplay    *display,
                                        MetaScreen     *screen,
                                        MetaWindow     *window,
                                        XEvent         *event,
                                        MetaKeyBinding *binding);
+static void handle_move_to_screen     (MetaDisplay    *display,
+                                       MetaScreen     *screen,
+                                       MetaWindow     *window,
+                                       XEvent         *event,
+                                       MetaKeyBinding *binding);
 static void handle_panel_keybinding   (MetaDisplay    *display,
                                        MetaScreen     *screen,
                                        MetaWindow     *window,
                                        XEvent         *event,
                                        MetaKeyBinding *binding);
@@ -212,10 +221,15 @@ static gboolean process_tab_grab        
 static gboolean process_workspace_switch_grab (MetaDisplay *display,
                                                MetaScreen  *screen,
                                                XEvent      *event,
                                                KeySym       keysym);
 
+static gboolean process_screen_switch_grab (MetaDisplay *display,
+                                            MetaScreen  *screen,
+                                            XEvent      *event,
+                                            KeySym       keysym);
+
 static void regrab_screen_bindings         (MetaDisplay *display);
 static void regrab_window_bindings         (MetaDisplay *display);
 
 typedef struct
 {
@@ -283,10 +297,14 @@ static const MetaKeyHandler screen_handl
     GINT_TO_POINTER (META_TAB_LIST_DOCKS) },  
   { META_KEYBINDING_CYCLE_PANELS_BACKWARD, handle_cycle_backward,
     GINT_TO_POINTER (META_TAB_LIST_DOCKS) },  
   { META_KEYBINDING_SHOW_DESKTOP, handle_toggle_desktop,
     NULL },
+  { META_KEYBINDING_SWITCH_SCREEN, handle_move_to_screen,
+    GINT_TO_POINTER (0) },
+  { META_KEYBINDING_SWITCH_SCREEN_BACKWARD, handle_move_to_screen,
+    GINT_TO_POINTER (1) },
   { META_KEYBINDING_PANEL_MAIN_MENU, handle_panel_keybinding,
     GINT_TO_POINTER (META_KEYBINDING_ACTION_PANEL_MAIN_MENU) },
   { META_KEYBINDING_PANEL_RUN_DIALOG, handle_panel_keybinding,
     GINT_TO_POINTER (META_KEYBINDING_ACTION_PANEL_RUN_DIALOG) },
   { META_KEYBINDING_COMMAND_1, handle_run_command,
@@ -1656,10 +1674,16 @@ meta_display_process_key_event (MetaDisp
           meta_topic (META_DEBUG_KEYBINDINGS,
                       "Processing event for keyboard workspace switching\n");
           handled = process_workspace_switch_grab (display, screen, event, keysym);
           break;
 
+        case META_GRAB_OP_KEYBOARD_SCREEN_SWITCHING:
+          meta_topic (META_DEBUG_KEYBINDINGS,
+                      "Processing event for keyboard screen switching\n");
+          handled = process_screen_switch_grab (display, screen, event, keysym);
+          break;
+
         default:
           break;
         }
     }
   
@@ -2744,10 +2768,118 @@ process_workspace_switch_grab (MetaDispl
   meta_topic (META_DEBUG_KEYBINDINGS,
               "Ending workspace tabbing, uninteresting key pressed\n");
   return FALSE;
 }
 
+static gboolean
+process_screen_switch_grab (MetaDisplay *display,
+                            MetaScreen  *screen,
+                            XEvent      *event,
+                            KeySym       keysym)
+{
+  MetaKeyBindingAction action;
+  gboolean backward;
+  gboolean key_used;
+
+  if (screen != display->grab_screen)
+    return FALSE;
+
+  g_return_val_if_fail (screen->tab_popup != NULL, FALSE);
+
+  if (event->type == KeyRelease &&
+      keycode_is_primary_modifier (display, event->xkey.keycode,
+                                   display->grab_mask))
+    {
+      MetaScreen *target_screen;
+
+      target_screen = (MetaScreen *) meta_ui_tab_popup_get_selected (screen->tab_popup);  
+
+      meta_topic (META_DEBUG_KEYBINDINGS,
+                  "Ending screen tab operation, primary modifier released\n");
+
+      if (target_screen)
+        {
+          meta_topic (META_DEBUG_KEYBINDINGS,
+                      "Ending grab early so we can focus the target screen\n");
+          meta_display_end_grab_op (display, event->xkey.time);
+
+          meta_topic (META_DEBUG_KEYBINDINGS,
+                      "Activating target screen\n");
+
+          meta_workspace_focus_mru_window (target_screen->active_workspace, NULL);
+          return TRUE; /* we already ended the grab */
+        }
+
+      return FALSE; /* end grab */
+    }
+
+  /* don't care about other releases, but eat them, don't end grab */
+  if (event->type == KeyRelease)
+    return TRUE;
+
+  /* don't end grab on modifier key presses */
+  if (is_modifier (display, event->xkey.keycode))
+    return TRUE;
+
+  action = display_get_keybinding_action (display,
+                                          keysym,
+                                          display->grab_mask);
+
+  backward = FALSE;
+  key_used = FALSE;
+
+  switch (action)
+    {
+    case META_KEYBINDING_ACTION_SWITCH_SCREEN:
+      backward = FALSE;
+      key_used = TRUE;
+      break;
+    case META_KEYBINDING_ACTION_SWITCH_SCREEN_BACKWARD:
+      backward = TRUE;
+      key_used = TRUE;
+      break;
+    default:
+      break;
+    }
+	 
+  if (key_used)
+    {
+      MetaScreen *target_screen;
+
+      meta_topic (META_DEBUG_KEYBINDINGS,
+                  "Key pressed, moving tab focus in popup\n");
+
+      if (event->xkey.state & ShiftMask)
+        backward = !backward;
+
+      if (backward)
+        meta_ui_tab_popup_backward (screen->tab_popup);
+      else
+        meta_ui_tab_popup_forward (screen->tab_popup);
+
+      target_screen = (MetaScreen *) meta_ui_tab_popup_get_selected (screen->tab_popup);
+
+      if (target_screen)
+        {
+          meta_topic (META_DEBUG_KEYBINDINGS,
+                      "Tab key pressed, moving tab focus in popup\n");
+
+          meta_topic (META_DEBUG_KEYBINDINGS,
+                      "Activating target screen\n");
+
+          meta_workspace_focus_mru_window (target_screen->active_workspace, NULL);
+        }
+    }
+  else
+    {
+      /* end grab */
+      meta_topic (META_DEBUG_KEYBINDINGS,
+                  "Ending screen tabbing, uninteresting key pressed\n");
+    }
+  return key_used;
+}
+
 static void
 handle_toggle_desktop (MetaDisplay    *display,
                        MetaScreen     *screen,
                        MetaWindow     *window,
                        XEvent         *event,
@@ -2758,10 +2890,104 @@ handle_toggle_desktop (MetaDisplay    *d
       meta_screen_unshow_desktop (screen);
       meta_workspace_focus_top_window (screen->active_workspace, NULL);
     }
   else
     meta_screen_show_desktop (screen);
+}
+
+int
+find_screen_neighbor (MetaDisplay    *display,
+                      MetaScreen     *screen,
+                      int             backward)
+{
+  int ind;
+
+  ind  = g_slist_index (display->screens, screen);
+
+  if (backward)
+    {
+      if (ind == (g_slist_length (display->screens) - 1))
+        ind = 0;
+      else
+	ind++;
+    }
+  else
+    {
+      if (!ind)
+        ind =  g_slist_length (display->screens) - 1;
+      else
+        ind--;
+    }
+  
+  return (ind);
+
+}
+
+static void
+handle_move_to_screen ( MetaDisplay    *display,
+                        MetaScreen     *screen,
+                        MetaWindow     *window,
+                        XEvent         *event,
+                        MetaKeyBinding *binding)
+{
+  int backward;
+  unsigned int grab_mask;
+
+  backward = GPOINTER_TO_INT (binding->handler->data);
+
+  /* reverse direction if shift is down */
+  if (event->xkey.state & ShiftMask)
+    backward = !backward;
+
+  meta_topic (META_DEBUG_KEYBINDINGS,
+              "Starting tab between screen, showing popup\n");
+
+  grab_mask = event->xkey.state & ~(display->ignored_modifier_mask);
+
+  if (meta_display_begin_grab_op (display,
+                                  screen,
+                                  NULL,
+                                  META_GRAB_OP_KEYBOARD_SCREEN_SWITCHING,
+                                  FALSE,
+                                  event->xkey.serial,
+                                  0,
+                                  grab_mask,
+                                  event->xkey.time,
+                                  0, 0))
+    {
+      MetaScreen *target_screen;
+      gboolean grabbed_before_release;
+      int ind;
+
+      ind = find_screen_neighbor (display, screen, backward);
+      target_screen = (MetaScreen *) g_slist_nth_data (display->screens, ind);
+
+      grabbed_before_release = primary_modifier_still_pressed (display, grab_mask);
+
+      meta_topic (META_DEBUG_KEYBINDINGS,
+                  "Activating target screen\n");
+
+      if (!grabbed_before_release)
+        {
+          /* end the grab right away, modifier possibly released
+           * before we could establish the grab and receive the
+           * release event. Must end grab before we can switch
+           * spaces.
+           */
+          meta_display_end_grab_op (display, event->xkey.time);
+        }
+
+      meta_workspace_focus_mru_window (target_screen->active_workspace, NULL);
+
+      if (grabbed_before_release)
+        {
+          meta_ui_tab_popup_select (screen->tab_popup, (MetaTabEntryKey) target_screen);
+
+          /* only after selecting proper space */
+          meta_ui_tab_popup_set_showing (screen->tab_popup, TRUE);
+        }
+    }
 }
 
 static void
 handle_panel_keybinding (MetaDisplay    *display,
                          MetaScreen     *screen,

Index: metacity/src/metacity.schemas.in
===================================================================
RCS file: /export/cvs/gnome-2.0/metacity/src/metacity.schemas.in,v
retrieving revision 1.34
diff -p -u -5 -r1.34 metacity.schemas.in
--- metacity/src/metacity.schemas.in	2004/02/28 01:56:31	1.34
+++ metacity/src/metacity.schemas.in	2004/03/19 10:28:36
@@ -1251,10 +1251,59 @@ you set
          </long>
       </locale>
     </schema>
 
     <schema>
+      <key>/schemas/apps/metacity/global_keybindings/switch_screen</key>
+      <applyto>/apps/metacity/global_keybindings/switch_screen</applyto>
+      <owner>metacity</owner>
+      <type>string</type>
+      <default>&lt;Control&gt;&lt;Alt&gt;s</default>
+      <locale name="C">
+         <short>Move between screens</short>
+         <long>
+          The keybinding used to move between screens in multihead setup.
+
+          The format looks like "&lt;Control&gt;a" or
+          "&lt;Shift&gt;&lt;Alt&gt;F1.
+
+          The parser is fairly liberal and allows lower or upper case,
+          and also abbreviations such as "&lt;Ctl&gt;" and
+          "&lt;Ctrl&gt;". If you set the option to the special string
+          "disabled", then there will be no keybinding for this
+          action.
+
+         </long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/metacity/global_keybindings/switch_screen_backward</key>
+      <applyto>/apps/metacity/global_keybindings/switch_screen_backward</applyto>
+      <owner>metacity</owner>
+      <type>string</type>
+      <default>disabled</default>
+      <locale name="C">
+         <short>Move between screens - backwards</short>
+         <long>
+          The keybinding used to move between screens in multihead setup in 
+	  backward direction.
+
+          The format looks like "&lt;Control&gt;a" or
+          "&lt;Shift&gt;&lt;Alt&gt;F1.
+
+          The parser is fairly liberal and allows lower or upper case,
+          and also abbreviations such as "&lt;Ctl&gt;" and
+          "&lt;Ctrl&gt;". If you set the option to the special string
+          "disabled", then there will be no keybinding for this
+          action.
+
+         </long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/metacity/global_keybindings/switch_to_workspace_1</key>
       <applyto>/apps/metacity/global_keybindings/switch_to_workspace_1</applyto>
       <owner>metacity</owner>
       <type>string</type>
       <default>disabled</default>

Index: metacity/src/prefs.c
===================================================================
RCS file: /export/cvs/gnome-2.0/metacity/src/prefs.c,v
retrieving revision 1.45
diff -p -u -5 -r1.45 prefs.c
--- metacity/src/prefs.c	2003/10/12 06:25:38	1.45
+++ metacity/src/prefs.c	2004/03/19 10:28:36
@@ -1405,10 +1405,12 @@ static MetaKeyPref screen_bindings[] = {
   { META_KEYBINDING_CYCLE_WINDOWS, 0, 0, TRUE },
   { META_KEYBINDING_CYCLE_WINDOWS_BACKWARD, 0, 0, TRUE },
   { META_KEYBINDING_CYCLE_PANELS, 0, 0, TRUE },
   { META_KEYBINDING_CYCLE_PANELS_BACKWARD, 0, 0, TRUE },
   { META_KEYBINDING_SHOW_DESKTOP, 0, 0, FALSE },
+  { META_KEYBINDING_SWITCH_SCREEN, 0, 0, TRUE },
+  { META_KEYBINDING_SWITCH_SCREEN_BACKWARD, 0, 0, TRUE },
   { META_KEYBINDING_PANEL_MAIN_MENU, 0, 0, FALSE },
   { META_KEYBINDING_PANEL_RUN_DIALOG, 0, 0, FALSE },
   { META_KEYBINDING_COMMAND_1, 0, 0, FALSE },
   { META_KEYBINDING_COMMAND_2, 0, 0, FALSE },
   { META_KEYBINDING_COMMAND_3, 0, 0, FALSE },

Index: metacity/src/prefs.h
===================================================================
RCS file: /export/cvs/gnome-2.0/metacity/src/prefs.h,v
retrieving revision 1.34
diff -p -u -5 -r1.34 prefs.h
--- metacity/src/prefs.h	2004/02/19 18:36:14	1.34
+++ metacity/src/prefs.h	2004/03/19 10:28:36
@@ -109,10 +109,12 @@ void        meta_prefs_change_workspace_
 #define META_KEYBINDING_CYCLE_WINDOWS            "cycle_windows"
 #define META_KEYBINDING_CYCLE_WINDOWS_BACKWARD   "cycle_windows_backward"
 #define META_KEYBINDING_CYCLE_PANELS             "cycle_panels"
 #define META_KEYBINDING_CYCLE_PANELS_BACKWARD    "cycle_panels_backward"
 #define META_KEYBINDING_SHOW_DESKTOP             "show_desktop"
+#define META_KEYBINDING_SWITCH_SCREEN            "switch_screen"
+#define META_KEYBINDING_SWITCH_SCREEN_BACKWARD   "switch_screen_backward"
 #define META_KEYBINDING_PANEL_MAIN_MENU          "panel_main_menu"
 #define META_KEYBINDING_PANEL_RUN_DIALOG         "panel_run_dialog"
 #define META_KEYBINDING_COMMAND_1                "run_command_1"
 #define META_KEYBINDING_COMMAND_2                "run_command_2"
 #define META_KEYBINDING_COMMAND_3                "run_command_3"
@@ -209,10 +211,12 @@ typedef enum _MetaKeyBindingAction
   META_KEYBINDING_ACTION_CYCLE_WINDOWS,
   META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD,
   META_KEYBINDING_ACTION_CYCLE_PANELS,
   META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD,
   META_KEYBINDING_ACTION_SHOW_DESKTOP,
+  META_KEYBINDING_ACTION_SWITCH_SCREEN,
+  META_KEYBINDING_ACTION_SWITCH_SCREEN_BACKWARD,
   META_KEYBINDING_ACTION_PANEL_MAIN_MENU,
   META_KEYBINDING_ACTION_PANEL_RUN_DIALOG,
   META_KEYBINDING_ACTION_COMMAND_1,
   META_KEYBINDING_ACTION_COMMAND_2,
   META_KEYBINDING_ACTION_COMMAND_3,

Index: metacity/src/screen.c
===================================================================
RCS file: /export/cvs/gnome-2.0/metacity/src/screen.c,v
retrieving revision 1.123
diff -p -u -5 -r1.123 screen.c
--- metacity/src/screen.c	2004/01/21 17:33:56	1.123
+++ metacity/src/screen.c	2004/03/19 10:28:37
@@ -1223,10 +1223,59 @@ meta_screen_ensure_workspace_popup (Meta
 
   /* don't show tab popup, since proper space isn't selected yet */
 }
 
 void
+meta_screen_ensure_screen_popup (MetaScreen *screen)
+{
+  MetaTabEntry *entries;
+  MetaDisplay *display;
+  MetaScreen *srn;
+  GSList *tmp;
+  GdkPixbuf *pixbuf;
+  char *path;
+  int len, i;
+  
+  if (screen->tab_popup) 
+    return ;
+
+  path = g_strdup_printf (METACITY_DATADIR "/pixmaps/gnome-monitor.png");
+
+  pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+
+  display = screen->display;
+  
+  len = g_slist_length (display->screens);  
+ 
+  entries = g_new (MetaTabEntry, len + 1);
+  entries[len].key = NULL;
+  entries[len].title = NULL;
+  entries[len].icon = NULL;
+
+  for (tmp = display->screens, i = len - 1; tmp; tmp = tmp->next, i--)
+    {
+      srn = (MetaScreen *) tmp->data;
+
+      entries[i].key = (MetaTabEntryKey) srn;
+      entries[i].title = g_strdup (srn->screen_name);
+      entries[i].icon = pixbuf;
+      entries[i].blank = FALSE;
+ 
+      g_assert (entries[i].title != NULL);
+    } 
+
+  screen->tab_popup = meta_ui_tab_popup_new (entries,
+                                             screen->number,
+                                             len,
+                                             5,
+                                             TRUE);
+
+  g_free (entries);
+  g_free (path);
+}
+	
+void
 meta_screen_focus_mouse_window (MetaScreen  *screen,
                                 MetaWindow  *not_this_one)
 {
   MetaWindow *window;
   Window root_return, child_return;
