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);
 | 
						{
 | 
				
			||||||
	if (event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window && can_start_move)
 | 
							const bool can_start_move = m_is_mod_key_held || target_window->title_text_area().contains(m_cursor);
 | 
				
			||||||
		m_is_moving_window = target_window->get_attributes().movable;
 | 
							if (can_start_move && !m_is_moving_window && event.pressed)
 | 
				
			||||||
	else if (m_is_moving_window && !event.pressed)
 | 
							{
 | 
				
			||||||
		m_is_moving_window = false;
 | 
								m_is_moving_window = target_window->get_attributes().movable;
 | 
				
			||||||
	else if (!event.pressed && event.button == LibInput::MouseButton::Left && target_window->close_button_area().contains(m_cursor))
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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