Skip to content

Commit e1bf1ea

Browse files
committed
Implement fullscreening
Also wire up maximization in Xwayland
1 parent 6d3c28e commit e1bf1ea

File tree

9 files changed

+186
-64
lines changed

9 files changed

+186
-64
lines changed

src/foreign_toplevel.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,16 @@ static void foreign_toplevel_handle_request_maximize_notify(wl_listener* listene
88
const ForeignToplevelHandle& handle = magpie_container_of(listener, handle, request_activate);
99
auto& event = *static_cast<wlr_foreign_toplevel_handle_v1_maximized_event*>(data);
1010

11-
handle.view.set_minimized(false);
12-
handle.view.set_maximized(event.maximized);
11+
auto placement = event.maximized ? VIEW_PLACEMENT_MAXIMIZED : VIEW_PLACEMENT_STACKING;
12+
handle.view.set_placement(placement);
13+
}
14+
15+
static void foreign_toplevel_handle_request_fullscreen_notify(wl_listener* listener, void* data) {
16+
const ForeignToplevelHandle& handle = magpie_container_of(listener, handle, request_activate);
17+
auto& event = *static_cast<wlr_foreign_toplevel_handle_v1_maximized_event*>(data);
18+
19+
auto placement = event.maximized ? VIEW_PLACEMENT_FULLSCREEN : VIEW_PLACEMENT_STACKING;
20+
handle.view.set_placement(placement);
1321
}
1422

