mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 09:02:43 +00:00 
			
		
		
		
	Start bringing up LibGUI properly (formerly Widgets.)
This commit is contained in:
		
							parent
							
								
									b91479d9b9
								
							
						
					
					
						commit
						8eae89a405
					
				
					 17 changed files with 258 additions and 33 deletions
				
			
		|  | @ -104,6 +104,7 @@ static void init_stage2() | ||||||
|     Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0); |     Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0); | ||||||
| #ifdef SPAWN_GUI_TEST_APP | #ifdef SPAWN_GUI_TEST_APP | ||||||
|     Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0); |     Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0); | ||||||
|  |     Process::create_user_process("/bin/guitest2", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0); | ||||||
| #endif | #endif | ||||||
| #ifdef SPAWN_MULTIPLE_SHELLS | #ifdef SPAWN_MULTIPLE_SHELLS | ||||||
|     Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty1); |     Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty1); | ||||||
|  |  | ||||||
|  | @ -4,6 +4,10 @@ sudo id | ||||||
| 
 | 
 | ||||||
| make -C ../LibC clean && \ | make -C ../LibC clean && \ | ||||||
| make -C ../LibC && \ | make -C ../LibC && \ | ||||||
|  | make -C ../LibGUI clean && \ | ||||||
|  | make -C ../LibGUI && \ | ||||||
|  | make -C ../Terminal clean && \ | ||||||
|  | make -C ../Terminal && \ | ||||||
| make -C ../Userland clean && \ | make -C ../Userland clean && \ | ||||||
| make -C ../Userland && \ | make -C ../Userland && \ | ||||||
| sudo ./sync.sh | sudo ./sync.sh | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ cp -v ../Userland/touch mnt/bin/touch | ||||||
| cp -v ../Userland/sync mnt/bin/sync | cp -v ../Userland/sync mnt/bin/sync | ||||||
| cp -v ../Userland/more mnt/bin/more | cp -v ../Userland/more mnt/bin/more | ||||||
| cp -v ../Userland/guitest mnt/bin/guitest | cp -v ../Userland/guitest mnt/bin/guitest | ||||||
|  | cp -v ../Userland/guitest2 mnt/bin/guitest2 | ||||||
| cp -v ../Userland/sysctl mnt/bin/sysctl | cp -v ../Userland/sysctl mnt/bin/sysctl | ||||||
| cp -v ../Terminal/Terminal mnt/bin/Terminal | cp -v ../Terminal/Terminal mnt/bin/Terminal | ||||||
| sh sync-local.sh | sh sync-local.sh | ||||||
|  |  | ||||||
|  | @ -134,9 +134,9 @@ private: | ||||||
| 
 | 
 | ||||||
| class GMouseEvent final : public GEvent { | class GMouseEvent final : public GEvent { | ||||||
| public: | public: | ||||||
|     GMouseEvent(Type type, int x, int y, GMouseButton button = GMouseButton::None) |     GMouseEvent(Type type, const Point& position, GMouseButton button = GMouseButton::None) | ||||||
|         : GEvent(type) |         : GEvent(type) | ||||||
|         , m_position(x, y) |         , m_position(position) | ||||||
|         , m_button(button) |         , m_button(button) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,13 @@ | ||||||
| #include "GEventLoop.h" | #include "GEventLoop.h" | ||||||
| #include "GEvent.h" | #include "GEvent.h" | ||||||
| #include "GObject.h" | #include "GObject.h" | ||||||
|  | #include "GWindow.h" | ||||||
|  | #include <LibC/unistd.h> | ||||||
|  | #include <LibC/stdio.h> | ||||||
|  | #include <LibC/fcntl.h> | ||||||
|  | #include <LibC/string.h> | ||||||
|  | #include <LibC/sys/select.h> | ||||||
|  | #include <LibC/gui.h> | ||||||
| 
 | 
 | ||||||
| static GEventLoop* s_mainGEventLoop; | static GEventLoop* s_mainGEventLoop; | ||||||
| 
 | 
 | ||||||
|  | @ -27,13 +34,19 @@ GEventLoop& GEventLoop::main() | ||||||
| 
 | 
 | ||||||
| int GEventLoop::exec() | int GEventLoop::exec() | ||||||
| { | { | ||||||
|  |     m_event_fd = open("/dev/gui_events", O_RDONLY); | ||||||
|  |     if (m_event_fd < 0) { | ||||||
|  |         perror("GEventLoop::exec(): open"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     m_running = true; |     m_running = true; | ||||||
|     for (;;) { |     for (;;) { | ||||||
|         if (m_queuedEvents.is_empty()) |         if (m_queued_events.is_empty()) | ||||||
|             waitForEvent(); |             wait_for_event(); | ||||||
|         Vector<QueuedEvent> events; |         Vector<QueuedEvent> events; | ||||||
|         { |         { | ||||||
|             events = move(m_queuedEvents); |             events = move(m_queued_events); | ||||||
|         } |         } | ||||||
|         for (auto& queuedEvent : events) { |         for (auto& queuedEvent : events) { | ||||||
|             auto* receiver = queuedEvent.receiver; |             auto* receiver = queuedEvent.receiver; | ||||||
|  | @ -56,12 +69,81 @@ int GEventLoop::exec() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GEventLoop::postEvent(GObject* receiver, OwnPtr<GEvent>&& event) | void GEventLoop::post_event(GObject* receiver, OwnPtr<GEvent>&& event) | ||||||
| { | { | ||||||
|     //printf("GEventLoop::postGEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr());
 |     //printf("GEventLoop::postGEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr());
 | ||||||
|     m_queuedEvents.append({ receiver, move(event) }); |     m_queued_events.append({ receiver, move(event) }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GEventLoop::waitForEvent() | void GEventLoop::handle_paint_event(const GUI_Event& event, GWindow& window) | ||||||
| { | { | ||||||
|  |     post_event(&window, make<GPaintEvent>(event.paint.rect)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window) | ||||||
|  | { | ||||||
|  |     GMouseEvent::Type type; | ||||||
|  |     switch (event.type) { | ||||||
|  |     case GUI_Event::Type::MouseMove: type = GEvent::MouseMove; break; | ||||||
|  |     case GUI_Event::Type::MouseUp: type = GEvent::MouseUp; break; | ||||||
|  |     case GUI_Event::Type::MouseDown: type = GEvent::MouseDown; break; | ||||||
|  |     default: ASSERT_NOT_REACHED(); break; | ||||||
|  |     } | ||||||
|  |     GMouseButton button { GMouseButton::None }; | ||||||
|  |     switch (event.mouse.button) { | ||||||
|  |     case GUI_MouseButton::NoButton: button = GMouseButton::None; break; | ||||||
|  |     case GUI_MouseButton::Left: button = GMouseButton::Left; break; | ||||||
|  |     case GUI_MouseButton::Right: button = GMouseButton::Right; break; | ||||||
|  |     case GUI_MouseButton::Middle: button = GMouseButton::Middle; break; | ||||||
|  |     default: ASSERT_NOT_REACHED(); break; | ||||||
|  |     } | ||||||
|  |     auto mouse_event = make<GMouseEvent>(type, event.mouse.position, button); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GEventLoop::wait_for_event() | ||||||
|  | { | ||||||
|  |     fd_set rfds; | ||||||
|  |     FD_ZERO(&rfds); | ||||||
|  |     FD_SET(m_event_fd, &rfds); | ||||||
|  |     int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, nullptr); | ||||||
|  |     if (rc < 0) { | ||||||
|  |         ASSERT_NOT_REACHED(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!FD_ISSET(m_event_fd, &rfds)) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     for (;;) { | ||||||
|  |         GUI_Event event; | ||||||
|  |         ssize_t nread = read(m_event_fd, &event, sizeof(GUI_Event)); | ||||||
|  |         if (nread < 0) { | ||||||
|  |             perror("read"); | ||||||
|  |             exit(1); // FIXME: This should cause EventLoop::exec() to return 1.
 | ||||||
|  |         } | ||||||
|  |         if (nread == 0) | ||||||
|  |             break; | ||||||
|  |         assert(nread == sizeof(event)); | ||||||
|  |         auto* window = GWindow::from_window_id(event.window_id); | ||||||
|  |         if (!window) { | ||||||
|  |             dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id); | ||||||
|  |         } | ||||||
|  |         switch (event.type) { | ||||||
|  |         case GUI_Event::Type::Paint: | ||||||
|  |             dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break; | ||||||
|  |             handle_paint_event(event, *window); | ||||||
|  |             break; | ||||||
|  |         case GUI_Event::Type::MouseDown: | ||||||
|  |         case GUI_Event::Type::MouseUp: | ||||||
|  |         case GUI_Event::Type::MouseMove: | ||||||
|  |             dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); | ||||||
|  |             handle_mouse_event(event, *window); | ||||||
|  |             break; | ||||||
|  |         case GUI_Event::Type::WindowActivated: | ||||||
|  |             dbgprintf("WID=%x WindowActivated\n", event.window_id); | ||||||
|  |             break; | ||||||
|  |         case GUI_Event::Type::WindowDeactivated: | ||||||
|  |             dbgprintf("WID=%x WindowDeactivated\n", event.window_id); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ | ||||||
| #include <AK/Vector.h> | #include <AK/Vector.h> | ||||||
| 
 | 
 | ||||||
| class GObject; | class GObject; | ||||||
|  | class GWindow; | ||||||
|  | struct GUI_Event; | ||||||
| 
 | 
 | ||||||
| class GEventLoop { | class GEventLoop { | ||||||
| public: | public: | ||||||
|  | @ -13,7 +15,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     int exec(); |     int exec(); | ||||||
| 
 | 
 | ||||||
|     void postEvent(GObject* receiver, OwnPtr<GEvent>&&); |     void post_event(GObject* receiver, OwnPtr<GEvent>&&); | ||||||
| 
 | 
 | ||||||
|     static GEventLoop& main(); |     static GEventLoop& main(); | ||||||
| 
 | 
 | ||||||
|  | @ -22,13 +24,16 @@ public: | ||||||
|     bool running() const { return m_running; } |     bool running() const { return m_running; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void waitForEvent(); |     void wait_for_event(); | ||||||
|  |     void handle_paint_event(const GUI_Event&, GWindow&); | ||||||
|  |     void handle_mouse_event(const GUI_Event&, GWindow&); | ||||||
| 
 | 
 | ||||||
|     struct QueuedEvent { |     struct QueuedEvent { | ||||||
|         GObject* receiver { nullptr }; |         GObject* receiver { nullptr }; | ||||||
|         OwnPtr<GEvent> event; |         OwnPtr<GEvent> event; | ||||||
|     }; |     }; | ||||||
|     Vector<QueuedEvent> m_queuedEvents; |     Vector<QueuedEvent> m_queued_events; | ||||||
| 
 | 
 | ||||||
|  |     int m_event_fd { -1 }; | ||||||
|     bool m_running { false }; |     bool m_running { false }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -71,6 +71,6 @@ void GObject::stopTimer() | ||||||
| 
 | 
 | ||||||
| void GObject::deleteLater() | void GObject::deleteLater() | ||||||
| { | { | ||||||
|     GEventLoop::main().postEvent(this, make<GEvent>(GEvent::DeferredDestroy)); |     GEventLoop::main().post_event(this, make<GEvent>(GEvent::DeferredDestroy)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,8 +37,6 @@ void GWidget::event(GEvent& event) | ||||||
|     case GEvent::Paint: |     case GEvent::Paint: | ||||||
|         m_hasPendingPaintEvent = false; |         m_hasPendingPaintEvent = false; | ||||||
|         if (auto* win = window()) { |         if (auto* win = window()) { | ||||||
|             if (win->is_being_dragged()) |  | ||||||
|                 return; |  | ||||||
|             if (!win->is_visible()) |             if (!win->is_visible()) | ||||||
|                 return; |                 return; | ||||||
|         } |         } | ||||||
|  | @ -112,7 +110,7 @@ void GWidget::update() | ||||||
|     if (m_hasPendingPaintEvent) |     if (m_hasPendingPaintEvent) | ||||||
|         return; |         return; | ||||||
|     m_hasPendingPaintEvent = true; |     m_hasPendingPaintEvent = true; | ||||||
|     GEventLoop::main().postEvent(w, make<GPaintEvent>(relativeRect())); |     GEventLoop::main().post_event(w, make<GPaintEvent>(relativeRect())); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GWidget::HitTestResult GWidget::hitTest(int x, int y) | GWidget::HitTestResult GWidget::hitTest(int x, int y) | ||||||
|  |  | ||||||
|  | @ -2,10 +2,51 @@ | ||||||
| #include "GEvent.h" | #include "GEvent.h" | ||||||
| #include "GEventLoop.h" | #include "GEventLoop.h" | ||||||
| #include <SharedGraphics/GraphicsBitmap.h> | #include <SharedGraphics/GraphicsBitmap.h> | ||||||
|  | #include <LibC/gui.h> | ||||||
|  | #include <LibC/stdio.h> | ||||||
|  | #include <LibC/stdlib.h> | ||||||
|  | #include <AK/HashMap.h> | ||||||
| 
 | 
 | ||||||
| GWindow::GWindow(int window_id) | static HashMap<int, GWindow*>* s_windows; | ||||||
|     : m_window_id(window_id) | 
 | ||||||
|  | static HashMap<int, GWindow*>& windows() | ||||||
| { | { | ||||||
|  |     if (!s_windows) | ||||||
|  |         s_windows = new HashMap<int, GWindow*>; | ||||||
|  |     return *s_windows; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GWindow* GWindow::from_window_id(int window_id) | ||||||
|  | { | ||||||
|  |     auto it = windows().find(window_id); | ||||||
|  |     if (it != windows().end()) | ||||||
|  |         return (*it).value; | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GWindow::GWindow(GObject* parent) | ||||||
|  |     : GObject(parent) | ||||||
|  | { | ||||||
|  |     GUI_CreateWindowParameters wparams; | ||||||
|  |     wparams.rect = { { 100, 400 }, { 140, 140 } }; | ||||||
|  |     wparams.background_color = 0xffc0c0; | ||||||
|  |     strcpy(wparams.title, "GWindow"); | ||||||
|  |     m_window_id = gui_create_window(&wparams); | ||||||
|  |     if (m_window_id < 0) { | ||||||
|  |         perror("gui_create_window"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     GUI_WindowBackingStoreInfo backing; | ||||||
|  |     int rc = gui_get_window_backing_store(m_window_id, &backing); | ||||||
|  |     if (rc < 0) { | ||||||
|  |         perror("gui_get_window_backing_store"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     m_backing = GraphicsBitmap::create_wrapper(backing.size, backing.pixels); | ||||||
|  | 
 | ||||||
|  |     windows().set(m_window_id, this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GWindow::~GWindow() | GWindow::~GWindow() | ||||||
|  | @ -40,3 +81,19 @@ void GWindow::close() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void GWindow::show() | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GWindow::update() | ||||||
|  | { | ||||||
|  |     gui_invalidate_window(m_window_id, nullptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GWindow::set_main_widget(GWidget* widget) | ||||||
|  | { | ||||||
|  |     if (m_main_widget == widget) | ||||||
|  |         return; | ||||||
|  |     m_main_widget = widget; | ||||||
|  |     update(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -5,11 +5,15 @@ | ||||||
| #include <SharedGraphics/GraphicsBitmap.h> | #include <SharedGraphics/GraphicsBitmap.h> | ||||||
| #include <AK/AKString.h> | #include <AK/AKString.h> | ||||||
| 
 | 
 | ||||||
|  | class GWidget; | ||||||
|  | 
 | ||||||
| class GWindow final : public GObject { | class GWindow final : public GObject { | ||||||
| public: | public: | ||||||
|     explicit GWindow(int window_id); |     GWindow(GObject* parent = nullptr); | ||||||
|     virtual ~GWindow() override; |     virtual ~GWindow() override; | ||||||
| 
 | 
 | ||||||
|  |     static GWindow* from_window_id(int); | ||||||
|  | 
 | ||||||
|     int window_id() const { return m_window_id; } |     int window_id() const { return m_window_id; } | ||||||
| 
 | 
 | ||||||
|     String title() const { return m_title; } |     String title() const { return m_title; } | ||||||
|  | @ -29,21 +33,24 @@ public: | ||||||
| 
 | 
 | ||||||
|     virtual void event(GEvent&) override; |     virtual void event(GEvent&) override; | ||||||
| 
 | 
 | ||||||
|     bool is_being_dragged() const { return m_is_being_dragged; } |  | ||||||
|     void set_is_being_dragged(bool b) { m_is_being_dragged = b; } |  | ||||||
| 
 |  | ||||||
|     bool is_visible() const; |     bool is_visible() const; | ||||||
| 
 | 
 | ||||||
|     void close(); |     void close(); | ||||||
| 
 | 
 | ||||||
|  |     void set_main_widget(GWidget*); | ||||||
|  | 
 | ||||||
|     GraphicsBitmap* backing() { return m_backing.ptr(); } |     GraphicsBitmap* backing() { return m_backing.ptr(); } | ||||||
| 
 | 
 | ||||||
|  |     void show(); | ||||||
|  | 
 | ||||||
|  |     void update(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     String m_title; |     String m_title; | ||||||
|     Rect m_rect; |     Rect m_rect; | ||||||
|     bool m_is_being_dragged { false }; |  | ||||||
| 
 | 
 | ||||||
|     RetainPtr<GraphicsBitmap> m_backing; |     RetainPtr<GraphicsBitmap> m_backing; | ||||||
|     int m_window_id { -1 }; |     int m_window_id { -1 }; | ||||||
|  |     GWidget* m_main_widget { nullptr }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								Userland/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								Userland/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -22,4 +22,5 @@ touch | ||||||
| sync | sync | ||||||
| more | more | ||||||
| guitest | guitest | ||||||
|  | guitest2 | ||||||
| sysctl | sysctl | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ OBJS = \ | ||||||
|        touch.o \
 |        touch.o \
 | ||||||
|        more.o \
 |        more.o \
 | ||||||
|        guitest.o \
 |        guitest.o \
 | ||||||
|  |        guitest2.o \
 | ||||||
|        sysctl.o |        sysctl.o | ||||||
| 
 | 
 | ||||||
| APPS = \
 | APPS = \
 | ||||||
|  | @ -45,6 +46,7 @@ APPS = \ | ||||||
|        sync \
 |        sync \
 | ||||||
|        more \
 |        more \
 | ||||||
|        guitest \
 |        guitest \
 | ||||||
|  |        guitest2 \
 | ||||||
|        sysctl |        sysctl | ||||||
| 
 | 
 | ||||||
| ARCH_FLAGS = | ARCH_FLAGS = | ||||||
|  | @ -131,6 +133,9 @@ more: more.o | ||||||
| guitest: guitest.o | guitest: guitest.o | ||||||
| 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | ||||||
| 
 | 
 | ||||||
|  | guitest2: guitest2.o | ||||||
|  | 	$(LD) -o $@ $(LDFLAGS) $< ../LibGUI/LibGUI.a ../LibC/LibC.a | ||||||
|  | 
 | ||||||
| sysctl: sysctl.o | sysctl: sysctl.o | ||||||
| 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										54
									
								
								Userland/guitest2.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Userland/guitest2.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <assert.h> | ||||||
|  | #include <Kernel/Syscall.h> | ||||||
|  | #include <SharedGraphics/GraphicsBitmap.h> | ||||||
|  | #include <SharedGraphics/Painter.h> | ||||||
|  | #include <LibGUI/GWindow.h> | ||||||
|  | #include <LibGUI/GWidget.h> | ||||||
|  | #include <LibGUI/GLabel.h> | ||||||
|  | #include <LibGUI/GEventLoop.h> | ||||||
|  | 
 | ||||||
|  | static GWindow* make_font_test_window(); | ||||||
|  | 
 | ||||||
|  | int main(int argc, char** argv) | ||||||
|  | { | ||||||
|  |     auto* window = make_font_test_window(); | ||||||
|  |     window->show(); | ||||||
|  | 
 | ||||||
|  |     GEventLoop loop; | ||||||
|  |     return loop.exec(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GWindow* make_font_test_window() | ||||||
|  | { | ||||||
|  |     auto* window = new GWindow; | ||||||
|  |     window->set_title("Font test"); | ||||||
|  |     window->set_rect({ 140, 100, 300, 80 }); | ||||||
|  | 
 | ||||||
|  |     auto* widget = new GWidget; | ||||||
|  |     window->set_main_widget(widget); | ||||||
|  |     widget->setWindowRelativeRect({ 0, 0, 300, 80 }); | ||||||
|  | 
 | ||||||
|  |     auto* l1 = new GLabel(widget); | ||||||
|  |     l1->setWindowRelativeRect({ 0, 0, 300, 20 }); | ||||||
|  |     l1->setText("0123456789"); | ||||||
|  | 
 | ||||||
|  |     auto* l2 = new GLabel(widget); | ||||||
|  |     l2->setWindowRelativeRect({ 0, 20, 300, 20 }); | ||||||
|  |     l2->setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); | ||||||
|  | 
 | ||||||
|  |     auto* l3 = new GLabel(widget); | ||||||
|  |     l3->setWindowRelativeRect({ 0, 40, 300, 20 }); | ||||||
|  |     l3->setText("abcdefghijklmnopqrstuvwxyz"); | ||||||
|  | 
 | ||||||
|  |     auto* l4 = new GLabel(widget); | ||||||
|  |     l4->setWindowRelativeRect({ 0, 60, 300, 20 }); | ||||||
|  |     l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~"); | ||||||
|  | 
 | ||||||
|  |     return window; | ||||||
|  | } | ||||||
|  | @ -80,9 +80,9 @@ private: | ||||||
| 
 | 
 | ||||||
| enum class MouseButton : byte { | enum class MouseButton : byte { | ||||||
|     None = 0, |     None = 0, | ||||||
|     Left, |     Left = 1, | ||||||
|     Middle, |     Right = 2, | ||||||
|     Right, |     Middle = 4, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum KeyboardKey { | enum KeyboardKey { | ||||||
|  | @ -121,9 +121,10 @@ private: | ||||||
| 
 | 
 | ||||||
| class MouseEvent final : public WSEvent { | class MouseEvent final : public WSEvent { | ||||||
| public: | public: | ||||||
|     MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None) |     MouseEvent(Type type, const Point& position, unsigned buttons, MouseButton button = MouseButton::None) | ||||||
|         : WSEvent(type) |         : WSEvent(type) | ||||||
|         , m_position(x, y) |         , m_position(position) | ||||||
|  |         , m_buttons(buttons) | ||||||
|         , m_button(button) |         , m_button(button) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | @ -132,8 +133,10 @@ public: | ||||||
|     int x() const { return m_position.x(); } |     int x() const { return m_position.x(); } | ||||||
|     int y() const { return m_position.y(); } |     int y() const { return m_position.y(); } | ||||||
|     MouseButton button() const { return m_button; } |     MouseButton button() const { return m_button; } | ||||||
|  |     unsigned buttons() const { return m_buttons; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Point m_position; |     Point m_position; | ||||||
|  |     unsigned m_buttons { 0 }; | ||||||
|     MouseButton m_button { MouseButton::None }; |     MouseButton m_button { MouseButton::None }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -41,8 +41,13 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ | ||||||
|         m_cursor_location.set_x(width() - 1); |         m_cursor_location.set_x(width() - 1); | ||||||
|     if (m_cursor_location.y() >= height()) |     if (m_cursor_location.y() >= height()) | ||||||
|         m_cursor_location.set_y(height() - 1); |         m_cursor_location.set_y(height() - 1); | ||||||
|  |     unsigned buttons = 0; | ||||||
|  |     if (left_button) | ||||||
|  |         buttons |= (unsigned)MouseButton::Left; | ||||||
|  |     if (right_button) | ||||||
|  |         buttons |= (unsigned)MouseButton::Right; | ||||||
|     if (m_cursor_location != prev_location) { |     if (m_cursor_location != prev_location) { | ||||||
|         auto event = make<MouseEvent>(WSEvent::MouseMove, m_cursor_location.x(), m_cursor_location.y()); |         auto event = make<MouseEvent>(WSEvent::MouseMove, m_cursor_location, buttons); | ||||||
|         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event)); |         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event)); | ||||||
|     } |     } | ||||||
|     bool prev_left_button = m_left_mouse_button_pressed; |     bool prev_left_button = m_left_mouse_button_pressed; | ||||||
|  | @ -50,11 +55,11 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ | ||||||
|     m_left_mouse_button_pressed = left_button; |     m_left_mouse_button_pressed = left_button; | ||||||
|     m_right_mouse_button_pressed = right_button; |     m_right_mouse_button_pressed = right_button; | ||||||
|     if (prev_left_button != left_button) { |     if (prev_left_button != left_button) { | ||||||
|         auto event = make<MouseEvent>(left_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Left); |         auto event = make<MouseEvent>(left_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location, buttons, MouseButton::Left); | ||||||
|         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event)); |         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event)); | ||||||
|     } |     } | ||||||
|     if (prev_right_button != right_button) { |     if (prev_right_button != right_button) { | ||||||
|         auto event = make<MouseEvent>(right_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Right); |         auto event = make<MouseEvent>(right_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location, buttons, MouseButton::Right); | ||||||
|         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event)); |         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event)); | ||||||
|     } |     } | ||||||
|     if (m_cursor_location != prev_location || prev_left_button != left_button) |     if (m_cursor_location != prev_location || prev_left_button != left_button) | ||||||
|  |  | ||||||
|  | @ -59,6 +59,7 @@ void WSWindow::event(WSEvent& event) | ||||||
|     case WSEvent::MouseMove: |     case WSEvent::MouseMove: | ||||||
|         gui_event.type = GUI_Event::Type::MouseMove; |         gui_event.type = GUI_Event::Type::MouseMove; | ||||||
|         gui_event.mouse.position = static_cast<MouseEvent&>(event).position(); |         gui_event.mouse.position = static_cast<MouseEvent&>(event).position(); | ||||||
|  |         gui_event.mouse.button = GUI_MouseButton::NoButton; | ||||||
|         break; |         break; | ||||||
|     case WSEvent::MouseDown: |     case WSEvent::MouseDown: | ||||||
|         gui_event.type = GUI_Event::Type::MouseDown; |         gui_event.type = GUI_Event::Type::MouseDown; | ||||||
|  |  | ||||||
|  | @ -285,9 +285,10 @@ void WSWindowManager::process_mouse_event(MouseEvent& event) | ||||||
|                 move_to_front(*window); |                 move_to_front(*window); | ||||||
|                 set_active_window(window); |                 set_active_window(window); | ||||||
|             } |             } | ||||||
|             // FIXME: Re-use the existing event instead of crafting a new one?
 |             // FIXME: Should we just alter the coordinates of the existing MouseEvent and pass it through?
 | ||||||
|             auto localEvent = make<MouseEvent>(event.type(), event.x() - window->rect().x(), event.y() - window->rect().y(), event.button()); |             Point position { event.x() - window->rect().x(), event.y() - window->rect().y() }; | ||||||
|             window->event(*localEvent); |             auto local_event = make<MouseEvent>(event.type(), position, event.buttons(), event.button()); | ||||||
|  |             window->event(*local_event); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling