Procházet zdrojové kódy

LibGUI: Exit the main event loop when the last window is deleted.

This behavior is the new opt-out default. If you don't want your app to exit
when the last GWindow is destroyed, call this:

    - void GApplication::set_quit_set_quit_when_last_window_deleted(bool)

Also renamed "windows()" to "reified_windows" in GWindow.cpp to reflect that
it only contains GWindows that have a server-side representation. :^)
Andreas Kling před 6 roky
rodič
revize
fbae03b737

+ 6 - 0
Libraries/LibGUI/GApplication.cpp

@@ -111,3 +111,9 @@ void GApplication::hide_tooltip()
     if (m_tooltip_window)
         m_tooltip_window->hide();
 }
+
+void GApplication::did_delete_last_window(Badge<GWindow>)
+{
+    if (m_quit_when_last_window_deleted)
+        m_event_loop->quit(0);
+}

+ 8 - 1
Libraries/LibGUI/GApplication.h

@@ -6,9 +6,10 @@
 #include <LibGUI/GShortcut.h>
 
 class GAction;
-class GKeyEvent;
 class GEventLoop;
+class GKeyEvent;
 class GMenuBar;
+class GWindow;
 class Point;
 
 class GApplication {
@@ -29,10 +30,16 @@ public:
     void show_tooltip(const StringView&, const Point& screen_location);
     void hide_tooltip();
 
+    bool quit_when_last_window_deleted() const { return m_quit_when_last_window_deleted; }
+    void set_quit_when_last_window_deleted(bool b) { m_quit_when_last_window_deleted = b; }
+
+    void did_delete_last_window(Badge<GWindow>);
+
 private:
     OwnPtr<GEventLoop> m_event_loop;
     OwnPtr<GMenuBar> m_menubar;
     HashMap<GShortcut, GAction*> m_global_shortcut_actions;
     class TooltipWindow;
     TooltipWindow* m_tooltip_window { nullptr };
+    bool m_quit_when_last_window_deleted { true };
 };

+ 18 - 17
Libraries/LibGUI/GWindow.cpp

@@ -1,30 +1,25 @@
-#include "GWindow.h"
-#include "GEvent.h"
-#include "GEventLoop.h"
-#include "GWidget.h"
 #include <AK/HashMap.h>
 #include <AK/StringBuilder.h>
 #include <LibC/stdio.h>
 #include <LibC/stdlib.h>
 #include <LibC/unistd.h>
-#include <LibGUI/GPainter.h>
 #include <LibDraw/GraphicsBitmap.h>
+#include <LibGUI/GApplication.h>
+#include <LibGUI/GEvent.h>
+#include <LibGUI/GEventLoop.h>
+#include <LibGUI/GPainter.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
 
 //#define UPDATE_COALESCING_DEBUG
 
-static HashMap<int, GWindow*>* s_windows;
-
-static HashMap<int, GWindow*>& windows()
-{
-    if (!s_windows)
-        s_windows = new HashMap<int, GWindow*>;
-    return *s_windows;
-}
+static HashTable<GWindow*> all_windows;
+static HashMap<int, GWindow*> reified_windows;
 
 GWindow* GWindow::from_window_id(int window_id)
 {
-    auto it = windows().find(window_id);
-    if (it != windows().end())
+    auto it = reified_windows.find(window_id);
+    if (it != reified_windows.end())
         return (*it).value;
     return nullptr;
 }
@@ -32,15 +27,21 @@ GWindow* GWindow::from_window_id(int window_id)
 GWindow::GWindow(CObject* parent)
     : CObject(parent)
 {
+    all_windows.set(this);
     m_rect_when_windowless = { 100, 400, 140, 140 };
     m_title_when_windowless = "GWindow";
 }
 
 GWindow::~GWindow()
 {
+    all_windows.remove(this);
     if (m_main_widget)
         delete m_main_widget;
     hide();
+
+    if (all_windows.is_empty()) {
+        GApplication::the().did_delete_last_window({});
+    }
 }
 
 void GWindow::close()
@@ -87,7 +88,7 @@ void GWindow::show()
     auto response = GWindowServerConnection::the().sync_request(request, WSAPI_ServerMessage::Type::DidCreateWindow);
     m_window_id = response.window_id;
 
-    windows().set(m_window_id, this);
+    reified_windows.set(m_window_id, this);
     update();
 }
 
@@ -95,7 +96,7 @@ void GWindow::hide()
 {
     if (!m_window_id)
         return;
-    windows().remove(m_window_id);
+    reified_windows.remove(m_window_id);
     WSAPI_ClientMessage request;
     request.type = WSAPI_ClientMessage::Type::DestroyWindow;
     request.window_id = m_window_id;