Cleanup: remove _DEBUG define usage
[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     : GHOST_DisplayManager(),
47       m_system(system)
48 {
49         /* nothing to do. */
50 }
51
52 GHOST_TSuccess
53 GHOST_DisplayManagerX11::
54 getNumDisplays(GHOST_TUns8& numDisplays) const
55 {
56         numDisplays =  m_system->getNumDisplays();
57         return GHOST_kSuccess;
58 }
59
60
61 GHOST_TSuccess
62 GHOST_DisplayManagerX11::
63 getNumDisplaySettings(
64                 GHOST_TUns8 display,
65                 GHOST_TInt32& numSettings) const
66 {
67 #ifdef WITH_X11_XF86VMODE
68         int majorVersion, minorVersion;
69         XF86VidModeModeInfo **vidmodes;
70         Display *dpy = m_system->getXDisplay();
71
72         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
73
74         if (dpy == NULL)
75                 return GHOST_kFailure;
76
77         majorVersion = minorVersion = 0;
78         if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
79                 fprintf(stderr, "Error: XF86VidMode extension missing!\n");
80                 return GHOST_kFailure;
81         }
82
83         if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes)) {
84                 XFree(vidmodes);
85         }
86
87 #else
88         /* We only have one X11 setting at the moment. */
89         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
90         numSettings = 1;
91 #endif
92
93         return GHOST_kSuccess;
94 }
95
96 /* from SDL2 */
97 #ifdef WITH_X11_XF86VMODE
98 static int
99 calculate_rate(XF86VidModeModeInfo *info)
100 {
101         return (info->htotal
102                 && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
103                                                              info->vtotal)) : 0;
104 }
105 #endif
106
107 GHOST_TSuccess
108 GHOST_DisplayManagerX11::
109 getDisplaySetting(
110                 GHOST_TUns8 display,
111                 GHOST_TInt32 index,
112                 GHOST_DisplaySetting& setting) const
113 {
114         Display *dpy = m_system->getXDisplay();
115
116         if (dpy == NULL)
117                 return GHOST_kFailure;
118
119 #ifdef WITH_X11_XF86VMODE
120         int majorVersion, minorVersion;
121
122         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
123
124         majorVersion = minorVersion = 0;
125         if (XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
126                 XF86VidModeModeInfo **vidmodes;
127                 int numSettings;
128
129                 if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes)) {
130                         GHOST_ASSERT(index < numSettings, "Requested setting outside of valid range.\n");
131
132                         setting.xPixels = vidmodes[index]->hdisplay;
133                         setting.yPixels = vidmodes[index]->vdisplay;
134                         setting.bpp = DefaultDepth(dpy, DefaultScreen(dpy));
135                         setting.frequency = calculate_rate(vidmodes[index]);
136                         XFree(vidmodes);
137
138                         return GHOST_kSuccess;
139                 }
140         }
141         else {
142                 fprintf(stderr, "Warning: XF86VidMode extension missing!\n");
143                 /* fallback to non xf86vmode below */
144         }
145 #endif  /* WITH_X11_XF86VMODE */
146
147         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
148         GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n");
149
150         setting.xPixels  = DisplayWidth(dpy, DefaultScreen(dpy));
151         setting.yPixels = DisplayHeight(dpy, DefaultScreen(dpy));
152         setting.bpp = DefaultDepth(dpy, DefaultScreen(dpy));
153         setting.frequency = 60.0f;
154
155         return GHOST_kSuccess;
156 }
157         
158 GHOST_TSuccess
159 GHOST_DisplayManagerX11::
160 getCurrentDisplaySetting(
161                 GHOST_TUns8 display,
162                 GHOST_DisplaySetting& setting) const
163 {
164         /* According to the xf86vidmodegetallmodelines man page,
165          * "The first element of the array corresponds to the current video mode."
166          */
167         return getDisplaySetting(display, 0, setting);
168 }
169
170
171 GHOST_TSuccess
172 GHOST_DisplayManagerX11::
173 setCurrentDisplaySetting(
174                 GHOST_TUns8 display,
175                 const GHOST_DisplaySetting& setting)
176 {
177 #ifdef WITH_X11_XF86VMODE
178         /* Mode switching code ported from SDL:
179          * See: src/video/x11/SDL_x11modes.c:set_best_resolution
180          */
181         int majorVersion, minorVersion;
182         XF86VidModeModeInfo **vidmodes;
183         Display *dpy = m_system->getXDisplay();
184         int scrnum, num_vidmodes;
185
186         if (dpy == NULL)
187                 return GHOST_kFailure;
188
189         scrnum = DefaultScreen(dpy);
190
191         /* Get video mode list */
192         majorVersion = minorVersion = 0;
193         if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
194                 fprintf(stderr, "Error: XF86VidMode extension missing!\n");
195                 return GHOST_kFailure;
196         }
197 #  ifdef DEBUG
198         printf("Using XFree86-VidModeExtension Version %d.%d\n",
199                majorVersion, minorVersion);
200 #  endif
201
202         if (XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes)) {
203                 int best_fit = -1;
204
205                 for (int i = 0; i < num_vidmodes; i++) {
206                         if (vidmodes[i]->hdisplay < setting.xPixels ||
207                             vidmodes[i]->vdisplay < setting.yPixels)
208                         {
209                                 continue;
210                         }
211
212                         if (best_fit == -1 ||
213                             (vidmodes[i]->hdisplay < vidmodes[best_fit]->hdisplay) ||
214                             (vidmodes[i]->hdisplay == vidmodes[best_fit]->hdisplay &&
215                              vidmodes[i]->vdisplay < vidmodes[best_fit]->vdisplay))
216                         {
217                                 best_fit = i;
218                                 continue;
219                         }
220
221                         if ((vidmodes[i]->hdisplay == vidmodes[best_fit]->hdisplay) &&
222                             (vidmodes[i]->vdisplay == vidmodes[best_fit]->vdisplay))
223                         {
224                                 if (!setting.frequency) {
225                                         /* Higher is better, right? */
226                                         if (calculate_rate(vidmodes[i]) >
227                                             calculate_rate(vidmodes[best_fit]))
228                                         {
229                                                 best_fit = i;
230                                         }
231                                 }
232                                 else {
233                                         if (abs(calculate_rate(vidmodes[i]) - (int)setting.frequency) <
234                                             abs(calculate_rate(vidmodes[best_fit]) - (int)setting.frequency))
235                                         {
236                                                 best_fit = i;
237                                         }
238                                 }
239                         }
240                 }
241
242                 if (best_fit != -1) {
243 #  ifdef DEBUG
244                         printf("Switching to video mode %dx%d %dx%d %d\n",
245                                vidmodes[best_fit]->hdisplay, vidmodes[best_fit]->vdisplay,
246                                vidmodes[best_fit]->htotal, vidmodes[best_fit]->vtotal,
247                                calculate_rate(vidmodes[best_fit]));
248 #  endif
249
250                         /* change to the mode */
251                         XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
252
253                         /* Move the viewport to top left */
254                         XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
255                 }
256
257                 XFree(vidmodes);
258         }
259         else {
260                 return GHOST_kFailure;
261         }
262
263         XFlush(dpy);
264         return GHOST_kSuccess;
265
266 #else
267         /* Just pretend the request was successful. */
268         return GHOST_kSuccess;
269 #endif
270 }