Explorar el Código

WindowServer: Add support for per-window override cursors.

Use this to implement automatic switching to an I-beam cursor when hovering
over a GTextEditor. :^)
Andreas Kling hace 6 años
padre
commit
dcf6726487

+ 13 - 0
LibGUI/GTextEditor.cpp

@@ -3,6 +3,7 @@
 #include <LibGUI/GFontDatabase.h>
 #include <LibGUI/GClipboard.h>
 #include <LibGUI/GPainter.h>
+#include <LibGUI/GWindow.h>
 #include <Kernel/KeyCode.h>
 #include <AK/StringBuilder.h>
 #include <unistd.h>
@@ -801,3 +802,15 @@ void GTextEditor::paste()
     printf("Paste: \"%s\"\n", paste_text.characters());
     insert_at_cursor_or_replace_selection(paste_text);
 }
+
+void GTextEditor::enter_event(GEvent&)
+{
+    ASSERT(window());
+    window()->set_override_cursor(GStandardCursor::IBeam);
+}
+
+void GTextEditor::leave_event(GEvent&)
+{
+    ASSERT(window());
+    window()->set_override_cursor(GStandardCursor::None);
+}

+ 3 - 0
LibGUI/GTextEditor.h

@@ -111,6 +111,9 @@ private:
     virtual void focusout_event(GEvent&) override;
     virtual void timer_event(GTimerEvent&) override;
     virtual bool accepts_focus() const override { return true; }
+    virtual void enter_event(GEvent&) override;
+    virtual void leave_event(GEvent&) override;
+
     void paint_ruler(Painter&);
     void update_content_size();
 

+ 11 - 0
LibGUI/GWindow.cpp

@@ -140,6 +140,17 @@ void GWindow::set_rect(const Rect& a_rect)
     GEventLoop::current().post_message_to_server(request);
 }
 
+void GWindow::set_override_cursor(GStandardCursor cursor)
+{
+    if (!m_window_id)
+        return;
+    WSAPI_ClientMessage request;
+    request.type = WSAPI_ClientMessage::Type::SetWindowOverrideCursor;
+    request.window_id = m_window_id;
+    request.cursor.cursor = (WSAPI_StandardCursor)cursor;
+    GEventLoop::current().post_message_to_server(request);
+}
+
 void GWindow::event(GEvent& event)
 {
     if (event.is_mouse_event()) {

+ 8 - 0
LibGUI/GWindow.h

@@ -8,6 +8,12 @@
 
 class GWidget;
 
+enum class GStandardCursor {
+    None = 0,
+    Arrow,
+    IBeam,
+};
+
 class GWindow : public GObject {
 public:
     GWindow(GObject* parent = nullptr);
@@ -84,6 +90,8 @@ public:
     Size base_size() const { return m_base_size; }
     void set_base_size(const Size& size) { m_base_size = size; }
 
+    void set_override_cursor(GStandardCursor);
+
     virtual const char* class_name() const override { return "GWindow"; }
 
 private:

+ 9 - 0
Servers/WindowServer/WSAPITypes.h

@@ -47,6 +47,11 @@ struct WSAPI_KeyModifiers { enum {
     Ctrl  = 1 << 2,
 }; };
 
+enum class WSAPI_StandardCursor : unsigned char {
+    None = 0,
+    Arrow,
+    IBeam,
+};
 
 struct WSAPI_ServerMessage {
     enum Type : unsigned {
@@ -164,6 +169,7 @@ struct WSAPI_ClientMessage {
         Greeting,
         SetWallpaper,
         GetWallpaper,
+        SetWindowOverrideCursor,
     };
     Type type { Invalid };
     int window_id { -1 };
@@ -203,6 +209,9 @@ struct WSAPI_ClientMessage {
             int shared_buffer_id;
             int contents_size;
         } clipboard;
+        struct {
+            WSAPI_StandardCursor cursor;
+        } cursor;
     };
 };
 

+ 14 - 0
Servers/WindowServer/WSClientConnection.cpp

@@ -491,6 +491,18 @@ void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& req
     window.set_global_cursor_tracking_enabled(request.value());
 }
 
+void WSClientConnection::handle_request(WSAPISetWindowOverrideCursorRequest& request)
+{
+    int window_id = request.window_id();
+    auto it = m_windows.find(window_id);
+    if (it == m_windows.end()) {
+        post_error("Bad window ID");
+        return;
+    }
+    auto& window = *(*it).value;
+    window.set_override_cursor(WSCursor::create(request.cursor()));
+}
+
 void WSClientConnection::on_request(WSAPIClientRequest& request)
 {
     switch (request.type()) {
@@ -542,6 +554,8 @@ void WSClientConnection::on_request(WSAPIClientRequest& request)
         return handle_request(static_cast<WSAPISetWallpaperRequest&>(request));
     case WSMessage::APIGetWallpaperRequest:
         return handle_request(static_cast<WSAPIGetWallpaperRequest&>(request));
+    case WSMessage::APISetWindowOverrideCursorRequest:
+        return handle_request(static_cast<WSAPISetWindowOverrideCursorRequest&>(request));
     default:
         break;
     }

+ 1 - 0
Servers/WindowServer/WSClientConnection.h

@@ -64,6 +64,7 @@ private:
     void handle_request(WSAPISetWindowOpacityRequest&);
     void handle_request(WSAPISetWallpaperRequest&);
     void handle_request(WSAPIGetWallpaperRequest&);
+    void handle_request(WSAPISetWindowOverrideCursorRequest&);
 
     void post_error(const String&);
 

+ 13 - 0
Servers/WindowServer/WSCursor.cpp

@@ -19,3 +19,16 @@ Retained<WSCursor> WSCursor::create(Retained<GraphicsBitmap>&& bitmap, const Poi
 {
     return adopt(*new WSCursor(move(bitmap), hotspot));
 }
+
+RetainPtr<WSCursor> WSCursor::create(WSStandardCursor standard_cursor)
+{
+    switch (standard_cursor) {
+    case WSStandardCursor::None:
+        return nullptr;
+    case WSStandardCursor::Arrow:
+        return create(*GraphicsBitmap::load_from_file("/res/cursors/arrow.png"));
+    case WSStandardCursor::IBeam:
+        return create(*GraphicsBitmap::load_from_file("/res/cursors/i-beam.png"));
+    }
+    ASSERT_NOT_REACHED();
+}

+ 7 - 0
Servers/WindowServer/WSCursor.h

@@ -2,10 +2,17 @@
 
 #include <SharedGraphics/GraphicsBitmap.h>
 
+enum class WSStandardCursor {
+    None = 0,
+    Arrow,
+    IBeam,
+};
+
 class WSCursor : public Retainable<WSCursor> {
 public:
     static Retained<WSCursor> create(Retained<GraphicsBitmap>&&, const Point& hotspot);
     static Retained<WSCursor> create(Retained<GraphicsBitmap>&&);
+    static RetainPtr<WSCursor> create(WSStandardCursor);
     ~WSCursor();
 
     Point hotspot() const { return m_hotspot; }

+ 19 - 0
Servers/WindowServer/WSMessage.h

@@ -5,6 +5,7 @@
 #include <AK/AKString.h>
 #include <AK/Types.h>
 #include <Kernel/KeyCode.h>
+#include <WindowServer/WSCursor.h>
 
 class WSMessage {
 public:
@@ -49,6 +50,7 @@ public:
         APIGetClipboardContentsRequest,
         APISetWallpaperRequest,
         APIGetWallpaperRequest,
+        APISetWindowOverrideCursorRequest,
         __End_API_Client_Requests,
     };
 
@@ -229,6 +231,23 @@ private:
     int m_menu_id { 0 };
 };
 
+class WSAPISetWindowOverrideCursorRequest final : public WSAPIClientRequest {
+public:
+    explicit WSAPISetWindowOverrideCursorRequest(int client_id, int window_id, WSStandardCursor cursor)
+        : WSAPIClientRequest(WSMessage::APISetWindowOverrideCursorRequest, client_id)
+        , m_window_id(window_id)
+        , m_cursor(cursor)
+    {
+    }
+
+    int window_id() const { return m_window_id; }
+    WSStandardCursor cursor() const { return m_cursor; }
+
+private:
+    int m_window_id { 0 };
+    WSStandardCursor m_cursor { WSStandardCursor::None };
+};
+
 class WSAPISetWallpaperRequest final : public WSAPIClientRequest {
 public:
     explicit WSAPISetWallpaperRequest(int client_id, String&& wallpaper)

+ 4 - 0
Servers/WindowServer/WSMessageLoop.cpp

@@ -5,6 +5,7 @@
 #include <WindowServer/WSScreen.h>
 #include <WindowServer/WSClientConnection.h>
 #include <WindowServer/WSAPITypes.h>
+#include <WindowServer/WSCursor.h>
 #include <Kernel/KeyCode.h>
 #include <Kernel/MousePacket.h>
 #include <LibC/sys/socket.h>
@@ -330,6 +331,9 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
         break;
     case WSAPI_ClientMessage::Type::GetWallpaper:
         post_message(client, make<WSAPIGetWallpaperRequest>(client_id));
+        break;
+    case WSAPI_ClientMessage::Type::SetWindowOverrideCursor:
+        post_message(client, make<WSAPISetWindowOverrideCursorRequest>(client_id, message.window_id, (WSStandardCursor)message.cursor.cursor));
     default:
         break;
     }

+ 5 - 0
Servers/WindowServer/WSWindow.h

@@ -8,6 +8,7 @@
 #include <WindowServer/WSWindowType.h>
 
 class WSClientConnection;
+class WSCursor;
 class WSMenu;
 class WSMouseEvent;
 
@@ -100,6 +101,9 @@ public:
     const GraphicsBitmap& icon() const { return *m_icon; }
     void set_icon(Retained<GraphicsBitmap>&& icon) { m_icon = move(icon); }
 
+    const WSCursor* override_cursor() const { return m_override_cursor.ptr(); }
+    void set_override_cursor(RetainPtr<WSCursor>&& cursor) { m_override_cursor = move(cursor); }
+
     // For InlineLinkedList.
     // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
     WSWindow* m_next { nullptr };
@@ -128,4 +132,5 @@ private:
     Size m_size_increment;
     Size m_base_size;
     Retained<GraphicsBitmap> m_icon;
+    RetainPtr<WSCursor> m_override_cursor;
 };

+ 3 - 0
Servers/WindowServer/WSWindowManager.cpp

@@ -1261,5 +1261,8 @@ const WSCursor& WSWindowManager::active_cursor() const
         }
     }
 
+    if (m_hovered_window && m_hovered_window->override_cursor())
+        return *m_hovered_window->override_cursor();
+
     return *m_arrow_cursor;
 }