forked from Bananymous/banan-os
				
			WindowServer: Implement window resizing
windows can now set resizable attribute which allows window server to resize them
This commit is contained in:
		
							parent
							
								
									fcfadd7c74
								
							
						
					
					
						commit
						7798145c74
					
				|  | @ -186,6 +186,7 @@ namespace LibGUI | ||||||
| 			bool focusable; | 			bool focusable; | ||||||
| 			bool rounded_corners; | 			bool rounded_corners; | ||||||
| 			bool alpha_channel; | 			bool alpha_channel; | ||||||
|  | 			bool resizable; | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		DEFINE_PACKET( | 		DEFINE_PACKET( | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ namespace LibGUI | ||||||
| 			.focusable       = true, | 			.focusable       = true, | ||||||
| 			.rounded_corners = true, | 			.rounded_corners = true, | ||||||
| 			.alpha_channel   = false, | 			.alpha_channel   = false, | ||||||
|  | 			.resizable       = false, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
|  |  | ||||||
|  | @ -123,19 +123,11 @@ void WindowServer::on_window_invalidate(int fd, const LibGUI::WindowPacket::Wind | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	const int32_t br_x = packet.x + packet.width - 1; |  | ||||||
| 	const int32_t br_y = packet.y + packet.height - 1; |  | ||||||
| 	if (!target_window->client_size().contains({ br_x, br_y })) |  | ||||||
| 	{ |  | ||||||
| 		dwarnln("invalid Invalidate packet parameters"); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	invalidate({ | 	invalidate({ | ||||||
| 		target_window->client_x() + static_cast<int32_t>(packet.x), | 		target_window->client_x() + static_cast<int32_t>(packet.x), | ||||||
| 		target_window->client_y() + static_cast<int32_t>(packet.y), | 		target_window->client_y() + static_cast<int32_t>(packet.y), | ||||||
| 		static_cast<int32_t>(packet.width), | 		BAN::Math::min<int32_t>(packet.width,  target_window->client_width()), | ||||||
| 		static_cast<int32_t>(packet.height), | 		BAN::Math::min<int32_t>(packet.height, target_window->client_height()) | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -388,6 +380,11 @@ void WindowServer::on_key_event(LibInput::KeyEvent event) | ||||||
| 		if (!m_focused_window) | 		if (!m_focused_window) | ||||||
| 			return; | 			return; | ||||||
| 		m_is_fullscreen_window = !m_is_fullscreen_window; | 		m_is_fullscreen_window = !m_is_fullscreen_window; | ||||||
|  | 		if (m_is_fullscreen_window) | ||||||
|  | 		{ | ||||||
|  | 			m_is_moving_window = false; | ||||||
|  | 			m_is_resizing_window = false; | ||||||
|  | 		} | ||||||
| 		invalidate(m_framebuffer.area()); | 		invalidate(m_framebuffer.area()); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  | @ -431,6 +428,40 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (m_is_moving_window && event.button == LibInput::MouseButton::Left && !event.pressed) | ||||||
|  | 	{ | ||||||
|  | 		m_is_moving_window = false; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (m_is_resizing_window && event.button == LibInput::MouseButton::Right && !event.pressed) | ||||||
|  | 	{ | ||||||
|  | 		const auto resize_area = this->resize_area(m_cursor); | ||||||
|  | 		m_is_resizing_window = false; | ||||||
|  | 		invalidate(resize_area.get_bounding_box(m_focused_window->full_area())); | ||||||
|  | 
 | ||||||
|  | 		const auto old_area = m_focused_window->full_area(); | ||||||
|  | 		if (auto ret = m_focused_window->resize(resize_area.width, resize_area.height - m_focused_window->title_bar_height()); ret.is_error()) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln("could not resize client window {}", ret.error()); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		LibGUI::EventPacket::ResizeWindowEvent event; | ||||||
|  | 		event.width = m_focused_window->client_width(); | ||||||
|  | 		event.height = m_focused_window->client_height(); | ||||||
|  | 		event.smo_key = m_focused_window->smo_key(); | ||||||
|  | 		if (auto ret = event.send_serialized(m_focused_window->client_fd()); ret.is_error()) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln("could not respond to window resize request: {}", ret.error()); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		invalidate(m_focused_window->full_area().get_bounding_box(old_area)); | ||||||
|  | 
 | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// Ignore mouse button events which are not on top of a window
 | 	// Ignore mouse button events which are not on top of a window
 | ||||||
| 	if (!target_window) | 	if (!target_window) | ||||||
| 		return; | 		return; | ||||||
|  | @ -438,13 +469,29 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event) | ||||||
| 	if (target_window->get_attributes().focusable) | 	if (target_window->get_attributes().focusable) | ||||||
| 		set_focused_window(target_window); | 		set_focused_window(target_window); | ||||||
| 
 | 
 | ||||||
| 	// Handle window moving when mod key is held or mouse press on title bar
 | 	if (!m_is_fullscreen_window && event.button == LibInput::MouseButton::Left) | ||||||
|  | 	{ | ||||||
| 		const bool can_start_move = m_is_mod_key_held || target_window->title_text_area().contains(m_cursor); | 		const bool can_start_move = m_is_mod_key_held || target_window->title_text_area().contains(m_cursor); | ||||||
| 	if (event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window && can_start_move) | 		if (can_start_move && !m_is_moving_window && event.pressed) | ||||||
|  | 		{ | ||||||
| 			m_is_moving_window = target_window->get_attributes().movable; | 			m_is_moving_window = target_window->get_attributes().movable; | ||||||
| 	else if (m_is_moving_window && !event.pressed) | 			return; | ||||||
| 		m_is_moving_window = false; | 		} | ||||||
| 	else if (!event.pressed && event.button == LibInput::MouseButton::Left && target_window->close_button_area().contains(m_cursor)) | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!m_is_fullscreen_window && event.button == LibInput::MouseButton::Right) | ||||||
|  | 	{ | ||||||
|  | 		const bool can_start_resize = m_is_mod_key_held; | ||||||
|  | 		if (can_start_resize && !m_is_resizing_window && event.pressed) | ||||||
|  | 		{ | ||||||
|  | 			m_is_resizing_window = target_window->get_attributes().resizable; | ||||||
|  | 			if (m_is_resizing_window) | ||||||
|  | 				m_resize_start = m_cursor; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!event.pressed && event.button == LibInput::MouseButton::Left && target_window->close_button_area().contains(m_cursor)) | ||||||
| 	{ | 	{ | ||||||
| 		// NOTE: we always have target window if code reaches here
 | 		// NOTE: we always have target window if code reaches here
 | ||||||
| 		LibGUI::EventPacket::CloseWindowEvent packet; | 		LibGUI::EventPacket::CloseWindowEvent packet; | ||||||
|  | @ -468,9 +515,6 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event) | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	if (m_is_fullscreen_window) |  | ||||||
| 		m_is_moving_window = false; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event) | void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event) | ||||||
|  | @ -537,6 +581,16 @@ void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event) | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (m_is_resizing_window) | ||||||
|  | 	{ | ||||||
|  | 		const auto max_cursor = Position { | ||||||
|  | 			.x = BAN::Math::max(old_cursor.x, new_cursor.x), | ||||||
|  | 			.y = BAN::Math::max(old_cursor.y, new_cursor.y), | ||||||
|  | 		}; | ||||||
|  | 		invalidate(resize_area(max_cursor).get_bounding_box(m_focused_window->full_area())); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (m_focused_window) | 	if (m_focused_window) | ||||||
| 	{ | 	{ | ||||||
| 		LibGUI::EventPacket::MouseMoveEvent packet; | 		LibGUI::EventPacket::MouseMoveEvent packet; | ||||||
|  | @ -916,10 +970,24 @@ void WindowServer::invalidate(Rectangle area) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (m_is_resizing_window) | ||||||
|  | 	{ | ||||||
|  | 		if (const auto overlap = resize_area(m_cursor).get_overlap(area); overlap.has_value()) | ||||||
|  | 		{ | ||||||
|  | 			for (int32_t y_off = 0; y_off < overlap->height; y_off++) | ||||||
|  | 			{ | ||||||
|  | 				for (int32_t x_off = 0; x_off < overlap->width; x_off++) | ||||||
|  | 				{ | ||||||
|  | 					auto& pixel = m_framebuffer.mmap[(overlap->y + y_off) * m_framebuffer.width + (overlap->x + x_off)]; | ||||||
|  | 					pixel = alpha_blend(0x80000000, pixel); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (!m_is_mouse_captured) | 	if (!m_is_mouse_captured) | ||||||
| 	{ | 	{ | ||||||
| 		const auto cursor = cursor_area(); | 		if (const auto overlap = cursor_area().get_overlap(area); overlap.has_value()) | ||||||
| 		if (auto overlap = cursor.get_overlap(area); overlap.has_value()) |  | ||||||
| 		{ | 		{ | ||||||
| 			for (int32_t y_off = 0; y_off < overlap->height; y_off++) | 			for (int32_t y_off = 0; y_off < overlap->height; y_off++) | ||||||
| 			{ | 			{ | ||||||
|  | @ -1071,6 +1139,16 @@ Rectangle WindowServer::cursor_area() const | ||||||
| 	return { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height }; | 	return { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Rectangle WindowServer::resize_area(Position cursor) const | ||||||
|  | { | ||||||
|  | 	ASSERT(m_is_resizing_window); | ||||||
|  | 	return { | ||||||
|  | 		.x = m_focused_window->full_x(), | ||||||
|  | 		.y = m_focused_window->full_y(), | ||||||
|  | 		.width  = BAN::Math::max<int32_t>(20, m_focused_window->full_width()  + cursor.x - m_resize_start.x), | ||||||
|  | 		.height = BAN::Math::max<int32_t>(20, m_focused_window->full_height() + cursor.y - m_resize_start.y), | ||||||
|  | 	}; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void WindowServer::add_client_fd(int fd) | void WindowServer::add_client_fd(int fd) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -50,6 +50,7 @@ public: | ||||||
| 	void sync(); | 	void sync(); | ||||||
| 
 | 
 | ||||||
| 	Rectangle cursor_area() const; | 	Rectangle cursor_area() const; | ||||||
|  | 	Rectangle resize_area(Position cursor) const; | ||||||
| 
 | 
 | ||||||
| 	void add_client_fd(int fd); | 	void add_client_fd(int fd); | ||||||
| 	void remove_client_fd(int fd); | 	void remove_client_fd(int fd); | ||||||
|  | @ -87,6 +88,9 @@ private: | ||||||
| 	BAN::RefPtr<Window> m_focused_window; | 	BAN::RefPtr<Window> m_focused_window; | ||||||
| 	Position m_cursor; | 	Position m_cursor; | ||||||
| 
 | 
 | ||||||
|  | 	bool m_is_resizing_window { false }; | ||||||
|  | 	Position m_resize_start; | ||||||
|  | 
 | ||||||
| 	bool m_is_mouse_captured { false }; | 	bool m_is_mouse_captured { false }; | ||||||
| 
 | 
 | ||||||
| 	bool m_deleted_window { false }; | 	bool m_deleted_window { false }; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue