소스 검색

Move double click events from LibGUI to the window server

Robin Burchell 6 년 전
부모
커밋
a4b0dfff43

+ 1 - 0
LibGUI/GEvent.h

@@ -18,6 +18,7 @@ public:
         Resize,
         MouseMove,
         MouseDown,
+        MouseDoubleClick,
         MouseUp,
         MouseWheel,
         Enter,

+ 2 - 0
LibGUI/GEventLoop.cpp

@@ -159,6 +159,7 @@ void GEventLoop::handle_mouse_event(const WSAPI_ServerMessage& event, GWindow& w
     case WSAPI_ServerMessage::Type::MouseMove: type = GEvent::MouseMove; break;
     case WSAPI_ServerMessage::Type::MouseUp: type = GEvent::MouseUp; break;
     case WSAPI_ServerMessage::Type::MouseDown: type = GEvent::MouseDown; break;
+    case WSAPI_ServerMessage::Type::MouseDoubleClick: type = GEvent::MouseDoubleClick; break;
     case WSAPI_ServerMessage::Type::MouseWheel: type = GEvent::MouseWheel; break;
     default: ASSERT_NOT_REACHED(); break;
     }
@@ -275,6 +276,7 @@ void GEventLoop::process_unprocessed_bundles()
             handle_paint_event(event, *window, bundle.extra_data);
             break;
         case WSAPI_ServerMessage::Type::MouseDown:
+        case WSAPI_ServerMessage::Type::MouseDoubleClick:
         case WSAPI_ServerMessage::Type::MouseUp:
         case WSAPI_ServerMessage::Type::MouseMove:
         case WSAPI_ServerMessage::Type::MouseWheel:

+ 7 - 29
LibGUI/GWidget.cpp

@@ -84,6 +84,8 @@ void GWidget::event(CEvent& event)
         return mousemove_event(static_cast<GMouseEvent&>(event));
     case GEvent::MouseDown:
         return handle_mousedown_event(static_cast<GMouseEvent&>(event));
+    case GEvent::MouseDoubleClick:
+        return handle_mousedoubleclick_event(static_cast<GMouseEvent&>(event));
     case GEvent::MouseUp:
         return handle_mouseup_event(static_cast<GMouseEvent&>(event));
     case GEvent::MouseWheel:
@@ -157,38 +159,9 @@ void GWidget::handle_resize_event(GResizeEvent& event)
     return resize_event(event);
 }
 
-CElapsedTimer& GWidget::click_clock(GMouseButton button)
-{
-    switch (button) {
-    case GMouseButton::Left: return m_left_click_clock;
-    case GMouseButton::Right: return m_right_click_clock;
-    case GMouseButton::Middle: return m_middle_click_clock;
-    default:
-        ASSERT_NOT_REACHED();
-    }
-}
-
 void GWidget::handle_mouseup_event(GMouseEvent& event)
 {
     mouseup_event(event);
-
-    if (!rect().contains(event.position()))
-        return;
-    auto& clock = click_clock(event.button());
-    // It's a click.. but is it a doubleclick?
-    // FIXME: This needs improvement.
-    if (!clock.is_valid()) {
-        clock.start();
-        return;
-    }
-    int elapsed_since_last_click = clock.elapsed();
-    clock.start();
-#if 0
-    dbgprintf("Click clock elapsed: %d\n", elapsed_since_last_click);
-#endif
-    if (elapsed_since_last_click < 250) {
-        doubleclick_event(event);
-    }
 }
 
 void GWidget::handle_mousedown_event(GMouseEvent& event)
@@ -202,6 +175,11 @@ void GWidget::handle_mousedown_event(GMouseEvent& event)
     }
 }
 
+void GWidget::handle_mousedoubleclick_event(GMouseEvent& event)
+{
+    doubleclick_event(event);
+}
+
 void GWidget::handle_enter_event(CEvent& event)
 {
     if (has_tooltip())

+ 1 - 6
LibGUI/GWidget.h

@@ -190,6 +190,7 @@ private:
     void handle_paint_event(GPaintEvent&);
     void handle_resize_event(GResizeEvent&);
     void handle_mousedown_event(GMouseEvent&);
+    void handle_mousedoubleclick_event(GMouseEvent&);
     void handle_mouseup_event(GMouseEvent&);
     void handle_enter_event(CEvent&);
     void handle_leave_event(CEvent&);
@@ -197,8 +198,6 @@ private:
     void focus_previous_widget();
     void focus_next_widget();
 
-    CElapsedTimer& click_clock(GMouseButton);
-
     GWindow* m_window { nullptr };
     OwnPtr<GLayout> m_layout;
 
@@ -219,9 +218,5 @@ private:
     bool m_layout_dirty { false };
     bool m_updates_enabled { true };
 
-    CElapsedTimer m_left_click_clock;
-    CElapsedTimer m_right_click_clock;
-    CElapsedTimer m_middle_click_clock;
-
     HashMap<GShortcut, GAction*> m_local_shortcut_actions;
 };

