Fix #106235: Use consistent order for multi-input socket links #106320

Closed
Iliya Katushenock wants to merge 17 commits from mod_moder:fix_internal_link_drawing into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
41 changed files with 2653 additions and 1263 deletions
Showing only changes of commit f0dcd9f626 - Show all commits

View File

@ -528,10 +528,10 @@ set(XR_OPENXR_SDK_HASH a2623ebab3d0b340bc16311b14f02075)
set(XR_OPENXR_SDK_HASH_TYPE MD5)
set(XR_OPENXR_SDK_FILE OpenXR-SDK-${XR_OPENXR_SDK_VERSION}.tar.gz)
set(WL_PROTOCOLS_VERSION 1.21)
set(WL_PROTOCOLS_VERSION 1.31)
set(WL_PROTOCOLS_FILE wayland-protocols-${WL_PROTOCOLS_VERSION}.tar.gz)
set(WL_PROTOCOLS_URI https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/${WL_PROTOCOLS_VERSION}/${WL_PROTOCOLS_FILE})
set(WL_PROTOCOLS_HASH af5ca07e13517cdbab33504492cef54a)
set(WL_PROTOCOLS_HASH a28ff59a56e2ebb746048b6ef8d931d6)
set(WL_PROTOCOLS_HASH_TYPE MD5)
set(WAYLAND_VERSION 1.21.0)

View File

@ -245,6 +245,7 @@ if(WITH_BOOST)
if(WITH_USD AND USD_PYTHON_SUPPORT)
list(APPEND _boost_FIND_COMPONENTS python${PYTHON_VERSION_NO_DOTS})
endif()
set(Boost_NO_WARN_NEW_VERSIONS ON)
find_package(Boost COMPONENTS ${_boost_FIND_COMPONENTS})
# Boost Python is separate to avoid linking Python into tests that don't need it.

View File

@ -394,6 +394,7 @@ if(WITH_BOOST)
list(APPEND __boost_packages python${PYTHON_VERSION_NO_DOTS})
endif()
list(APPEND __boost_packages system)
set(Boost_NO_WARN_NEW_VERSIONS ON)
find_package(Boost 1.48 COMPONENTS ${__boost_packages})
if(NOT Boost_FOUND)
# try to find non-multithreaded if -mt not found, this flag

View File

@ -1,7 +1,7 @@
Project: fast_float
URL: https://github.com/fastfloat/fast_float
License: MIT
Upstream version: 3.4.0 (b7f9d6c)
Upstream version: 4.0.0 (fbd5bd7, 2023 Mar 31)
Local modifications:
- Took only the fast_float.h header and the license/readme files

View File

@ -1,12 +1,5 @@
## fast_float number parsing library: 4x faster than strtod
![Ubuntu 20.04 CI (GCC 9)](https://github.com/lemire/fast_float/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)
![Ubuntu 18.04 CI (GCC 7)](https://github.com/lemire/fast_float/workflows/Ubuntu%2018.04%20CI%20(GCC%207)/badge.svg)
![Alpine Linux](https://github.com/lemire/fast_float/workflows/Alpine%20Linux/badge.svg)
![MSYS2-CI](https://github.com/lemire/fast_float/workflows/MSYS2-CI/badge.svg)
![VS16-CLANG-CI](https://github.com/lemire/fast_float/workflows/VS16-CLANG-CI/badge.svg)
[![VS16-CI](https://github.com/fastfloat/fast_float/actions/workflows/vs16-ci.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/vs16-ci.yml)
The fast_float library provides fast header-only implementations for the C++ from_chars
functions for `float` and `double` types. These functions convert ASCII strings representing
decimal values (e.g., `1.3e10`) into binary types. We provide exact rounding (including
@ -28,8 +21,8 @@ struct from_chars_result {
```
It parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
a locale-independent format equivalent to the C++17 from_chars function.
The resulting floating-point value is the closest floating-point values (using either float or double),
a locale-independent format equivalent to the C++17 from_chars function.
The resulting floating-point value is the closest floating-point values (using either float or double),
using the "round to even" convention for values that would otherwise fall right in-between two values.
That is, we provide exact parsing according to the IEEE standard.
@ -47,7 +40,7 @@ Example:
``` C++
#include "fast_float/fast_float.h"
#include <iostream>
int main() {
const std::string input = "3.1416 xyz ";
double result;
@ -60,39 +53,60 @@ int main() {
Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
the type `fast_float::chars_format`. It is a bitset value: we check whether
the type `fast_float::chars_format`. It is a bitset value: we check whether
`fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
to determine whether we allow the fixed point and scientific notation respectively.
The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
The library seeks to follow the C++17 (see [20.19.3](http://eel.is/c++draft/charconv.from.chars).(7.1)) specification.
The library seeks to follow the C++17 (see [20.19.3](http://eel.is/c++draft/charconv.from.chars).(7.1)) specification.
* The `from_chars` function does not skip leading white-space characters.
* [A leading `+` sign](https://en.cppreference.com/w/cpp/utility/from_chars) is forbidden.
* It is generally impossible to represent a decimal value exactly as binary floating-point number (`float` and `double` types). We seek the nearest value. We round to an even mantissa when we are in-between two binary floating-point numbers.
* It is generally impossible to represent a decimal value exactly as binary floating-point number (`float` and `double` types). We seek the nearest value. We round to an even mantissa when we are in-between two binary floating-point numbers.
Furthermore, we have the following restrictions:
* We only support `float` and `double` types at this time.
* We only support the decimal format: we do not support hexadecimal strings.
* For values that are either very large or very small (e.g., `1e9999`), we represent it using the infinity or negative infinity value.
* For values that are either very large or very small (e.g., `1e9999`), we represent it using the infinity or negative infinity value and the returned `ec` is set to `std::errc::result_out_of_range`.
We support Visual Studio, macOS, Linux, freeBSD. We support big and little endian. We support 32-bit and 64-bit systems.
We assume that the rounding mode is set to nearest (`std::fegetround() == FE_TONEAREST`).
## C++20: compile-time evaluation (constexpr)
In C++20, you may use `fast_float::from_chars` to parse strings
at compile-time, as in the following example:
```C++
// consteval forces compile-time evaluation of the function in C++20.
consteval double parse(std::string_view input) {
double result;
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
if(answer.ec != std::errc()) { return -1.0; }
return result;
}
// This function should compile to a function which
// merely returns 3.1415.
constexpr double constexptest() {
return parse("3.1415 input");
}
```
## Using commas as decimal separator
The C++ standard stipulate that `from_chars` has to be locale-independent. In
particular, the decimal separator has to be the period (`.`). However,
some users still want to use the `fast_float` library with in a locale-dependent
particular, the decimal separator has to be the period (`.`). However,
some users still want to use the `fast_float` library with in a locale-dependent
manner. Using a separate function called `from_chars_advanced`, we allow the users
to pass a `parse_options` instance which contains a custom decimal separator (e.g.,
to pass a `parse_options` instance which contains a custom decimal separator (e.g.,
the comma). You may use it as follows.
```C++
#include "fast_float/fast_float.h"
#include <iostream>
int main() {
const std::string input = "3,1416 xyz ";
double result;
@ -104,25 +118,62 @@ int main() {
}
```
You can parse delimited numbers:
```C++
const std::string input = "234532.3426362,7869234.9823,324562.645";
double result;
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
if(answer.ec != std::errc()) {
// check error
}
// we have result == 234532.3426362.
if(answer.ptr[0] != ',') {
// unexpected delimiter
}
answer = fast_float::from_chars(answer.ptr + 1, input.data()+input.size(), result);
if(answer.ec != std::errc()) {
// check error
}
// we have result == 7869234.9823.
if(answer.ptr[0] != ',') {
// unexpected delimiter
}
answer = fast_float::from_chars(answer.ptr + 1, input.data()+input.size(), result);
if(answer.ec != std::errc()) {
// check error
}
// we have result == 324562.645.
```
## Reference
- Daniel Lemire, [Number Parsing at a Gigabyte per Second](https://arxiv.org/abs/2101.11408), Software: Pratice and Experience 51 (8), 2021.
## Relation With Other Work
The fast_float library is part of:
- GCC (as of version 12): the `from_chars` function in GCC relies on fast_float.
- [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's web browser)
The fastfloat algorithm is part of the [LLVM standard libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba).
There is a [derived implementation part of AdaCore](https://github.com/AdaCore/VSS).
The fast_float library provides a performance similar to that of the [fast_double_parser](https://github.com/lemire/fast_double_parser) library but using an updated algorithm reworked from the ground up, and while offering an API more in line with the expectations of C++ programmers. The fast_double_parser library is part of the [Microsoft LightGBM machine-learning framework](https://github.com/microsoft/LightGBM).
## References
- Daniel Lemire, [Number Parsing at a Gigabyte per Second](https://arxiv.org/abs/2101.11408), Software: Practice and Experience 51 (8), 2021.
- Noble Mushtak, Daniel Lemire, [Fast Number Parsing Without Fallback](https://arxiv.org/abs/2212.06644), Software: Practice and Experience (to appear)
## Other programming languages
- [There is an R binding](https://github.com/eddelbuettel/rcppfastfloat) called `rcppfastfloat`.
- [There is a Rust port of the fast_float library](https://github.com/aldanor/fast-float-rust/) called `fast-float-rust`.
- [There is a Java port of the fast_float library](https://github.com/wrandelshofer/FastDoubleParser) called `FastDoubleParser`.
- [There is a Java port of the fast_float library](https://github.com/wrandelshofer/FastDoubleParser) called `FastDoubleParser`. It used for important systems such as [Jackson](https://github.com/FasterXML/jackson-core).
- [There is a C# port of the fast_float library](https://github.com/CarlVerret/csFastFloat) called `csFastFloat`.
## Relation With Other Work
The fastfloat algorithm is part of the [LLVM standard libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba).
The fast_float library provides a performance similar to that of the [fast_double_parser](https://github.com/lemire/fast_double_parser) library but using an updated algorithm reworked from the ground up, and while offering an API more in line with the expectations of C++ programmers. The fast_double_parser library is part of the [Microsoft LightGBM machine-learning framework](https://github.com/microsoft/LightGBM).
## Users
The fast_float library is used by [Apache Arrow](https://github.com/apache/arrow/pull/8494) where it multiplied the number parsing speed by two or three times. It is also used by [Yandex ClickHouse](https://github.com/ClickHouse/ClickHouse) and by [Google Jsonnet](https://github.com/google/jsonnet).
@ -135,14 +186,14 @@ It can parse random floating-point numbers at a speed of 1 GB/s on some systems.
<img src="http://lemire.me/blog/wp-content/uploads/2020/11/fastfloat_speed.png" width="400">
```
$ ./build/benchmarks/benchmark
$ ./build/benchmarks/benchmark
# parsing random integers in the range [0,1)
volume = 2.09808 MB
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
volume = 2.09808 MB
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
```
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
@ -183,23 +234,23 @@ You should change the `GIT_TAG` line so that you recover the version you wish to
## Using as single header
The script `script/amalgamate.py` may be used to generate a single header
The script `script/amalgamate.py` may be used to generate a single header
version of the library if so desired.
Just run the script from the root directory of this repository.
Just run the script from the root directory of this repository.
You can customize the license type and output file if desired as described in
the command line help.
You may directly download automatically generated single-header files:
https://github.com/fastfloat/fast_float/releases/download/v1.1.2/fast_float.h
https://github.com/fastfloat/fast_float/releases/download/v3.4.0/fast_float.h
## Credit
Though this work is inspired by many different people, this work benefited especially from exchanges with
Michael Eisel, who motivated the original research with his key insights, and with Nigel Tao who provided
Though this work is inspired by many different people, this work benefited especially from exchanges with
Michael Eisel, who motivated the original research with his key insights, and with Nigel Tao who provided
invaluable feedback. Rémy Oudompheng first implemented a fast path we use in the case of long digits.
The library includes code adapted from Google Wuffs (written by Nigel Tao) which was originally published
The library includes code adapted from Google Wuffs (written by Nigel Tao) which was originally published
under the Apache 2.0 license.
## License

File diff suppressed because it is too large Load Diff

View File

@ -378,6 +378,14 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
unset(_name)
endmacro()
macro(generate_protocol_bindings_when_found PROT_DEF FOUND_VAR)
if(EXISTS ${PROT_DEF})
generate_protocol_bindings(${PROT_DEF})
set(${FOUND_VAR} TRUE)
else()
set(${FOUND_VAR} FALSE)
endif()
endmacro()
list(APPEND INC_SYS
${INC_DST}
@ -402,6 +410,17 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/staging/xdg-activation/xdg-activation-v1.xml"
)
# Fractional scale.
generate_protocol_bindings_when_found(
"${WAYLAND_PROTOCOLS_DIR}/staging/fractional-scale/fractional-scale-v1.xml"
_has_fractional_scale
)
if(_has_fractional_scale)
# Viewport (only required when fractional scale is in use).
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/stable/viewporter/viewporter.xml"
)
endif()
# Pointer-constraints.
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
@ -427,6 +446,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
add_definitions(-DWITH_GHOST_WAYLAND)
if(_has_fractional_scale)
add_definitions(-DWITH_GHOST_WAYLAND_FRACTIONAL_SCALE)
endif()
unset(_has_fractional_scale)
if(NOT WITH_GHOST_WAYLAND_APP_ID STREQUAL "")
add_definitions(-DWITH_GHOST_WAYLAND_APP_ID=${WITH_GHOST_WAYLAND_APP_ID})
endif()

View File

@ -61,6 +61,10 @@
#include <tablet-unstable-v2-client-protocol.h>
#include <xdg-activation-v1-client-protocol.h>
#include <xdg-output-unstable-v1-client-protocol.h>
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
# include <fractional-scale-v1-client-protocol.h>
# include <viewporter-client-protocol.h>
#endif
/* Decorations `xdg_decor`. */
#include <xdg-decoration-unstable-v1-client-protocol.h>
@ -944,6 +948,10 @@ struct GWL_Display {
struct zwp_relative_pointer_manager_v1 *wp_relative_pointer_manager = nullptr;
struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr;
struct xdg_activation_v1 *xdg_activation_manager = nullptr;
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager = nullptr;
struct wp_viewporter *wp_viewporter = nullptr;
#endif
struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr;
struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr;
@ -3006,19 +3014,6 @@ static void gesture_pinch_handle_begin(void *data,
if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
win = ghost_wl_surface_user_data(wl_surface_focus);
}
/* NOTE(@ideasman42): Blender's use of track-pad coordinates is inconsistent and needs work.
* This isn't specific to WAYLAND, in practice they tend to work well enough in most cases.
* Some operators scale by the UI scale, some don't.
* Even this window scale is not correct because it doesn't account for:
* 1) Fractional window scale.
* 2) Blender's UI scale preference (which GHOST doesn't know about).
*
* If support for this were all that was needed it could be handled in GHOST,
* however as the operators are not even using coordinates compatible with each other,
* it would be better to resolve this by passing rotation & zoom levels directly,
* instead of attempting to handle them as cursor coordinates.
*/
const wl_fixed_t win_scale = win ? win->scale() : 1;
/* NOTE(@ideasman42): Scale factors match Blender's operators & default preferences.
* For these values to work correctly, operator logic will need to be changed not to scale input
@ -3033,10 +3028,30 @@ static void gesture_pinch_handle_begin(void *data,
seat->pointer_gesture_pinch.scale.value = wl_fixed_from_int(1);
/* The value 300 matches a value used in clip & image zoom operators.
* It seems OK for the 3D view too. */
seat->pointer_gesture_pinch.scale.factor = 300 * win_scale;
seat->pointer_gesture_pinch.scale.factor = 300;
/* The value 5 is used on macOS and roughly maps 1:1 with turntable rotation,
* although preferences can scale the sensitivity (which would be skipped ideally). */
seat->pointer_gesture_pinch.rotation.factor = 5 * win_scale;
seat->pointer_gesture_pinch.rotation.factor = 5;
if (win) {
/* NOTE(@ideasman42): Blender's use of track-pad coordinates is inconsistent and needs work.
* This isn't specific to WAYLAND, in practice they tend to work well enough in most cases.
* Some operators scale by the UI scale, some don't.
* Even this window scale is not correct because it doesn't account for:
* 1) Fractional window scale.
* 2) Blender's UI scale preference (which GHOST doesn't know about).
*
* If support for this were all that was needed it could be handled in GHOST,
* however as the operators are not even using coordinates compatible with each other,
* it would be better to resolve this by passing rotation & zoom levels directly,
* instead of attempting to handle them as cursor coordinates.
*/
const struct GWL_WindowScaleParams &scale_params = win->scale_params();
seat->pointer_gesture_pinch.scale.factor = gwl_window_scale_int_to(
scale_params, seat->pointer_gesture_pinch.scale.factor);
seat->pointer_gesture_pinch.rotation.factor = gwl_window_scale_int_to(
scale_params, seat->pointer_gesture_pinch.rotation.factor);
}
}
static void gesture_pinch_handle_update(void *data,
@ -5167,6 +5182,47 @@ static void gwl_registry_xdg_activation_remove(GWL_Display *display,
*value_p = nullptr;
}
/* #GWL_Display.wp_fractional_scale_manger */
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
static void gwl_registry_wp_fractional_scale_manager_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wp_fractional_scale_manager = static_cast<wp_fractional_scale_manager_v1 *>(
wl_registry_bind(
display->wl_registry, params->name, &wp_fractional_scale_manager_v1_interface, 1));
gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_fractional_scale_manager_remove(GWL_Display *display,
void * /*user_data*/,
const bool /*on_exit*/)
{
struct wp_fractional_scale_manager_v1 **value_p = &display->wp_fractional_scale_manager;
wp_fractional_scale_manager_v1_destroy(*value_p);
*value_p = nullptr;
}
/* #GWL_Display.wl_viewport */
static void gwl_registry_wp_viewporter_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wp_viewporter = static_cast<wp_viewporter *>(
wl_registry_bind(display->wl_registry, params->name, &wp_viewporter_interface, 1));
gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_viewporter_remove(GWL_Display *display,
void * /*user_data*/,
const bool /*on_exit*/)
{
struct wp_viewporter **value_p = &display->wp_viewporter;
wp_viewporter_destroy(*value_p);
*value_p = nullptr;
}
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
/* #GWL_Display.wp_primary_selection_device_manager */
static void gwl_registry_wp_primary_selection_device_manager_add(
@ -5276,6 +5332,20 @@ static const GWL_RegistryHandler gwl_registry_handlers[] = {
/*update_fn*/ nullptr,
/*remove_fn*/ gwl_registry_xdg_activation_remove,
},
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
{
/*interface_p*/ &wp_fractional_scale_manager_v1_interface.name,
/*add_fn*/ gwl_registry_wp_fractional_scale_manager_add,
/*update_fn*/ nullptr,
/*remove_fn*/ gwl_registry_wp_fractional_scale_manager_remove,
},
{
/*interface_p*/ &wp_viewporter_interface.name,
/*add_fn*/ gwl_registry_wp_viewporter_add,
/*update_fn*/ nullptr,
/*remove_fn*/ gwl_registry_wp_viewporter_remove,
},
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
/* Display outputs. */
{
/*interface_p*/ &wl_output_interface.name,
@ -6840,6 +6910,17 @@ struct xdg_activation_v1 *GHOST_SystemWayland::xdg_activation_manager()
return display_->xdg_activation_manager;
}
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
struct wp_fractional_scale_manager_v1 *GHOST_SystemWayland::wp_fractional_scale_manager()
{
return display_->wp_fractional_scale_manager;
}
struct wp_viewporter *GHOST_SystemWayland::wp_viewporter()
{
return display_->wp_viewporter;
}
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
struct zwp_pointer_gestures_v1 *GHOST_SystemWayland::wp_pointer_gestures()
{
return display_->wp_pointer_gestures;
@ -7055,7 +7136,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
const GHOST_Rect *wrap_bounds,
const GHOST_TAxisFlag wrap_axis,
wl_surface *wl_surface,
const int scale)
const struct GWL_WindowScaleParams &scale_params)
{
/* Caller must lock `server_mutex`. */
@ -7115,10 +7196,14 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
GHOST_Rect bounds_scale;
bounds_scale.m_l = wl_fixed_from_int(wrap_bounds->m_l) / scale;
bounds_scale.m_t = wl_fixed_from_int(wrap_bounds->m_t) / scale;
bounds_scale.m_r = wl_fixed_from_int(wrap_bounds->m_r) / scale;
bounds_scale.m_b = wl_fixed_from_int(wrap_bounds->m_b) / scale;
bounds_scale.m_l = gwl_window_scale_wl_fixed_from(scale_params,
wl_fixed_from_int(wrap_bounds->m_l));
bounds_scale.m_t = gwl_window_scale_wl_fixed_from(scale_params,
wl_fixed_from_int(wrap_bounds->m_t));
bounds_scale.m_r = gwl_window_scale_wl_fixed_from(scale_params,
wl_fixed_from_int(wrap_bounds->m_r));
bounds_scale.m_b = gwl_window_scale_wl_fixed_from(scale_params,
wl_fixed_from_int(wrap_bounds->m_b));
bounds_scale.wrapPoint(UNPACK2(xy_next), 0, wrap_axis);
@ -7138,8 +7223,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
if ((init_grab_xy[0] != seat->grab_lock_xy[0]) ||
(init_grab_xy[1] != seat->grab_lock_xy[1])) {
const wl_fixed_t xy_next[2] = {
wl_fixed_from_int(init_grab_xy[0]) / scale,
wl_fixed_from_int(init_grab_xy[1]) / scale,
gwl_window_scale_wl_fixed_from(scale_params, wl_fixed_from_int(init_grab_xy[0])),
gwl_window_scale_wl_fixed_from(scale_params, wl_fixed_from_int(init_grab_xy[1])),
};
zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer,
UNPACK2(xy_next));
@ -7164,13 +7249,13 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
#endif
if (xy_motion_create_event) {
seat->system->pushEvent_maybe_pending(
new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
ghost_wl_surface_user_data(wl_surface),
wl_fixed_to_int(scale * xy_motion[0]),
wl_fixed_to_int(scale * xy_motion[1]),
GHOST_TABLET_DATA_NONE));
seat->system->pushEvent_maybe_pending(new GHOST_EventCursor(
seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
ghost_wl_surface_user_data(wl_surface),
wl_fixed_to_int(gwl_window_scale_wl_fixed_to(scale_params, xy_motion[0])),
wl_fixed_to_int(gwl_window_scale_wl_fixed_to(scale_params, xy_motion[1])),
GHOST_TABLET_DATA_NONE));
}
zwp_locked_pointer_v1_destroy(seat->wp_locked_pointer);
@ -7206,8 +7291,10 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
if (mode == GHOST_kGrabHide) {
/* Set the initial position to detect any changes when un-grabbing,
* otherwise the unlocked cursor defaults to un-locking in-place. */
init_grab_xy[0] = wl_fixed_to_int(scale * seat->pointer.xy[0]);
init_grab_xy[1] = wl_fixed_to_int(scale * seat->pointer.xy[1]);
init_grab_xy[0] = wl_fixed_to_int(
gwl_window_scale_wl_fixed_to(scale_params, seat->pointer.xy[0]));
init_grab_xy[1] = wl_fixed_to_int(
gwl_window_scale_wl_fixed_to(scale_params, seat->pointer.xy[1]));
seat->grab_lock_xy[0] = init_grab_xy[0];
seat->grab_lock_xy[1] = init_grab_xy[1];
}

View File

@ -47,6 +47,26 @@ void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *surface);
bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *surface);
void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface);
/* Scaling to: translates from WAYLAND into GHOST (viewport local) coordinates.
* Scaling from: performs the reverse translation.
*
* Scaling "to" is used to map WAYLAND location cursor coordinates to GHOST coordinates.
* Scaling "from" is used to clamp cursor coordinates in WAYLAND local coordinates. */
struct GWL_WindowScaleParams;
wl_fixed_t gwl_window_scale_wl_fixed_to(const GWL_WindowScaleParams &scale_params,
wl_fixed_t value);
wl_fixed_t gwl_window_scale_wl_fixed_from(const GWL_WindowScaleParams &scale_params,
wl_fixed_t value);
/* Avoid this where possible as scaling integers often incurs rounding errors.
* Scale #wl_fixed_t where possible.
*
* In general scale by large values where this is less likely to be a problem. */
int gwl_window_scale_int_to(const GWL_WindowScaleParams &scale_params, int value);
int gwl_window_scale_int_from(const GWL_WindowScaleParams &scale_params, int value);
#ifdef WITH_GHOST_WAYLAND_DYNLOAD
/**
* Return true when all required WAYLAND libraries are present,
@ -181,6 +201,10 @@ class GHOST_SystemWayland : public GHOST_System {
struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_manager();
struct xdg_activation_v1 *xdg_activation_manager();
struct zwp_pointer_gestures_v1 *wp_pointer_gestures();
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager();
struct wp_viewporter *wp_viewporter();
#endif
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
libdecor *libdecor_context();
@ -234,7 +258,7 @@ class GHOST_SystemWayland : public GHOST_System {
const GHOST_Rect *wrap_bounds,
GHOST_TAxisFlag wrap_axis,
wl_surface *wl_surface,
int scale);
const struct GWL_WindowScaleParams &scale_params);
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
static bool use_libdecor_runtime();

View File

@ -38,6 +38,11 @@
#include <xdg-activation-v1-client-protocol.h>
#include <xdg-decoration-unstable-v1-client-protocol.h>
#include <xdg-shell-client-protocol.h>
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
# include <fractional-scale-v1-client-protocol.h>
# include <viewporter-client-protocol.h>
# define FRACTIONAL_DENOMINATOR 120
#endif
#include <atomic>
@ -83,6 +88,52 @@ static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
delete decor;
}
/* -------------------------------------------------------------------- */
/** \name Window-Viewport/Wayland to/from Scale Conversion
* \{ */
struct GWL_WindowScaleParams {
bool is_fractional = false;
/**
* When fractional:
* Scale is multiplied by #FRACTIONAL_DENOMINATOR.
* Otherwise scale is an integer.
*/
wl_fixed_t scale = 0;
};
wl_fixed_t gwl_window_scale_wl_fixed_to(const GWL_WindowScaleParams &scale_params,
wl_fixed_t value)
{
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (scale_params.is_fractional) {
return (value * scale_params.scale) / FRACTIONAL_DENOMINATOR;
}
#endif
return value * scale_params.scale;
}
wl_fixed_t gwl_window_scale_wl_fixed_from(const GWL_WindowScaleParams &scale_params,
wl_fixed_t value)
{
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (scale_params.is_fractional) {
return (value * FRACTIONAL_DENOMINATOR) / scale_params.scale;
}
#endif
return value / scale_params.scale;
}
int gwl_window_scale_int_to(const GWL_WindowScaleParams &scale_params, int value)
{
return wl_fixed_to_int(gwl_window_scale_wl_fixed_to(scale_params, wl_fixed_from_int(value)));
}
int gwl_window_scale_int_from(const GWL_WindowScaleParams &scale_params, int value)
{
return wl_fixed_to_int(gwl_window_scale_wl_fixed_from(scale_params, wl_fixed_from_int(value)));
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Internal #GWL_Window
* \{ */
@ -111,10 +162,18 @@ enum eGWL_PendingWindowActions {
#endif /* USE_EVENT_BACKGROUND_THREAD */
struct GWL_WindowFrame {
/**
* The frame size (in GHOST window coordinates).
*
* These must be converted to WAYLADN relative coordinates when the window is scaled
* by Hi-DPI/fractional scaling.
*/
int32_t size[2] = {0, 0};
bool is_maximised = false;
bool is_fullscreen = false;
bool is_active = false;
/** Disable when the fractional scale is a whole number. */
int fractional_scale = 0;
};
struct GWL_Window {
@ -132,14 +191,20 @@ struct GWL_Window {
/** The scale value written to #wl_surface_set_buffer_scale. */
int scale = 0;
/**
* The fractional scale used to calculate the DPI.
* (always set, even when scaling is rounded to whole units).
* The scale value to be used in the case fractional scale is disable.
* In general this should only be used when changing states
* (when disabling fractional scale).
*/
wl_fixed_t scale_fractional = 0;
int scale_on_output = 0;
/** A temporary token used for the window to be notified of it's activation. */
struct xdg_activation_token_v1 *xdg_activation_token = nullptr;
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
struct wp_viewport *viewport = nullptr;
struct wp_fractional_scale_v1 *fractional_scale_handle = nullptr;
#endif
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
WGL_LibDecor_Window *libdecor = nullptr;
#endif
@ -166,6 +231,9 @@ struct GWL_Window {
bool is_dialog = false;
/** Currently only initialized on access (avoids allocations & allows to keep private). */
GWL_WindowScaleParams scale_params;
#ifdef USE_EVENT_BACKGROUND_THREAD
/**
* These pending actions can't be performed when WAYLAND handlers are running from a thread.
@ -310,6 +378,124 @@ static bool gwl_window_state_set(GWL_Window *win, const GHOST_TWindowState state
/** \} */
/* -------------------------------------------------------------------- */
/** \name Internal #GWL_Window Viewport Setup/Teardown
*
* A viewport is needed to implement fractional scale,
* as the outputs scale may change at runtime, support creating & clearing the viewport as needed.
* \{ */
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
/**
* Scale a value from a viewport value to Wayland windowing.
* Scale down or not at all.
*/
static int gwl_window_fractional_to_viewport(const GWL_WindowFrame &frame, int value)
{
GHOST_ASSERT(frame.fractional_scale != 0, "Not fractional or called before initiazlized!");
return (value * frame.fractional_scale) / FRACTIONAL_DENOMINATOR;
}
/**
* Scale a value from a Wayland windowing value to the viewport.
* Scales up or not at all.
*/
static int gwl_window_fractional_from_viewport(const GWL_WindowFrame &frame, int value)
{
GHOST_ASSERT(frame.fractional_scale != 0, "Not fractional or called before initiazlized!");
return (value * FRACTIONAL_DENOMINATOR) / frame.fractional_scale;
}
/* NOTE: rounded versions are needed for window-frame dimensions conversions.
* (rounding is part of the WAYLAND spec). All other conversions such as cursor coordinates
* can used simple integer division as rounding is not defined in this case. */
static int gwl_window_fractional_to_viewport_round(const GWL_WindowFrame &frame, int value)
{
GHOST_ASSERT(frame.fractional_scale != 0, "Not fractional or called before initiazlized!");
return lroundf(double(value * frame.fractional_scale) / double(FRACTIONAL_DENOMINATOR));
}
static int gwl_window_fractional_from_viewport_round(const GWL_WindowFrame &frame, int value)
{
GHOST_ASSERT(frame.fractional_scale != 0, "Not fractional or called before initiazlized!");
return lroundf(double(value * FRACTIONAL_DENOMINATOR) / double(frame.fractional_scale));
}
static bool gwl_window_viewport_set(GWL_Window *win, bool *r_surface_needs_commit)
{
if (win->viewport != nullptr) {
return false;
}
struct wp_viewporter *viewporter = win->ghost_system->wp_viewporter();
if (viewporter == nullptr) {
return false;
}
win->viewport = wp_viewporter_get_viewport(viewporter, win->wl_surface);
if (win->viewport == nullptr) {
return false;
}
/* Set the buffer scale to 1 since a viewport will be used. */
if (win->scale != 1) {
win->scale = 1;
wl_surface_set_buffer_scale(win->wl_surface, win->scale);
if (r_surface_needs_commit) {
*r_surface_needs_commit = true;
}
else {
wl_surface_commit(win->wl_surface);
}
}
return true;
}
static bool gwl_window_viewport_unset(GWL_Window *win, bool *r_surface_needs_commit)
{
if (win->viewport == nullptr) {
return false;
}
wp_viewport_destroy(win->viewport);
win->viewport = nullptr;
GHOST_ASSERT(win->scale == 1, "Unexpected scale!");
if (win->scale != win->scale_on_output) {
win->scale = win->scale_on_output;
wl_surface_set_buffer_scale(win->wl_surface, win->scale);
if (r_surface_needs_commit) {
*r_surface_needs_commit = true;
}
else {
wl_surface_commit(win->wl_surface);
}
}
return true;
}
static bool gwl_window_viewport_size_update(GWL_Window *win)
{
if (win->viewport == nullptr) {
return false;
}
wp_viewport_set_source(win->viewport,
wl_fixed_from_int(0),
wl_fixed_from_int(0),
wl_fixed_from_int(win->frame.size[0]),
wl_fixed_from_int(win->frame.size[1]));
wp_viewport_set_destination(
win->viewport,
gwl_window_fractional_from_viewport_round(win->frame, win->frame.size[0]),
gwl_window_fractional_from_viewport_round(win->frame, win->frame.size[1]));
return true;
}
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
/** \} */
/* -------------------------------------------------------------------- */
/** \name Internal #GWL_Window Activation
* \{ */
@ -369,7 +555,26 @@ static void gwl_window_activate(GWL_Window *win)
/** \name Internal #GWL_Window Pending Actions
* \{ */
static void gwl_window_frame_pending_size_set(GWL_Window *win)
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
static void gwl_window_frame_pending_fractional_scale_set(GWL_Window *win,
bool *r_surface_needs_commit)
{
if (win->frame_pending.fractional_scale == win->frame.fractional_scale) {
return;
}
win->frame.fractional_scale = win->frame_pending.fractional_scale;
if (win->frame_pending.fractional_scale) {
gwl_window_viewport_set(win, r_surface_needs_commit);
gwl_window_viewport_size_update(win);
}
else {
gwl_window_viewport_unset(win, r_surface_needs_commit);
}
}
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
static void gwl_window_frame_pending_size_set(GWL_Window *win, bool *r_surface_needs_commit)
{
if (win->frame_pending.size[0] == 0 || win->frame_pending.size[1] == 0) {
return;
@ -378,7 +583,19 @@ static void gwl_window_frame_pending_size_set(GWL_Window *win)
win->frame.size[0] = win->frame_pending.size[0];
win->frame.size[1] = win->frame_pending.size[1];
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (win->frame_pending.fractional_scale != win->frame.fractional_scale) {
gwl_window_frame_pending_fractional_scale_set(win, r_surface_needs_commit);
}
else {
gwl_window_viewport_size_update(win);
}
#else
(void)r_surface_needs_commit;
#endif
wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0);
win->ghost_window->notify_size();
win->frame_pending.size[0] = 0;
@ -401,6 +618,9 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
gwl_window_frame_update_from_pending(win);
}
if (win->pending_actions[PENDING_EGL_WINDOW_RESIZE].exchange(false)) {
# ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
gwl_window_viewport_size_update(win);
# endif
wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0);
}
# ifdef GHOST_OPENGL_ALPHA
@ -427,13 +647,32 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
#endif
const bool dpi_changed = win->frame_pending.fractional_scale != win->frame.fractional_scale;
bool surface_needs_commit = false;
if (win->frame_pending.size[0] != 0 && win->frame_pending.size[1] != 0) {
if ((win->frame.size[0] != win->frame_pending.size[0]) ||
(win->frame.size[1] != win->frame_pending.size[1])) {
gwl_window_frame_pending_size_set(win);
gwl_window_frame_pending_size_set(win, &surface_needs_commit);
}
}
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (win->frame_pending.fractional_scale != win->frame.fractional_scale) {
gwl_window_frame_pending_fractional_scale_set(win, &surface_needs_commit);
}
#endif
if (surface_needs_commit) {
wl_surface_commit(win->wl_surface);
}
if (dpi_changed) {
GHOST_SystemWayland *system = win->ghost_system;
system->pushEvent(new GHOST_Event(
system->getMilliSeconds(), GHOST_kEventWindowDPIHintChanged, win->ghost_window));
}
if (win->frame_pending.is_active) {
win->ghost_window->activate();
}
@ -476,26 +715,11 @@ static int output_scale_cmp(const GWL_Output *output_a, const GWL_Output *output
if (output_a->scale > output_b->scale) {
return 1;
}
if (output_a->has_scale_fractional || output_b->has_scale_fractional) {
const wl_fixed_t scale_fractional_a = output_a->has_scale_fractional ?
output_a->scale_fractional :
wl_fixed_from_int(output_a->scale);
const wl_fixed_t scale_fractional_b = output_b->has_scale_fractional ?
output_b->scale_fractional :
wl_fixed_from_int(output_b->scale);
if (scale_fractional_a < scale_fractional_b) {
return -1;
}
if (scale_fractional_a > scale_fractional_b) {
return 1;
}
}
return 0;
}
static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs,
const int32_t scale_default,
wl_fixed_t *r_scale_fractional)
const int32_t scale_default)
{
const GWL_Output *output_max = nullptr;
for (const GWL_Output *reg_output : outputs) {
@ -505,17 +729,9 @@ static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs
}
if (output_max) {
if (r_scale_fractional) {
*r_scale_fractional = output_max->has_scale_fractional ?
output_max->scale_fractional :
wl_fixed_from_int(output_max->scale);
}
return output_max->scale;
}
if (r_scale_fractional) {
*r_scale_fractional = wl_fixed_from_int(scale_default);
}
return scale_default;
}
@ -543,8 +759,17 @@ static void xdg_toplevel_handle_configure(void *data,
std::lock_guard lock_frame_guard{win->frame_pending_mutex};
#endif
win->frame_pending.size[0] = win->scale * width;
win->frame_pending.size[1] = win->scale * height;
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (win->frame.fractional_scale) {
win->frame_pending.size[0] = gwl_window_fractional_to_viewport_round(win->frame, width);
win->frame_pending.size[1] = gwl_window_fractional_to_viewport_round(win->frame, height);
}
else
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
{
win->frame_pending.size[0] = width * win->scale;
win->frame_pending.size[1] = height * win->scale;
}
win->frame_pending.is_maximised = false;
win->frame_pending.is_fullscreen = false;
@ -619,6 +844,63 @@ static const struct xdg_activation_token_v1_listener *xdg_activation_listener_ge
/** \} */
/* -------------------------------------------------------------------- */
/** \name Listener (Fractional Scale), #wp_fractional_scale_manager_v1_interface
*
* Used by #gwl_window_activate.
* \{ */
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
static CLG_LogRef LOG_WL_FRACTIONAL_SCALE = {"ghost.wl.handle.fractional_scale"};
# define LOG (&LOG_WL_FRACTIONAL_SCALE)
static void wp_fractional_scale_handle_preferred_scale(
void *data, struct wp_fractional_scale_v1 * /*wp_fractional_scale_v1*/, uint preferred_scale)
{
CLOG_INFO(LOG,
2,
"preferred_scale (preferred_scale=%.6f)",
double(preferred_scale) / FRACTIONAL_DENOMINATOR);
GWL_Window *win = static_cast<GWL_Window *>(data);
const bool is_fractional = (preferred_scale % FRACTIONAL_DENOMINATOR) != 0;
/* When non-fractional, never use fractional scaling! */
win->frame_pending.fractional_scale = is_fractional ? preferred_scale : 0;
if (win->frame.fractional_scale != win->frame_pending.fractional_scale) {
/* Resize the window failing to do so results in severe flickering with a
* multi-monitor setup when multiple monitors have different scales.
*
* NOTE: some flickering is still possible even when resizing this
* happens when dragging the right hand side of the title-bar in KDE
* as expanding changed the size on the RHS, this may be up to the compositor to fix. */
const int scale_prev = win->frame.fractional_scale ?
win->frame.fractional_scale :
win->scale_on_output * FRACTIONAL_DENOMINATOR;
const int scale_next = win->frame_pending.fractional_scale ?
win->frame_pending.fractional_scale :
win->scale_on_output * FRACTIONAL_DENOMINATOR;
for (size_t i = 0; i < ARRAY_SIZE(win->frame_pending.size); i++) {
const int value = win->frame_pending.size[i] ? win->frame_pending.size[i] :
win->frame.size[i];
win->frame_pending.size[i] = lroundf(value * (double(scale_next) / double(scale_prev)));
}
gwl_window_pending_actions_tag(win, PENDING_WINDOW_FRAME_CONFIGURE);
}
}
static const struct wp_fractional_scale_v1_listener wp_fractional_scale_listener = {
/*preferred_scale*/ wp_fractional_scale_handle_preferred_scale,
};
# undef LOG
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
/** \} */
/* -------------------------------------------------------------------- */
/** \name Listener (LibDecor Frame), #libdecor_frame_interface
* \{ */
@ -643,16 +925,27 @@ static void frame_handle_configure(struct libdecor_frame *frame,
/* Set the size. */
int size_next[2];
{
const int scale = static_cast<GWL_Window *>(data)->scale;
GWL_Window *win = static_cast<GWL_Window *>(data);
const int scale = win->scale;
if (!libdecor_configuration_get_content_size(
configuration, frame, &size_next[0], &size_next[1])) {
GWL_Window *win = static_cast<GWL_Window *>(data);
size_next[0] = win->frame.size[0] / scale;
size_next[1] = win->frame.size[1] / scale;
}
frame_pending->size[0] = scale * size_next[0];
frame_pending->size[1] = scale * size_next[1];
# ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (win->frame.fractional_scale) {
win->frame_pending.size[0] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[0]);
win->frame_pending.size[1] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[1]);
}
else
# endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
{
frame_pending->size[0] = size_next[0] * scale;
frame_pending->size[1] = size_next[1] * scale;
}
}
/* Set the state. */
@ -892,7 +1185,8 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
*
* Using the maximum scale is best as it results in the window first being smaller,
* avoiding a large window flashing before it's made smaller. */
window_->scale = outputs_max_scale_or_default(system_->outputs(), 1, &window_->scale_fractional);
window_->scale = outputs_max_scale_or_default(system_->outputs(), 1);
window_->scale_on_output = window_->scale;
window_->frame.size[0] = int32_t(width);
window_->frame.size[1] = int32_t(height);
@ -915,6 +1209,17 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
window_->egl_window = wl_egl_window_create(
window_->wl_surface, int(window_->frame.size[0]), int(window_->frame.size[1]));
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
struct wp_fractional_scale_manager_v1 *fractional_scale_manager =
system->wp_fractional_scale_manager();
if (fractional_scale_manager) {
window_->fractional_scale_handle = wp_fractional_scale_manager_v1_get_fractional_scale(
fractional_scale_manager, window_->wl_surface);
wp_fractional_scale_v1_add_listener(
window_->fractional_scale_handle, &wp_fractional_scale_listener, window_);
}
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
/* NOTE: The limit is in points (not pixels) so Hi-DPI will limit to larger number of pixels.
* This has the advantage that the size limit is the same when moving the window between monitors
* with different scales set. If it was important to limit in pixels it could be re-calculated
@ -1033,13 +1338,14 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mo
}
bounds = &bounds_buf;
}
if (system_->window_cursor_grab_set(mode,
m_cursorGrab,
m_cursorGrabInitPos,
bounds,
m_cursorGrabAxis,
window_->wl_surface,
window_->scale)) {
this->scale_params())) {
return GHOST_kSuccess;
}
return GHOST_kFailure;
@ -1125,7 +1431,7 @@ GHOST_TSuccess GHOST_WindowWayland::setClientSize(const uint32_t width, const ui
window_->frame_pending.size[0] = width;
window_->frame_pending.size[1] = height;
gwl_window_frame_pending_size_set(window_);
gwl_window_frame_pending_size_set(window_, nullptr);
return GHOST_kSuccess;
}
@ -1163,6 +1469,18 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
window_->xdg_activation_token = nullptr;
}
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (window_->fractional_scale_handle) {
wp_fractional_scale_v1_destroy(window_->fractional_scale_handle);
window_->fractional_scale_handle = nullptr;
}
if (window_->viewport) {
wp_viewport_destroy(window_->viewport);
window_->viewport = nullptr;
}
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
if (use_libdecor) {
gwl_libdecor_window_destroy(window_->libdecor);
@ -1192,25 +1510,13 @@ uint16_t GHOST_WindowWayland::getDPIHint()
/* No need to lock `server_mutex`
* (`outputs_changed_update_scale` never changes values in a non-main thread). */
const wl_fixed_t scale_fractional = window_->scale_fractional;
GHOST_ASSERT(wl_fixed_from_int(window_->scale) >= scale_fractional,
"Fractional scale should always be less than the fixed scale.");
/* Using the physical DPI will cause wrong scaling of the UI
* use a multiplier for the default DPI as a workaround. */
if (wl_fixed_from_int(window_->scale) == scale_fractional || window_->scale <= 1) {
/* No fractional scaling. */
return window_->scale * base_dpi;
#ifdef WITH_GHOST_WAYLAND_FRACTIONAL_SCALE
if (window_->frame.fractional_scale) {
return gwl_window_fractional_to_viewport(window_->frame, base_dpi);
}
const int scale_ceil = window_->scale;
const int scale_floor = scale_ceil - 1;
const wl_fixed_t scale_fractional_final = wl_fixed_to_int(
scale_fractional *
/* Compensate for the buffer being rendered at `window_->scale`,
* then scaled down fractionally. */
(wl_fixed_from_int(1) + ((wl_fixed_from_int(scale_ceil) - scale_fractional) / scale_floor)));
#endif /* WITH_GHOST_WAYLAND_FRACTIONAL_SCALE */
return wl_fixed_to_int(scale_fractional_final * base_dpi);
return window_->scale * base_dpi;
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
@ -1383,18 +1689,34 @@ int GHOST_WindowWayland::scale() const
return window_->scale;
}
wl_fixed_t GHOST_WindowWayland::scale_fractional() const
const struct GWL_WindowScaleParams &GHOST_WindowWayland::scale_params() const
{
return window_->scale_fractional;
/* NOTE(@ideasman42): This could be kept initialized,