1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-23 19:15:07 +00:00

WindowServer: Add support for per-window override cursors.

Use this to implement automatic switching to an I-beam cursor when hovering
over a GTextEditor. :^)
This commit is contained in:
Andreas Kling 2019-03-31 23:52:02 +02:00
parent 42c95959a8
commit dcf6726487
13 changed files with 110 additions and 0 deletions

View file

@ -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);
}

View file

@ -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();

View file

@ -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()) {

View file

@ -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:

View file

@ -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;
};
};

View file

@ -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;
}

View file

@ -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&);

View file

@ -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();
}

View file

@ -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; }

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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;
}