mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 04:12:43 +00:00 
			
		
		
		
	LibGUI+WindowServer: Add a GResizeCorner widget.
This widget is automatically included in GStatusBar, but can be added in any other place, too. When clicked (with the left button), it initiates a window resize (using a WM request.) In this patch I also fixed up some issues with override cursors being cleared after the WindowServer finishes a drag or resize.
This commit is contained in:
		
							parent
							
								
									34c5db61aa
								
							
						
					
					
						commit
						ea9a39a9f2
					
				
					 19 changed files with 189 additions and 26 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								Base/res/icons/resize-corner.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Base/res/icons/resize-corner.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 127 B | 
|  | @ -24,6 +24,7 @@ | ||||||
| //#define COALESCING_DEBUG
 | //#define COALESCING_DEBUG
 | ||||||
| 
 | 
 | ||||||
| int GEventLoop::s_event_fd = -1; | int GEventLoop::s_event_fd = -1; | ||||||
|  | int GEventLoop::s_my_client_id = -1; | ||||||
| pid_t GEventLoop::s_server_pid = -1; | pid_t GEventLoop::s_server_pid = -1; | ||||||
| 
 | 
 | ||||||
| void GEventLoop::connect_to_server() | void GEventLoop::connect_to_server() | ||||||
|  | @ -59,8 +60,7 @@ void GEventLoop::connect_to_server() | ||||||
|     request.type = WSAPI_ClientMessage::Type::Greeting; |     request.type = WSAPI_ClientMessage::Type::Greeting; | ||||||
|     request.greeting.client_pid = getpid(); |     request.greeting.client_pid = getpid(); | ||||||
|     auto response = sync_request(request, WSAPI_ServerMessage::Type::Greeting); |     auto response = sync_request(request, WSAPI_ServerMessage::Type::Greeting); | ||||||
|     s_server_pid = response.greeting.server_pid; |     handle_greeting(response); | ||||||
|     GDesktop::the().did_receive_screen_rect(Badge<GEventLoop>(), response.greeting.screen_rect); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GEventLoop::GEventLoop() | GEventLoop::GEventLoop() | ||||||
|  | @ -235,8 +235,7 @@ void GEventLoop::process_unprocessed_bundles() | ||||||
|     for (auto& bundle : unprocessed_bundles) { |     for (auto& bundle : unprocessed_bundles) { | ||||||
|         auto& event = bundle.message; |         auto& event = bundle.message; | ||||||
|         if (event.type == WSAPI_ServerMessage::Type::Greeting) { |         if (event.type == WSAPI_ServerMessage::Type::Greeting) { | ||||||
|             s_server_pid = event.greeting.server_pid; |             handle_greeting(event); | ||||||
|             GDesktop::the().did_receive_screen_rect(Badge<GEventLoop>(), event.greeting.screen_rect); |  | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -402,3 +401,10 @@ WSAPI_ServerMessage GEventLoop::sync_request(const WSAPI_ClientMessage& request, | ||||||
|     ASSERT(success); |     ASSERT(success); | ||||||
|     return response; |     return response; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void GEventLoop::handle_greeting(WSAPI_ServerMessage& message) | ||||||
|  | { | ||||||
|  |     s_server_pid = message.greeting.server_pid; | ||||||
|  |     s_my_client_id = message.greeting.your_client_id; | ||||||
|  |     GDesktop::the().did_receive_screen_rect(Badge<GEventLoop>(), message.greeting.screen_rect); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ public: | ||||||
|     WSAPI_ServerMessage sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type); |     WSAPI_ServerMessage sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type); | ||||||
| 
 | 
 | ||||||
|     static pid_t server_pid() { return s_server_pid; } |     static pid_t server_pid() { return s_server_pid; } | ||||||
|  |     static int my_client_id() { return s_my_client_id; } | ||||||
| 
 | 
 | ||||||
|     virtual void take_pending_events_from(CEventLoop& other) override |     virtual void take_pending_events_from(CEventLoop& other) override | ||||||
|     { |     { | ||||||
|  | @ -59,6 +60,7 @@ private: | ||||||
|     void handle_menu_event(const WSAPI_ServerMessage&); |     void handle_menu_event(const WSAPI_ServerMessage&); | ||||||
|     void handle_window_entered_or_left_event(const WSAPI_ServerMessage&, GWindow&); |     void handle_window_entered_or_left_event(const WSAPI_ServerMessage&, GWindow&); | ||||||
|     void handle_wm_event(const WSAPI_ServerMessage&, GWindow&); |     void handle_wm_event(const WSAPI_ServerMessage&, GWindow&); | ||||||
|  |     void handle_greeting(WSAPI_ServerMessage&); | ||||||
|     void connect_to_server(); |     void connect_to_server(); | ||||||
| 
 | 
 | ||||||
|     struct IncomingWSMessageBundle { |     struct IncomingWSMessageBundle { | ||||||
|  | @ -68,5 +70,6 @@ private: | ||||||
| 
 | 
 | ||||||
|     Vector<IncomingWSMessageBundle, 64> m_unprocessed_bundles; |     Vector<IncomingWSMessageBundle, 64> m_unprocessed_bundles; | ||||||
|     static pid_t s_server_pid; |     static pid_t s_server_pid; | ||||||
|     static pid_t s_event_fd; |     static int s_my_client_id; | ||||||
|  |     static int s_event_fd; | ||||||
| }; | }; | ||||||
|  |  | ||||||
							
								
								
									
										46
									
								
								LibGUI/GResizeCorner.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								LibGUI/GResizeCorner.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | ||||||
|  | #include <LibGUI/GResizeCorner.h> | ||||||
|  | #include <LibGUI/GPainter.h> | ||||||
|  | #include <LibGUI/GWindow.h> | ||||||
|  | #include <SharedGraphics/GraphicsBitmap.h> | ||||||
|  | #include <WindowServer/WSAPITypes.h> | ||||||
|  | 
 | ||||||
|  | GResizeCorner::GResizeCorner(GWidget* parent) | ||||||
|  |     : GWidget(parent) | ||||||
|  | { | ||||||
|  |     set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); | ||||||
|  |     set_preferred_size({ 16, 16 }); | ||||||
|  |     m_bitmap = GraphicsBitmap::load_from_file("/res/icons/resize-corner.png"); | ||||||
|  |     ASSERT(m_bitmap); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GResizeCorner::~GResizeCorner() | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GResizeCorner::paint_event(GPaintEvent& event) | ||||||
|  | { | ||||||
|  |     GPainter painter(*this); | ||||||
|  |     painter.add_clip_rect(event.rect()); | ||||||
|  |     painter.fill_rect(rect(), background_color()); | ||||||
|  |     painter.blit({ 0, 0 }, *m_bitmap, m_bitmap->rect()); | ||||||
|  |     GWidget::paint_event(event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GResizeCorner::mousedown_event(GMouseEvent& event) | ||||||
|  | { | ||||||
|  |     if (event.button() == GMouseButton::Left) | ||||||
|  |         window()->start_wm_resize(); | ||||||
|  |     GWidget::mousedown_event(event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GResizeCorner::enter_event(CEvent& event) | ||||||
|  | { | ||||||
|  |     window()->set_override_cursor(GStandardCursor::ResizeDiagonalTLBR); | ||||||
|  |     GWidget::enter_event(event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GResizeCorner::leave_event(CEvent& event) | ||||||
|  | { | ||||||
|  |     window()->set_override_cursor(GStandardCursor::None); | ||||||
|  |     GWidget::leave_event(event); | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								LibGUI/GResizeCorner.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								LibGUI/GResizeCorner.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | #include <LibGUI/GWidget.h> | ||||||
|  | 
 | ||||||
|  | class GResizeCorner : public GWidget { | ||||||
|  | public: | ||||||
|  |     explicit GResizeCorner(GWidget* parent); | ||||||
|  |     virtual ~GResizeCorner() override; | ||||||
|  | 
 | ||||||
|  |     virtual const char* class_name() const override { return "GResizeCorner"; } | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     virtual void paint_event(GPaintEvent&) override; | ||||||
|  |     virtual void mousedown_event(GMouseEvent&) override; | ||||||
|  |     virtual void enter_event(CEvent&) override; | ||||||
|  |     virtual void leave_event(CEvent&) override; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     RetainPtr<GraphicsBitmap> m_bitmap; | ||||||
|  | }; | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| #include <LibGUI/GBoxLayout.h> | #include <LibGUI/GBoxLayout.h> | ||||||
| #include <SharedGraphics/StylePainter.h> | #include <SharedGraphics/StylePainter.h> | ||||||
| #include <LibGUI/GPainter.h> | #include <LibGUI/GPainter.h> | ||||||
|  | #include <LibGUI/GResizeCorner.h> | ||||||
| 
 | 
 | ||||||
| GStatusBar::GStatusBar(GWidget* parent) | GStatusBar::GStatusBar(GWidget* parent) | ||||||
|     : GWidget(parent) |     : GWidget(parent) | ||||||
|  | @ -17,6 +18,8 @@ GStatusBar::GStatusBar(GWidget* parent) | ||||||
|     m_label->set_frame_shape(FrameShape::Panel); |     m_label->set_frame_shape(FrameShape::Panel); | ||||||
|     m_label->set_frame_thickness(1); |     m_label->set_frame_thickness(1); | ||||||
|     m_label->set_text_alignment(TextAlignment::CenterLeft); |     m_label->set_text_alignment(TextAlignment::CenterLeft); | ||||||
|  | 
 | ||||||
|  |     m_corner = new GResizeCorner(this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GStatusBar::~GStatusBar() | GStatusBar::~GStatusBar() | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| #include <LibGUI/GWidget.h> | #include <LibGUI/GWidget.h> | ||||||
| 
 | 
 | ||||||
| class GLabel; | class GLabel; | ||||||
|  | class GResizeCorner; | ||||||
| 
 | 
 | ||||||
| class GStatusBar : public GWidget { | class GStatusBar : public GWidget { | ||||||
| public: | public: | ||||||
|  | @ -18,4 +19,5 @@ private: | ||||||
|     virtual void paint_event(GPaintEvent&) override; |     virtual void paint_event(GPaintEvent&) override; | ||||||
| 
 | 
 | ||||||
|     GLabel* m_label { nullptr }; |     GLabel* m_label { nullptr }; | ||||||
|  |     GResizeCorner* m_corner { nullptr }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -490,3 +490,12 @@ void GWindow::set_icon_path(const String& path) | ||||||
|     message.text_length = path.length(); |     message.text_length = path.length(); | ||||||
|     GEventLoop::post_message_to_server(message); |     GEventLoop::post_message_to_server(message); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void GWindow::start_wm_resize() | ||||||
|  | { | ||||||
|  |     WSAPI_ClientMessage message; | ||||||
|  |     message.type = WSAPI_ClientMessage::Type::WM_StartWindowResize; | ||||||
|  |     message.wm.client_id = GEventLoop::my_client_id(); | ||||||
|  |     message.wm.window_id = m_window_id; | ||||||
|  |     GEventLoop::post_message_to_server(message); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -16,6 +16,8 @@ enum class GStandardCursor { | ||||||
|     IBeam, |     IBeam, | ||||||
|     ResizeHorizontal, |     ResizeHorizontal, | ||||||
|     ResizeVertical, |     ResizeVertical, | ||||||
|  |     ResizeDiagonalTLBR, | ||||||
|  |     ResizeDiagonalBLTR, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class GWindow : public CObject { | class GWindow : public CObject { | ||||||
|  | @ -71,6 +73,8 @@ public: | ||||||
|     void hide(); |     void hide(); | ||||||
|     void close(); |     void close(); | ||||||
| 
 | 
 | ||||||
|  |     void start_wm_resize(); | ||||||
|  | 
 | ||||||
|     GWidget* main_widget() { return m_main_widget; } |     GWidget* main_widget() { return m_main_widget; } | ||||||
|     const GWidget* main_widget() const { return m_main_widget; } |     const GWidget* main_widget() const { return m_main_widget; } | ||||||
|     void set_main_widget(GWidget*); |     void set_main_widget(GWidget*); | ||||||
|  |  | ||||||
|  | @ -53,6 +53,7 @@ LIBGUI_OBJS = \ | ||||||
|     GSpinBox.o \
 |     GSpinBox.o \
 | ||||||
|     GGroupBox.o \
 |     GGroupBox.o \
 | ||||||
|     GSlider.o \
 |     GSlider.o \
 | ||||||
|  |     GResizeCorner.o \
 | ||||||
|     GWindow.o |     GWindow.o | ||||||
| 
 | 
 | ||||||
| OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS) | OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS) | ||||||
|  |  | ||||||
|  | @ -55,6 +55,8 @@ enum class WSAPI_StandardCursor : unsigned char { | ||||||
|     IBeam, |     IBeam, | ||||||
|     ResizeHorizontal, |     ResizeHorizontal, | ||||||
|     ResizeVertical, |     ResizeVertical, | ||||||
|  |     ResizeDiagonalTLBR, | ||||||
|  |     ResizeDiagonalBLTR, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum WSAPI_WMEventMask : unsigned { | enum WSAPI_WMEventMask : unsigned { | ||||||
|  | @ -126,6 +128,7 @@ struct WSAPI_ServerMessage { | ||||||
|     union { |     union { | ||||||
|         struct { |         struct { | ||||||
|             int server_pid; |             int server_pid; | ||||||
|  |             int your_client_id; | ||||||
|             WSAPI_Rect screen_rect; |             WSAPI_Rect screen_rect; | ||||||
|         } greeting; |         } greeting; | ||||||
|         struct { |         struct { | ||||||
|  | @ -211,6 +214,7 @@ struct WSAPI_ClientMessage { | ||||||
|         SetWindowOverrideCursor, |         SetWindowOverrideCursor, | ||||||
|         WM_SetActiveWindow, |         WM_SetActiveWindow, | ||||||
|         WM_SetWindowMinimized, |         WM_SetWindowMinimized, | ||||||
|  |         WM_StartWindowResize, | ||||||
|         PopupMenu, |         PopupMenu, | ||||||
|         DismissMenu, |         DismissMenu, | ||||||
|         SetWindowIcon, |         SetWindowIcon, | ||||||
|  |  | ||||||
|  | @ -48,6 +48,7 @@ WSClientConnection::WSClientConnection(int fd) | ||||||
|     WSAPI_ServerMessage message; |     WSAPI_ServerMessage message; | ||||||
|     message.type = WSAPI_ServerMessage::Type::Greeting; |     message.type = WSAPI_ServerMessage::Type::Greeting; | ||||||
|     message.greeting.server_pid = getpid(); |     message.greeting.server_pid = getpid(); | ||||||
|  |     message.greeting.your_client_id = m_client_id; | ||||||
|     message.greeting.screen_rect = WSScreen::the().rect(); |     message.greeting.screen_rect = WSScreen::the().rect(); | ||||||
|     post_message(message); |     post_message(message); | ||||||
| } | } | ||||||
|  | @ -645,6 +646,24 @@ void WSClientConnection::handle_request(const WSWMAPISetActiveWindowRequest& req | ||||||
|     WSWindowManager::the().move_to_front_and_make_active(window); |     WSWindowManager::the().move_to_front_and_make_active(window); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void WSClientConnection::handle_request(const WSWMAPIStartWindowResizeRequest& request) | ||||||
|  | { | ||||||
|  |     auto* client = WSClientConnection::from_client_id(request.target_client_id()); | ||||||
|  |     if (!client) { | ||||||
|  |         post_error("WSWMAPIStartWindowResizeRequest: Bad client ID"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     auto it = client->m_windows.find(request.target_window_id()); | ||||||
|  |     if (it == client->m_windows.end()) { | ||||||
|  |         post_error("WSWMAPIStartWindowResizeRequest: Bad window ID"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     auto& window = *(*it).value; | ||||||
|  |     // FIXME: We are cheating a bit here by using the current cursor location and hard-coding the left button.
 | ||||||
|  |     //        Maybe the client should be allowed to specify what initiated this request?
 | ||||||
|  |     WSWindowManager::the().start_window_resize(window, WSScreen::the().cursor_location(), MouseButton::Left); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void WSClientConnection::handle_request(const WSWMAPISetWindowMinimizedRequest& request) | void WSClientConnection::handle_request(const WSWMAPISetWindowMinimizedRequest& request) | ||||||
| { | { | ||||||
|     auto* client = WSClientConnection::from_client_id(request.target_client_id()); |     auto* client = WSClientConnection::from_client_id(request.target_client_id()); | ||||||
|  | @ -722,6 +741,8 @@ void WSClientConnection::on_request(const WSAPIClientRequest& request) | ||||||
|         return handle_request(static_cast<const WSWMAPISetActiveWindowRequest&>(request)); |         return handle_request(static_cast<const WSWMAPISetActiveWindowRequest&>(request)); | ||||||
|     case WSEvent::WMAPISetWindowMinimizedRequest: |     case WSEvent::WMAPISetWindowMinimizedRequest: | ||||||
|         return handle_request(static_cast<const WSWMAPISetWindowMinimizedRequest&>(request)); |         return handle_request(static_cast<const WSWMAPISetWindowMinimizedRequest&>(request)); | ||||||
|  |     case WSEvent::WMAPIStartWindowResizeRequest: | ||||||
|  |         return handle_request(static_cast<const WSWMAPIStartWindowResizeRequest&>(request)); | ||||||
|     case WSEvent::APIPopupMenuRequest: |     case WSEvent::APIPopupMenuRequest: | ||||||
|         return handle_request(static_cast<const WSAPIPopupMenuRequest&>(request)); |         return handle_request(static_cast<const WSAPIPopupMenuRequest&>(request)); | ||||||
|     case WSEvent::APIDismissMenuRequest: |     case WSEvent::APIDismissMenuRequest: | ||||||
|  |  | ||||||
|  | @ -74,6 +74,7 @@ private: | ||||||
|     void handle_request(const WSAPISetWindowOverrideCursorRequest&); |     void handle_request(const WSAPISetWindowOverrideCursorRequest&); | ||||||
|     void handle_request(const WSWMAPISetActiveWindowRequest&); |     void handle_request(const WSWMAPISetActiveWindowRequest&); | ||||||
|     void handle_request(const WSWMAPISetWindowMinimizedRequest&); |     void handle_request(const WSWMAPISetWindowMinimizedRequest&); | ||||||
|  |     void handle_request(const WSWMAPIStartWindowResizeRequest&); | ||||||
|     void handle_request(const WSAPIPopupMenuRequest&); |     void handle_request(const WSAPIPopupMenuRequest&); | ||||||
|     void handle_request(const WSAPIDismissMenuRequest&); |     void handle_request(const WSAPIDismissMenuRequest&); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -34,6 +34,10 @@ RetainPtr<WSCursor> WSCursor::create(WSStandardCursor standard_cursor) | ||||||
|         return WSWindowManager::the().resize_horizontally_cursor(); |         return WSWindowManager::the().resize_horizontally_cursor(); | ||||||
|     case WSStandardCursor::ResizeVertical: |     case WSStandardCursor::ResizeVertical: | ||||||
|         return WSWindowManager::the().resize_vertically_cursor(); |         return WSWindowManager::the().resize_vertically_cursor(); | ||||||
|  |     case WSStandardCursor::ResizeDiagonalTLBR: | ||||||
|  |         return WSWindowManager::the().resize_diagonally_tlbr_cursor(); | ||||||
|  |     case WSStandardCursor::ResizeDiagonalBLTR: | ||||||
|  |         return WSWindowManager::the().resize_diagonally_bltr_cursor(); | ||||||
|     } |     } | ||||||
|     ASSERT_NOT_REACHED(); |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ enum class WSStandardCursor { | ||||||
|     IBeam, |     IBeam, | ||||||
|     ResizeHorizontal, |     ResizeHorizontal, | ||||||
|     ResizeVertical, |     ResizeVertical, | ||||||
|  |     ResizeDiagonalTLBR, | ||||||
|  |     ResizeDiagonalBLTR, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class WSCursor : public Retainable<WSCursor> { | class WSCursor : public Retainable<WSCursor> { | ||||||
|  |  | ||||||
|  | @ -62,6 +62,7 @@ public: | ||||||
|         APISetWindowOverrideCursorRequest, |         APISetWindowOverrideCursorRequest, | ||||||
|         WMAPISetActiveWindowRequest, |         WMAPISetActiveWindowRequest, | ||||||
|         WMAPISetWindowMinimizedRequest, |         WMAPISetWindowMinimizedRequest, | ||||||
|  |         WMAPIStartWindowResizeRequest, | ||||||
|         APIPopupMenuRequest, |         APIPopupMenuRequest, | ||||||
|         APIDismissMenuRequest, |         APIDismissMenuRequest, | ||||||
|         __End_API_Client_Requests, |         __End_API_Client_Requests, | ||||||
|  | @ -104,6 +105,23 @@ private: | ||||||
|     int m_client_id { 0 }; |     int m_client_id { 0 }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | class WSWMAPIStartWindowResizeRequest : public WSAPIClientRequest { | ||||||
|  | public: | ||||||
|  |     WSWMAPIStartWindowResizeRequest(int client_id, int target_client_id, int target_window_id) | ||||||
|  |         : WSAPIClientRequest(WSEvent::WMAPIStartWindowResizeRequest, client_id) | ||||||
|  |         , m_target_client_id(target_client_id) | ||||||
|  |         , m_target_window_id(target_window_id) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int target_client_id() const { return m_target_client_id; } | ||||||
|  |     int target_window_id() const { return m_target_window_id; } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     int m_target_client_id; | ||||||
|  |     int m_target_window_id; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class WSWMAPISetActiveWindowRequest : public WSAPIClientRequest { | class WSWMAPISetActiveWindowRequest : public WSAPIClientRequest { | ||||||
| public: | public: | ||||||
|     WSWMAPISetActiveWindowRequest(int client_id, int target_client_id, int target_window_id) |     WSWMAPISetActiveWindowRequest(int client_id, int target_client_id, int target_window_id) | ||||||
|  |  | ||||||
|  | @ -250,6 +250,9 @@ bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag | ||||||
|     case WSAPI_ClientMessage::Type::WM_SetWindowMinimized: |     case WSAPI_ClientMessage::Type::WM_SetWindowMinimized: | ||||||
|         post_event(client, make<WSWMAPISetWindowMinimizedRequest>(client_id, message.wm.client_id, message.wm.window_id, message.wm.minimized)); |         post_event(client, make<WSWMAPISetWindowMinimizedRequest>(client_id, message.wm.client_id, message.wm.window_id, message.wm.minimized)); | ||||||
|         break; |         break; | ||||||
|  |     case WSAPI_ClientMessage::Type::WM_StartWindowResize: | ||||||
|  |         post_event(client, make<WSWMAPIStartWindowResizeRequest>(client_id, message.wm.client_id, message.wm.window_id)); | ||||||
|  |         break; | ||||||
|     default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -490,7 +490,7 @@ void WSWindowManager::start_window_drag(WSWindow& window, const WSMouseEvent& ev | ||||||
|     invalidate(window); |     invalidate(window); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::start_window_resize(WSWindow& window, const WSMouseEvent& event) | void WSWindowManager::start_window_resize(WSWindow& window, const Point& position, MouseButton button) | ||||||
| { | { | ||||||
|     move_to_front_and_make_active(window); |     move_to_front_and_make_active(window); | ||||||
|     constexpr ResizeDirection direction_for_hot_area[3][3] = { |     constexpr ResizeDirection direction_for_hot_area[3][3] = { | ||||||
|  | @ -499,9 +499,9 @@ void WSWindowManager::start_window_resize(WSWindow& window, const WSMouseEvent& | ||||||
|         { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight }, |         { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight }, | ||||||
|     }; |     }; | ||||||
|     Rect outer_rect = window.frame().rect(); |     Rect outer_rect = window.frame().rect(); | ||||||
|     ASSERT(outer_rect.contains(event.position())); |     ASSERT(outer_rect.contains(position)); | ||||||
|     int window_relative_x = event.x() - outer_rect.x(); |     int window_relative_x = position.x() - outer_rect.x(); | ||||||
|     int window_relative_y = event.y() - outer_rect.y(); |     int window_relative_y = position.y() - outer_rect.y(); | ||||||
|     int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3)); |     int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3)); | ||||||
|     int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3)); |     int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3)); | ||||||
|     m_resize_direction = direction_for_hot_area[hot_area_row][hot_area_column]; |     m_resize_direction = direction_for_hot_area[hot_area_row][hot_area_column]; | ||||||
|  | @ -513,15 +513,20 @@ void WSWindowManager::start_window_resize(WSWindow& window, const WSMouseEvent& | ||||||
| #ifdef RESIZE_DEBUG | #ifdef RESIZE_DEBUG | ||||||
|     printf("[WM] Begin resizing WSWindow{%p}\n", &window); |     printf("[WM] Begin resizing WSWindow{%p}\n", &window); | ||||||
| #endif | #endif | ||||||
|     m_resizing_mouse_button = event.button(); |     m_resizing_mouse_button = button; | ||||||
|     m_resize_window = window.make_weak_ptr();; |     m_resize_window = window.make_weak_ptr();; | ||||||
|     m_resize_origin = event.position(); |     m_resize_origin = position; | ||||||
|     m_resize_window_original_rect = window.rect(); |     m_resize_window_original_rect = window.rect(); | ||||||
| 
 | 
 | ||||||
|     invalidate(window); |     invalidate(window); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool WSWindowManager::process_ongoing_window_drag(const WSMouseEvent& event, WSWindow*&) | void WSWindowManager::start_window_resize(WSWindow& window, const WSMouseEvent& event) | ||||||
|  | { | ||||||
|  |     start_window_resize(window, event.position(), event.button()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool WSWindowManager::process_ongoing_window_drag(const WSMouseEvent& event, WSWindow*& hovered_window) | ||||||
| { | { | ||||||
|     if (!m_drag_window) |     if (!m_drag_window) | ||||||
|         return false; |         return false; | ||||||
|  | @ -530,6 +535,8 @@ bool WSWindowManager::process_ongoing_window_drag(const WSMouseEvent& event, WSW | ||||||
|         printf("[WM] Finish dragging WSWindow{%p}\n", m_drag_window.ptr()); |         printf("[WM] Finish dragging WSWindow{%p}\n", m_drag_window.ptr()); | ||||||
| #endif | #endif | ||||||
|         invalidate(*m_drag_window); |         invalidate(*m_drag_window); | ||||||
|  |         if (m_drag_window->rect().contains(event.position())) | ||||||
|  |             hovered_window = m_drag_window; | ||||||
|         m_drag_window = nullptr; |         m_drag_window = nullptr; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  | @ -539,12 +546,14 @@ bool WSWindowManager::process_ongoing_window_drag(const WSMouseEvent& event, WSW | ||||||
| #endif | #endif | ||||||
|         Point pos = m_drag_window_origin.translated(event.position() - m_drag_origin); |         Point pos = m_drag_window_origin.translated(event.position() - m_drag_origin); | ||||||
|         m_drag_window->set_position_without_repaint(pos); |         m_drag_window->set_position_without_repaint(pos); | ||||||
|  |         if (m_drag_window->rect().contains(event.position())) | ||||||
|  |             hovered_window = m_drag_window; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool WSWindowManager::process_ongoing_window_resize(const WSMouseEvent& event, WSWindow*&) | bool WSWindowManager::process_ongoing_window_resize(const WSMouseEvent& event, WSWindow*& hovered_window) | ||||||
| { | { | ||||||
|     if (!m_resize_window) |     if (!m_resize_window) | ||||||
|         return false; |         return false; | ||||||
|  | @ -555,6 +564,8 @@ bool WSWindowManager::process_ongoing_window_resize(const WSMouseEvent& event, W | ||||||
| #endif | #endif | ||||||
|         WSEventLoop::the().post_event(*m_resize_window, make<WSResizeEvent>(m_resize_window->rect(), m_resize_window->rect())); |         WSEventLoop::the().post_event(*m_resize_window, make<WSResizeEvent>(m_resize_window->rect(), m_resize_window->rect())); | ||||||
|         invalidate(*m_resize_window); |         invalidate(*m_resize_window); | ||||||
|  |         if (m_resize_window->rect().contains(event.position())) | ||||||
|  |             hovered_window = m_resize_window; | ||||||
|         m_resize_window = nullptr; |         m_resize_window = nullptr; | ||||||
|         m_resizing_mouse_button = MouseButton::None; |         m_resizing_mouse_button = MouseButton::None; | ||||||
|         return true; |         return true; | ||||||
|  | @ -627,6 +638,9 @@ bool WSWindowManager::process_ongoing_window_resize(const WSMouseEvent& event, W | ||||||
|         new_rect.set_height(m_resize_window->base_size().height() + vertical_incs * m_resize_window->size_increment().height()); |         new_rect.set_height(m_resize_window->base_size().height() + vertical_incs * m_resize_window->size_increment().height()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (new_rect.contains(event.position())) | ||||||
|  |         hovered_window = m_resize_window; | ||||||
|  | 
 | ||||||
|     if (m_resize_window->rect() == new_rect) |     if (m_resize_window->rect() == new_rect) | ||||||
|         return true; |         return true; | ||||||
| #ifdef RESIZE_DEBUG | #ifdef RESIZE_DEBUG | ||||||
|  | @ -644,14 +658,14 @@ void WSWindowManager::set_cursor_tracking_button(WSButton* button) | ||||||
|     m_cursor_tracking_button = button ? button->make_weak_ptr() : nullptr; |     m_cursor_tracking_button = button ? button->make_weak_ptr() : nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& event_window) | void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& hovered_window) | ||||||
| { | { | ||||||
|     event_window = nullptr; |     hovered_window = nullptr; | ||||||
| 
 | 
 | ||||||
|     if (process_ongoing_window_drag(event, event_window)) |     if (process_ongoing_window_drag(event, hovered_window)) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     if (process_ongoing_window_resize(event, event_window)) |     if (process_ongoing_window_resize(event, hovered_window)) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     if (m_cursor_tracking_button) |     if (m_cursor_tracking_button) | ||||||
|  | @ -687,7 +701,7 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& | ||||||
|             if (event.type() == WSEvent::MouseDown || event.type() == WSEvent::MouseUp) |             if (event.type() == WSEvent::MouseDown || event.type() == WSEvent::MouseUp) | ||||||
|                 close_current_menu(); |                 close_current_menu(); | ||||||
|         } else { |         } else { | ||||||
|             event_window = &window; |             hovered_window = &window; | ||||||
|             auto translated_event = event.translated(-window.position()); |             auto translated_event = event.translated(-window.position()); | ||||||
|             window.event(translated_event); |             window.event(translated_event); | ||||||
|         } |         } | ||||||
|  | @ -708,10 +722,12 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& | ||||||
|         // In those cases, the event is swallowed by the window manager.
 |         // In those cases, the event is swallowed by the window manager.
 | ||||||
|         if (window.type() == WSWindowType::Normal) { |         if (window.type() == WSWindowType::Normal) { | ||||||
|             if (m_keyboard_modifiers == Mod_Logo && event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left) { |             if (m_keyboard_modifiers == Mod_Logo && event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left) { | ||||||
|  |                 hovered_window = &window; | ||||||
|                 start_window_drag(window, event); |                 start_window_drag(window, event); | ||||||
|                 return IterationDecision::Abort; |                 return IterationDecision::Abort; | ||||||
|             } |             } | ||||||
|             if (window.is_resizable() && m_keyboard_modifiers == Mod_Logo && event.type() == WSEvent::MouseDown && event.button() == MouseButton::Right && !window.is_blocked_by_modal_window()) { |             if (window.is_resizable() && m_keyboard_modifiers == Mod_Logo && event.type() == WSEvent::MouseDown && event.button() == MouseButton::Right && !window.is_blocked_by_modal_window()) { | ||||||
|  |                 hovered_window = &window; | ||||||
|                 start_window_resize(window, event); |                 start_window_resize(window, event); | ||||||
|                 return IterationDecision::Abort; |                 return IterationDecision::Abort; | ||||||
|             } |             } | ||||||
|  | @ -720,7 +736,7 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& | ||||||
|         if (window.rect().contains(event.position())) { |         if (window.rect().contains(event.position())) { | ||||||
|             if (window.type() == WSWindowType::Normal && event.type() == WSEvent::MouseDown) |             if (window.type() == WSWindowType::Normal && event.type() == WSEvent::MouseDown) | ||||||
|                 move_to_front_and_make_active(window); |                 move_to_front_and_make_active(window); | ||||||
|             event_window = &window; |             hovered_window = &window; | ||||||
|             if (!window.global_cursor_tracking() && !windows_who_received_mouse_event_due_to_cursor_tracking.contains(&window)) { |             if (!window.global_cursor_tracking() && !windows_who_received_mouse_event_due_to_cursor_tracking.contains(&window)) { | ||||||
|                 auto translated_event = event.translated(-window.position()); |                 auto translated_event = event.translated(-window.position()); | ||||||
|                 window.event(translated_event); |                 window.event(translated_event); | ||||||
|  | @ -987,9 +1003,9 @@ void WSWindowManager::draw_cursor() | ||||||
| void WSWindowManager::event(CEvent& event) | void WSWindowManager::event(CEvent& event) | ||||||
| { | { | ||||||
|     if (static_cast<WSEvent&>(event).is_mouse_event()) { |     if (static_cast<WSEvent&>(event).is_mouse_event()) { | ||||||
|         WSWindow* event_window = nullptr; |         WSWindow* hovered_window = nullptr; | ||||||
|         process_mouse_event(static_cast<const WSMouseEvent&>(event), event_window); |         process_mouse_event(static_cast<const WSMouseEvent&>(event), hovered_window); | ||||||
|         set_hovered_window(event_window); |         set_hovered_window(hovered_window); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -116,14 +116,16 @@ public: | ||||||
|     void tell_wm_listeners_window_icon_changed(WSWindow&); |     void tell_wm_listeners_window_icon_changed(WSWindow&); | ||||||
|     void tell_wm_listeners_window_rect_changed(WSWindow&); |     void tell_wm_listeners_window_rect_changed(WSWindow&); | ||||||
| 
 | 
 | ||||||
|  |     void start_window_resize(WSWindow&, const Point&, MouseButton); | ||||||
|  |     void start_window_resize(WSWindow&, const WSMouseEvent&); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     void process_mouse_event(const WSMouseEvent&, WSWindow*& event_window); |     void process_mouse_event(const WSMouseEvent&, WSWindow*& hovered_window); | ||||||
|     bool process_ongoing_window_resize(const WSMouseEvent&, WSWindow*& event_window); |     bool process_ongoing_window_resize(const WSMouseEvent&, WSWindow*& hovered_window); | ||||||
|     bool process_ongoing_window_drag(const WSMouseEvent&, WSWindow*& event_window); |     bool process_ongoing_window_drag(const WSMouseEvent&, WSWindow*& hovered_window); | ||||||
|     void handle_menu_mouse_event(WSMenu&, const WSMouseEvent&); |     void handle_menu_mouse_event(WSMenu&, const WSMouseEvent&); | ||||||
|     void handle_menubar_mouse_event(const WSMouseEvent&); |     void handle_menubar_mouse_event(const WSMouseEvent&); | ||||||
|     void handle_close_button_mouse_event(WSWindow&, const WSMouseEvent&); |     void handle_close_button_mouse_event(WSWindow&, const WSMouseEvent&); | ||||||
|     void start_window_resize(WSWindow&, const WSMouseEvent&); |  | ||||||
|     void start_window_drag(WSWindow&, const WSMouseEvent&); |     void start_window_drag(WSWindow&, const WSMouseEvent&); | ||||||
|     void handle_client_request(const WSAPIClientRequest&); |     void handle_client_request(const WSAPIClientRequest&); | ||||||
|     void set_hovered_window(WSWindow*); |     void set_hovered_window(WSWindow*); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling