GNOME Bugzilla – Bug 341571
tabs too easily reordered
Last modified: 2011-02-04 16:10:27 UTC
when clicking over a tab somehow it thinks i'm dragging it when i only want to bring that tab to the front. After clicking on the tab i move the mouse of out it, and it starts moving getting crazy. Also if i actually want to drag the tab the movement is very unpleasant it move too fast and sometimes shakes...
I see this too. If I'm moving the mouse left-right over the tab labels and do a quick left-click, I can get into a mode where the tab is sliding with the mouse even though the button isn't pressed anymore! -> gtk+
I've been investigating these issues: - the "shaking" movement looks exactly the same than the stated in comment #12 from bug #335707. It appeared when I began using the GdkEvent coordinates to avoid gdk_window_get_pointer() calls from ::motion-notify (synchronous and network unfriendly), with some latency, the event coordinates relative to a moving GdkWindow were unreliable, and hence the "shaking" effect when moving the window to the new position. some investigation has shown me that during normal tabs movement, the ::motion-notify handler is called ~100 times per second in my computer, and that number may even grow. So my proposed solution would be to limit it to a saner ammount (say ~30 times per second) and use the totally reliable gdk_window_get_pointer, that will get rid of the "shaking" effect, and hopefully would be more network friendly. - regarding comment #2, curiously the BUTTON_RELEASE_EVENT gets swallowed at some point, because it doesn't even enter in the GtkNotebook handler, and the drag isn't terminated. I'm a bit puzzled by this. comments/ideas?
we should avoid get_pointer roundtrips, if at all possible
It would be good to know when the BUTTON_RELEASE gets dropped. Set a breakpoint in gdk/x11/gdkevents-x11.c:gdk_event_translate() on the case where it processes ButtonRelease, and trace the program from there to see if GTK+ drops the event. Also, consider watching the event->state of your motion events. (event->state & GDK_BUTTON1_MASK) will be turned on while the button is down, and off when the button is released. You can use that to know if the button was released.
Oh, thanks Federico for the clues :), I already found gdk_event_translate() the hard way through grepping for gdk_event_new() and some code learning, I wasn't aware of event->state until now, thanks heaps for this :). It turns out that the event gets filtered in this code segment: if (window_private && GDK_WINDOW_DESTROYED (window)) { if (xevent->type != DestroyNotify) { return_val = FALSE; goto done; } } so the window that's receiving the ButtonRelease event is destroyed (evidently it's not the GdkWindow I expected to get the event), after all my debugging I couldn't know which GdkWindow is getting the event, my guess is that it's one inside tab_label (it's unrealized and reparented to get drawn inside drag_window) I think I'll take the more reliable event->state path, unless you tell me that what I've described is a blatant bug :)
Created attachment 66550 [details] [review] proposed patch - uses gdk_window_get_pointer() - limits the ammount of drag_window repositioning (and thus, of gdk_window_get_pointer() calls) to a maximum of 45 times per second. Actually it gets drawn between 28 and 36 times per second in this computer. This reduces CPU use and hopefully will be more network friendly. - also stops the drag operation if event->state & GDK_BUTTON1_MASK is false in ::motion-notify-event - Takes into account the pointer offset inside the tab when beginning a drag operation, this gets rid of the "tab jumps to mouse position" sensation - Gets rid of gtk_notebook_redraw_tabs_union(), I could see artifacts with it (rarely), and the performance gain seemed quite small... - Also contains the fix I suggested for bug #168105 I'll try to find out what could make event coordinates unreliable, so not only GtkNotebook could benefit from this, but also the other gdk_window_get_pointer()-during-motion-events users (GtkIconView and GtkTextView, from what I could see...)
I haven't reviewed the patch in detail, but while testing it, a number of beauty warts showed up. - if the drag fails, the cancel animation just shows a gray tab, while the tab label gets immediately reparented back. It would be much nicer if we could reparent it back when the animation is done. - when dragging "lemonade" up to the northwest notebook, I noticed that it occasionally shoots over a bit (ie it gets drawn a few pixels outside of the east border of the notebook. And when tearing it off again, a small artifact is left behind there.
Created attachment 66656 [details] [review] updated patch Fixes the first issue commented by Matthias, plus some fixes related to detachable and not reorderable tabs. Matthias, I haven't been able to reproduce your second issue, moving the "lemonade" tab here doesn't make tabs arrive to the east border, and moving more tabs make the arrows appear. Could that be related somehow to bug #168105?
Created attachment 67437 [details] [review] updated patch, now compiles agains HEAD, plus other small fixes
Works much better. Can you commit it, please ?
Committed, thanks :) 2006-06-15 Carlos Garnacho <carlosg@gnome.org> * gtk/gtknotebook.c (gtk_notebook_motion_notify): use gdk_window_get_pointer() to get pointer coordinates, but limit its calls to a maximum of 45 times per second for not being too CPU/network abusive. stop drag operation if (event->state & GDK_BUTTON1_MASK) is FALSE to prevent tabs from "adhering" to the pointer. Fixes bug #341571 (gtk_notebook_calculate_tabs_allocation), (gtk_notebook_button_press): get rid of the "tab jumps to pointer" sensation when beginning a drag by using the pointer offset in the tab when the drag begins as an anchor. (gtk_notebook_redraw_tabs_union): remove, it wasn't worth the little performance gain and could draw artifacts under some circumstances. (gtk_notebook_drag_end): do not reparent the detached tab label until the animation has ended.