Fix #106235: Use consistent order for multi-input socket links #106320
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
2
extern/fast_float/README.blender
vendored
2
extern/fast_float/README.blender
vendored
@ -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
|
||||
|
131
extern/fast_float/README.md
vendored
131
extern/fast_float/README.md
vendored
@ -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
|
||||
|
2111
extern/fast_float/fast_float.h
vendored
2111
extern/fast_float/fast_float.h
vendored
File diff suppressed because it is too large
Load Diff
@ -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()
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||