mirror of
				https://github.com/glfw/glfw.git
				synced 2025-10-26 18:12:31 +00:00 
			
		
		
		
	Wayland: Add support for fractional scaling
This adds basic support for fractional-scale-v1. Note that this introduces a potential discrepancy between window and monitor content scales.
This commit is contained in:
		
							parent
							
								
									a9cc7c7260
								
							
						
					
					
						commit
						2b3f919b60
					
				| @ -182,6 +182,7 @@ information on what to include when reporting a bug. | ||||
|    would abort (#1649) | ||||
|  - [Wayland] Added support for `glfwRequestWindowAttention` (#2287) | ||||
|  - [Wayland] Added support for `glfwFocusWindow` | ||||
|  - [Wayland] Added support for fractional scaling of window contents | ||||
|  - [Wayland] Added dynamic loading of all Wayland libraries | ||||
|  - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled | ||||
|  - [Wayland] Bugfix: `GLFW_HOVERED` was true when the cursor was over any | ||||
|  | ||||
							
								
								
									
										102
									
								
								deps/wayland/fractional-scale-v1.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								deps/wayland/fractional-scale-v1.xml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <protocol name="fractional_scale_v1"> | ||||
|   <copyright> | ||||
|     Copyright © 2022 Kenny Levinsen | ||||
| 
 | ||||
|     Permission is hereby granted, free of charge, to any person obtaining a | ||||
|     copy of this software and associated documentation files (the "Software"), | ||||
|     to deal in the Software without restriction, including without limitation | ||||
|     the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|     and/or sell copies of the Software, and to permit persons to whom the | ||||
|     Software is furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
|     The above copyright notice and this permission notice (including the next | ||||
|     paragraph) shall be included in all copies or substantial portions of the | ||||
|     Software. | ||||
| 
 | ||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
|     DEALINGS IN THE SOFTWARE. | ||||
|   </copyright> | ||||
| 
 | ||||
|   <description summary="Protocol for requesting fractional surface scales"> | ||||
|     This protocol allows a compositor to suggest for surfaces to render at | ||||
|     fractional scales. | ||||
| 
 | ||||
|     A client can submit scaled content by utilizing wp_viewport. This is done by | ||||
|     creating a wp_viewport object for the surface and setting the destination | ||||
|     rectangle to the surface size before the scale factor is applied. | ||||
| 
 | ||||
|     The buffer size is calculated by multiplying the surface size by the | ||||
|     intended scale. | ||||
| 
 | ||||
|     The wl_surface buffer scale should remain set to 1. | ||||
| 
 | ||||
|     If a surface has a surface-local size of 100 px by 50 px and wishes to | ||||
|     submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should | ||||
|     be used and the wp_viewport destination rectangle should be 100 px by 50 px. | ||||
| 
 | ||||
|     For toplevel surfaces, the size is rounded halfway away from zero. The | ||||
|     rounding algorithm for subsurface position and size is not defined. | ||||
|   </description> | ||||
| 
 | ||||
|   <interface name="wp_fractional_scale_manager_v1" version="1"> | ||||
|     <description summary="fractional surface scale information"> | ||||
|       A global interface for requesting surfaces to use fractional scales. | ||||
|     </description> | ||||
| 
 | ||||
|     <request name="destroy" type="destructor"> | ||||
|       <description summary="unbind the fractional surface scale interface"> | ||||
|         Informs the server that the client will not be using this protocol | ||||
|         object anymore. This does not affect any other objects, | ||||
|         wp_fractional_scale_v1 objects included. | ||||
|       </description> | ||||
|     </request> | ||||
| 
 | ||||
|     <enum name="error"> | ||||
|       <entry name="fractional_scale_exists" value="0" | ||||
|         summary="the surface already has a fractional_scale object associated"/> | ||||
|     </enum> | ||||
| 
 | ||||
|     <request name="get_fractional_scale"> | ||||
|       <description summary="extend surface interface for scale information"> | ||||
|         Create an add-on object for the the wl_surface to let the compositor | ||||
|         request fractional scales. If the given wl_surface already has a | ||||
|         wp_fractional_scale_v1 object associated, the fractional_scale_exists | ||||
|         protocol error is raised. | ||||
|       </description> | ||||
|       <arg name="id" type="new_id" interface="wp_fractional_scale_v1" | ||||
|            summary="the new surface scale info interface id"/> | ||||
|       <arg name="surface" type="object" interface="wl_surface" | ||||
|            summary="the surface"/> | ||||
|     </request> | ||||
|   </interface> | ||||
| 
 | ||||
|   <interface name="wp_fractional_scale_v1" version="1"> | ||||
|     <description summary="fractional scale interface to a wl_surface"> | ||||
|       An additional interface to a wl_surface object which allows the compositor | ||||
|       to inform the client of the preferred scale. | ||||
|     </description> | ||||
| 
 | ||||
|     <request name="destroy" type="destructor"> | ||||
|       <description summary="remove surface scale information for surface"> | ||||
|         Destroy the fractional scale object. When this object is destroyed, | ||||
|         preferred_scale events will no longer be sent. | ||||
|       </description> | ||||
|     </request> | ||||
| 
 | ||||
|     <event name="preferred_scale"> | ||||
|       <description summary="notify of new preferred scale"> | ||||
|         Notification of a new preferred scale for this surface that the | ||||
|         compositor suggests that the client should use. | ||||
| 
 | ||||
|         The sent scale is the numerator of a fraction with a denominator of 120. | ||||
|       </description> | ||||
|       <arg name="scale" type="uint" summary="the new preferred scale"/> | ||||
|     </event> | ||||
|   </interface> | ||||
| </protocol> | ||||
| @ -150,6 +150,14 @@ window focus and attention requests do nothing. | ||||
| 
 | ||||
| [xdg-activation-v1]: https://wayland.app/protocols/xdg-activation-v1 | ||||
| 
 | ||||
| GLFW uses the [fractional-scale-v1][] protocol to implement fine-grained | ||||
| framebuffer scaling.  If the running compositor does not support this protocol, | ||||
| the @ref GLFW_SCALE_FRAMEBUFFER window hint will only be able to scale the | ||||
| framebuffer by integer scales.  This will typically be the smallest integer not | ||||
| less than the actual scale. | ||||
| 
 | ||||
| [fractional-scale-v1]: https://wayland.app/protocols/fractional-scale-v1 | ||||
| 
 | ||||
| 
 | ||||
| ## GLX extensions {#compat_glx} | ||||
| 
 | ||||
|  | ||||
| @ -2705,6 +2705,9 @@ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* | ||||
|  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref | ||||
|  *  GLFW_PLATFORM_ERROR. | ||||
|  * | ||||
|  *  @remark @wayland Fractional scaling information is not yet available for | ||||
|  *  monitors, so this function only returns integer content scales. | ||||
|  * | ||||
|  *  @thread_safety This function must only be called from the main thread. | ||||
|  * | ||||
|  *  @sa @ref monitor_scale | ||||
|  | ||||
| @ -101,6 +101,7 @@ if (GLFW_BUILD_WAYLAND) | ||||
|     generate_wayland_protocol("idle-inhibit-unstable-v1.xml") | ||||
|     generate_wayland_protocol("pointer-constraints-unstable-v1.xml") | ||||
|     generate_wayland_protocol("relative-pointer-unstable-v1.xml") | ||||
|     generate_wayland_protocol("fractional-scale-v1.xml") | ||||
|     generate_wayland_protocol("xdg-activation-v1.xml") | ||||
|     generate_wayland_protocol("xdg-decoration-unstable-v1.xml") | ||||
| endif() | ||||
|  | ||||
| @ -46,6 +46,7 @@ | ||||
| #include "viewporter-client-protocol.h" | ||||
| #include "relative-pointer-unstable-v1-client-protocol.h" | ||||
| #include "pointer-constraints-unstable-v1-client-protocol.h" | ||||
| #include "fractional-scale-v1-client-protocol.h" | ||||
| #include "xdg-activation-v1-client-protocol.h" | ||||
| #include "idle-inhibit-unstable-v1-client-protocol.h" | ||||
| 
 | ||||
| @ -78,6 +79,10 @@ | ||||
| #include "pointer-constraints-unstable-v1-client-protocol-code.h" | ||||
| #undef types | ||||
| 
 | ||||
| #define types _glfw_fractional_scale_types | ||||
| #include "fractional-scale-v1-client-protocol-code.h" | ||||
| #undef types | ||||
| 
 | ||||
| #define types _glfw_xdg_activation_types | ||||
| #include "xdg-activation-v1-client-protocol-code.h" | ||||
| #undef types | ||||
| @ -189,6 +194,13 @@ static void registryHandleGlobal(void* userData, | ||||
|                              &xdg_activation_v1_interface, | ||||
|                              1); | ||||
|     } | ||||
|     else if (strcmp(interface, "wp_fractional_scale_manager_v1") == 0) | ||||
|     { | ||||
|         _glfw.wl.fractionalScaleManager = | ||||
|             wl_registry_bind(registry, name, | ||||
|                              &wp_fractional_scale_manager_v1_interface, | ||||
|                              1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void registryHandleGlobalRemove(void* userData, | ||||
| @ -969,6 +981,8 @@ void _glfwTerminateWayland(void) | ||||
|         zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); | ||||
|     if (_glfw.wl.activationManager) | ||||
|         xdg_activation_v1_destroy(_glfw.wl.activationManager); | ||||
|     if (_glfw.wl.fractionalScaleManager) | ||||
|         wp_fractional_scale_manager_v1_destroy(_glfw.wl.fractionalScaleManager); | ||||
|     if (_glfw.wl.registry) | ||||
|         wl_registry_destroy(_glfw.wl.registry); | ||||
|     if (_glfw.wl.display) | ||||
|  | ||||
| @ -131,6 +131,8 @@ struct wl_output; | ||||
| #define xdg_wm_base_interface _glfw_xdg_wm_base_interface | ||||
| #define xdg_activation_v1_interface _glfw_xdg_activation_v1_interface | ||||
| #define xdg_activation_token_v1_interface _glfw_xdg_activation_token_v1_interface | ||||
| #define wl_surface_interface _glfw_wl_surface_interface | ||||
| #define wp_fractional_scale_v1_interface _glfw_wp_fractional_scale_v1_interface | ||||
| 
 | ||||
| #define GLFW_WAYLAND_WINDOW_STATE         _GLFWwindowWayland  wl; | ||||
| #define GLFW_WAYLAND_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl; | ||||
| @ -395,6 +397,10 @@ typedef struct _GLFWwindowWayland | ||||
|     size_t                      outputScaleCount; | ||||
|     size_t                      outputScaleSize; | ||||
| 
 | ||||
|     struct wp_viewport*             scalingViewport; | ||||
|     uint32_t                        scalingNumerator; | ||||
|     struct wp_fractional_scale_v1*  fractionalScale; | ||||
| 
 | ||||
|     struct zwp_relative_pointer_v1* relativePointer; | ||||
|     struct zwp_locked_pointer_v1*   lockedPointer; | ||||
|     struct zwp_confined_pointer_v1* confinedPointer; | ||||
| @ -431,6 +437,7 @@ typedef struct _GLFWlibraryWayland | ||||
|     struct zwp_pointer_constraints_v1*      pointerConstraints; | ||||
|     struct zwp_idle_inhibit_manager_v1*     idleInhibitManager; | ||||
|     struct xdg_activation_v1*               activationManager; | ||||
|     struct wp_fractional_scale_manager_v1*  fractionalScaleManager; | ||||
| 
 | ||||
|     _GLFWofferWayland*          offers; | ||||
|     unsigned int                offerCount; | ||||
|  | ||||
| @ -50,6 +50,7 @@ | ||||
| #include "pointer-constraints-unstable-v1-client-protocol.h" | ||||
| #include "xdg-activation-v1-client-protocol.h" | ||||
| #include "idle-inhibit-unstable-v1-client-protocol.h" | ||||
| #include "fractional-scale-v1-client-protocol.h" | ||||
| 
 | ||||
| #define GLFW_BORDER_SIZE    4 | ||||
| #define GLFW_CAPTION_HEIGHT 24 | ||||
| @ -312,8 +313,16 @@ static void setContentAreaOpaque(_GLFWwindow* window) | ||||
| 
 | ||||
| static void resizeFramebuffer(_GLFWwindow* window) | ||||
| { | ||||
|     window->wl.fbWidth = window->wl.width * window->wl.bufferScale; | ||||
|     window->wl.fbHeight = window->wl.height * window->wl.bufferScale; | ||||
|     if (window->wl.fractionalScale) | ||||
|     { | ||||
|         window->wl.fbWidth = (window->wl.width * window->wl.scalingNumerator) / 120; | ||||
|         window->wl.fbHeight = (window->wl.height * window->wl.scalingNumerator) / 120; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         window->wl.fbWidth = window->wl.width * window->wl.bufferScale; | ||||
|         window->wl.fbHeight = window->wl.height * window->wl.bufferScale; | ||||
|     } | ||||
| 
 | ||||
|     if (window->wl.egl.window) | ||||
|     { | ||||
| @ -333,6 +342,13 @@ static void resizeWindow(_GLFWwindow* window) | ||||
| { | ||||
|     resizeFramebuffer(window); | ||||
| 
 | ||||
|     if (window->wl.scalingViewport) | ||||
|     { | ||||
|         wp_viewport_set_destination(window->wl.scalingViewport, | ||||
|                                     window->wl.width, | ||||
|                                     window->wl.height); | ||||
|     } | ||||
| 
 | ||||
|     if (window->wl.fallback.decorations) | ||||
|     { | ||||
|         wp_viewport_set_destination(window->wl.fallback.top.viewport, | ||||
| @ -372,6 +388,10 @@ void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window) | ||||
|     if (!window->wl.scaleFramebuffer) | ||||
|         return; | ||||
| 
 | ||||
|     // When using fractional scaling, the buffer scale should remain at 1
 | ||||
|     if (window->wl.fractionalScale) | ||||
|         return; | ||||
| 
 | ||||
|     // Get the scale factor from the highest scale monitor.
 | ||||
|     int32_t maxScale = 1; | ||||
| 
 | ||||
| @ -505,6 +525,25 @@ static void releaseMonitor(_GLFWwindow* window) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void fractionalScaleHandlePreferredScale(void* userData, | ||||
|                                          struct wp_fractional_scale_v1* fractionalScale, | ||||
|                                          uint32_t numerator) | ||||
| { | ||||
|     _GLFWwindow* window = userData; | ||||
| 
 | ||||
|     window->wl.scalingNumerator = numerator; | ||||
|     _glfwInputWindowContentScale(window, numerator / 120.f, numerator / 120.f); | ||||
|     resizeFramebuffer(window); | ||||
| 
 | ||||
|     if (window->wl.visible) | ||||
|         _glfwInputWindowDamage(window); | ||||
| } | ||||
| 
 | ||||
| const struct wp_fractional_scale_v1_listener fractionalScaleListener = | ||||
| { | ||||
|     fractionalScaleHandlePreferredScale, | ||||
| }; | ||||
| 
 | ||||
| static void xdgToplevelHandleConfigure(void* userData, | ||||
|                                        struct xdg_toplevel* toplevel, | ||||
|                                        int32_t width, | ||||
| @ -980,9 +1019,11 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, | ||||
|     window->wl.height = wndconfig->height; | ||||
|     window->wl.fbWidth = wndconfig->width; | ||||
|     window->wl.fbHeight = wndconfig->height; | ||||
|     window->wl.bufferScale = 1; | ||||
|     window->wl.title = _glfw_strdup(wndconfig->title); | ||||
|     window->wl.appId = _glfw_strdup(wndconfig->wl.appId); | ||||
| 
 | ||||
|     window->wl.bufferScale = 1; | ||||
|     window->wl.scalingNumerator = 120; | ||||
|     window->wl.scaleFramebuffer = wndconfig->scaleFramebuffer; | ||||
| 
 | ||||
|     window->wl.maximized = wndconfig->maximized; | ||||
| @ -991,6 +1032,28 @@ static GLFWbool createNativeSurface(_GLFWwindow* window, | ||||
|     if (!window->wl.transparent) | ||||
|         setContentAreaOpaque(window); | ||||
| 
 | ||||
|     if (_glfw.wl.fractionalScaleManager) | ||||
|     { | ||||
|         if (window->wl.scaleFramebuffer) | ||||
|         { | ||||
|             window->wl.scalingViewport = | ||||
|                 wp_viewporter_get_viewport(_glfw.wl.viewporter, window->wl.surface); | ||||
| 
 | ||||
|             wp_viewport_set_destination(window->wl.scalingViewport, | ||||
|                                         window->wl.width, | ||||
|                                         window->wl.height); | ||||
| 
 | ||||
|             window->wl.fractionalScale = | ||||
|                 wp_fractional_scale_manager_v1_get_fractional_scale( | ||||
|                     _glfw.wl.fractionalScaleManager, | ||||
|                     window->wl.surface); | ||||
| 
 | ||||
|             wp_fractional_scale_v1_add_listener(window->wl.fractionalScale, | ||||
|                                                 &fractionalScaleListener, | ||||
|                                                 window); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return GLFW_TRUE; | ||||
| } | ||||
| 
 | ||||
| @ -2315,10 +2378,20 @@ void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window, | ||||
| void _glfwGetWindowContentScaleWayland(_GLFWwindow* window, | ||||
|                                        float* xscale, float* yscale) | ||||
| { | ||||
|     if (xscale) | ||||
|         *xscale = (float) window->wl.bufferScale; | ||||
|     if (yscale) | ||||
|         *yscale = (float) window->wl.bufferScale; | ||||
|     if (window->wl.fractionalScale) | ||||
|     { | ||||
|         if (xscale) | ||||
|             *xscale = (float) window->wl.scalingNumerator / 120.f; | ||||
|         if (yscale) | ||||
|             *yscale = (float) window->wl.scalingNumerator / 120.f; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (xscale) | ||||
|             *xscale = (float) window->wl.bufferScale; | ||||
|         if (yscale) | ||||
|             *yscale = (float) window->wl.bufferScale; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void _glfwIconifyWindowWayland(_GLFWwindow* window) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user