mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 09:17:35 +00:00
Add a simple close button ("X") to windows.
Clicking the button generates a WindowCloseRequest event which the client app then has to deal with. The default behavior for GWindow is to close() itself. I also added a flag, GWindow::should_exit_event_loop_on_close() which does what it sounds like it does. This patch exposed some bugs in GWindow and GWidget teardown.
This commit is contained in:
parent
d0078b6574
commit
11db8c1697
14 changed files with 103 additions and 1 deletions
|
@ -24,6 +24,7 @@ public:
|
|||
WindowBecameActive,
|
||||
FocusIn,
|
||||
FocusOut,
|
||||
WindowCloseRequest,
|
||||
};
|
||||
|
||||
GEvent() { }
|
||||
|
|
|
@ -35,6 +35,12 @@ GEventLoop& GEventLoop::main()
|
|||
return *s_mainGEventLoop;
|
||||
}
|
||||
|
||||
void GEventLoop::exit(int code)
|
||||
{
|
||||
m_exit_requested = true;
|
||||
m_exit_code = code;
|
||||
}
|
||||
|
||||
int GEventLoop::exec()
|
||||
{
|
||||
m_event_fd = open("/dev/gui_events", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
|
@ -45,6 +51,8 @@ int GEventLoop::exec()
|
|||
|
||||
m_running = true;
|
||||
for (;;) {
|
||||
if (m_exit_requested)
|
||||
return m_exit_code;
|
||||
if (m_queued_events.is_empty())
|
||||
wait_for_event();
|
||||
Vector<QueuedEvent> events = move(m_queued_events);
|
||||
|
@ -69,6 +77,7 @@ int GEventLoop::exec()
|
|||
}
|
||||
}
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void GEventLoop::post_event(GObject* receiver, OwnPtr<GEvent>&& event)
|
||||
|
@ -95,6 +104,11 @@ void GEventLoop::handle_window_activation_event(const GUI_Event& event, GWindow&
|
|||
post_event(&window, make<GEvent>(event.type == GUI_Event::Type::WindowActivated ? GEvent::WindowBecameActive : GEvent::WindowBecameInactive));
|
||||
}
|
||||
|
||||
void GEventLoop::handle_window_close_request_event(const GUI_Event&, GWindow& window)
|
||||
{
|
||||
post_event(&window, make<GEvent>(GEvent::WindowCloseRequest));
|
||||
}
|
||||
|
||||
void GEventLoop::handle_key_event(const GUI_Event& event, GWindow& window)
|
||||
{
|
||||
#ifdef GEVENTLOOP_DEBUG
|
||||
|
@ -192,6 +206,9 @@ void GEventLoop::wait_for_event()
|
|||
case GUI_Event::Type::WindowDeactivated:
|
||||
handle_window_activation_event(event, *window);
|
||||
break;
|
||||
case GUI_Event::Type::WindowCloseRequest:
|
||||
handle_window_close_request_event(event, *window);
|
||||
break;
|
||||
case GUI_Event::Type::KeyDown:
|
||||
case GUI_Event::Type::KeyUp:
|
||||
handle_key_event(event, *window);
|
||||
|
|
|
@ -27,12 +27,15 @@ public:
|
|||
int register_timer(GObject&, int milliseconds, bool should_reload);
|
||||
bool unregister_timer(int timer_id);
|
||||
|
||||
void exit(int);
|
||||
|
||||
private:
|
||||
void wait_for_event();
|
||||
void handle_paint_event(const GUI_Event&, GWindow&);
|
||||
void handle_mouse_event(const GUI_Event&, GWindow&);
|
||||
void handle_key_event(const GUI_Event&, GWindow&);
|
||||
void handle_window_activation_event(const GUI_Event&, GWindow&);
|
||||
void handle_window_close_request_event(const GUI_Event&, GWindow&);
|
||||
|
||||
void get_next_timer_expiration(timeval&);
|
||||
|
||||
|
@ -44,6 +47,8 @@ private:
|
|||
|
||||
int m_event_fd { -1 };
|
||||
bool m_running { false };
|
||||
bool m_exit_requested { false };
|
||||
int m_exit_code { 0 };
|
||||
|
||||
int m_next_timer_id { 1 };
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ GObject::GObject(GObject* parent)
|
|||
|
||||
GObject::~GObject()
|
||||
{
|
||||
stop_timer();
|
||||
if (m_parent)
|
||||
m_parent->remove_child(*this);
|
||||
auto children_to_delete = move(m_children);
|
||||
|
|
|
@ -35,11 +35,17 @@ GWindow::GWindow(GObject* parent)
|
|||
|
||||
GWindow::~GWindow()
|
||||
{
|
||||
if (m_main_widget)
|
||||
delete m_main_widget;
|
||||
hide();
|
||||
}
|
||||
|
||||
void GWindow::close()
|
||||
{
|
||||
// FIXME: If we exit the event loop, we're never gonna deal with the delete_later request!
|
||||
// This will become relevant once we support nested event loops.
|
||||
if (should_exit_app_on_close())
|
||||
GEventLoop::main().exit(0);
|
||||
delete_later();
|
||||
}
|
||||
|
||||
|
@ -160,6 +166,11 @@ void GWindow::event(GEvent& event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (event.type() == GEvent::WindowCloseRequest) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
GObject::event(event);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,9 @@ public:
|
|||
GWidget* global_cursor_tracking_widget() { return m_global_cursor_tracking_widget.ptr(); }
|
||||
const GWidget* global_cursor_tracking_widget() const { return m_global_cursor_tracking_widget.ptr(); }
|
||||
|
||||
bool should_exit_app_on_close() const { return m_should_exit_app_on_close; }
|
||||
void set_should_exit_app_on_close(bool b) { m_should_exit_app_on_close = b; }
|
||||
|
||||
private:
|
||||
RetainPtr<GraphicsBitmap> m_backing;
|
||||
int m_window_id { 0 };
|
||||
|
@ -62,5 +65,6 @@ private:
|
|||
WeakPtr<GWidget> m_global_cursor_tracking_widget;
|
||||
Rect m_rect_when_windowless;
|
||||
String m_title_when_windowless;
|
||||
bool m_should_exit_app_on_close { false };
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue