Style Cleanup: remove preprocessor indentation (updated wiki style guide too)
[blender.git] / intern / ghost / intern / GHOST_DisplayManagerX11.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Video mode switching
24  * Copyright (C) 1997-2001 Id Software, Inc.
25  * Ported from Quake 2 by Alex Fraser <alex@phatcore.com>
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file ghost/intern/GHOST_DisplayManagerX11.cpp
31  *  \ingroup GHOST
32  */
33
34 #ifdef WITH_X11_XF86VMODE
35 #  include <X11/Xlib.h>
36 #  include <X11/extensions/xf86vmode.h>
37 #endif
38
39 #include "GHOST_DisplayManagerX11.h"
40 #include "GHOST_SystemX11.h"
41
42
43 GHOST_DisplayManagerX11::
44 GHOST_DisplayManagerX11(
45     GHOST_SystemX11 *system
46     ) :
47         GHOST_DisplayManager(),
48         m_system(system)
49 {
50         /* nothing to do. */
51 }
52
53 GHOST_TSuccess
54 GHOST_DisplayManagerX11::
55 getNumDisplays(GHOST_TUns8& numDisplays) const
56 {
57         numDisplays =  m_system->getNumDisplays();
58         return GHOST_kSuccess;
59 }
60
61
62 GHOST_TSuccess
63 GHOST_DisplayManagerX11::
64 getNumDisplaySettings(
65                 GHOST_TUns8 display,
66                 GHOST_TInt32& numSettings) const
67 {
68 #ifdef WITH_X11_XF86VMODE
69         int majorVersion, minorVersion;
70         XF86VidModeModeInfo **vidmodes;
71         Display *dpy = m_system->getXDisplay();
72
73         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
74
75         if (dpy == NULL)
76                 return GHOST_kFailure;
77
78         majorVersion = minorVersion = 0;
79         if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
80                 fprintf(stderr, "Error: XF86VidMode extension missing!\n");
81                 return GHOST_kFailure;
82         }
83
84         if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes)) {
85                 XFree(vidmodes);
86         }
87
88 #else
89         /* We only have one X11 setting at the moment. */
90         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
91         numSettings = 1;
92 #endif
93
94         return GHOST_kSuccess;
95 }
96
97 /* from SDL2 */
98 #ifdef WITH_X11_XF86VMODE
99 static int
100 calculate_rate(XF86VidModeModeInfo *info)
101 {
102         return (info->htotal
103                 && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
104                                                              info->vtotal)) : 0;
105 }
106 #endif
107
108 GHOST_TSuccess
109 GHOST_DisplayManagerX11::
110 getDisplaySetting(
111                 GHOST_TUns8 display,
112                 GHOST_TInt32 index,
113                 GHOST_DisplaySetting& setting) const
114 {
115         Display *dpy = m_system->getXDisplay();
116
117         if (dpy == NULL)
118                 return GHOST_kFailure;
119
120 #ifdef WITH_X11_XF86VMODE
121         int majorVersion, minorVersion;
122
123         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
124
125         majorVersion = minorVersion = 0;
126         if (XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
127                 XF86VidModeModeInfo **vidmodes;
128                 int numSettings;
129
130                 if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes)) {
131                         GHOST_ASSERT(index < numSettings, "Requested setting outside of valid range.\n");
132
133                         setting.xPixels = vidmodes[index]->hdisplay;
134                         setting.yPixels = vidmodes[index]->vdisplay;
135                         setting.bpp = DefaultDepth(dpy, DefaultScreen(dpy));
136                         setting.frequency = calculate_rate(vidmodes[index]);
137                         XFree(vidmodes);
138
139                         return GHOST_kSuccess;
140                 }
141         }
142         else {
143                 fprintf(stderr, "Warning: XF86VidMode extension missing!\n");
144                 /* fallback to non xf86vmode below */
145         }
146 #endif  /* WITH_X11_XF86VMODE */
147
148         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
149         GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n");
150
151         setting.xPixels  = DisplayWidth(dpy, DefaultScreen(dpy));
152         setting.yPixels = DisplayHeight(dpy, DefaultScreen(dpy));
153         setting.bpp = DefaultDepth(dpy, DefaultScreen(dpy));
154         setting.frequency = 60.0f;
155
156         return GHOST_kSuccess;
157 }
158         
159 GHOST_TSuccess
160 GHOST_DisplayManagerX11::
161 getCurrentDisplaySetting(
162                 GHOST_TUns8 display,
163                 GHOST_DisplaySetting& setting) const
164 {
165         /* According to the xf86vidmodegetallmodelines man page,
166          * "The first element of the array corresponds to the current video mode."
167          */
168         return getDisplaySetting(display, 0, setting);
169 }
170
171
172 GHOST_TSuccess
173 GHOST_DisplayManagerX11::
174 setCurrentDisplaySetting(
175                 GHOST_TUns8 display,
176                 const GHOST_DisplaySetting& setting)
177 {
178 #ifdef WITH_X11_XF86VMODE
179         /* Mode switching code ported from SDL:
180          * See: src/video/x11/SDL_x11modes.c:set_best_resolution
181          */
182         int majorVersion, minorVersion;
183         XF86VidModeModeInfo **vidmodes;
184         Display *dpy = m_system->getXDisplay();
185         int scrnum, num_vidmodes;
186
187         if (dpy == NULL)
188                 return GHOST_kFailure;
189
190         scrnum = DefaultScreen(dpy);
191
192         /* Get video mode list */
193         majorVersion = minorVersion = 0;
194         if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
195                 fprintf(stderr, "Error: XF86VidMode extension missing!\n");
196                 return GHOST_kFailure;
197         }
198 #  ifdef _DEBUG
199         printf("Using XFree86-VidModeExtension Version %d.%d\n",
200                majorVersion, minorVersion);
201 #  endif
202
203         if (XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes)) {
204                 int best_fit = -1;
205
206                 for (int i = 0; i < num_vidmodes; i++) {
207                         if (vidmodes[i]->hdisplay < setting.xPixels ||
208                             vidmodes[i]->vdisplay < setting.yPixels)
209                         {
210                                 continue;
211                         }
212
213                         if (best_fit == -1 ||
214                             (vidmodes[i]->hdisplay < vidmodes[best_fit]->hdisplay) ||
215                             (vidmodes[i]->hdisplay == vidmodes[best_fit]->hdisplay &&
216                              vidmodes[i]->vdisplay < vidmodes[best_fit]->vdisplay))
217                         {
218                                 best_fit = i;
219                                 continue;
220                         }
221
222                         if ((vidmodes[i]->hdisplay == vidmodes[best_fit]->hdisplay) &&
223                             (vidmodes[i]->vdisplay == vidmodes[best_fit]->vdisplay))
224                         {
225                                 if (!setting.frequency) {
226                                         /* Higher is better, right? */
227                                         if (calculate_rate(vidmodes[i]) >
228                                             calculate_rate(vidmodes[best_fit]))
229                                         {
230                                                 best_fit = i;
231                                         }
232                                 }
233                                 else {
234                                         if (abs(calculate_rate(vidmodes[i]) - (int)setting.frequency) <
235                                             abs(calculate_rate(vidmodes[best_fit]) - (int)setting.frequency))
236                                         {
237                                                 best_fit = i;
238                                         }
239                                 }
240                         }
241                 }
242
243                 if (best_fit != -1) {
244 #  ifdef _DEBUG
245                         printf("Switching to video mode %dx%d %dx%d %d\n",
246                                vidmodes[best_fit]->hdisplay, vidmodes[best_fit]->vdisplay,
247                                vidmodes[best_fit]->htotal, vidmodes[best_fit]->vtotal,
248                                calculate_rate(vidmodes[best_fit]));
249 #  endif
250
251                         /* change to the mode */
252                         XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
253
254                         /* Move the viewport to top left */
255                         XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
256                 }
257
258                 XFree(vidmodes);
259         }
260         else {
261                 return GHOST_kFailure;
262         }
263
264         XFlush(dpy);
265         return GHOST_kSuccess;
266
267 #else
268         /* Just pretend the request was successful. */
269         return GHOST_kSuccess;
270 #endif
271 }