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:
Andreas Kling 2019-03-19 00:52:39 +01:00
parent 57ff293a51
commit 43304d2adf
13 changed files with 89 additions and 17 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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