+ 1 - 1
LibGUI/GWindow.cpp

@@ -170,7 +170,7 @@ void GWindow::set_override_cursor(GStandardCursor cursor)
 
 void GWindow::event(CEvent& event)
 {
-    if (event.type() == GEvent::MouseUp || event.type() == GEvent::MouseDown || event.type() == GEvent::MouseMove || event.type() == GEvent::MouseWheel) {
+    if (event.type() == GEvent::MouseUp || event.type() == GEvent::MouseDown || event.type() == GEvent::MouseDoubleClick || event.type() == GEvent::MouseMove || event.type() == GEvent::MouseWheel) {
         auto& mouse_event = static_cast<GMouseEvent&>(event);
         if (m_global_cursor_tracking_widget) {
             auto window_relative_rect = m_global_cursor_tracking_widget->window_relative_rect();

+ 1 - 0
Servers/WindowServer/WSAPITypes.h

@@ -73,6 +73,7 @@ struct WSAPI_ServerMessage {
         Paint,
         MouseMove,
         MouseDown,
+        MouseDoubleClick,
         MouseUp,
         MouseWheel,
         WindowEntered,

+ 2 - 1
Servers/WindowServer/WSEvent.h

@@ -17,6 +17,7 @@ public:
         WM_ClientDisconnected,
         MouseMove,
         MouseDown,
+        MouseDoubleClick,
         MouseUp,
         MouseWheel,
         WindowEntered,
@@ -75,7 +76,7 @@ public:
     virtual ~WSEvent() { }
 
     bool is_client_request() const { return type() > __Begin_API_Client_Requests && type() < __End_API_Client_Requests; }
-    bool is_mouse_event() const { return type() == MouseMove || type() == MouseDown || type() == MouseUp || type() == MouseWheel; }
+    bool is_mouse_event() const { return type() == MouseMove || type() == MouseDown || type() == MouseDoubleClick || type() == MouseUp || type() == MouseWheel; }
     bool is_key_event() const { return type() == KeyUp || type() == KeyDown; }
 };
 

+ 1 - 0
Servers/WindowServer/WSWindow.cpp

@@ -94,6 +94,7 @@ void WSWindow::handle_mouse_event(const WSMouseEvent& event)
     switch (event.type()) {
     case WSEvent::MouseMove: server_message.type = WSAPI_ServerMessage::Type::MouseMove; break;
     case WSEvent::MouseDown: server_message.type = WSAPI_ServerMessage::Type::MouseDown; break;
+    case WSEvent::MouseDoubleClick: server_message.type = WSAPI_ServerMessage::Type::MouseDoubleClick; break;
     case WSEvent::MouseUp: server_message.type = WSAPI_ServerMessage::Type::MouseUp; break;
     case WSEvent::MouseWheel: server_message.type = WSAPI_ServerMessage::Type::MouseWheel; break;
     default: ASSERT_NOT_REACHED();

+ 57 - 5
Servers/WindowServer/WSWindowManager.cpp

@@ -658,7 +658,58 @@ void WSWindowManager::set_cursor_tracking_button(WSButton* button)
     m_cursor_tracking_button = button ? button->make_weak_ptr() : nullptr;
 }
 
-void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& hovered_window)
+CElapsedTimer& WSWindowManager::DoubleClickInfo::click_clock(MouseButton button)
+{
+    switch (button) {
+    case MouseButton::Left: return m_left_click_clock;
+    case MouseButton::Right: return m_right_click_clock;
+    case MouseButton::Middle: return m_middle_click_clock;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+
+// #define DOUBLECLICK_DEBUG
+
+void WSWindowManager::deliver_mouse_event(WSWindow& window, WSMouseEvent& event)
+{
+    if (event.type() == WSEvent::MouseUp) {
+        if (&window != m_double_click_info.m_clicked_window) {
+            // we either haven't clicked anywhere, or we haven't clicked on this
+            // window. set the current click window, and reset the timers.
+#if defined(DOUBLECLICK_DEBUG)
+            dbgprintf("Initial mouseup on window %p (previous was %p)\n", &window, m_double_click_info.m_clicked_window);
+#endif
+            m_double_click_info.m_clicked_window = window.make_weak_ptr();
+            m_double_click_info.reset();
+        }
+
+        auto& clock = m_double_click_info.click_clock(event.button());
+
+        // if the clock is invalid, we haven't clicked with this button on this
+        // window yet, so there's nothing to do.
+        if (clock.is_valid()) {
+            int elapsed_since_last_click = clock.elapsed();
+            clock.start();
+
+            // FIXME: It might be a sensible idea to also add a distance travel check.
+            // If the pointer moves too far, it's not a double click.
+            if (elapsed_since_last_click < 250) {
+#if defined(DOUBLECLICK_DEBUG)
+                dbgprintf("Transforming MouseUp to MouseDoubleClick!\n");
+#endif
+                event = WSMouseEvent(WSEvent::MouseDoubleClick, event.position(), event.buttons(), event.button(), event.modifiers(), event.wheel_delta());
+            }
+        }
+
+        // start (or re-start, if it was invalid) the double click timer again.
+        clock.start();
+    }
+
+    window.event(event);
+}
+
+void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& hovered_window)
 {
     hovered_window = nullptr;
 
@@ -684,7 +735,7 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*&
         ASSERT(!window->is_minimized()); // Maybe this should also be supported? Idk.
         windows_who_received_mouse_event_due_to_cursor_tracking.set(window);
         auto translated_event = event.translated(-window->position());
-        window->event(translated_event);
+        deliver_mouse_event(*window, translated_event);
     }
 
     if (menubar_rect().contains(event.position())) {
@@ -703,7 +754,7 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*&
         } else {
             hovered_window = &window;
             auto translated_event = event.translated(-window.position());
-            window.event(translated_event);
+            deliver_mouse_event(window, translated_event);
         }
         return;
     }
@@ -736,10 +787,11 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*&
         if (window.rect().contains(event.position())) {
             if (window.type() == WSWindowType::Normal && event.type() == WSEvent::MouseDown)
                 move_to_front_and_make_active(window);
+
             hovered_window = &window;
             if (!window.global_cursor_tracking() && !windows_who_received_mouse_event_due_to_cursor_tracking.contains(&window)) {
                 auto translated_event = event.translated(-window.position());
-                window.event(translated_event);
+                deliver_mouse_event(window, translated_event);
             }
             return IterationDecision::Abort;
         }
@@ -1004,7 +1056,7 @@ void WSWindowManager::event(CEvent& event)
 {
     if (static_cast<WSEvent&>(event).is_mouse_event()) {
         WSWindow* hovered_window = nullptr;
-        process_mouse_event(static_cast<const WSMouseEvent&>(event), hovered_window);
+        process_mouse_event(static_cast<WSMouseEvent&>(event), hovered_window);
         set_hovered_window(hovered_window);
         return;
     }

+ 19 - 1
Servers/WindowServer/WSWindowManager.h

@@ -15,6 +15,7 @@
 #include <WindowServer/WSCursor.h>
 #include <WindowServer/WSEvent.h>
 #include <WindowServer/WSCPUMonitor.h>
+#include <LibCore/CElapsedTimer.h>
 
 class WSAPIClientRequest;
 class WSScreen;
@@ -122,7 +123,8 @@ public:
     void start_window_resize(WSWindow&, const WSMouseEvent&);
 
 private:
-    void process_mouse_event(const WSMouseEvent&, WSWindow*& hovered_window);
+    void process_mouse_event(WSMouseEvent&, WSWindow*& hovered_window);
+    void deliver_mouse_event(WSWindow& window, WSMouseEvent& event);
     bool process_ongoing_window_resize(const WSMouseEvent&, WSWindow*& hovered_window);
     bool process_ongoing_window_drag(const WSMouseEvent&, WSWindow*& hovered_window);
     void handle_menu_mouse_event(WSMenu&, const WSMouseEvent&);
@@ -171,6 +173,22 @@ private:
     HashTable<WSWindow*> m_windows;
     InlineLinkedList<WSWindow> m_windows_in_order;
 
+    struct DoubleClickInfo
+    {
+        CElapsedTimer& click_clock(MouseButton);
+        void reset() {
+            m_left_click_clock = CElapsedTimer();
+            m_right_click_clock = CElapsedTimer();
+            m_middle_click_clock = CElapsedTimer();
+        }
+
+        WeakPtr<WSWindow> m_clicked_window;
+        CElapsedTimer m_left_click_clock;
+        CElapsedTimer m_right_click_clock;
+        CElapsedTimer m_middle_click_clock;
+    };
+    DoubleClickInfo m_double_click_info;
+
     WeakPtr<WSWindow> m_active_window;
     WeakPtr<WSWindow> m_hovered_window;
     WeakPtr<WSWindow> m_highlight_window;