Index: src/include/ui.h
===================================================================
--- src/include/ui.h	(revision 4179)
+++ src/include/ui.h	(working copy)
@@ -34,6 +34,8 @@
 /* This is between GTK_PRIORITY_RESIZE (+10) and GTK_PRIORITY_REDRAW (+20) */
 #define META_PRIORITY_RESIZE    (G_PRIORITY_HIGH_IDLE + 15)
 
+#define KEYCODE_IS_BUTTON  1024
+
 typedef struct _MetaUI MetaUI;
 
 typedef struct _MetaImageWindow MetaImageWindow;
Index: src/core/display.c
===================================================================
--- src/core/display.c	(revision 4179)
+++ src/core/display.c	(working copy)
@@ -1589,7 +1589,12 @@
       meta_display_process_key_event (display, window, event);
       break;
     case ButtonPress:
-      if ((window &&
+      if (event->xbutton.button > 5)
+        {
+          /* can only be a keybinding */
+          meta_display_process_key_event (display, window, event);
+        }
+      else if ((window &&
            grab_op_is_mouse (display->grab_op) &&
            display->grab_button != (int) event->xbutton.button &&
            display->grab_window == window) ||
Index: src/core/keybindings.c
===================================================================
--- src/core/keybindings.c	(revision 4179)
+++ src/core/keybindings.c	(working copy)
@@ -118,7 +118,7 @@
 {
   const char *name;
   KeySym keysym;
-  KeyCode keycode;
+  unsigned int keycode : 11;
   unsigned int mask;
   MetaVirtualModifier modifiers;
   const MetaKeyHandler *handler;
@@ -657,16 +657,36 @@
 
       if (meta_is_debugging ())
         meta_error_trap_push_with_return (display);
-      if (grab)
-        XGrabKey (display->xdisplay, keycode,
-                  modmask | ignored_mask,
-                  xwindow,
-                  True,
-                  GrabModeAsync, GrabModeSync);
+
+      if (keycode & KEYCODE_IS_BUTTON)
+        {
+          if (grab)
+            XGrabButton (display->xdisplay,
+                         keycode ^ KEYCODE_IS_BUTTON,
+                         modmask | ignored_mask,
+                         xwindow, False,
+                         ButtonPressMask|ButtonReleaseMask|PointerMotionMask|PointerMotionHintMask,
+                         GrabModeAsync, GrabModeAsync,
+                         False, None);
+          else
+            XUngrabButton (display->xdisplay,
+                           keycode ^ KEYCODE_IS_BUTTON,
+                           modmask | ignored_mask,
+                           xwindow);
+        }
       else
-        XUngrabKey (display->xdisplay, keycode,
-                    modmask | ignored_mask,
-                    xwindow);
+        {
+          if (grab)
+            XGrabKey (display->xdisplay, keycode,
+                      modmask | ignored_mask,
+                      xwindow,
+                      True,
+                      GrabModeAsync, GrabModeSync);
+          else
+            XUngrabKey (display->xdisplay, keycode,
+                        modmask | ignored_mask,
+                        xwindow);
+        }
 
       if (meta_is_debugging ())
         {
@@ -1167,10 +1187,11 @@
                MetaScreen           *screen,
                MetaWindow           *window,
                XEvent               *event,
-               KeySym                keysym,
-               gboolean              on_window)
+               unsigned int         keycode,
+               gboolean             on_window)
 {
   int i;
+  gboolean is_keypress = event->type == KeyPress || event->type == KeyRelease;
 
   /* we used to have release-based bindings but no longer. */
   if (event->type == KeyRelease)
@@ -1185,9 +1206,9 @@
       const MetaKeyHandler *handler = bindings[i].handler;
 
       if ((!on_window && handler->flags & BINDING_PER_WINDOW) ||
-          event->type != KeyPress ||
-          bindings[i].keycode != event->xkey.keycode ||
-          ((event->xkey.state & 0xff & ~(display->ignored_modifier_mask)) !=
+          bindings[i].keycode != keycode ||
+          (is_keypress &&
+           (event->xkey.state & 0xff & ~(display->ignored_modifier_mask)) !=
            bindings[i].mask))
         continue;
         
@@ -1243,20 +1264,22 @@
                                 MetaWindow  *window,
                                 XEvent      *event)
 {
-  KeySym keysym;
+  unsigned int keysym;
   gboolean keep_grab;
   gboolean all_keys_grabbed;
   const char *str;
   MetaScreen *screen;
+  gboolean is_keypress = event->type == KeyPress || event->type == KeyRelease;
 
   XAllowEvents (display->xdisplay,
                 all_bindings_disabled ? ReplayKeyboard : AsyncKeyboard,
-                event->xkey.time);
+                is_keypress? event->xkey.time: event->xbutton.time);
+
   if (all_bindings_disabled)
     return;
   
   /* if key event was on root window, we have a shortcut */
-  screen = meta_display_screen_for_root (display, event->xkey.window);
+  screen = meta_display_screen_for_root (display, event->xany.window);
   
   /* else round-trip to server */
   if (screen == NULL)
@@ -1272,12 +1295,14 @@
     return;
   
   /* window may be NULL */
-  
-  keysym = XKeycodeToKeysym (display->xdisplay, event->xkey.keycode, 0);
 
+  if (is_keypress)
+    keysym = XKeycodeToKeysym (display->xdisplay, event->xkey.keycode, 0);
+  else
+    keysym = 0;
+
   str = XKeysymToString (keysym);
   
-  /* was topic */
   meta_topic (META_DEBUG_KEYBINDINGS,
               "Processing key %s event, keysym: %s state: 0x%x window: %s\n",
               event->type == KeyPress ? "press" : "release",
@@ -1372,7 +1397,10 @@
   /* Do the normal keybindings */
   process_event (display->key_bindings,
                  display->n_key_bindings,
-                 display, screen, window, event, keysym,
+                 display, screen, window, event,
+                 is_keypress?
+                 event->xkey.keycode:
+                 event->xbutton.button | KEYCODE_IS_BUTTON,
                  !all_keys_grabbed && window);
 }
 
Index: src/ui/ui.c
===================================================================
--- src/ui/ui.c	(revision 4179)
+++ src/ui/ui.c	(working copy)
@@ -769,10 +769,27 @@
     return TRUE;
   
   meta_ui_accelerator_parse (accel, &gdk_sym, &gdk_code, &gdk_mask);
-  if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0)
-    return FALSE;
 
   if (gdk_sym == None && gdk_code == 0)
+    {
+      int button_number;
+      /* maybe it was a mouse button */
+      char *button = strstr(accel, "Button");
+
+      if (!button)
+        return FALSE;
+
+      button_number = atoi (button+6);
+
+      /* don't let them bind to left, right, middle, or the scroll wheel */
+      if (button_number <= 5)
+        return FALSE;
+
+      gdk_sym = 0;
+      gdk_code = KEYCODE_IS_BUTTON | button_number;
+    }
+
+  if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0)
     return FALSE;
   
   if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */
