Skip to content

Commit 5a333fa

Browse files
committed
xwayland: implement forced scaling
1 parent a8f18ec commit 5a333fa

18 files changed

Lines changed: 331 additions & 83 deletions

metadata/workarounds.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,10 @@
105105
<min>0</min>
106106
<max>500</max>
107107
</option>
108+
<option name="force_xwayland_scaling" type="bool">
109+
<_short>Force Xwayland DPI scaling</_short>
110+
<_long>Disables the default blurry scaling for Xwayland and forces client-side scaling for Xwayland windows dependent on the DPI settings.</_long>
111+
<default>false</default>
112+
</option>
108113
</plugin>
109114
</wayfire>

src/api/wayfire/unstable/wlr-surface-node.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct surface_state_t
1919
wlr_texture *texture; // The texture of the wlr_client_buffer
2020

2121
wf::region_t accumulated_damage;
22+
wf::region_t opaque_region;
2223
wf::dimensions_t size = {0, 0};
2324
std::optional<wlr_fbox> src_viewport;
2425
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
@@ -69,7 +70,7 @@ class wlr_surface_node_t : public node_t, public zero_copy_texturable_node_t
6970
std::optional<wf::texture_t> to_texture() const override;
7071

7172
wlr_surface *get_surface() const;
72-
void apply_state(surface_state_t&& state);
73+
virtual void apply_state(surface_state_t&& state);
7374
void apply_current_surface_state();
7475
void send_frame_done(bool delay_until_vblank);
7576

@@ -92,6 +93,8 @@ class wlr_surface_node_t : public node_t, public zero_copy_texturable_node_t
9293
wf::wl_listener_wrapper on_surface_commit;
9394

9495
const bool autocommit;
96+
97+
protected:
9598
surface_state_t current_state;
9699
};
97100
}

src/api/wayfire/unstable/xwl-toplevel-base.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@
1010

1111
#include <wayfire/nonstd/wlroots-full.hpp>
1212
#include <wayfire/view.hpp>
13+
#include <wayfire/util.hpp>
1314
#include <wayfire/unstable/wlr-surface-node.hpp>
1415

1516
namespace wf
1617
{
1718
#if WF_HAS_XWAYLAND
19+
namespace xw
20+
{
21+
class xwayland_surface_node_t;
22+
}
23+
1824
/**
1925
* A base class for views which base on a wlr_xwayland surface.
2026
* Contains the implementation of view_interface_t functions used in them.
@@ -50,7 +56,7 @@ class xwayland_view_base_t : public virtual wf::view_interface_t
5056
void handle_title_changed(std::string new_title);
5157

5258
wf::wl_listener_wrapper on_destroy, on_set_title, on_set_app_id, on_ping_timeout;
53-
std::shared_ptr<wf::scene::wlr_surface_node_t> main_surface;
59+
std::shared_ptr<wf::xw::xwayland_surface_node_t> main_surface;
5460
};
5561
#endif
5662
}

src/core/xdg-output-management.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <wayfire/geometry.hpp>
1212
#include <wlr/types/wlr_output.h>
1313
#include <wayfire/signal-provider.hpp>
14+
#include "view/view-impl.hpp"
1415
#include "wayfire/debug.hpp"
1516
#include "xdg-output-unstable-v1-protocol.h"
1617

@@ -62,6 +63,11 @@ class xdg_output_v1_resource
6263
}
6364
}
6465

66+
bool is_xwayland() const
67+
{
68+
return wl_resource_get_client(xdg_output) == wf::xwayland_get_client();
69+
}
70+
6571
bool resend_details(wf::geometry_t geometry)
6672
{
6773
if (last_sent_geometry == geometry)
@@ -117,12 +123,14 @@ void xdg_output_manager_v1::update_outputs()
117123
return config.count(output) && (config[output].source & OUTPUT_IMAGE_SOURCE_SELF);
118124
};
119125

120-
const auto& update_output = [&] (wlr_output *output, wf::geometry_t geometry)
126+
const auto& update_output = [&] (wlr_output *output, wf::geometry_t geometry,
127+
wf::geometry_t xwayland_geometry)
121128
{
122129
bool changed = false;
123130
for (auto& resource : output_resources[output])
124131
{
125-
changed |= resource->resend_details(geometry);
132+
wf::geometry_t to_send = resource->is_xwayland() ? xwayland_geometry : geometry;
133+
changed |= resource->resend_details(to_send);
126134
}
127135

128136
if (changed)
@@ -131,6 +139,9 @@ void xdg_output_manager_v1::update_outputs()
131139
}
132140
};
133141

142+
static wf::option_wrapper_t<bool> force_xwayland_scaling{"workarounds/force_xwayland_scaling"};
143+
144+
int xwayland_location_x = 0;
134145
auto it = output_resources.begin();
135146
while (it != output_resources.end())
136147
{
@@ -139,8 +150,22 @@ void xdg_output_manager_v1::update_outputs()
139150
it = output_resources.erase(it);
140151
} else
141152
{
142-
auto geometry = ol->find_output(it->first)->get_layout_geometry();
143-
update_output(it->first, geometry);
153+
auto wo = ol->find_output(it->first);
154+
auto geometry = wo->get_layout_geometry();
155+
if (force_xwayland_scaling)
156+
{
157+
int width, height;
158+
wlr_output_transformed_resolution(it->first, &width, &height);
159+
wf::geometry_t xwayland_geometry = {xwayland_location_x, 0, width, height};
160+
update_output(it->first, geometry, xwayland_geometry);
161+
xwayland_location_x += width;
162+
wo->get_data_safe<wf::xdg_output_xwayland_geometry>()->geometry = xwayland_geometry;
163+
} else
164+
{
165+
update_output(it->first, geometry, geometry);
166+
wo->get_data_safe<wf::xdg_output_xwayland_geometry>()->geometry = geometry;
167+
}
168+
144169
++it;
145170
}
146171
}

src/core/xdg-output-management.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
#include <memory>
44
#include <map>
55
#include <vector>
6+
#include "wayfire/object.hpp"
67
#include "xdg-output-unstable-v1-protocol.h"
78
#include <wayfire/output-layout.hpp>
89

910
namespace wf
1011
{
1112
class xdg_output_v1_resource;
13+
class xdg_output_xwayland_geometry : public wf::custom_data_t
14+
{
15+
public:
16+
std::optional<wf::geometry_t> geometry;
17+
};
1218

1319
class xdg_output_manager_v1
1420
{

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ wayfire_sources = ['geometry.cpp',
5151
'view/xwayland/xwayland-view-base.cpp',
5252
'view/xwayland/xwayland-toplevel.cpp',
5353
'view/xwayland/xwayland-helpers.cpp',
54+
'view/xwayland/xwayland-surface.cpp',
5455
'view/layer-shell/layer-shell.cpp',
5556
'view/layer-shell/layer-shell-node.cpp',
5657
'view/view-3d.cpp',

src/view/view-impl.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ void xwayland_update_default_cursor();
7676
/* Ensure that the given surface is on top of the Xwayland stack order. */
7777
void xwayland_bring_to_front(wlr_surface *surface);
7878
int xwayland_get_pid();
79+
wl_client *xwayland_get_client();
7980

8081
void init_desktop_apis();
8182
void fini_desktop_apis();

src/view/wlr-surface-node.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "wayfire/unstable/wlr-surface-node.hpp"
2-
#include "pixman.h"
32
#include "wayfire/geometry.hpp"
43
#include "wayfire/render-manager.hpp"
54
#include "wayfire/scene-render.hpp"
@@ -32,6 +31,7 @@ wf::scene::surface_state_t& wf::scene::surface_state_t::operator =(surface_state
3231
current_buffer = other.current_buffer;
3332
texture = other.texture;
3433
accumulated_damage = other.accumulated_damage;
34+
opaque_region = other.opaque_region;
3535
seq = other.seq;
3636
size = other.size;
3737
src_viewport = other.src_viewport;
@@ -40,6 +40,7 @@ wf::scene::surface_state_t& wf::scene::surface_state_t::operator =(surface_state
4040
other.current_buffer = NULL;
4141
other.texture = NULL;
4242
other.accumulated_damage.clear();
43+
other.opaque_region.clear();
4344
other.src_viewport.reset();
4445
other.seq.reset();
4546
return *this;
@@ -86,6 +87,7 @@ void wf::scene::surface_state_t::merge_state(wlr_surface *surface)
8687
wf::region_t current_damage;
8788
wlr_surface_get_effective_damage(surface, current_damage.to_pixman());
8889
this->accumulated_damage |= current_damage;
90+
this->opaque_region = wf::region_t{&surface->current.opaque};
8991
}
9092

9193
wf::scene::surface_state_t::~surface_state_t()
@@ -312,8 +314,7 @@ class wf::scene::wlr_surface_node_t::wlr_surface_render_instance_t : public rend
312314

313315
if (self->surface)
314316
{
315-
pixman_region32_subtract(damage.to_pixman(), damage.to_pixman(),
316-
&self->surface->opaque_region);
317+
damage ^= self->current_state.opaque_region;
317318
}
318319
}
319320
}
@@ -402,8 +403,7 @@ class wf::scene::wlr_surface_node_t::wlr_surface_render_instance_t : public rend
402403
output->connect(&on_frame_done);
403404
if (use_opaque_optimizations && self->surface)
404405
{
405-
pixman_region32_subtract(visible.to_pixman(), visible.to_pixman(),
406-
&self->surface->opaque_region);
406+
visible ^= self->current_state.opaque_region;
407407
}
408408
}
409409
}

src/view/xwayland.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,14 @@ int wf::xwayland_get_pid()
337337
return -1;
338338
#endif
339339
}
340+
341+
wl_client*wf::xwayland_get_client()
342+
{
343+
#if WF_HAS_XWAYLAND
344+
345+
return (xwayland_handle && xwayland_handle->server) ? xwayland_handle->server->client : NULL;
346+
#else
347+
348+
return nullptr;
349+
#endif
350+
}

src/view/xwayland/xwayland-helpers.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "xwayland-helpers.hpp"
2+
#include "core/xdg-output-management.hpp"
23

34
#if WF_HAS_XWAYLAND
45

@@ -50,4 +51,58 @@ bool wf::xw::has_type(wlr_xwayland_surface *xw, xcb_atom_t type)
5051
return false;
5152
}
5253

54+
wf::output_t*wf::xw::find_xwayland_surface_output(wlr_xwayland_surface *xw)
55+
{
56+
auto& ol = wf::get_core().output_layout;
57+
double cx = xw->x + xw->width / 2.0;
58+
double cy = xw->y + xw->height / 2.0;
59+
wf::output_t *closest = ol->get_outputs().empty() ? nullptr : ol->get_outputs().front();
60+
double closest_dist = std::numeric_limits<double>::max();
61+
for (auto & wo : ol->get_outputs())
62+
{
63+
auto data = wo->get_data_safe<wf::xdg_output_xwayland_geometry>();
64+
if (!data->geometry.has_value())
65+
{
66+
continue;
67+
}
68+
69+
double dx;
70+
double dy;
71+
wlr_box_closest_point(&data->geometry.value(), cx, cy, &dx, &dy);
72+
const double dist = (dx - cx) * (dx - cx) + (dy - cy) * (dy - cy);
73+
if (dist < closest_dist)
74+
{
75+
closest_dist = dist;
76+
closest = wo;
77+
}
78+
}
79+
80+
return closest;
81+
}
82+
83+
wf::geometry_t wf::xw::calculate_wayfire_geometry(wf::output_t *ref_output, wf::geometry_t geometry)
84+
{
85+
if (!ref_output)
86+
{
87+
return geometry;
88+
}
89+
90+
auto data = ref_output->get_data_safe<wf::xdg_output_xwayland_geometry>();
91+
if (!data->geometry.has_value())
92+
{
93+
LOGW("Xwayland geometry not set for output ", ref_output->to_string(),
94+
", returning original geometry");
95+
return geometry;
96+
}
97+
98+
geometry = geometry - wf::origin(data->geometry.value());
99+
static wf::option_wrapper_t<bool> force_xwayland_scaling{"workarounds/force_xwayland_scaling"};
100+
if (force_xwayland_scaling)
101+
{
102+
geometry = geometry * (1.0 / ref_output->get_scale());
103+
}
104+
105+
return geometry;
106+
}
107+
53108
#endif

0 commit comments

Comments
 (0)