mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 11:12:45 +00:00 
			
		
		
		
	LibGUI: Implement destroying individual windows without exiting the process.
This commit is contained in:
		
							parent
							
								
									5c25f0c4db
								
							
						
					
					
						commit
						37ab7b7a8c
					
				
					 8 changed files with 85 additions and 30 deletions
				
			
		|  | @ -80,6 +80,8 @@ int Process::gui$destroy_window(int window_id) | ||||||
|     auto it = m_windows.find(window_id); |     auto it = m_windows.find(window_id); | ||||||
|     if (it == m_windows.end()) |     if (it == m_windows.end()) | ||||||
|         return -EBADWINDOW; |         return -EBADWINDOW; | ||||||
|  |     auto message = make<WSMessage>(WSMessage::WM_DestroyWindow); | ||||||
|  |     WSMessageLoop::the().post_message((*it).value.leakPtr(), move(message), true); | ||||||
|     m_windows.remove(window_id); |     m_windows.remove(window_id); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,12 @@ int gui_create_window(const GUI_WindowParameters* params) | ||||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); |     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int gui_destroy_window(int window_id) | ||||||
|  | { | ||||||
|  |     int rc = syscall(SC_gui_destroy_window, window_id); | ||||||
|  |     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int gui_invalidate_window(int window_id, const GUI_Rect* rect) | int gui_invalidate_window(int window_id, const GUI_Rect* rect) | ||||||
| { | { | ||||||
|     int rc = syscall(SC_gui_invalidate_window, window_id, rect); |     int rc = syscall(SC_gui_invalidate_window, window_id, rect); | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| __BEGIN_DECLS | __BEGIN_DECLS | ||||||
| 
 | 
 | ||||||
| int gui_create_window(const GUI_WindowParameters*); | int gui_create_window(const GUI_WindowParameters*); | ||||||
|  | int gui_destroy_window(int window_id); | ||||||
| int gui_invalidate_window(int window_id, const GUI_Rect*); | int gui_invalidate_window(int window_id, const GUI_Rect*); | ||||||
| int gui_notify_paint_finished(int window_id, const GUI_Rect*); | int gui_notify_paint_finished(int window_id, const GUI_Rect*); | ||||||
| int gui_get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo*); | int gui_get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo*); | ||||||
|  |  | ||||||
|  | @ -69,7 +69,7 @@ void GObject::stopTimer() | ||||||
|     m_timerID = 0; |     m_timerID = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GObject::deleteLater() | void GObject::delete_later() | ||||||
| { | { | ||||||
|     GEventLoop::main().post_event(this, make<GEvent>(GEvent::DeferredDestroy)); |     GEventLoop::main().post_event(this, make<GEvent>(GEvent::DeferredDestroy)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -27,7 +27,7 @@ public: | ||||||
|     void addChild(GObject&); |     void addChild(GObject&); | ||||||
|     void removeChild(GObject&); |     void removeChild(GObject&); | ||||||
| 
 | 
 | ||||||
|     void deleteLater(); |     void delete_later(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     virtual void timerEvent(GTimerEvent&); |     virtual void timerEvent(GTimerEvent&); | ||||||
|  |  | ||||||
|  | @ -29,10 +29,29 @@ GWindow* GWindow::from_window_id(int window_id) | ||||||
| GWindow::GWindow(GObject* parent) | GWindow::GWindow(GObject* parent) | ||||||
|     : GObject(parent) |     : GObject(parent) | ||||||
| { | { | ||||||
|  |     m_rect_when_windowless = { 100, 400, 140, 140 }; | ||||||
|  |     m_title_when_windowless = "GWindow"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GWindow::~GWindow() | ||||||
|  | { | ||||||
|  |     hide(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GWindow::close() | ||||||
|  | { | ||||||
|  |     delete_later(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GWindow::show() | ||||||
|  | { | ||||||
|  |     if (m_window_id) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|     GUI_WindowParameters wparams; |     GUI_WindowParameters wparams; | ||||||
|     wparams.rect = { { 100, 400 }, { 140, 140 } }; |     wparams.rect = m_rect_when_windowless; | ||||||
|     wparams.background_color = 0xffc0c0; |     wparams.background_color = 0xffc0c0; | ||||||
|     strcpy(wparams.title, "GWindow"); |     strcpy(wparams.title, m_title_when_windowless.characters()); | ||||||
|     m_window_id = gui_create_window(&wparams); |     m_window_id = gui_create_window(&wparams); | ||||||
|     if (m_window_id < 0) { |     if (m_window_id < 0) { | ||||||
|         perror("gui_create_window"); |         perror("gui_create_window"); | ||||||
|  | @ -40,33 +59,54 @@ GWindow::GWindow(GObject* parent) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     windows().set(m_window_id, this); |     windows().set(m_window_id, this); | ||||||
|  |     update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GWindow::~GWindow() | void GWindow::hide() | ||||||
| { | { | ||||||
|  |     if (!m_window_id) | ||||||
|  |         return; | ||||||
|  |     windows().remove(m_window_id); | ||||||
|  |     int rc = gui_destroy_window(m_window_id); | ||||||
|  |     if (rc < 0) { | ||||||
|  |         perror("gui_destroy_window"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GWindow::set_title(String&& title) | void GWindow::set_title(String&& title) | ||||||
| { | { | ||||||
|     dbgprintf("GWindow::set_title \"%s\"\n", title.characters()); |     dbgprintf("GWindow::set_title \"%s\"\n", title.characters()); | ||||||
|  |     m_title_when_windowless = title; | ||||||
|  |     if (m_window_id) { | ||||||
|         int rc = gui_set_window_title(m_window_id, title.characters(), title.length()); |         int rc = gui_set_window_title(m_window_id, title.characters(), title.length()); | ||||||
|     ASSERT(rc == 0); |         if (rc < 0) { | ||||||
|  |             perror("gui_set_window_title"); | ||||||
|  |             exit(1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String GWindow::title() const | String GWindow::title() const | ||||||
| { | { | ||||||
|  |     if (m_window_id) { | ||||||
|         char buffer[256]; |         char buffer[256]; | ||||||
|         int rc = gui_get_window_title(m_window_id, buffer, sizeof(buffer)); |         int rc = gui_get_window_title(m_window_id, buffer, sizeof(buffer)); | ||||||
|         ASSERT(rc >= 0); |         ASSERT(rc >= 0); | ||||||
|         return String(buffer, rc); |         return String(buffer, rc); | ||||||
|  |     } | ||||||
|  |     return m_title_when_windowless; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GWindow::set_rect(const Rect& a_rect) | void GWindow::set_rect(const Rect& a_rect) | ||||||
| { | { | ||||||
|     dbgprintf("GWindow::set_rect! %d,%d %dx%d\n", a_rect.x(), a_rect.y(), a_rect.width(), a_rect.height()); |     dbgprintf("GWindow::set_rect! %d,%d %dx%d\n", a_rect.x(), a_rect.y(), a_rect.width(), a_rect.height()); | ||||||
|  |     m_rect_when_windowless = a_rect; | ||||||
|  |     if (m_window_id) { | ||||||
|         GUI_Rect rect = a_rect; |         GUI_Rect rect = a_rect; | ||||||
|         int rc = gui_set_window_rect(m_window_id, &rect); |         int rc = gui_set_window_rect(m_window_id, &rect); | ||||||
|         ASSERT(rc == 0); |         ASSERT(rc == 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GWindow::event(GEvent& event) | void GWindow::event(GEvent& event) | ||||||
|  | @ -99,9 +139,11 @@ void GWindow::event(GEvent& event) | ||||||
|         if (rect.is_empty()) |         if (rect.is_empty()) | ||||||
|             rect = m_main_widget->rect(); |             rect = m_main_widget->rect(); | ||||||
|         m_main_widget->event(*make<GPaintEvent>(rect)); |         m_main_widget->event(*make<GPaintEvent>(rect)); | ||||||
|  |         if (m_window_id) { | ||||||
|             GUI_Rect gui_rect = rect; |             GUI_Rect gui_rect = rect; | ||||||
|             int rc = gui_notify_paint_finished(m_window_id, &gui_rect); |             int rc = gui_notify_paint_finished(m_window_id, &gui_rect); | ||||||
|             ASSERT(rc == 0); |             ASSERT(rc == 0); | ||||||
|  |         } | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -126,16 +168,10 @@ bool GWindow::is_visible() const | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GWindow::close() |  | ||||||
| { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void GWindow::show() |  | ||||||
| { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void GWindow::update(const Rect& a_rect) | void GWindow::update(const Rect& a_rect) | ||||||
| { | { | ||||||
|  |     if (!m_window_id) | ||||||
|  |         return; | ||||||
|     GUI_Rect rect = a_rect; |     GUI_Rect rect = a_rect; | ||||||
|     int rc = gui_invalidate_window(m_window_id, a_rect.is_null() ? nullptr : &rect); |     int rc = gui_invalidate_window(m_window_id, a_rect.is_null() ? nullptr : &rect); | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
|  | @ -168,6 +204,7 @@ void GWindow::set_focused_widget(GWidget* widget) | ||||||
| 
 | 
 | ||||||
| void GWindow::set_global_cursor_tracking_widget(GWidget* widget) | void GWindow::set_global_cursor_tracking_widget(GWidget* widget) | ||||||
| { | { | ||||||
|  |     ASSERT(m_window_id); | ||||||
|     if (widget == m_global_cursor_tracking_widget.ptr()) |     if (widget == m_global_cursor_tracking_widget.ptr()) | ||||||
|         return; |         return; | ||||||
|     m_global_cursor_tracking_widget = widget ? widget->makeWeakPtr() : nullptr; |     m_global_cursor_tracking_widget = widget ? widget->makeWeakPtr() : nullptr; | ||||||
|  |  | ||||||
|  | @ -35,6 +35,8 @@ public: | ||||||
|     bool is_visible() const; |     bool is_visible() const; | ||||||
|     bool is_active() const { return m_is_active; } |     bool is_active() const { return m_is_active; } | ||||||
| 
 | 
 | ||||||
|  |     void show(); | ||||||
|  |     void hide(); | ||||||
|     void close(); |     void close(); | ||||||
| 
 | 
 | ||||||
|     GWidget* main_widget() { return m_main_widget; } |     GWidget* main_widget() { return m_main_widget; } | ||||||
|  | @ -45,8 +47,6 @@ public: | ||||||
|     const GWidget* focused_widget() const { return m_focused_widget; } |     const GWidget* focused_widget() const { return m_focused_widget; } | ||||||
|     void set_focused_widget(GWidget*); |     void set_focused_widget(GWidget*); | ||||||
| 
 | 
 | ||||||
|     void show(); |  | ||||||
| 
 |  | ||||||
|     void update(const Rect& = Rect()); |     void update(const Rect& = Rect()); | ||||||
| 
 | 
 | ||||||
|     void set_global_cursor_tracking_widget(GWidget*); |     void set_global_cursor_tracking_widget(GWidget*); | ||||||
|  | @ -55,10 +55,12 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     RetainPtr<GraphicsBitmap> m_backing; |     RetainPtr<GraphicsBitmap> m_backing; | ||||||
|     int m_window_id { -1 }; |     int m_window_id { 0 }; | ||||||
|     bool m_is_active { false }; |     bool m_is_active { false }; | ||||||
|     GWidget* m_main_widget { nullptr }; |     GWidget* m_main_widget { nullptr }; | ||||||
|     GWidget* m_focused_widget { nullptr }; |     GWidget* m_focused_widget { nullptr }; | ||||||
|     WeakPtr<GWidget> m_global_cursor_tracking_widget; |     WeakPtr<GWidget> m_global_cursor_tracking_widget; | ||||||
|  |     Rect m_rect_when_windowless; | ||||||
|  |     String m_title_when_windowless; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -63,11 +63,11 @@ GWindow* make_launcher_window() | ||||||
| { | { | ||||||
|     auto* window = new GWindow; |     auto* window = new GWindow; | ||||||
|     window->set_title("Launcher"); |     window->set_title("Launcher"); | ||||||
|     window->set_rect({ 100, 400, 100, 200 }); |     window->set_rect({ 100, 400, 100, 230 }); | ||||||
| 
 | 
 | ||||||
|     auto* widget = new GWidget; |     auto* widget = new GWidget; | ||||||
|     window->set_main_widget(widget); |     window->set_main_widget(widget); | ||||||
|     widget->set_relative_rect({ 0, 0, 100, 200 }); |     widget->set_relative_rect({ 0, 0, 100, 230 }); | ||||||
| 
 | 
 | ||||||
|     auto* label = new GLabel(widget); |     auto* label = new GLabel(widget); | ||||||
|     label->set_relative_rect({ 0, 0, 100, 20 }); |     label->set_relative_rect({ 0, 0, 100, 20 }); | ||||||
|  | @ -124,5 +124,12 @@ GWindow* make_launcher_window() | ||||||
| 
 | 
 | ||||||
|     window->set_focused_widget(textbox); |     window->set_focused_widget(textbox); | ||||||
| 
 | 
 | ||||||
|  |     auto* close_button = new GButton(widget); | ||||||
|  |     close_button->set_relative_rect({ 5, 200, 90, 20 }); | ||||||
|  |     close_button->set_caption("Close"); | ||||||
|  |     close_button->on_click = [window] (GButton&) { | ||||||
|  |         window->close(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     return window; |     return window; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling