1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 18:57:35 +00:00

WindowServer+LibGUI: Add ability to set per-window icons.

The icons are passed around as filesystem paths for now, since the shared
memory bitmaps only support 2 sides.
This commit is contained in:
Andreas Kling 2019-04-13 16:59:55 +02:00
parent 7a74b76769
commit c09c114d77
19 changed files with 151 additions and 16 deletions

View file

@ -116,6 +116,8 @@ struct WSAPI_ServerMessage {
bool is_active;
bool is_minimized;
WSAPI_WindowType window_type;
int icon_path_length;
char icon_path[256];
} wm;
struct {
WSAPI_Rect rect;
@ -193,6 +195,7 @@ struct WSAPI_ClientMessage {
SetWindowOverrideCursor,
WM_SetActiveWindow,
PopupMenu,
SetWindowIcon,
};
Type type { Invalid };
int window_id { -1 };

View file

@ -339,6 +339,28 @@ void WSClientConnection::handle_request(const WSAPIGetWindowTitleRequest& reques
post_message(response);
}
void WSClientConnection::handle_request(const WSAPISetWindowIconRequest& request)
{
int window_id = request.window_id();
auto it = m_windows.find(window_id);
if (it == m_windows.end()) {
post_error("WSAPISetWindowIconRequest: Bad window ID");
return;
}
auto& window = *(*it).value;
if (request.icon_path().is_empty()) {
window.set_default_icon();
} else {
auto icon = GraphicsBitmap::load_from_file(request.icon_path());
if (!icon)
return;
window.set_icon(request.icon_path(), *icon);
}
window.frame().invalidate_title_bar();
WSWindowManager::the().tell_wm_listeners_window_state_changed(window);
}
void WSClientConnection::handle_request(const WSAPISetWindowRectRequest& request)
{
int window_id = request.window_id();
@ -601,6 +623,8 @@ void WSClientConnection::on_request(const WSAPIClientRequest& request)
return handle_request(static_cast<const WSAPISetWindowRectRequest&>(request));
case WSMessage::APIGetWindowRectRequest:
return handle_request(static_cast<const WSAPIGetWindowRectRequest&>(request));
case WSMessage::APISetWindowIconRequest:
return handle_request(static_cast<const WSAPISetWindowIconRequest&>(request));
case WSMessage::APISetClipboardContentsRequest:
return handle_request(static_cast<const WSAPISetClipboardContentsRequest&>(request));
case WSMessage::APIGetClipboardContentsRequest:

View file

@ -56,6 +56,7 @@ private:
void handle_request(const WSAPIGetWindowTitleRequest&);
void handle_request(const WSAPISetWindowRectRequest&);
void handle_request(const WSAPIGetWindowRectRequest&);
void handle_request(const WSAPISetWindowIconRequest&);
void handle_request(const WSAPISetClipboardContentsRequest&);
void handle_request(const WSAPIGetClipboardContentsRequest&);
void handle_request(const WSAPICreateWindowRequest&);

View file

@ -45,6 +45,7 @@ public:
APIGetWindowTitleRequest,
APISetWindowRectRequest,
APIGetWindowRectRequest,
APISetWindowIconRequest,
APIInvalidateRectRequest,
APIDidFinishPaintingNotification,
APIGetWindowBackingStoreRequest,
@ -463,6 +464,23 @@ private:
Rect m_rect;
};
class WSAPISetWindowIconRequest final : public WSAPIClientRequest {
public:
explicit WSAPISetWindowIconRequest(int client_id, int window_id, const String& icon_path)
: WSAPIClientRequest(WSMessage::APISetWindowIconRequest, client_id)
, m_window_id(window_id)
, m_icon_path(icon_path)
{
}
int window_id() const { return m_window_id; }
String icon_path() const { return m_icon_path; }
private:
int m_window_id { 0 };
String m_icon_path;
};
class WSAPIGetWindowRectRequest final : public WSAPIClientRequest {
public:
explicit WSAPIGetWindowRectRequest(int client_id, int window_id)
@ -684,9 +702,10 @@ public:
class WSWMWindowStateChangedEvent : public WSWMEvent {
public:
WSWMWindowStateChangedEvent(int client_id, int window_id, const String& title, const Rect& rect, bool is_active, WSWindowType window_type, bool is_minimized)
WSWMWindowStateChangedEvent(int client_id, int window_id, const String& title, const Rect& rect, bool is_active, WSWindowType window_type, bool is_minimized, const String& icon_path)
: WSWMEvent(WSMessage::WM_WindowStateChanged, client_id, window_id)
, m_title(title)
, m_icon_path(icon_path)
, m_rect(rect)
, m_active(is_active)
, m_window_type(window_type)
@ -695,6 +714,7 @@ public:
}
String title() const { return m_title; }
String icon_path() const { return m_icon_path; }
Rect rect() const { return m_rect; }
bool is_active() const { return m_active; }
WSWindowType window_type() const { return m_window_type; }
@ -702,6 +722,7 @@ public:
private:
String m_title;
String m_icon_path;
Rect m_rect;
bool m_active;
WSWindowType m_window_type;

View file

@ -293,6 +293,10 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
case WSAPI_ClientMessage::Type::PopupMenu:
post_message(client, make<WSAPIPopupMenuRequest>(client_id, message.menu.menu_id, message.menu.position));
break;
case WSAPI_ClientMessage::Type::SetWindowIcon:
ASSERT(message.text_length < (ssize_t)sizeof(message.text));
post_message(client, make<WSAPISetWindowIconRequest>(client_id, message.window_id, String(message.text, message.text_length)));
break;
case WSAPI_ClientMessage::Type::DestroyMenu:
post_message(client, make<WSAPIDestroyMenuRequest>(client_id, message.menu.menu_id));
break;

View file

@ -5,11 +5,16 @@
#include <WindowServer/WSAPITypes.h>
#include <WindowServer/WSClientConnection.h>
static String default_window_icon_path()
{
return "/res/icons/16x16/window.png";
}
static GraphicsBitmap& default_window_icon()
{
static GraphicsBitmap* s_icon;
if (!s_icon)
s_icon = GraphicsBitmap::load_from_file("/res/icons/16x16/window.png").leak_ref();
s_icon = GraphicsBitmap::load_from_file(default_window_icon_path()).leak_ref();
return *s_icon;
}
@ -17,6 +22,7 @@ WSWindow::WSWindow(WSMessageReceiver& internal_owner, WSWindowType type)
: m_internal_owner(&internal_owner)
, m_type(type)
, m_icon(default_window_icon())
, m_icon_path(default_window_icon_path())
, m_frame(*this)
{
WSWindowManager::the().add_window(*this);
@ -28,6 +34,7 @@ WSWindow::WSWindow(WSClientConnection& client, WSWindowType window_type, int win
, m_modal(modal)
, m_window_id(window_id)
, m_icon(default_window_icon())
, m_icon_path(default_window_icon_path())
, m_frame(*this)
{
// FIXME: This should not be hard-coded here.
@ -189,6 +196,9 @@ void WSWindow::on_message(const WSMessage& message)
memcpy(server_message.text, changed_event.title().characters(), changed_event.title().length());
server_message.text_length = changed_event.title().length();
server_message.wm.rect = changed_event.rect();
ASSERT(changed_event.icon_path().length() < sizeof(server_message.wm.icon_path));
memcpy(server_message.wm.icon_path, changed_event.icon_path().characters(), changed_event.icon_path().length());
server_message.wm.icon_path_length = changed_event.icon_path().length();
break;
}
@ -236,3 +246,9 @@ bool WSWindow::is_blocked_by_modal_window() const
{
return !is_modal() && client() && client()->is_showing_modal_window();
}
void WSWindow::set_default_icon()
{
m_icon = default_window_icon();
m_icon_path = default_window_icon_path();
}

View file

@ -113,7 +113,13 @@ public:
void set_base_size(const Size& size) { m_base_size = size; }
const GraphicsBitmap& icon() const { return *m_icon; }
void set_icon(Retained<GraphicsBitmap>&& icon) { m_icon = move(icon); }
String icon_path() const { return m_icon_path; }
void set_icon(const String& path, Retained<GraphicsBitmap>&& icon)
{
m_icon_path = path;
m_icon = move(icon);
}
void set_default_icon();
const WSCursor* override_cursor() const { return m_override_cursor.ptr(); }
void set_override_cursor(RetainPtr<WSCursor>&& cursor) { m_override_cursor = move(cursor); }
@ -146,6 +152,7 @@ private:
Size m_size_increment;
Size m_base_size;
Retained<GraphicsBitmap> m_icon;
String m_icon_path;
RetainPtr<WSCursor> m_override_cursor;
WSWindowFrame m_frame;
Color m_background_color { Color::LightGray };

View file

@ -363,7 +363,7 @@ void WSWindowManager::remove_window(WSWindow& window)
void WSWindowManager::tell_wm_listener_about_window(WSWindow& listener, WSWindow& window)
{
if (window.client())
WSMessageLoop::the().post_message(listener, make<WSWMWindowStateChangedEvent>(window.client()->client_id(), window.window_id(), window.title(), window.rect(), window.is_active(), window.type(), window.is_minimized()));
WSMessageLoop::the().post_message(listener, make<WSWMWindowStateChangedEvent>(window.client()->client_id(), window.window_id(), window.title(), window.rect(), window.is_active(), window.type(), window.is_minimized(), window.icon_path()));
}
void WSWindowManager::tell_wm_listeners_window_state_changed(WSWindow& window)

View file

@ -111,6 +111,8 @@ public:
bool any_opaque_window_contains_rect(const Rect&);
bool any_opaque_window_above_this_one_contains_rect(const WSWindow&, const Rect&);
void tell_wm_listeners_window_state_changed(WSWindow&);
private:
void process_mouse_event(const WSMouseEvent&, WSWindow*& event_window);
bool process_ongoing_window_resize(const WSMouseEvent&, WSWindow*& event_window);
@ -135,7 +137,6 @@ private:
void paint_window_frame(const WSWindow&);
void flip_buffers();
void tick_clock();
void tell_wm_listeners_window_state_changed(WSWindow&);
void tell_wm_listener_about_window(WSWindow& listener, WSWindow&);
void pick_new_active_window();