Просмотр исходного кода

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.
Andreas Kling 6 лет назад
Родитель
Сommit
43304d2adf

+ 2 - 0
AK/Types.h

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

+ 3 - 3
Applications/IRCClient/IRCAppWindow.cpp

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

+ 2 - 0
LibGUI/GWindow.cpp

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

+ 1 - 0
LibGUI/GWindow.h

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

+ 2 - 6
WindowServer/WSAPITypes.h

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

+ 12 - 1
WindowServer/WSClientConnection.cpp

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

+ 25 - 0
WindowServer/WSClientConnection.h

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

+ 7 - 1
WindowServer/WSMessage.h

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

+ 1 - 1
WindowServer/WSMessageLoop.cpp

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

+ 17 - 2
WindowServer/WSWindow.cpp

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

+ 10 - 1
WindowServer/WSWindow.h

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

+ 7 - 1
WindowServer/WSWindowManager.cpp

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

+ 0 - 1
WindowServer/WSWindowManager.h

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