mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-03 04:50:29 +00:00
WindowServer: Add special treatment for modal windows.
While a WSClientConnection has a modal window showing, non-modal windows belonging to that client are not sent any events.
This commit is contained in:
parent
57ff293a51
commit
43304d2adf
Notes:
sideshowbarker
2024-07-19 15:00:40 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/43304d2adf8
13 changed files with 89 additions and 17 deletions
|
@ -48,6 +48,8 @@ constexpr unsigned KB = 1024;
|
|||
constexpr unsigned MB = KB * KB;
|
||||
constexpr unsigned GB = KB * KB * KB;
|
||||
|
||||
enum class IterationDecision { Continue, Abort };
|
||||
|
||||
namespace std {
|
||||
typedef decltype(nullptr) nullptr_t;
|
||||
}
|
||||
|
|
|
@ -41,9 +41,6 @@ void IRCAppWindow::setup_client()
|
|||
};
|
||||
|
||||
m_client.on_connect = [this] {
|
||||
GMessageBox box("We are connected!", "Message");
|
||||
int code = box.exec();
|
||||
dbgprintf("GMessageBox::exec() returned %d\n", code);
|
||||
m_client.join_channel("#test");
|
||||
};
|
||||
|
||||
|
@ -62,6 +59,9 @@ void IRCAppWindow::setup_actions()
|
|||
|
||||
m_whois_action = GAction::create("Whois user", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-whois.rgb", { 16, 16 }), [] (auto&) {
|
||||
printf("FIXME: Implement whois action\n");
|
||||
GMessageBox box("Who would you like to WHOIS?", "Whois user");
|
||||
int code = box.exec();
|
||||
dbgprintf("GMessageBox::exec() returned %d\n", code);
|
||||
});
|
||||
|
||||
m_open_query_action = GAction::create("Open query", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-open-query.rgb", { 16, 16 }), [] (auto&) {
|
||||
|
|
|
@ -59,6 +59,8 @@ void GWindow::show()
|
|||
request.window_id = m_window_id;
|
||||
request.window.rect = m_rect_when_windowless;
|
||||
request.window.has_alpha_channel = m_has_alpha_channel;
|
||||
request.window.modal = m_modal;
|
||||
request.window.resizable = m_resizable;
|
||||
request.window.opacity = m_opacity_when_windowless;
|
||||
request.window.size_increment = m_size_increment;
|
||||
request.window.base_size = m_base_size;
|
||||
|
|
|
@ -105,5 +105,6 @@ private:
|
|||
bool m_has_alpha_channel { false };
|
||||
bool m_double_buffering_enabled { true };
|
||||
bool m_modal { false };
|
||||
bool m_resizable { true };
|
||||
};
|
||||
|
||||
|
|
|
@ -3,12 +3,6 @@
|
|||
#include <SharedGraphics/Color.h>
|
||||
#include <SharedGraphics/Rect.h>
|
||||
|
||||
// GUI system call API types.
|
||||
|
||||
struct WSAPI_WindowFlags { enum {
|
||||
Visible = 1 << 0,
|
||||
}; };
|
||||
|
||||
typedef unsigned WSAPI_Color;
|
||||
|
||||
struct WSAPI_Point {
|
||||
|
@ -186,6 +180,8 @@ struct WSAPI_ClientMessage {
|
|||
struct {
|
||||
WSAPI_Rect rect;
|
||||
bool has_alpha_channel;
|
||||
bool modal;
|
||||
bool resizable;
|
||||
float opacity;
|
||||
WSAPI_Size base_size;
|
||||
WSAPI_Size size_increment;
|
||||
|
|
|
@ -350,8 +350,9 @@ void WSClientConnection::handle_request(WSAPIGetClipboardContentsRequest&)
|
|||
void WSClientConnection::handle_request(WSAPICreateWindowRequest& request)
|
||||
{
|
||||
int window_id = m_next_window_id++;
|
||||
auto window = make<WSWindow>(*this, window_id);
|
||||
auto window = make<WSWindow>(*this, window_id, request.is_modal());
|
||||
window->set_has_alpha_channel(request.has_alpha_channel());
|
||||
window->set_resizable(request.is_resizable());
|
||||
window->set_title(request.title());
|
||||
window->set_rect(request.rect());
|
||||
window->set_opacity(request.opacity());
|
||||
|
@ -531,3 +532,13 @@ void WSClientConnection::on_request(WSAPIClientRequest& request)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool WSClientConnection::is_showing_modal_window() const
|
||||
{
|
||||
for (auto& it : m_windows) {
|
||||
auto& window = *it.value;
|
||||
if (window.is_visible() && window.is_modal())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,11 @@ public:
|
|||
int fd() const { return m_fd; }
|
||||
pid_t pid() const { return m_pid; }
|
||||
|
||||
bool is_showing_modal_window() const;
|
||||
|
||||
template<typename Matching, typename Callback> void for_each_window_matching(Matching, Callback);
|
||||
template<typename Callback> void for_each_window(Callback);
|
||||
|
||||
private:
|
||||
virtual void on_message(WSMessage&) override;
|
||||
|
||||
|
@ -74,3 +79,23 @@ private:
|
|||
|
||||
RetainPtr<SharedBuffer> m_last_sent_clipboard_content;
|
||||
};
|
||||
|
||||
template<typename Matching, typename Callback>
|
||||
void WSClientConnection::for_each_window_matching(Matching matching, Callback callback)
|
||||
{
|
||||
for (auto& it : m_windows) {
|
||||
if (matching(*it.value)) {
|
||||
if (callback(*it.value) == IterationDecision::Abort)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
void WSClientConnection::for_each_window(Callback callback)
|
||||
{
|
||||
for (auto& it : m_windows) {
|
||||
if (callback(*it.value) == IterationDecision::Abort)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -392,12 +392,14 @@ private:
|
|||
|
||||
class WSAPICreateWindowRequest : public WSAPIClientRequest {
|
||||
public:
|
||||
WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title, bool has_alpha_channel, float opacity, const Size& base_size, const Size& size_increment)
|
||||
WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title, bool has_alpha_channel, bool modal, bool resizable, float opacity, const Size& base_size, const Size& size_increment)
|
||||
: WSAPIClientRequest(WSMessage::APICreateWindowRequest, client_id)
|
||||
, m_rect(rect)
|
||||
, m_title(title)
|
||||
, m_opacity(opacity)
|
||||
, m_has_alpha_channel(has_alpha_channel)
|
||||
, m_modal(modal)
|
||||
, m_resizable(resizable)
|
||||
, m_size_increment(size_increment)
|
||||
, m_base_size(base_size)
|
||||
{
|
||||
|
@ -406,6 +408,8 @@ public:
|
|||
Rect rect() const { return m_rect; }
|
||||
String title() const { return m_title; }
|
||||
bool has_alpha_channel() const { return m_has_alpha_channel; }
|
||||
bool is_modal() const { return m_modal; }
|
||||
bool is_resizable() const { return m_resizable; }
|
||||
float opacity() const { return m_opacity; }
|
||||
Size size_increment() const { return m_size_increment; }
|
||||
Size base_size() const { return m_base_size; }
|
||||
|
@ -415,6 +419,8 @@ private:
|
|||
String m_title;
|
||||
float m_opacity { 0 };
|
||||
bool m_has_alpha_channel { false };
|
||||
bool m_modal { false };
|
||||
bool m_resizable { false };
|
||||
Size m_size_increment;
|
||||
Size m_base_size;
|
||||
};
|
||||
|
|
|
@ -286,7 +286,7 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
|
|||
break;
|
||||
case WSAPI_ClientMessage::Type::CreateWindow:
|
||||
ASSERT(message.text_length < (ssize_t)sizeof(message.text));
|
||||
post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.opacity, message.window.base_size, message.window.size_increment));
|
||||
post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.modal, message.window.resizable, message.window.opacity, message.window.base_size, message.window.size_increment));
|
||||
break;
|
||||
case WSAPI_ClientMessage::Type::DestroyWindow:
|
||||
post_message(client, make<WSAPIDestroyWindowRequest>(client_id, message.window_id));
|
||||
|
|
|
@ -21,9 +21,10 @@ WSWindow::WSWindow(WSMessageReceiver& internal_owner, WSWindowType type)
|
|||
WSWindowManager::the().add_window(*this);
|
||||
}
|
||||
|
||||
WSWindow::WSWindow(WSClientConnection& client, int window_id)
|
||||
WSWindow::WSWindow(WSClientConnection& client, int window_id, bool modal)
|
||||
: m_client(&client)
|
||||
, m_type(WSWindowType::Normal)
|
||||
, m_modal(modal)
|
||||
, m_window_id(window_id)
|
||||
, m_icon(default_window_icon())
|
||||
{
|
||||
|
@ -73,6 +74,9 @@ void WSWindow::on_message(WSMessage& message)
|
|||
if (m_internal_owner)
|
||||
return m_internal_owner->on_message(message);
|
||||
|
||||
if (is_blocked_by_modal_window())
|
||||
return;
|
||||
|
||||
WSAPI_ServerMessage server_message;
|
||||
server_message.window_id = window_id();
|
||||
|
||||
|
@ -137,7 +141,6 @@ void WSWindow::on_message(WSMessage& message)
|
|||
if (server_message.type == WSAPI_ServerMessage::Type::Invalid)
|
||||
return;
|
||||
|
||||
ASSERT(m_client);
|
||||
m_client->post_message(server_message);
|
||||
}
|
||||
|
||||
|
@ -154,6 +157,13 @@ void WSWindow::set_visible(bool b)
|
|||
invalidate();
|
||||
}
|
||||
|
||||
void WSWindow::set_resizable(bool resizable)
|
||||
{
|
||||
if (m_resizable == resizable)
|
||||
return;
|
||||
m_resizable = resizable;
|
||||
}
|
||||
|
||||
void WSWindow::invalidate()
|
||||
{
|
||||
WSWindowManager::the().invalidate(*this);
|
||||
|
@ -163,3 +173,8 @@ bool WSWindow::is_active() const
|
|||
{
|
||||
return WSWindowManager::the().active_window() == this;
|
||||
}
|
||||
|
||||
bool WSWindow::is_blocked_by_modal_window() const
|
||||
{
|
||||
return !is_modal() && client() && client()->is_showing_modal_window();
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@ class WSMenu;
|
|||
|
||||
class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode<WSWindow> {
|
||||
public:
|
||||
WSWindow(WSClientConnection&, int window_id);
|
||||
WSWindow(WSClientConnection&, int window_id, bool modal);
|
||||
WSWindow(WSMessageReceiver&, WSWindowType);
|
||||
virtual ~WSWindow() override;
|
||||
|
||||
bool is_blocked_by_modal_window() const;
|
||||
|
||||
WSClientConnection* client() { return m_client; }
|
||||
const WSClientConnection* client() const { return m_client; }
|
||||
|
||||
|
@ -38,6 +40,11 @@ public:
|
|||
bool is_visible() const { return m_visible; }
|
||||
void set_visible(bool);
|
||||
|
||||
bool is_modal() const { return m_modal; }
|
||||
|
||||
bool is_resizable() const { return m_resizable; }
|
||||
void set_resizable(bool);
|
||||
|
||||
Rect rect() const { return m_rect; }
|
||||
void set_rect(const Rect&);
|
||||
void set_rect(int x, int y, int width, int height) { set_rect({ x, y, width, height }); }
|
||||
|
@ -106,6 +113,8 @@ private:
|
|||
bool m_visible { true };
|
||||
bool m_has_alpha_channel { false };
|
||||
bool m_has_painted_since_last_resize { false };
|
||||
bool m_modal { false };
|
||||
bool m_resizable { false };
|
||||
RetainPtr<GraphicsBitmap> m_backing_store;
|
||||
RetainPtr<GraphicsBitmap> m_last_backing_store;
|
||||
int m_window_id { -1 };
|
||||
|
|
|
@ -512,7 +512,7 @@ void WSWindowManager::add_window(WSWindow& window)
|
|||
{
|
||||
m_windows.set(&window);
|
||||
m_windows_in_order.append(&window);
|
||||
if (!active_window())
|
||||
if (!active_window() || active_window()->client() == window.client())
|
||||
set_active_window(&window);
|
||||
if (m_switcher.is_visible() && window.type() != WSWindowType::WindowSwitcher)
|
||||
m_switcher.refresh();
|
||||
|
@ -520,6 +520,9 @@ void WSWindowManager::add_window(WSWindow& window)
|
|||
|
||||
void WSWindowManager::move_to_front(WSWindow& window)
|
||||
{
|
||||
if (window.is_blocked_by_modal_window())
|
||||
return;
|
||||
|
||||
if (m_windows_in_order.tail() != &window)
|
||||
invalidate(window);
|
||||
m_windows_in_order.remove(&window);
|
||||
|
@ -1095,6 +1098,9 @@ void WSWindowManager::set_highlight_window(WSWindow* window)
|
|||
|
||||
void WSWindowManager::set_active_window(WSWindow* window)
|
||||
{
|
||||
if (window && window->is_blocked_by_modal_window())
|
||||
return;
|
||||
|
||||
if (window->type() != WSWindowType::Normal) {
|
||||
dbgprintf("WSWindowManager: Attempted to make a non-normal window active.\n");
|
||||
return;
|
||||
|
|
|
@ -26,7 +26,6 @@ class WSWindowSwitcher;
|
|||
class CharacterBitmap;
|
||||
class GraphicsBitmap;
|
||||
|
||||
enum class IterationDecision { Continue, Abort };
|
||||
enum class ResizeDirection { None, Left, UpLeft, Up, UpRight, Right, DownRight, Down, DownLeft };
|
||||
|
||||
class WSWindowManager : public WSMessageReceiver {
|
||||
|
|
Loading…
Reference in a new issue