1//======================================================================== 2// GLFW 3.5 Wayland - www.glfw.org 3//------------------------------------------------------------------------ 4// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com> 5// 6// This software is provided 'as-is', without any express or implied 7// warranty. In no event will the authors be held liable for any damages 8// arising from the use of this software. 9// 10// Permission is granted to anyone to use this software for any purpose, 11// including commercial applications, and to alter it and redistribute it 12// freely, subject to the following restrictions: 13// 14// 1. The origin of this software must not be misrepresented; you must not 15// claim that you wrote the original software. If you use this software 16// in a product, an acknowledgment in the product documentation would 17// be appreciated but is not required. 18// 19// 2. Altered source versions must be plainly marked as such, and must not 20// be misrepresented as being the original software. 21// 22// 3. This notice may not be removed or altered from any source 23// distribution. 24// 25//======================================================================== 26 27#include "internal.h" 28 29#if defined(_GLFW_WAYLAND) 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#include <errno.h> 35#include <math.h> 36#include <assert.h> 37 38#include "wayland-client-protocol.h" 39 40 41static void outputHandleGeometry(void* userData, 42 struct wl_output* output, 43 int32_t x, 44 int32_t y, 45 int32_t physicalWidth, 46 int32_t physicalHeight, 47 int32_t subpixel, 48 const char* make, 49 const char* model, 50 int32_t transform) 51{ 52 struct _GLFWmonitor* monitor = userData; 53 54 monitor->wl.x = x; 55 monitor->wl.y = y; 56 monitor->widthMM = physicalWidth; 57 monitor->heightMM = physicalHeight; 58 59 if (strlen(monitor->name) == 0) 60 snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); 61} 62 63static void outputHandleMode(void* userData, 64 struct wl_output* output, 65 uint32_t flags, 66 int32_t width, 67 int32_t height, 68 int32_t refresh) 69{ 70 struct _GLFWmonitor* monitor = userData; 71 GLFWvidmode mode; 72 73 mode.width = width; 74 mode.height = height; 75 mode.redBits = 8; 76 mode.greenBits = 8; 77 mode.blueBits = 8; 78 mode.refreshRate = (int) round(refresh / 1000.0); 79 80 monitor->modeCount++; 81 monitor->modes = 82 _glfw_realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode)); 83 monitor->modes[monitor->modeCount - 1] = mode; 84 85 if (flags & WL_OUTPUT_MODE_CURRENT) 86 monitor->wl.currentMode = monitor->modeCount - 1; 87} 88 89static void outputHandleDone(void* userData, struct wl_output* output) 90{ 91 struct _GLFWmonitor* monitor = userData; 92 93 if (monitor->widthMM <= 0 || monitor->heightMM <= 0) 94 { 95 // If Wayland does not provide a physical size, assume the default 96 DPI 96 const GLFWvidmode* mode = &monitor->modes[monitor->wl.currentMode]; 97 monitor->widthMM = (int) (mode->width * 25.4f / 96.f); 98 monitor->heightMM = (int) (mode->height * 25.4f / 96.f); 99 } 100 101 for (int i = 0; i < _glfw.monitorCount; i++) 102 { 103 if (_glfw.monitors[i] == monitor) 104 return; 105 } 106 107 _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); 108} 109 110static void outputHandleScale(void* userData, 111 struct wl_output* output, 112 int32_t factor) 113{ 114 struct _GLFWmonitor* monitor = userData; 115 116 monitor->wl.scale = factor; 117 118 for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) 119 { 120 for (size_t i = 0; i < window->wl.outputScaleCount; i++) 121 { 122 if (window->wl.outputScales[i].output == monitor->wl.output) 123 { 124 window->wl.outputScales[i].factor = monitor->wl.scale; 125 _glfwUpdateBufferScaleFromOutputsWayland(window); 126 break; 127 } 128 } 129 } 130} 131 132void outputHandleName(void* userData, struct wl_output* wl_output, const char* name) 133{ 134 struct _GLFWmonitor* monitor = userData; 135 136 strncpy(monitor->name, name, sizeof(monitor->name) - 1); 137} 138 139void outputHandleDescription(void* userData, 140 struct wl_output* wl_output, 141 const char* description) 142{ 143} 144 145static const struct wl_output_listener outputListener = 146{ 147 outputHandleGeometry, 148 outputHandleMode, 149 outputHandleDone, 150 outputHandleScale, 151 outputHandleName, 152 outputHandleDescription, 153}; 154 155 156////////////////////////////////////////////////////////////////////////// 157////// GLFW internal API ////// 158////////////////////////////////////////////////////////////////////////// 159 160void _glfwAddOutputWayland(uint32_t name, uint32_t version) 161{ 162 if (version < 2) 163 { 164 _glfwInputError(GLFW_PLATFORM_ERROR, 165 "Wayland: Unsupported output interface version"); 166 return; 167 } 168 169 version = _glfw_min(version, WL_OUTPUT_NAME_SINCE_VERSION); 170 171 struct wl_output* output = wl_registry_bind(_glfw.wl.registry, 172 name, 173 &wl_output_interface, 174 version); 175 if (!output) 176 return; 177 178 // The actual name of this output will be set in the geometry handler 179 _GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0); 180 monitor->wl.scale = 1; 181 monitor->wl.output = output; 182 monitor->wl.name = name; 183 184 wl_proxy_set_tag((struct wl_proxy*) output, &_glfw.wl.tag); 185 wl_output_add_listener(output, &outputListener, monitor); 186} 187 188 189////////////////////////////////////////////////////////////////////////// 190////// GLFW platform API ////// 191////////////////////////////////////////////////////////////////////////// 192 193void _glfwFreeMonitorWayland(_GLFWmonitor* monitor) 194{ 195 if (monitor->wl.output) 196 wl_output_destroy(monitor->wl.output); 197} 198 199void _glfwGetMonitorPosWayland(_GLFWmonitor* monitor, int* xpos, int* ypos) 200{ 201 if (xpos) 202 *xpos = monitor->wl.x; 203 if (ypos) 204 *ypos = monitor->wl.y; 205} 206 207void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor, 208 float* xscale, float* yscale) 209{ 210 if (xscale) 211 *xscale = (float) monitor->wl.scale; 212 if (yscale) 213 *yscale = (float) monitor->wl.scale; 214} 215 216void _glfwGetMonitorWorkareaWayland(_GLFWmonitor* monitor, 217 int* xpos, int* ypos, 218 int* width, int* height) 219{ 220 if (xpos) 221 *xpos = monitor->wl.x; 222 if (ypos) 223 *ypos = monitor->wl.y; 224 if (width) 225 *width = monitor->modes[monitor->wl.currentMode].width; 226 if (height) 227 *height = monitor->modes[monitor->wl.currentMode].height; 228} 229 230GLFWvidmode* _glfwGetVideoModesWayland(_GLFWmonitor* monitor, int* found) 231{ 232 *found = monitor->modeCount; 233 return monitor->modes; 234} 235 236GLFWbool _glfwGetVideoModeWayland(_GLFWmonitor* monitor, GLFWvidmode* mode) 237{ 238 *mode = monitor->modes[monitor->wl.currentMode]; 239 return GLFW_TRUE; 240} 241 242GLFWbool _glfwGetGammaRampWayland(_GLFWmonitor* monitor, GLFWgammaramp* ramp) 243{ 244 _glfwInputError(GLFW_FEATURE_UNAVAILABLE, 245 "Wayland: Gamma ramp access is not available"); 246 return GLFW_FALSE; 247} 248 249void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) 250{ 251 _glfwInputError(GLFW_FEATURE_UNAVAILABLE, 252 "Wayland: Gamma ramp access is not available"); 253} 254 255 256////////////////////////////////////////////////////////////////////////// 257////// GLFW native API ////// 258////////////////////////////////////////////////////////////////////////// 259 260GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle) 261{ 262 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 263 264 if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND) 265 { 266 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Wayland: Platform not initialized"); 267 return NULL; 268 } 269 270 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 271 assert(monitor != NULL); 272 273 return monitor->wl.output; 274} 275 276#endif // _GLFW_WAYLAND 277 278