WindowServer: Add support for fullscreen windows.
Fullscreen windows are rendered alone and above everything else when they are active, and as part of the regular window stack order when something else is active. Currently windows cannot be made fullscreen after-the-fact, but must have the fullscreen flag included in their CreateWindow message. It should not possible to interact with the menu, taskbar or window frame while the active window is fullscreened. :^)
This commit is contained in:
parent
5babcac289
commit
33d0916d29
Notes:
sideshowbarker
2024-07-19 14:03:02 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/33d0916d294
11 changed files with 54 additions and 13 deletions
|
@ -61,6 +61,7 @@ void GWindow::show()
|
|||
request.window.has_alpha_channel = m_has_alpha_channel;
|
||||
request.window.modal = m_modal;
|
||||
request.window.resizable = m_resizable;
|
||||
request.window.fullscreen = m_fullscreen;
|
||||
request.window.opacity = m_opacity_when_windowless;
|
||||
request.window.background_color = m_background_color.value();
|
||||
request.window.size_increment = m_size_increment;
|
||||
|
|
|
@ -30,6 +30,9 @@ public:
|
|||
bool is_modal() const { return m_modal; }
|
||||
void set_modal(bool);
|
||||
|
||||
bool is_fullscreen() const { return m_fullscreen; }
|
||||
void set_fullscreen(bool fullscreen) { m_fullscreen = fullscreen; }
|
||||
|
||||
bool is_resizable() const { return m_resizable; }
|
||||
void set_resizable(bool resizable) { m_resizable = resizable; }
|
||||
|
||||
|
@ -150,4 +153,5 @@ private:
|
|||
bool m_double_buffering_enabled { true };
|
||||
bool m_modal { false };
|
||||
bool m_resizable { true };
|
||||
bool m_fullscreen { false };
|
||||
};
|
||||
|
|
|
@ -264,6 +264,7 @@ struct WSAPI_ClientMessage {
|
|||
bool has_alpha_channel;
|
||||
bool modal;
|
||||
bool resizable;
|
||||
bool fullscreen;
|
||||
WSAPI_WindowType type;
|
||||
float opacity;
|
||||
WSAPI_Size base_size;
|
||||
|
|
|
@ -413,6 +413,10 @@ void WSClientConnection::handle_request(const WSAPISetWindowRectRequest& request
|
|||
return;
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
if (window.is_fullscreen()) {
|
||||
dbgprintf("WSClientConnection: Ignoring SetWindowRect request for fullscreen window\n");
|
||||
return;
|
||||
}
|
||||
window.set_rect(request.rect());
|
||||
window.request_update(request.rect());
|
||||
}
|
||||
|
@ -474,11 +478,12 @@ void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&)
|
|||
void WSClientConnection::handle_request(const WSAPICreateWindowRequest& request)
|
||||
{
|
||||
int window_id = m_next_window_id++;
|
||||
auto window = make<WSWindow>(*this, request.window_type(), window_id, request.is_modal(), request.is_resizable());
|
||||
auto window = make<WSWindow>(*this, request.window_type(), window_id, request.is_modal(), request.is_resizable(), request.is_fullscreen());
|
||||
window->set_background_color(request.background_color());
|
||||
window->set_has_alpha_channel(request.has_alpha_channel());
|
||||
window->set_title(request.title());
|
||||
window->set_rect(request.rect());
|
||||
if (!request.is_fullscreen())
|
||||
window->set_rect(request.rect());
|
||||
window->set_opacity(request.opacity());
|
||||
window->set_size_increment(request.size_increment());
|
||||
window->set_base_size(request.base_size());
|
||||
|
|
|
@ -581,7 +581,7 @@ private:
|
|||
|
||||
class WSAPICreateWindowRequest : public WSAPIClientRequest {
|
||||
public:
|
||||
WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title, bool has_alpha_channel, bool modal, bool resizable, float opacity, const Size& base_size, const Size& size_increment, WSWindowType window_type, Color background_color)
|
||||
WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title, bool has_alpha_channel, bool modal, bool resizable, bool fullscreen, float opacity, const Size& base_size, const Size& size_increment, WSWindowType window_type, Color background_color)
|
||||
: WSAPIClientRequest(WSEvent::APICreateWindowRequest, client_id)
|
||||
, m_rect(rect)
|
||||
, m_title(title)
|
||||
|
@ -589,6 +589,7 @@ public:
|
|||
, m_has_alpha_channel(has_alpha_channel)
|
||||
, m_modal(modal)
|
||||
, m_resizable(resizable)
|
||||
, m_fullscreen(fullscreen)
|
||||
, m_size_increment(size_increment)
|
||||
, m_base_size(base_size)
|
||||
, m_window_type(window_type)
|
||||
|
@ -601,6 +602,7 @@ public:
|
|||
bool has_alpha_channel() const { return m_has_alpha_channel; }
|
||||
bool is_modal() const { return m_modal; }
|
||||
bool is_resizable() const { return m_resizable; }
|
||||
bool is_fullscreen() const { return m_fullscreen; }
|
||||
float opacity() const { return m_opacity; }
|
||||
Size size_increment() const { return m_size_increment; }
|
||||
Size base_size() const { return m_base_size; }
|
||||
|
@ -614,6 +616,7 @@ private:
|
|||
bool m_has_alpha_channel { false };
|
||||
bool m_modal { false };
|
||||
bool m_resizable { false };
|
||||
bool m_fullscreen { false };
|
||||
Size m_size_increment;
|
||||
Size m_base_size;
|
||||
WSWindowType m_window_type;
|
||||
|
|
|
@ -185,7 +185,7 @@ bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag
|
|||
break;
|
||||
case WSAPI_ClientMessage::Type::CreateWindow:
|
||||
ASSERT(message.text_length < (ssize_t)sizeof(message.text));
|
||||
post_event(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.modal, message.window.resizable, message.window.opacity, message.window.base_size, message.window.size_increment, from_api(message.window.type), Color::from_rgba(message.window.background_color)));
|
||||
post_event(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.modal, message.window.resizable, message.window.fullscreen, message.window.opacity, message.window.base_size, message.window.size_increment, from_api(message.window.type), Color::from_rgba(message.window.background_color)));
|
||||
break;
|
||||
case WSAPI_ClientMessage::Type::DestroyWindow:
|
||||
post_event(client, make<WSAPIDestroyWindowRequest>(client_id, message.window_id));
|
||||
|
|
|
@ -28,11 +28,12 @@ WSWindow::WSWindow(CObject& internal_owner, WSWindowType type)
|
|||
WSWindowManager::the().add_window(*this);
|
||||
}
|
||||
|
||||
WSWindow::WSWindow(WSClientConnection& client, WSWindowType window_type, int window_id, bool modal, bool resizable)
|
||||
WSWindow::WSWindow(WSClientConnection& client, WSWindowType window_type, int window_id, bool modal, bool resizable, bool fullscreen)
|
||||
: m_client(&client)
|
||||
, m_type(window_type)
|
||||
, m_modal(modal)
|
||||
, m_resizable(resizable)
|
||||
, m_fullscreen(fullscreen)
|
||||
, m_window_id(window_id)
|
||||
, m_icon(default_window_icon())
|
||||
, m_icon_path(default_window_icon_path())
|
||||
|
|
|
@ -16,7 +16,7 @@ class WSMouseEvent;
|
|||
|
||||
class WSWindow final : public CObject, public InlineLinkedListNode<WSWindow> {
|
||||
public:
|
||||
WSWindow(WSClientConnection&, WSWindowType, int window_id, bool modal, bool resizable);
|
||||
WSWindow(WSClientConnection&, WSWindowType, int window_id, bool modal, bool resizable, bool fullscreen);
|
||||
WSWindow(CObject&, WSWindowType);
|
||||
virtual ~WSWindow() override;
|
||||
|
||||
|
@ -32,6 +32,8 @@ public:
|
|||
bool is_maximized() const { return m_maximized; }
|
||||
void set_maximized(bool);
|
||||
|
||||
bool is_fullscreen() const { return m_fullscreen; }
|
||||
|
||||
WSWindowFrame& frame() { return m_frame; }
|
||||
const WSWindowFrame& frame() const { return m_frame; }
|
||||
|
||||
|
@ -63,7 +65,7 @@ public:
|
|||
|
||||
bool is_modal() const { return m_modal; }
|
||||
|
||||
bool is_resizable() const { return m_resizable; }
|
||||
bool is_resizable() const { return m_resizable && !m_fullscreen; }
|
||||
|
||||
Rect rect() const { return m_rect; }
|
||||
void set_rect(const Rect&);
|
||||
|
@ -155,6 +157,7 @@ private:
|
|||
bool m_listens_to_wm_events { false };
|
||||
bool m_minimized { false };
|
||||
bool m_maximized { false };
|
||||
bool m_fullscreen { false };
|
||||
RetainPtr<GraphicsBitmap> m_backing_store;
|
||||
RetainPtr<GraphicsBitmap> m_last_backing_store;
|
||||
int m_window_id { -1 };
|
||||
|
|
|
@ -254,6 +254,8 @@ void WSWindowFrame::notify_window_rect_changed(const Rect& old_rect, const Rect&
|
|||
|
||||
void WSWindowFrame::on_mouse_event(const WSMouseEvent& event)
|
||||
{
|
||||
ASSERT(!m_window.is_fullscreen());
|
||||
|
||||
auto& wm = WSWindowManager::the();
|
||||
if (m_window.type() != WSWindowType::Normal)
|
||||
return;
|
||||
|
|
|
@ -311,6 +311,12 @@ void WSWindowManager::add_window(WSWindow& window)
|
|||
{
|
||||
m_windows.set(&window);
|
||||
m_windows_in_order.append(&window);
|
||||
|
||||
if (window.is_fullscreen()) {
|
||||
WSEventLoop::the().post_event(window, make<WSResizeEvent>(window.rect(), m_screen_rect));
|
||||
window.set_rect(m_screen_rect);
|
||||
}
|
||||
|
||||
set_active_window(&window);
|
||||
if (m_switcher.is_visible() && window.type() != WSWindowType::WindowSwitcher)
|
||||
m_switcher.refresh();
|
||||
|
@ -792,7 +798,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& hovere
|
|||
// First check if we should initiate a drag or resize (Logo+LMB or Logo+RMB).
|
||||
// In those cases, the event is swallowed by the window manager.
|
||||
if (window.type() == WSWindowType::Normal) {
|
||||
if (m_keyboard_modifiers == Mod_Logo && event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left) {
|
||||
if (!window.is_fullscreen() && m_keyboard_modifiers == Mod_Logo && event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left) {
|
||||
hovered_window = &window;
|
||||
start_window_drag(window, event);
|
||||
return IterationDecision::Abort;
|
||||
|
@ -913,7 +919,7 @@ void WSWindowManager::compose()
|
|||
m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect);
|
||||
}
|
||||
|
||||
for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
|
||||
auto compose_window = [&] (WSWindow& window) -> IterationDecision {
|
||||
if (!any_dirty_rect_intersects_window(window))
|
||||
return IterationDecision::Continue;
|
||||
PainterStateSaver saver(*m_back_painter);
|
||||
|
@ -926,7 +932,8 @@ void WSWindowManager::compose()
|
|||
m_back_painter->add_clip_rect(dirty_rect);
|
||||
if (!backing_store)
|
||||
m_back_painter->fill_rect(dirty_rect, window.background_color());
|
||||
window.frame().paint(*m_back_painter);
|
||||
if (!window.is_fullscreen())
|
||||
window.frame().paint(*m_back_painter);
|
||||
if (!backing_store)
|
||||
continue;
|
||||
Rect dirty_rect_in_window_coordinates = Rect::intersection(dirty_rect, window.rect());
|
||||
|
@ -949,10 +956,19 @@ void WSWindowManager::compose()
|
|||
}
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
};
|
||||
|
||||
if (auto* fullscreen_window = active_fullscreen_window()) {
|
||||
compose_window(*fullscreen_window);
|
||||
} else {
|
||||
for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
|
||||
return compose_window(window);
|
||||
});
|
||||
|
||||
draw_geometry_label();
|
||||
draw_menubar();
|
||||
}
|
||||
|
||||
draw_geometry_label();
|
||||
draw_menubar();
|
||||
draw_cursor();
|
||||
|
||||
if (m_flash_flush) {
|
||||
|
@ -977,6 +993,8 @@ void WSWindowManager::invalidate_cursor()
|
|||
|
||||
Rect WSWindowManager::menubar_rect() const
|
||||
{
|
||||
if (active_fullscreen_window())
|
||||
return { };
|
||||
return { 0, 0, m_screen_rect.width(), 18 };
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,9 @@ public:
|
|||
void start_window_resize(WSWindow&, const Point&, MouseButton);
|
||||
void start_window_resize(WSWindow&, const WSMouseEvent&);
|
||||
|
||||
const WSWindow* active_fullscreen_window() const { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
|
||||
WSWindow* active_fullscreen_window() { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
|
||||
|
||||
private:
|
||||
void process_mouse_event(WSMouseEvent&, WSWindow*& hovered_window);
|
||||
void deliver_mouse_event(WSWindow& window, WSMouseEvent& event);
|
||||
|
|
Loading…
Add table
Reference in a new issue