diff -u metacity-2.30.1/debian/changelog metacity-2.30.1/debian/changelog --- metacity-2.30.1/debian/changelog +++ metacity-2.30.1/debian/changelog @@ -1,3 +1,11 @@ +metacity (1:2.30.1-0ubuntu1.1) lucid-proposed; urgency=low + + * debian/patches/14_stop_confusing_gdk_grab_tracking.patch: + - Fix for issue where clicking a window title brought focus + to window underneith it. (LP: #494096) + + -- Scott Moser Thu, 17 Feb 2011 11:07:59 -0500 + metacity (1:2.30.1-0ubuntu1) lucid; urgency=low * New upsteam release: diff -u metacity-2.30.1/debian/patches/series metacity-2.30.1/debian/patches/series --- metacity-2.30.1/debian/patches/series +++ metacity-2.30.1/debian/patches/series @@ -9,4 +9,5 @@ 12_dont-show-as-user.patch 13_better_support_for_button_layout.patch +14_stop_confusing_gdk_grab_tracking.patch 90_autotools.patch 99_ltmain_as-needed.patch only in patch2: unchanged: --- metacity-2.30.1.orig/debian/patches/14_stop_confusing_gdk_grab_tracking.patch +++ metacity-2.30.1/debian/patches/14_stop_confusing_gdk_grab_tracking.patch @@ -0,0 +1,223 @@ +From 1637a7d5e4d7ffe121a0fe425ada1229137a66be Mon Sep 17 00:00:00 2001 +From: Owen W. Taylor +Date: Wed, 9 Jun 2010 19:38:35 -0400 +Subject: [PATCH] Stop confusing GDK's grab tracking + +With client side windows, mixing GDK event delivery with explicit calls +to XUngrabPointer() can result in GDK losing button release events +it expects to get. This means that GDK thinks there is an implicit +grab in effect when there is none and send events to the wrong window. + +Avoid this by bypassing GDK's event handling for most mouse events. +We do a simplified conversion of the X event into a GdkEvent and send +it to directly to libgtk for delivery. + +We make an exception when a GDK grab is already in effect - this is +needed for the correct operation of menus. + +http://bugzilla.gnome.org/show_bug.cgi?id=599181 +--- + src/ui/ui.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 files changed, 152 insertions(+), 4 deletions(-) + +--- a/src/ui/ui.c ++++ b/src/ui/ui.c +@@ -46,6 +46,13 @@ + Display *xdisplay; + Screen *xscreen; + MetaFrames *frames; ++ ++ /* For double-click tracking */ ++ guint button_click_number; ++ Window button_click_window; ++ int button_click_x; ++ int button_click_y; ++ guint32 button_click_time; + }; + + void +@@ -63,6 +70,136 @@ + return gdk_display; + } + ++/* We do some of our event handling in frames.c, which expects ++ * GDK events delivered by GTK+. However, since the transition to ++ * client side windows, we can't let GDK see button events, since the ++ * client-side tracking of implicit and explicit grabs it does will ++ * get confused by our direct use of X grabs in the core code. ++ * ++ * So we do a very minimal GDK => GTK event conversion here and send on the ++ * events we care about, and then filter them out so they don't go ++ * through the normal GDK event handling. ++ * ++ * To reduce the amount of code, the only events fields filled out ++ * below are the ones that frames.c uses. If frames.c is modified to ++ * use more fields, more fields need to be filled out below. ++ */ ++ ++static gboolean ++maybe_redirect_mouse_event (XEvent *xevent) ++{ ++ GdkDisplay *gdisplay; ++ MetaUI *ui; ++ GdkEvent gevent; ++ GdkWindow *gdk_window; ++ Window window; ++ ++ switch (xevent->type) ++ { ++ case ButtonPress: ++ case ButtonRelease: ++ window = xevent->xbutton.window; ++ break; ++ case MotionNotify: ++ window = xevent->xmotion.window; ++ break; ++ case EnterNotify: ++ case LeaveNotify: ++ window = xevent->xcrossing.window; ++ break; ++ default: ++ return FALSE; ++ } ++ ++ gdisplay = gdk_x11_lookup_xdisplay (xevent->xany.display); ++ ui = g_object_get_data (G_OBJECT (gdisplay), "meta-ui"); ++ if (!ui) ++ return FALSE; ++ ++ gdk_window = gdk_window_lookup_for_display (gdisplay, window); ++ if (gdk_window == NULL) ++ return FALSE; ++ ++ /* If GDK already thinks it has a grab, we better let it see events; this ++ * is the menu-navigation case and events need to get sent to the appropriate ++ * (client-side) subwindow for individual menu items. ++ */ ++ if (gdk_display_pointer_is_grabbed (gdisplay)) ++ return FALSE; ++ ++ memset (&gevent, 0, sizeof (gevent)); ++ ++ switch (xevent->type) ++ { ++ case ButtonPress: ++ case ButtonRelease: ++ if (xevent->type == ButtonPress) ++ { ++ GtkSettings *settings = gtk_settings_get_default (); ++ int double_click_time; ++ int double_click_distance; ++ ++ g_object_get (settings, ++ "gtk-double-click-time", &double_click_time, ++ "gtk-double-click-distance", &double_click_distance, ++ NULL); ++ ++ if (xevent->xbutton.button == ui->button_click_number && ++ xevent->xbutton.window == ui->button_click_window && ++ xevent->xbutton.time < ui->button_click_time + double_click_time && ++ ABS (xevent->xbutton.x - ui->button_click_x) <= double_click_distance && ++ ABS (xevent->xbutton.y - ui->button_click_y) <= double_click_distance) ++ { ++ gevent.button.type = GDK_2BUTTON_PRESS; ++ ++ ui->button_click_number = 0; ++ } ++ else ++ { ++ gevent.button.type = GDK_BUTTON_PRESS; ++ ui->button_click_number = xevent->xbutton.button; ++ ui->button_click_window = xevent->xbutton.window; ++ ui->button_click_time = xevent->xbutton.time; ++ ui->button_click_x = xevent->xbutton.x; ++ ui->button_click_y = xevent->xbutton.y; ++ } ++ } ++ else ++ { ++ gevent.button.type = GDK_BUTTON_RELEASE; ++ } ++ ++ gevent.button.window = gdk_window; ++ gevent.button.button = xevent->xbutton.button; ++ gevent.button.time = xevent->xbutton.time; ++ gevent.button.x = xevent->xbutton.x; ++ gevent.button.y = xevent->xbutton.y; ++ gevent.button.x_root = xevent->xbutton.x_root; ++ gevent.button.y_root = xevent->xbutton.y_root; ++ ++ break; ++ case MotionNotify: ++ gevent.motion.type = GDK_MOTION_NOTIFY; ++ gevent.motion.window = gdk_window; ++ break; ++ case EnterNotify: ++ case LeaveNotify: ++ gevent.crossing.type = xevent->type == EnterNotify ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY; ++ gevent.crossing.window = gdk_window; ++ gevent.crossing.x = xevent->xcrossing.x; ++ gevent.crossing.y = xevent->xcrossing.y; ++ break; ++ default: ++ g_assert_not_reached (); ++ break; ++ } ++ ++ /* If we've gotten here, we've filled in the gdk_event and should send it on */ ++ gtk_main_do_event (&gevent); ++ ++ return TRUE; ++} ++ + typedef struct _EventFunc EventFunc; + + struct _EventFunc +@@ -80,7 +217,8 @@ + { + g_return_val_if_fail (ef != NULL, GDK_FILTER_CONTINUE); + +- if ((* ef->func) (xevent, ef->data)) ++ if ((* ef->func) (xevent, ef->data) || ++ maybe_redirect_mouse_event (xevent)) + return GDK_FILTER_REMOVE; + else + return GDK_FILTER_CONTINUE; +@@ -118,24 +256,34 @@ + meta_ui_new (Display *xdisplay, + Screen *screen) + { ++ GdkDisplay *gdisplay; + MetaUI *ui; + +- ui = g_new (MetaUI, 1); ++ ui = g_new0 (MetaUI, 1); + ui->xdisplay = xdisplay; + ui->xscreen = screen; + +- g_assert (xdisplay == gdk_display); ++ gdisplay = gdk_x11_lookup_xdisplay (xdisplay); ++ g_assert (gdisplay == gdk_display_get_default ()); ++ + ui->frames = meta_frames_new (XScreenNumberOfScreen (screen)); + gtk_widget_realize (GTK_WIDGET (ui->frames)); +- ++ ++ g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui); ++ + return ui; + } + + void + meta_ui_free (MetaUI *ui) + { ++ GdkDisplay *gdisplay; ++ + gtk_widget_destroy (GTK_WIDGET (ui->frames)); + ++ gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay); ++ g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL); ++ + g_free (ui); + } +