1523
static void foreign_toplevel_handle_request_minimize_notify(wl_listener* listener, void* data) {
@@ -24,12 +32,7 @@ static void foreign_toplevel_handle_request_activate_notify(wl_listener* listene
2432
(void) data;
2533

2634
handle.view.set_minimized(false);
27-
handle.view.get_server().focus_view(&handle.view, handle.view.get_wlr_surface());
28-
}
29-
30-
static void foreign_toplevel_handle_request_fullscreen_notify(wl_listener* listener, void* data) {
31-
(void) listener;
32-
(void) data;
35+
handle.view.get_server().focus_view(&handle.view);
3336
}
3437

3538
static void foreign_toplevel_handle_request_close_notify(wl_listener* listener, void* data) {
@@ -89,6 +92,11 @@ void ForeignToplevelHandle::set_parent(std::optional<std::reference_wrapper<cons
8992
wlr_foreign_toplevel_handle_v1_set_parent(&handle, (parent.has_value()) ? nullptr : &parent->get().handle);
9093
}
9194

95+
void ForeignToplevelHandle::set_placement(const ViewPlacement placement) {
96+
set_maximized(placement == VIEW_PLACEMENT_MAXIMIZED);
97+
set_fullscreen(placement == VIEW_PLACEMENT_FULLSCREEN);
98+
}
99+
92100
void ForeignToplevelHandle::set_maximized(const bool maximized) {
93101
wlr_foreign_toplevel_handle_v1_set_maximized(&handle, maximized);
94102
}

src/foreign_toplevel.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ class ForeignToplevelHandle {
3636
void set_title(const char* title);
3737
void set_app_id(const char* app_id);
3838
void set_parent(std::optional<std::reference_wrapper<const ForeignToplevelHandle>> parent);
39-
void set_maximized(bool maximized);
40-
void set_minimized(bool minimized);
41-
void set_activated(bool activated);
42-
void set_fullscreen(bool fullscreen);
39+
void set_placement(const ViewPlacement placement);
40+
void set_maximized(const bool maximized);
41+
void set_fullscreen(const bool fullscreen);
42+
void set_minimized(const bool minimized);
43+
void set_activated(const bool activated);
4344
void output_enter(const Output& output);
4445
void output_leave(const Output& output);
4546
};

src/output.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ void Output::update_layout() {
9494
}
9595
}
9696

97+
wlr_box Output::full_area_in_layout_coords() const {
98+
double layout_x = 0, layout_y = 0;
99+
wlr_output_layout_output_coords(server.output_layout, &wlr, &layout_x, &layout_y);
100+
101+
wlr_box box = full_area;
102+
box.x += layout_x;
103+
box.y += layout_y;
104+
return box;
105+
}
106+
97107
wlr_box Output::usable_area_in_layout_coords() const {
98108
double layout_x = 0, layout_y = 0;
99109
wlr_output_layout_output_coords(server.output_layout, &wlr, &layout_x, &layout_y);

src/output.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class Output {
3939
~Output() noexcept;
4040

4141
void update_layout();
42+
wlr_box full_area_in_layout_coords() const;
4243
wlr_box usable_area_in_layout_coords() const;
4344
};
4445

src/surface/view.cpp

Lines changed: 88 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
#include "output.hpp"
66
#include "server.hpp"
77

8+
#include "types.hpp"
89
#include "wlr-wrap-start.hpp"
910
#include <wlr/types/wlr_compositor.h>
1011
#include <wlr/types/wlr_cursor.h>
1112
#include <wlr/types/wlr_output_layout.h>
1213
#include <wlr/types/wlr_scene.h>
1314
#include <wlr/types/wlr_seat.h>
1415
#include <wlr/util/edges.h>
16+
#include <wlr/util/log.h>
1517
#include "wlr-wrap-end.hpp"
1618

1719
const std::optional<const Output*> View::find_output_for_maximize() {
@@ -94,15 +96,23 @@ void View::begin_interactive(const CursorMode mode, const uint32_t edges) {
9496
}
9597

9698
void View::set_position(const int new_x, const int new_y) {
97-
previous.x = current.x;
98-
previous.y = current.y;
99+
if (curr_placement == VIEW_PLACEMENT_STACKING) {
100+
previous.x = current.x;
101+
previous.y = current.y;
102+
}
99103
current.x = new_x;
100104
current.y = new_y;
101105
wlr_scene_node_set_position(scene_node, new_x, new_y);
102106
impl_set_position(new_x, new_y);
103107
}
104108

105109
void View::set_size(const int new_width, const int new_height) {
110+
if (curr_placement == VIEW_PLACEMENT_STACKING) {
111+
previous.width = current.width;
112+
previous.height = current.height;
113+
}
114+
current.width = new_width;
115+
current.height = new_height;
106116
impl_set_size(new_width, new_height);
107117
}
108118

@@ -114,47 +124,78 @@ void View::set_activated(const bool activated) {
114124
}
115125
}
116126

117-
void View::set_maximized(const bool maximized) {
127+
void View::set_placement(const ViewPlacement new_placement, const bool force) {
118128
Server& server = get_server();
119-
if (this->is_maximized == maximized) {
120-
/* Don't honor request if already maximized. */
121-
return;
122-
}
123129

124-
wlr_surface* focused_surface = server.seat->wlr->pointer_state.focused_surface;
125-
if (get_wlr_surface() != wlr_surface_get_root_surface(focused_surface)) {
126-
/* Deny maximize requests from unfocused clients. */
127-
return;
130+
if (!force) {
131+
if (curr_placement == new_placement) {
132+
return;
133+
}
134+
135+
wlr_surface* focused_surface = server.seat->wlr->pointer_state.focused_surface;
136+
if (focused_surface == nullptr || get_wlr_surface() != wlr_surface_get_root_surface(focused_surface)) {
137+
/* Deny placement requests from unfocused clients. */
138+
return;
139+
}
128140
}
129141

130-
if (this->is_maximized) {
131-
set_size(previous.width, previous.height);
132-
impl_set_maximized(false);
133-
current.x = previous.x;
134-
current.y = previous.y;
135-
wlr_scene_node_set_position(scene_node, current.x, current.y);
136-
} else {
137-
previous = get_geometry();
138-
previous.x = current.x;
139-
previous.y = current.y;
142+
bool res = true;
143+
144+
switch (new_placement) {
145+
case VIEW_PLACEMENT_STACKING:
146+
stack();
147+
break;
148+
case VIEW_PLACEMENT_MAXIMIZED:
149+
res = maximize();
150+
break;
151+
case VIEW_PLACEMENT_FULLSCREEN:
152+
res = fullscreen();
153+
break;
154+
}
140155

141-
auto best_output = find_output_for_maximize();
142-
if (!best_output.has_value()) {
143-
return;
156+
if (res) {
157+
prev_placement = curr_placement;
158+
curr_placement = new_placement;
159+
if (toplevel_handle.has_value()) {
160+
toplevel_handle->set_placement(new_placement);
144161
}
162+
}
163+
}
164+
165+
void View::stack() {
166+
set_size(previous.width, previous.height);
167+
impl_set_maximized(false);
168+
impl_set_fullscreen(false);
169+
set_position(previous.x, previous.y);
170+
}
145171

146-
wlr_box output_box = best_output.value()->usable_area_in_layout_coords();
147-
set_size(output_box.width, output_box.height);
148-
impl_set_maximized(true);
149-
current.x = output_box.x;
150-
current.y = output_box.y;
151-
wlr_scene_node_set_position(scene_node, current.x, current.y);
172+
bool View::maximize() {
173+
auto best_output = find_output_for_maximize();
174+
if (!best_output.has_value()) {
175+
return false;
152176
}
153177

154-
this->is_maximized = maximized;
155-
if (toplevel_handle.has_value()) {
156-
toplevel_handle->set_maximized(maximized);
178+
wlr_box output_box = best_output.value()->usable_area_in_layout_coords();
179+
set_size(output_box.width, output_box.height);
180+
impl_set_fullscreen(false);
181+
impl_set_maximized(true);
182+
set_position(output_box.x, output_box.y);
183+
184+
return true;
185+
}
186+
187+
bool View::fullscreen() {
188+
auto best_output = find_output_for_maximize();
189+
if (!best_output.has_value()) {
190+
return false;
157191
}
192+
193+
wlr_box output_box = best_output.value()->full_area_in_layout_coords();
194+
set_size(output_box.width, output_box.height);
195+
impl_set_fullscreen(true);
196+
set_position(output_box.x, output_box.y);
197+
198+
return true;
158199
}
159200

160201
void View::set_minimized(const bool minimized) {
@@ -175,3 +216,17 @@ void View::set_minimized(const bool minimized) {
175216
map();
176217
}
177218
}
219+
220+
void View::toggle_maximize() {
221+
if (curr_placement != VIEW_PLACEMENT_FULLSCREEN) {
222+
set_placement(curr_placement != VIEW_PLACEMENT_MAXIMIZED ? VIEW_PLACEMENT_MAXIMIZED : VIEW_PLACEMENT_STACKING);
223+
}
224+
}
225+
226+
void View::toggle_fullscreen() {
227+
if (curr_placement == VIEW_PLACEMENT_FULLSCREEN) {
228+
set_placement(prev_placement);
229+
} else {
230+
set_placement(VIEW_PLACEMENT_FULLSCREEN);
231+
}
232+
}

src/surface/view.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
#include "wlr-wrap-end.hpp"
1616

1717
struct View : public Surface {
18-
bool is_maximized;
19-
bool is_minimized;
18+
ViewPlacement prev_placement = VIEW_PLACEMENT_STACKING;
19+
ViewPlacement curr_placement = VIEW_PLACEMENT_STACKING;
20+
bool is_minimized = false;
2021
wlr_box current;
2122
wlr_box pending;
2223
wlr_box previous;
@@ -35,11 +36,16 @@ struct View : public Surface {
3536
void set_position(const int new_x, const int new_y);
3637
void set_size(const int new_width, const int new_height);
3738
void set_activated(const bool activated);
38-
void set_maximized(const bool maximized);
39+
void set_placement(const ViewPlacement placement, const bool force = false);
3940
void set_minimized(const bool minimized);
41+
void toggle_maximize();
42+
void toggle_fullscreen();
4043

4144
private:
4245
const std::optional<const Output*> find_output_for_maximize();
46+
void stack();
47+
bool maximize();
48+
bool fullscreen();
4349

4450
protected:
4551
virtual void impl_set_position(const int new_x, const int new_y) = 0;
@@ -106,6 +112,8 @@ class XWaylandView : public View {
106112
wl_listener request_configure;
107113
wl_listener request_move;
108114
wl_listener request_resize;
115+
wl_listener request_maximize;
116+
wl_listener request_fullscreen;
109117
wl_listener set_geometry;
110118
wl_listener set_title;
111119
wl_listener set_class;

src/surface/xdg_view.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static void xdg_toplevel_request_move_notify(wl_listener* listener, void* data)
4848
XdgView& view = magpie_container_of(listener, view, request_move);
4949
(void) data;
5050

51-
view.set_maximized(false);
51+
view.set_placement(VIEW_PLACEMENT_STACKING);
5252
view.begin_interactive(MAGPIE_CURSOR_MOVE, 0);
5353
}
5454

@@ -61,7 +61,7 @@ static void xdg_toplevel_request_resize_notify(wl_listener* listener, void* data
6161
XdgView& view = magpie_container_of(listener, view, request_resize);
6262
auto* event = static_cast<wlr_xdg_toplevel_resize_event*>(data);
6363

64-
view.set_maximized(false);
64+
view.set_placement(VIEW_PLACEMENT_STACKING);
6565
view.begin_interactive(MAGPIE_CURSOR_RESIZE, event->edges);
6666
}
6767

@@ -72,23 +72,23 @@ static void xdg_toplevel_request_maximize_notify(wl_listener* listener, void* da
7272
XdgView& view = magpie_container_of(listener, view, request_maximize);
7373
(void) data;
7474

75-
view.set_maximized(!view.is_maximized);
75+
view.toggle_maximize();
7676
wlr_xdg_surface_schedule_configure(view.xdg_toplevel.base);
7777
}
7878

79-
static void xdg_toplevel_request_minimize_notify(wl_listener* listener, void* data) {
80-
XdgView& view = magpie_container_of(listener, view, request_minimize);
79+
static void xdg_toplevel_request_fullscreen_notify(wl_listener* listener, void* data) {
80+
XdgView& view = magpie_container_of(listener, view, request_fullscreen);
8181
(void) data;
8282

83-
view.set_minimized(!view.is_minimized);
83+
view.toggle_fullscreen();
8484
wlr_xdg_surface_schedule_configure(view.xdg_toplevel.base);
8585
}
8686

87-
static void xdg_toplevel_request_fullscreen_notify(wl_listener* listener, void* data) {
88-
XdgView& view = magpie_container_of(listener, view, request_fullscreen);
87+
static void xdg_toplevel_request_minimize_notify(wl_listener* listener, void* data) {
88+
XdgView& view = magpie_container_of(listener, view, request_minimize);
8989
(void) data;
9090

91-
/* We must send a configure here, even on a no-op. */
91+
view.set_minimized(!view.is_minimized);
9292
wlr_xdg_surface_schedule_configure(view.xdg_toplevel.base);
9393
}
9494

@@ -126,8 +126,9 @@ XdgView::XdgView(Server& server, wlr_xdg_toplevel& toplevel) noexcept
126126
auto* scene_tree = wlr_scene_xdg_surface_create(&server.scene->tree, toplevel.base);
127127
scene_node = &scene_tree->node;
128128

129-
wlr_xdg_toplevel_set_wm_capabilities(
130-
&toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE | WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE);
129+
wlr_xdg_toplevel_set_wm_capabilities(&toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE |
130+
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE |
131+
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
131132

132133
scene_node->data = this;
133134
toplevel.base->surface->data = this;
@@ -214,7 +215,14 @@ void XdgView::map() {
214215
}
215216

216217
wlr_scene_node_set_enabled(scene_node, true);
217-
is_maximized = xdg_toplevel.current.maximized;
218+
if (xdg_toplevel.current.fullscreen) {
219+
set_placement(VIEW_PLACEMENT_FULLSCREEN);
220+
} else if (xdg_toplevel.current.maximized) {
221+
set_placement(VIEW_PLACEMENT_MAXIMIZED);
222+
} else {
223+
set_placement(VIEW_PLACEMENT_STACKING);
224+
}
225+
218226
server.focus_view(this);
219227
}
220228

0 commit comments

Comments
 (0)