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