mirror of
https://github.com/RGBCube/serenity
synced 2025-05-28 09: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:
parent
42c95959a8
commit
dcf6726487
13 changed files with 110 additions and 0 deletions
|
@ -3,6 +3,7 @@
|
||||||
#include <LibGUI/GFontDatabase.h>
|
#include <LibGUI/GFontDatabase.h>
|
||||||
#include <LibGUI/GClipboard.h>
|
#include <LibGUI/GClipboard.h>
|
||||||
#include <LibGUI/GPainter.h>
|
#include <LibGUI/GPainter.h>
|
||||||
|
#include <LibGUI/GWindow.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -801,3 +802,15 @@ void GTextEditor::paste()
|
||||||
printf("Paste: \"%s\"\n", paste_text.characters());
|
printf("Paste: \"%s\"\n", paste_text.characters());
|
||||||
insert_at_cursor_or_replace_selection(paste_text);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -111,6 +111,9 @@ private:
|
||||||
virtual void focusout_event(GEvent&) override;
|
virtual void focusout_event(GEvent&) override;
|
||||||
virtual void timer_event(GTimerEvent&) override;
|
virtual void timer_event(GTimerEvent&) override;
|
||||||
virtual bool accepts_focus() const override { return true; }
|
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 paint_ruler(Painter&);
|
||||||
void update_content_size();
|
void update_content_size();
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,17 @@ void GWindow::set_rect(const Rect& a_rect)
|
||||||
GEventLoop::current().post_message_to_server(request);
|
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)
|
void GWindow::event(GEvent& event)
|
||||||
{
|
{
|
||||||
if (event.is_mouse_event()) {
|
if (event.is_mouse_event()) {
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
|
|
||||||
class GWidget;
|
class GWidget;
|
||||||
|
|
||||||
|
enum class GStandardCursor {
|
||||||
|
None = 0,
|
||||||
|
Arrow,
|
||||||
|
IBeam,
|
||||||
|
};
|
||||||
|
|
||||||
class GWindow : public GObject {
|
class GWindow : public GObject {
|
||||||
public:
|
public:
|
||||||
GWindow(GObject* parent = nullptr);
|
GWindow(GObject* parent = nullptr);
|
||||||
|
@ -84,6 +90,8 @@ public:
|
||||||
Size base_size() const { return m_base_size; }
|
Size base_size() const { return m_base_size; }
|
||||||
void set_base_size(const Size& size) { m_base_size = 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"; }
|
virtual const char* class_name() const override { return "GWindow"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -47,6 +47,11 @@ struct WSAPI_KeyModifiers { enum {
|
||||||
Ctrl = 1 << 2,
|
Ctrl = 1 << 2,
|
||||||
}; };
|
}; };
|
||||||
|
|
||||||
|
enum class WSAPI_StandardCursor : unsigned char {
|
||||||
|
None = 0,
|
||||||
|
Arrow,
|
||||||
|
IBeam,
|
||||||
|
};
|
||||||
|
|
||||||
struct WSAPI_ServerMessage {
|
struct WSAPI_ServerMessage {
|
||||||
enum Type : unsigned {
|
enum Type : unsigned {
|
||||||
|
@ -164,6 +169,7 @@ struct WSAPI_ClientMessage {
|
||||||
Greeting,
|
Greeting,
|
||||||
SetWallpaper,
|
SetWallpaper,
|
||||||
GetWallpaper,
|
GetWallpaper,
|
||||||
|
SetWindowOverrideCursor,
|
||||||
};
|
};
|
||||||
Type type { Invalid };
|
Type type { Invalid };
|
||||||
int window_id { -1 };
|
int window_id { -1 };
|
||||||
|
@ -203,6 +209,9 @@ struct WSAPI_ClientMessage {
|
||||||
int shared_buffer_id;
|
int shared_buffer_id;
|
||||||
int contents_size;
|
int contents_size;
|
||||||
} clipboard;
|
} clipboard;
|
||||||
|
struct {
|
||||||
|
WSAPI_StandardCursor cursor;
|
||||||
|
} cursor;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -491,6 +491,18 @@ void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& req
|
||||||
window.set_global_cursor_tracking_enabled(request.value());
|
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)
|
void WSClientConnection::on_request(WSAPIClientRequest& request)
|
||||||
{
|
{
|
||||||
switch (request.type()) {
|
switch (request.type()) {
|
||||||
|
@ -542,6 +554,8 @@ void WSClientConnection::on_request(WSAPIClientRequest& request)
|
||||||
return handle_request(static_cast<WSAPISetWallpaperRequest&>(request));
|
return handle_request(static_cast<WSAPISetWallpaperRequest&>(request));
|
||||||
case WSMessage::APIGetWallpaperRequest:
|
case WSMessage::APIGetWallpaperRequest:
|
||||||
return handle_request(static_cast<WSAPIGetWallpaperRequest&>(request));
|
return handle_request(static_cast<WSAPIGetWallpaperRequest&>(request));
|
||||||
|
case WSMessage::APISetWindowOverrideCursorRequest:
|
||||||
|
return handle_request(static_cast<WSAPISetWindowOverrideCursorRequest&>(request));
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ private:
|
||||||
void handle_request(WSAPISetWindowOpacityRequest&);
|
void handle_request(WSAPISetWindowOpacityRequest&);
|
||||||
void handle_request(WSAPISetWallpaperRequest&);
|
void handle_request(WSAPISetWallpaperRequest&);
|
||||||
void handle_request(WSAPIGetWallpaperRequest&);
|
void handle_request(WSAPIGetWallpaperRequest&);
|
||||||
|
void handle_request(WSAPISetWindowOverrideCursorRequest&);
|
||||||
|
|
||||||
void post_error(const String&);
|
void post_error(const String&);
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,16 @@ Retained<WSCursor> WSCursor::create(Retained<GraphicsBitmap>&& bitmap, const Poi
|
||||||
{
|
{
|
||||||
return adopt(*new WSCursor(move(bitmap), hotspot));
|
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();
|
||||||
|
}
|
||||||
|
|
|
@ -2,10 +2,17 @@
|
||||||
|
|
||||||
#include <SharedGraphics/GraphicsBitmap.h>
|
#include <SharedGraphics/GraphicsBitmap.h>
|
||||||
|
|
||||||
|
enum class WSStandardCursor {
|
||||||
|
None = 0,
|
||||||
|
Arrow,
|
||||||
|
IBeam,
|
||||||
|
};
|
||||||
|
|
||||||
class WSCursor : public Retainable<WSCursor> {
|
class WSCursor : public Retainable<WSCursor> {
|
||||||
public:
|
public:
|
||||||
static Retained<WSCursor> create(Retained<GraphicsBitmap>&&, const Point& hotspot);
|
static Retained<WSCursor> create(Retained<GraphicsBitmap>&&, const Point& hotspot);
|
||||||
static Retained<WSCursor> create(Retained<GraphicsBitmap>&&);
|
static Retained<WSCursor> create(Retained<GraphicsBitmap>&&);
|
||||||
|
static RetainPtr<WSCursor> create(WSStandardCursor);
|
||||||
~WSCursor();
|
~WSCursor();
|
||||||
|
|
||||||
Point hotspot() const { return m_hotspot; }
|
Point hotspot() const { return m_hotspot; }
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <AK/AKString.h>
|
#include <AK/AKString.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
|
#include <WindowServer/WSCursor.h>
|
||||||
|
|
||||||
class WSMessage {
|
class WSMessage {
|
||||||
public:
|
public:
|
||||||
|
@ -49,6 +50,7 @@ public:
|
||||||
APIGetClipboardContentsRequest,
|
APIGetClipboardContentsRequest,
|
||||||
APISetWallpaperRequest,
|
APISetWallpaperRequest,
|
||||||
APIGetWallpaperRequest,
|
APIGetWallpaperRequest,
|
||||||
|
APISetWindowOverrideCursorRequest,
|
||||||
__End_API_Client_Requests,
|
__End_API_Client_Requests,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -229,6 +231,23 @@ private:
|
||||||
int m_menu_id { 0 };
|
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 {
|
class WSAPISetWallpaperRequest final : public WSAPIClientRequest {
|
||||||
public:
|
public:
|
||||||
explicit WSAPISetWallpaperRequest(int client_id, String&& wallpaper)
|
explicit WSAPISetWallpaperRequest(int client_id, String&& wallpaper)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <WindowServer/WSScreen.h>
|
#include <WindowServer/WSScreen.h>
|
||||||
#include <WindowServer/WSClientConnection.h>
|
#include <WindowServer/WSClientConnection.h>
|
||||||
#include <WindowServer/WSAPITypes.h>
|
#include <WindowServer/WSAPITypes.h>
|
||||||
|
#include <WindowServer/WSCursor.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
#include <Kernel/MousePacket.h>
|
#include <Kernel/MousePacket.h>
|
||||||
#include <LibC/sys/socket.h>
|
#include <LibC/sys/socket.h>
|
||||||
|
@ -330,6 +331,9 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
|
||||||
break;
|
break;
|
||||||
case WSAPI_ClientMessage::Type::GetWallpaper:
|
case WSAPI_ClientMessage::Type::GetWallpaper:
|
||||||
post_message(client, make<WSAPIGetWallpaperRequest>(client_id));
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <WindowServer/WSWindowType.h>
|
#include <WindowServer/WSWindowType.h>
|
||||||
|
|
||||||
class WSClientConnection;
|
class WSClientConnection;
|
||||||
|
class WSCursor;
|
||||||
class WSMenu;
|
class WSMenu;
|
||||||
class WSMouseEvent;
|
class WSMouseEvent;
|
||||||
|
|
||||||
|
@ -100,6 +101,9 @@ public:
|
||||||
const GraphicsBitmap& icon() const { return *m_icon; }
|
const GraphicsBitmap& icon() const { return *m_icon; }
|
||||||
void set_icon(Retained<GraphicsBitmap>&& icon) { m_icon = move(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.
|
// For InlineLinkedList.
|
||||||
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
|
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
|
||||||
WSWindow* m_next { nullptr };
|
WSWindow* m_next { nullptr };
|
||||||
|
@ -128,4 +132,5 @@ private:
|
||||||
Size m_size_increment;
|
Size m_size_increment;
|
||||||
Size m_base_size;
|
Size m_base_size;
|
||||||
Retained<GraphicsBitmap> m_icon;
|
Retained<GraphicsBitmap> m_icon;
|
||||||
|
RetainPtr<WSCursor> m_override_cursor;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
return *m_arrow_cursor;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue