1 //========================================================================
2 // GLFW 3.0 X11 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
6 //
7 // This software is provided 'as-is', without any express or implied
8 // warranty. In no event will the authors be held liable for any damages
9 // arising from the use of this software.
10 //
11 // Permission is granted to anyone to use this software for any purpose,
12 // including commercial applications, and to alter it and redistribute it
13 // freely, subject to the following restrictions:
14 //
15 // 1. The origin of this software must not be misrepresented; you must not
16 // claim that you wrote the original software. If you use this software
17 // in a product, an acknowledgment in the product documentation would
18 // be appreciated but is not required.
19 //
20 // 2. Altered source versions must be plainly marked as such, and must not
21 // be misrepresented as being the original software.
22 //
23 // 3. This notice may not be removed or altered from any source
24 // distribution.
25 //
26 //========================================================================
27
28 #include "internal.h"
29
30 #include <limits.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34
calculateRefreshRate(const XRRModeInfo * mi)35 static int calculateRefreshRate(const XRRModeInfo* mi)
36 {
37 if (!mi->hTotal || !mi->vTotal)
38 return 0;
39
40 return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal));
41 }
42
getModeInfo(const XRRScreenResources * sr,RRMode id)43 static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
44 {
45 int i;
46
47 for (i = 0; i < sr->nmode; i++)
48 {
49 if (sr->modes[i].id == id)
50 return sr->modes + i;
51 }
52
53 return NULL;
54 }
55
56
57 //////////////////////////////////////////////////////////////////////////
58 ////// GLFW internal API //////
59 //////////////////////////////////////////////////////////////////////////
60
61 // Set the current video mode for the specified monitor
62 //
_glfwSetVideoMode(_GLFWmonitor * monitor,const GLFWvidmode * desired)63 void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired)
64 {
65 if (_glfw.x11.randr.available)
66 {
67 int i, j;
68 XRRScreenResources* sr;
69 XRRCrtcInfo* ci;
70 XRROutputInfo* oi;
71 RRMode bestMode = 0;
72 unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
73 unsigned int rateDiff, leastRateDiff = UINT_MAX;
74
75 sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
76 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
77 oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
78
79 for (i = 0; i < sr->nmode; i++)
80 {
81 const XRRModeInfo* mi = sr->modes + i;
82
83 if (mi->modeFlags & RR_Interlace)
84 continue;
85
86 for (j = 0; j < oi->nmode; j++)
87 {
88 if (oi->modes[j] == mi->id)
89 break;
90 }
91
92 if (j == oi->nmode)
93 continue;
94
95 sizeDiff = (mi->width - desired->width) *
96 (mi->width - desired->width) +
97 (mi->height - desired->height) *
98 (mi->height - desired->height);
99
100 if (desired->refreshRate)
101 rateDiff = abs(calculateRefreshRate(mi) - desired->refreshRate);
102 else
103 rateDiff = UINT_MAX - calculateRefreshRate(mi);
104
105 if ((sizeDiff < leastSizeDiff) ||
106 (sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
107 {
108 bestMode = mi->id;
109 leastSizeDiff = sizeDiff;
110 leastRateDiff = rateDiff;
111 }
112 }
113
114 if (monitor->x11.oldMode == None)
115 monitor->x11.oldMode = ci->mode;
116
117 XRRSetCrtcConfig(_glfw.x11.display,
118 sr, monitor->x11.crtc,
119 CurrentTime,
120 ci->x, ci->y,
121 bestMode,
122 ci->rotation,
123 ci->outputs,
124 ci->noutput);
125
126 XRRFreeOutputInfo(oi);
127 XRRFreeCrtcInfo(ci);
128 XRRFreeScreenResources(sr);
129 }
130 }
131
132 // Restore the saved (original) video mode for the specified monitor
133 //
_glfwRestoreVideoMode(_GLFWmonitor * monitor)134 void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
135 {
136 if (_glfw.x11.randr.available)
137 {
138 XRRScreenResources* sr;
139 XRRCrtcInfo* ci;
140
141 if (monitor->x11.oldMode == None)
142 return;
143
144 sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
145 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
146
147 XRRSetCrtcConfig(_glfw.x11.display,
148 sr, monitor->x11.crtc,
149 CurrentTime,
150 ci->x, ci->y,
151 monitor->x11.oldMode,
152 ci->rotation,
153 ci->outputs,
154 ci->noutput);
155
156 XRRFreeCrtcInfo(ci);
157 XRRFreeScreenResources(sr);
158
159 monitor->x11.oldMode = None;
160 }
161 }
162
163
164 //////////////////////////////////////////////////////////////////////////
165 ////// GLFW platform API //////
166 //////////////////////////////////////////////////////////////////////////
167
_glfwPlatformGetMonitors(int * count)168 _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
169 {
170 _GLFWmonitor** monitors = NULL;
171
172 *count = 0;
173
174 if (_glfw.x11.randr.available)
175 {
176 int i, found = 0;
177 RROutput primary;
178 XRRScreenResources* sr;
179
180 sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
181 primary = XRRGetOutputPrimary(_glfw.x11.display, _glfw.x11.root);
182
183 monitors = calloc(sr->ncrtc, sizeof(_GLFWmonitor*));
184
185 for (i = 0; i < sr->ncrtc; i++)
186 {
187 int j;
188 XRROutputInfo* oi;
189 XRRCrtcInfo* ci;
190 RROutput output;
191
192 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, sr->crtcs[i]);
193 if (ci->noutput == 0)
194 {
195 XRRFreeCrtcInfo(ci);
196 continue;
197 }
198
199 output = ci->outputs[0];
200
201 for (j = 0; j < ci->noutput; j++)
202 {
203 if (ci->outputs[j] == primary)
204 {
205 output = primary;
206 break;
207 }
208 }
209
210 oi = XRRGetOutputInfo(_glfw.x11.display, sr, output);
211 if (oi->connection != RR_Connected)
212 {
213 XRRFreeOutputInfo(oi);
214 XRRFreeCrtcInfo(ci);
215 continue;
216 }
217
218 monitors[found] = _glfwCreateMonitor(oi->name,
219 oi->mm_width, oi->mm_height);
220
221 monitors[found]->x11.output = output;
222 monitors[found]->x11.crtc = oi->crtc;
223
224 XRRFreeOutputInfo(oi);
225 XRRFreeCrtcInfo(ci);
226
227 found++;
228 }
229
230 XRRFreeScreenResources(sr);
231
232 for (i = 0; i < found; i++)
233 {
234 if (monitors[i]->x11.output == primary)
235 {
236 _GLFWmonitor* temp = monitors[0];
237 monitors[0] = monitors[i];
238 monitors[i] = temp;
239 break;
240 }
241 }
242
243 if (found == 0)
244 {
245 free(monitors);
246 monitors = NULL;
247 }
248
249 *count = found;
250 }
251 else
252 {
253 monitors = calloc(1, sizeof(_GLFWmonitor*));
254 monitors[0] = _glfwCreateMonitor("Display",
255 DisplayWidthMM(_glfw.x11.display,
256 _glfw.x11.screen),
257 DisplayHeightMM(_glfw.x11.display,
258 _glfw.x11.screen));
259 *count = 1;
260 }
261
262 return monitors;
263 }
264
_glfwPlatformIsSameMonitor(_GLFWmonitor * first,_GLFWmonitor * second)265 GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
266 {
267 return first->x11.crtc == second->x11.crtc;
268 }
269
_glfwPlatformGetMonitorPos(_GLFWmonitor * monitor,int * xpos,int * ypos)270 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
271 {
272 if (_glfw.x11.randr.available)
273 {
274 XRRScreenResources* sr;
275 XRRCrtcInfo* ci;
276
277 sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
278 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
279
280 if (xpos)
281 *xpos = ci->x;
282 if (ypos)
283 *ypos = ci->y;
284
285 XRRFreeCrtcInfo(ci);
286 XRRFreeScreenResources(sr);
287 }
288 else
289 {
290 if (xpos)
291 *xpos = 0;
292 if (ypos)
293 *ypos = 0;
294 }
295 }
296
_glfwPlatformGetVideoModes(_GLFWmonitor * monitor,int * found)297 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
298 {
299 GLFWvidmode* result;
300 int depth, r, g, b;
301
302 depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
303 _glfwSplitBPP(depth, &r, &g, &b);
304
305 *found = 0;
306
307 // Build array of available resolutions
308
309 if (_glfw.x11.randr.available)
310 {
311 int i, j;
312 XRRScreenResources* sr;
313 XRROutputInfo* oi;
314
315 sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
316 oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
317
318 result = calloc(oi->nmode, sizeof(GLFWvidmode));
319
320 for (i = 0; i < oi->nmode; i++)
321 {
322 GLFWvidmode mode;
323 const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
324
325 mode.width = mi->width;
326 mode.height = mi->height;
327 mode.refreshRate = calculateRefreshRate(mi);
328
329 for (j = 0; j < *found; j++)
330 {
331 if (result[j].width == mode.width &&
332 result[j].height == mode.height &&
333 result[j].refreshRate == mode.refreshRate)
334 {
335 break;
336 }
337 }
338
339 if (j < *found)
340 {
341 // This is a duplicate, so skip it
342 continue;
343 }
344
345 mode.redBits = r;
346 mode.greenBits = g;
347 mode.blueBits = b;
348
349 result[*found] = mode;
350 (*found)++;
351 }
352
353 XRRFreeOutputInfo(oi);
354 XRRFreeScreenResources(sr);
355 }
356 else
357 {
358 *found = 1;
359
360 result = calloc(1, sizeof(GLFWvidmode));
361
362 result[0].width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
363 result[0].height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
364 result[0].redBits = r;
365 result[0].greenBits = g;
366 result[0].blueBits = b;
367 result[0].refreshRate = 0;
368 }
369
370 return result;
371 }
372
_glfwPlatformGetVideoMode(_GLFWmonitor * monitor,GLFWvidmode * mode)373 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
374 {
375 if (_glfw.x11.randr.available)
376 {
377 XRRScreenResources* sr;
378 XRRCrtcInfo* ci;
379
380 sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
381 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
382
383 mode->width = ci->width;
384 mode->height = ci->height;
385
386 mode->refreshRate = calculateRefreshRate(getModeInfo(sr, ci->mode));
387
388 XRRFreeCrtcInfo(ci);
389 XRRFreeScreenResources(sr);
390 }
391 else
392 {
393 mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
394 mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
395 mode->refreshRate = 0;
396 }
397
398 _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
399 &mode->redBits, &mode->greenBits, &mode->blueBits);
400 }
401
402