]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix race conditions in mouse button handling on Haiku
authorPo Lu <luangruo@yahoo.com>
Thu, 28 Jul 2022 07:17:04 +0000 (07:17 +0000)
committerPo Lu <luangruo@yahoo.com>
Thu, 28 Jul 2022 07:17:04 +0000 (07:17 +0000)
* src/haiku_support.cc (class EmacsView): New field
`grabbed_buttons'.  Remove `previous_buttons'.
(BasicMouseDown, BasicMouseUp): Accept new parameter `message'.
Use data from that message instead.
(MouseDown, MouseUp): Pass the current message to BasicMouseUp
and BasicMouseDown.

src/haiku_support.cc

index 098739cd98b7e8f099af283b01d61da09439b3b4..204fdb81c2d6e9355bd48834eb7c2cdd0ecfad9a 100644 (file)
@@ -1496,7 +1496,6 @@ public:
 class EmacsView : public BView
 {
 public:
-  uint32_t previous_buttons;
   int looper_locked_count;
   BRegion sb_region;
   BRegion invalid_region;
@@ -1512,10 +1511,10 @@ public:
 #endif
 
   BMessage *wait_for_release_message;
+  int64 grabbed_buttons;
 
   EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs",
                        B_FOLLOW_NONE, B_WILL_DRAW),
-                previous_buttons (0),
                 looper_locked_count (0),
                 offscreen_draw_view (NULL),
                 offscreen_draw_bitmap_1 (NULL),
@@ -1524,7 +1523,8 @@ public:
                 cr_surface (NULL),
                 cr_context (NULL),
 #endif
-                wait_for_release_message (NULL)
+                wait_for_release_message (NULL),
+                grabbed_buttons (0)
   {
 
   }
@@ -1826,42 +1826,51 @@ public:
   }
 
   void
-  BasicMouseDown (BPoint point, BView *scroll_bar)
+  BasicMouseDown (BPoint point, BView *scroll_bar, BMessage *message)
   {
     struct haiku_button_event rq;
-    uint32 mods, buttons;
+    int64 when;
+    int32 mods, buttons, button;
 
-    this->GetMouse (&point, &buttons, false);
+    if (message->FindInt64 ("when", &when) != B_OK
+       || message->FindInt32 ("modifiers", &mods) != B_OK
+       || message->FindInt32 ("buttons", &buttons) != B_OK)
+      return;
 
-    if (!grab_view_locker.Lock ())
-      gui_abort ("Couldn't lock grab view locker");
-    if (buttons)
-      grab_view = this;
-    grab_view_locker.Unlock ();
+    /* Find which button was pressed by comparing the previous button
+       mask to the current one.  This assumes that B_MOUSE_DOWN will
+       be sent for each button press.  */
+    button = buttons & ~grabbed_buttons;
+    grabbed_buttons = buttons;
+
+    if (!scroll_bar)
+      {
+       if (!grab_view_locker.Lock ())
+         gui_abort ("Couldn't lock grab view locker");
+       grab_view = this;
+       grab_view_locker.Unlock ();
+      }
 
     rq.window = this->Window ();
     rq.scroll_bar = scroll_bar;
 
-    if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON)
-       && (buttons & B_PRIMARY_MOUSE_BUTTON))
+    if (button == B_PRIMARY_MOUSE_BUTTON)
       rq.btn_no = 0;
-    else if (!(previous_buttons & B_SECONDARY_MOUSE_BUTTON)
-            && (buttons & B_SECONDARY_MOUSE_BUTTON))
+    else if (button == B_SECONDARY_MOUSE_BUTTON)
       rq.btn_no = 2;
-    else if (!(previous_buttons & B_TERTIARY_MOUSE_BUTTON)
-            && (buttons & B_TERTIARY_MOUSE_BUTTON))
+    else if (button == B_TERTIARY_MOUSE_BUTTON)
       rq.btn_no = 1;
     else
+      /* We don't know which button was pressed.  This usually happens
+        when a B_MOUSE_UP is sent to a view that didn't receive a
+        corresponding B_MOUSE_DOWN event, so simply ignore the
+        message.  */
       return;
 
-    previous_buttons = buttons;
-
     rq.x = point.x;
     rq.y = point.y;
-
-    mods = modifiers ();
-
     rq.modifiers = 0;
+
     if (mods & B_SHIFT_KEY)
       rq.modifiers |= HAIKU_MODIFIER_SHIFT;
 
@@ -1878,62 +1887,73 @@ public:
       SetMouseEventMask (B_POINTER_EVENTS, (B_LOCK_WINDOW_FOCUS
                                            | B_NO_POINTER_HISTORY));
 
-    rq.time = system_time ();
+    rq.time = when;
     haiku_write (BUTTON_DOWN, &rq);
   }
 
   void
   MouseDown (BPoint point)
   {
-    BasicMouseDown (point, NULL);
+    BMessage *msg;
+    BLooper *looper;
+
+    looper = Looper ();
+    msg = (looper
+          ? looper->CurrentMessage ()
+          : NULL);
+
+    if (msg)
+      BasicMouseDown (point, NULL, msg);
   }
 
   void
-  BasicMouseUp (BPoint point, BView *scroll_bar)
+  BasicMouseUp (BPoint point, BView *scroll_bar, BMessage *message)
   {
     struct haiku_button_event rq;
-    uint32 buttons, mods;
+    int64 when;
+    int32 mods, button, buttons;
 
-    this->GetMouse (&point, &buttons, false);
+    if (message->FindInt64 ("when", &when) != B_OK
+       || message->FindInt32 ("modifiers", &mods) != B_OK
+       || message->FindInt32 ("buttons", &buttons) != B_OK)
+      return;
 
-    if (!grab_view_locker.Lock ())
-      gui_abort ("Couldn't lock grab view locker");
-    if (!buttons)
-      grab_view = NULL;
-    grab_view_locker.Unlock ();
+    if (!scroll_bar)
+      {
+       if (!grab_view_locker.Lock ())
+         gui_abort ("Couldn't lock grab view locker");
+       if (!buttons)
+         grab_view = NULL;
+       grab_view_locker.Unlock ();
+      }
 
-    if (!buttons && wait_for_release_message)
+    button = (grabbed_buttons & ~buttons);
+    grabbed_buttons = buttons;
+
+    if (!grabbed_buttons && wait_for_release_message)
       {
        wait_for_release_message->SendReply (wait_for_release_message);
        delete wait_for_release_message;
        wait_for_release_message = NULL;
 
-       previous_buttons = buttons;
        return;
       }
 
     rq.window = this->Window ();
     rq.scroll_bar = scroll_bar;
 
-    if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON)
-       && !(buttons & B_PRIMARY_MOUSE_BUTTON))
+    if (button == B_PRIMARY_MOUSE_BUTTON)
       rq.btn_no = 0;
-    else if ((previous_buttons & B_SECONDARY_MOUSE_BUTTON)
-            && !(buttons & B_SECONDARY_MOUSE_BUTTON))
+    else if (button == B_SECONDARY_MOUSE_BUTTON)
       rq.btn_no = 2;
-    else if ((previous_buttons & B_TERTIARY_MOUSE_BUTTON)
-            && !(buttons & B_TERTIARY_MOUSE_BUTTON))
+    else if (button == B_TERTIARY_MOUSE_BUTTON)
       rq.btn_no = 1;
     else
       return;
 
-    previous_buttons = buttons;
-
     rq.x = point.x;
     rq.y = point.y;
 
-    mods = modifiers ();
-
     rq.modifiers = 0;
     if (mods & B_SHIFT_KEY)
       rq.modifiers |= HAIKU_MODIFIER_SHIFT;
@@ -1947,14 +1967,23 @@ public:
     if (mods & B_OPTION_KEY)
       rq.modifiers |= HAIKU_MODIFIER_SUPER;
 
-    rq.time = system_time ();
+    rq.time = when;
     haiku_write (BUTTON_UP, &rq);
   }
 
   void
   MouseUp (BPoint point)
   {
-    BasicMouseUp (point, NULL);
+    BMessage *msg;
+    BLooper *looper;
+
+    looper = Looper ();
+    msg = (looper
+          ? looper->CurrentMessage ()
+          : NULL);
+
+    if (msg)
+      BasicMouseUp (point, NULL, msg);
   }
 };
 
@@ -2205,13 +2234,13 @@ public:
 
     if (message && (message->FindInt32 ("modifiers", &mods)
                    == B_OK)
-       && mods & B_CONTROL_KEY)
+       && mods & B_CONTROL_KEY && !handle_button)
       {
        /* Allow C-mouse-3 to split the window on a scroll bar.   */
        handle_button = true;
        SetMouseEventMask (B_POINTER_EVENTS, (B_SUSPEND_VIEW_FOCUS
                                              | B_LOCK_WINDOW_FOCUS));
-       parent->BasicMouseDown (ConvertToParent (pt), this);
+       parent->BasicMouseDown (ConvertToParent (pt), this, message);
 
        return;
       }
@@ -2274,6 +2303,8 @@ public:
   MouseUp (BPoint pt)
   {
     struct haiku_scroll_bar_drag_event rq;
+    BMessage *msg;
+    BLooper *looper;
 
     in_overscroll = false;
     maybe_overscroll = false;
@@ -2281,7 +2312,14 @@ public:
     if (handle_button)
       {
        handle_button = false;
-       parent->BasicMouseUp (ConvertToParent (pt), this);
+       looper = Looper ();
+       msg = (looper
+              ? looper->CurrentMessage ()
+              : NULL);
+
+       if (msg)
+         parent->BasicMouseUp (ConvertToParent (pt),
+                               this, msg);
 
        return;
       }