LibGUI: Add support for focusable windows and mouse capturing
These are essential parts of a window server! This allows making TaskBar non-focusable.
This commit is contained in:
parent
12bc7480e0
commit
da8170c5b6
|
@ -267,6 +267,20 @@ namespace LibGUI
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Window::set_mouse_capture(bool captured)
|
||||||
|
{
|
||||||
|
WindowPacket::WindowSetMouseCapture packet;
|
||||||
|
packet.captured = captured;
|
||||||
|
|
||||||
|
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||||
|
{
|
||||||
|
dprintln("failed to set mouse capture: {}", ret.error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Window::set_position(int32_t x, int32_t y)
|
bool Window::set_position(int32_t x, int32_t y)
|
||||||
{
|
{
|
||||||
WindowPacket::WindowSetPosition packet;
|
WindowPacket::WindowSetPosition packet;
|
||||||
|
@ -285,10 +299,7 @@ namespace LibGUI
|
||||||
bool Window::set_attributes(Attributes attributes)
|
bool Window::set_attributes(Attributes attributes)
|
||||||
{
|
{
|
||||||
WindowPacket::WindowSetAttributes packet;
|
WindowPacket::WindowSetAttributes packet;
|
||||||
packet.title_bar = attributes.title_bar;
|
packet.attributes = attributes;
|
||||||
packet.movable = attributes.movable;
|
|
||||||
packet.rounded_corners = attributes.rounded_corners;
|
|
||||||
packet.alpha_channel = attributes.alpha_channel;
|
|
||||||
|
|
||||||
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||||
{
|
{
|
||||||
|
|
|
@ -162,6 +162,7 @@ namespace LibGUI
|
||||||
WindowInvalidate,
|
WindowInvalidate,
|
||||||
WindowSetPosition,
|
WindowSetPosition,
|
||||||
WindowSetAttributes,
|
WindowSetAttributes,
|
||||||
|
WindowSetMouseCapture,
|
||||||
|
|
||||||
DestroyWindowEvent,
|
DestroyWindowEvent,
|
||||||
CloseWindowEvent,
|
CloseWindowEvent,
|
||||||
|
@ -174,35 +175,49 @@ namespace LibGUI
|
||||||
namespace WindowPacket
|
namespace WindowPacket
|
||||||
{
|
{
|
||||||
|
|
||||||
DEFINE_PACKET(WindowCreate,
|
DEFINE_PACKET(
|
||||||
|
WindowCreate,
|
||||||
uint32_t, width,
|
uint32_t, width,
|
||||||
uint32_t, height,
|
uint32_t, height,
|
||||||
BAN::String, title
|
BAN::String, title
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_PACKET(WindowCreateResponse,
|
DEFINE_PACKET(
|
||||||
|
WindowCreateResponse,
|
||||||
uint32_t, width,
|
uint32_t, width,
|
||||||
uint32_t, height,
|
uint32_t, height,
|
||||||
long, smo_key
|
long, smo_key
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_PACKET(WindowInvalidate,
|
DEFINE_PACKET(
|
||||||
|
WindowInvalidate,
|
||||||
uint32_t, x,
|
uint32_t, x,
|
||||||
uint32_t, y,
|
uint32_t, y,
|
||||||
uint32_t, width,
|
uint32_t, width,
|
||||||
uint32_t, height
|
uint32_t, height
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_PACKET(WindowSetPosition,
|
DEFINE_PACKET(
|
||||||
|
WindowSetPosition,
|
||||||
int32_t, x,
|
int32_t, x,
|
||||||
int32_t, y
|
int32_t, y
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_PACKET(WindowSetAttributes,
|
DEFINE_PACKET_EXTRA(
|
||||||
bool, title_bar,
|
WindowSetAttributes,
|
||||||
bool, rounded_corners,
|
struct Attributes {
|
||||||
bool, movable,
|
bool title_bar;
|
||||||
bool, alpha_channel
|
bool movable;
|
||||||
|
bool focusable;
|
||||||
|
bool rounded_corners;
|
||||||
|
bool alpha_channel;
|
||||||
|
},
|
||||||
|
Attributes, attributes
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_PACKET(
|
||||||
|
WindowSetMouseCapture,
|
||||||
|
bool, captured
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,14 @@ namespace LibGUI
|
||||||
class Window
|
class Window
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Attributes
|
using Attributes = WindowPacket::WindowSetAttributes::Attributes;
|
||||||
{
|
|
||||||
bool title_bar { true };
|
static constexpr Attributes default_attributes = {
|
||||||
bool movable { true };
|
.title_bar = true,
|
||||||
bool rounded_corners { true };
|
.movable = true,
|
||||||
bool alpha_channel { false };
|
.focusable = true,
|
||||||
|
.rounded_corners = true,
|
||||||
|
.alpha_channel = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -58,6 +60,8 @@ namespace LibGUI
|
||||||
bool invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
bool invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||||
bool invalidate() { return invalidate(0, 0, width(), height()); }
|
bool invalidate() { return invalidate(0, 0, width(), height()); }
|
||||||
|
|
||||||
|
bool set_mouse_capture(bool captured);
|
||||||
|
|
||||||
bool set_position(int32_t x, int32_t y);
|
bool set_position(int32_t x, int32_t y);
|
||||||
|
|
||||||
Attributes get_attributes() const { return m_attributes; }
|
Attributes get_attributes() const { return m_attributes; }
|
||||||
|
|
|
@ -13,12 +13,14 @@ int main()
|
||||||
|
|
||||||
auto window = MUST(LibGUI::Window::create(0, font.height() + 2 * padding, "TaskBar"));
|
auto window = MUST(LibGUI::Window::create(0, font.height() + 2 * padding, "TaskBar"));
|
||||||
|
|
||||||
auto attributes = window->get_attributes();
|
auto attributes = LibGUI::Window::default_attributes;
|
||||||
attributes.title_bar = false;
|
attributes.title_bar = false;
|
||||||
attributes.movable = false;
|
attributes.movable = false;
|
||||||
|
attributes.focusable = false;
|
||||||
attributes.alpha_channel = false;
|
attributes.alpha_channel = false;
|
||||||
attributes.rounded_corners = false;
|
attributes.rounded_corners = false;
|
||||||
window->set_attributes(attributes);
|
window->set_attributes(attributes);
|
||||||
|
|
||||||
window->set_close_window_event_callback([]() {});
|
window->set_close_window_event_callback([]() {});
|
||||||
|
|
||||||
window->set_position(0, 0);
|
window->set_position(0, 0);
|
||||||
|
|
|
@ -112,7 +112,7 @@ void Terminal::run()
|
||||||
|
|
||||||
m_window = MUST(LibGUI::Window::create(600, 400, "Terminal"_sv));
|
m_window = MUST(LibGUI::Window::create(600, 400, "Terminal"_sv));
|
||||||
|
|
||||||
auto attributes = m_window->get_attributes();
|
auto attributes = LibGUI::Window::default_attributes;
|
||||||
attributes.alpha_channel = true;
|
attributes.alpha_channel = true;
|
||||||
m_window->set_attributes(attributes);
|
m_window->set_attributes(attributes);
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ private:
|
||||||
uint32_t* m_title_bar_data { nullptr };
|
uint32_t* m_title_bar_data { nullptr };
|
||||||
BAN::String m_title;
|
BAN::String m_title;
|
||||||
|
|
||||||
LibGUI::Window::Attributes m_attributes;
|
LibGUI::Window::Attributes m_attributes { LibGUI::Window::default_attributes };
|
||||||
|
|
||||||
friend class BAN::RefPtr<Window>;
|
friend class BAN::RefPtr<Window>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -181,14 +181,55 @@ void WindowServer::on_window_set_attributes(int fd, const LibGUI::WindowPacket::
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto old_client_area = target_window->full_area();
|
const auto old_client_area = target_window->full_area();
|
||||||
target_window->set_attributes({
|
target_window->set_attributes(packet.attributes);
|
||||||
.title_bar = packet.title_bar,
|
|
||||||
.movable = packet.movable,
|
|
||||||
.rounded_corners = packet.rounded_corners,
|
|
||||||
.alpha_channel = packet.alpha_channel,
|
|
||||||
});
|
|
||||||
const auto new_client_area = target_window->full_area();
|
const auto new_client_area = target_window->full_area();
|
||||||
invalidate(new_client_area.get_bounding_box(old_client_area));
|
invalidate(new_client_area.get_bounding_box(old_client_area));
|
||||||
|
|
||||||
|
if (!packet.attributes.focusable && m_focused_window == target_window)
|
||||||
|
{
|
||||||
|
m_focused_window = nullptr;
|
||||||
|
for (size_t i = m_client_windows.size(); i > 0; i--)
|
||||||
|
{
|
||||||
|
if (auto& window = m_client_windows[i - 1]; window->get_attributes().focusable)
|
||||||
|
{
|
||||||
|
set_focused_window(window);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowServer::on_window_set_mouse_capture(int fd, const LibGUI::WindowPacket::WindowSetMouseCapture& packet)
|
||||||
|
{
|
||||||
|
if (m_is_mouse_captured && packet.captured)
|
||||||
|
{
|
||||||
|
ASSERT(m_focused_window);
|
||||||
|
if (fd != m_focused_window->client_fd())
|
||||||
|
dwarnln("client tried to set mouse capture while other window has it already captured");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<Window> target_window;
|
||||||
|
for (auto& window : m_client_windows)
|
||||||
|
{
|
||||||
|
if (window->client_fd() != fd)
|
||||||
|
continue;
|
||||||
|
target_window = window;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target_window)
|
||||||
|
{
|
||||||
|
dwarnln("client tried to set mouse capture while not owning a window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet.captured == m_is_mouse_captured)
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_focused_window(target_window);
|
||||||
|
m_is_mouse_captured = packet.captured;
|
||||||
|
invalidate(cursor_area());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||||
|
@ -247,6 +288,20 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||||
|
|
||||||
void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
||||||
{
|
{
|
||||||
|
if (m_is_mouse_captured)
|
||||||
|
{
|
||||||
|
ASSERT(m_focused_window);
|
||||||
|
|
||||||
|
LibGUI::EventPacket::MouseButtonEvent packet;
|
||||||
|
packet.event.button = event.button;
|
||||||
|
packet.event.pressed = event.pressed;
|
||||||
|
packet.event.x = 0;
|
||||||
|
packet.event.y = 0;
|
||||||
|
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
||||||
|
dwarnln("could not send mouse button event: {}", ret.error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::RefPtr<Window> target_window;
|
BAN::RefPtr<Window> target_window;
|
||||||
for (size_t i = m_client_windows.size(); i > 0; i--)
|
for (size_t i = m_client_windows.size(); i > 0; i--)
|
||||||
{
|
{
|
||||||
|
@ -261,6 +316,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
||||||
if (!target_window)
|
if (!target_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
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
|
// Handle window moving when mod key is held or mouse press on title bar
|
||||||
|
@ -289,7 +345,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
||||||
packet.event.y = m_cursor.y - m_focused_window->client_y();
|
packet.event.y = m_cursor.y - m_focused_window->client_y();
|
||||||
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
||||||
{
|
{
|
||||||
dwarnln("could not send mouse button event event: {}", ret.error());
|
dwarnln("could not send mouse button event: {}", ret.error());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,6 +353,18 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
||||||
|
|
||||||
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
|
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
|
||||||
{
|
{
|
||||||
|
if (m_is_mouse_captured)
|
||||||
|
{
|
||||||
|
ASSERT(m_focused_window);
|
||||||
|
|
||||||
|
LibGUI::EventPacket::MouseMoveEvent packet;
|
||||||
|
packet.event.x = event.rel_x;
|
||||||
|
packet.event.y = -event.rel_y;
|
||||||
|
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
||||||
|
dwarnln("could not send mouse move event: {}", ret.error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const int32_t new_x = BAN::Math::clamp(m_cursor.x + event.rel_x, 0, m_framebuffer.width);
|
const int32_t new_x = BAN::Math::clamp(m_cursor.x + event.rel_x, 0, m_framebuffer.width);
|
||||||
const int32_t new_y = BAN::Math::clamp(m_cursor.y - event.rel_y, 0, m_framebuffer.height);
|
const int32_t new_y = BAN::Math::clamp(m_cursor.y - event.rel_y, 0, m_framebuffer.height);
|
||||||
|
|
||||||
|
@ -341,7 +409,7 @@ void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
|
||||||
packet.event.y = m_cursor.y - m_focused_window->client_y();
|
packet.event.y = m_cursor.y - m_focused_window->client_y();
|
||||||
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
||||||
{
|
{
|
||||||
dwarnln("could not send mouse move event event: {}", ret.error());
|
dwarnln("could not send mouse move event: {}", ret.error());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +423,7 @@ void WindowServer::on_mouse_scroll(LibInput::MouseScrollEvent event)
|
||||||
packet.event.scroll = event.scroll;
|
packet.event.scroll = event.scroll;
|
||||||
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
|
||||||
{
|
{
|
||||||
dwarnln("could not send mouse scroll event event: {}", ret.error());
|
dwarnln("could not send mouse scroll event: {}", ret.error());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,6 +434,12 @@ void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
|
||||||
if (m_focused_window == window)
|
if (m_focused_window == window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (m_is_mouse_captured)
|
||||||
|
{
|
||||||
|
m_is_mouse_captured = false;
|
||||||
|
invalidate(cursor_area());
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = m_client_windows.size(); i > 0; i--)
|
for (size_t i = m_client_windows.size(); i > 0; i--)
|
||||||
{
|
{
|
||||||
if (m_client_windows[i - 1] == window)
|
if (m_client_windows[i - 1] == window)
|
||||||
|
@ -589,6 +663,8 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_is_mouse_captured)
|
||||||
|
{
|
||||||
auto cursor = cursor_area();
|
auto cursor = cursor_area();
|
||||||
if (auto overlap = cursor.get_overlap(area); overlap.has_value())
|
if (auto overlap = cursor.get_overlap(area); overlap.has_value())
|
||||||
{
|
{
|
||||||
|
@ -608,6 +684,7 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
||||||
const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
||||||
|
@ -618,6 +695,8 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
size_t index = (mmap_addr - reinterpret_cast<uintptr_t>(m_framebuffer.mmap)) / 4096;
|
size_t index = (mmap_addr - reinterpret_cast<uintptr_t>(m_framebuffer.mmap)) / 4096;
|
||||||
size_t byte = index / 8;
|
size_t byte = index / 8;
|
||||||
size_t bit = index % 8;
|
size_t bit = index % 8;
|
||||||
|
//dprintln("{}/{}", byte, m_pages_to_sync_bitmap.size());
|
||||||
|
if (byte < m_pages_to_sync_bitmap.size())
|
||||||
m_pages_to_sync_bitmap[byte] |= 1 << bit;
|
m_pages_to_sync_bitmap[byte] |= 1 << bit;
|
||||||
mmap_addr += 4096;
|
mmap_addr += 4096;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
void on_window_invalidate(int fd, const LibGUI::WindowPacket::WindowInvalidate&);
|
void on_window_invalidate(int fd, const LibGUI::WindowPacket::WindowInvalidate&);
|
||||||
void on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition&);
|
void on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition&);
|
||||||
void on_window_set_attributes(int fd, const LibGUI::WindowPacket::WindowSetAttributes&);
|
void on_window_set_attributes(int fd, const LibGUI::WindowPacket::WindowSetAttributes&);
|
||||||
|
void on_window_set_mouse_capture(int fd, const LibGUI::WindowPacket::WindowSetMouseCapture&);
|
||||||
|
|
||||||
void on_key_event(LibInput::KeyEvent event);
|
void on_key_event(LibInput::KeyEvent event);
|
||||||
void on_mouse_button(LibInput::MouseButtonEvent event);
|
void on_mouse_button(LibInput::MouseButtonEvent event);
|
||||||
|
@ -70,6 +71,8 @@ private:
|
||||||
BAN::RefPtr<Window> m_focused_window;
|
BAN::RefPtr<Window> m_focused_window;
|
||||||
Position m_cursor;
|
Position m_cursor;
|
||||||
|
|
||||||
|
bool m_is_mouse_captured { false };
|
||||||
|
|
||||||
bool m_deleted_window { false };
|
bool m_deleted_window { false };
|
||||||
bool m_is_stopped { false };
|
bool m_is_stopped { false };
|
||||||
bool m_is_bouncing_window = false;
|
bool m_is_bouncing_window = false;
|
||||||
|
|
|
@ -350,6 +350,10 @@ int main()
|
||||||
if (auto ret = LibGUI::WindowPacket::WindowSetAttributes::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
if (auto ret = LibGUI::WindowPacket::WindowSetAttributes::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
||||||
window_server.on_window_set_attributes(fd, ret.release_value());
|
window_server.on_window_set_attributes(fd, ret.release_value());
|
||||||
break;
|
break;
|
||||||
|
case LibGUI::PacketType::WindowSetMouseCapture:
|
||||||
|
if (auto ret = LibGUI::WindowPacket::WindowSetMouseCapture::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
||||||
|
window_server.on_window_set_mouse_capture(fd, ret.release_value());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
|
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue