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