svn merge ^/trunk/blender -r48592:HEAD
[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
44 GHOST_DisplayManagerX11::
45 GHOST_DisplayManagerX11(
46     GHOST_SystemX11 *system
47     ) :
48         GHOST_DisplayManager(),
49         m_system(system)
50 {
51         /* nothing to do. */
52 }
53
54 GHOST_TSuccess
55 GHOST_DisplayManagerX11::
56 getNumDisplays(GHOST_TUns8& numDisplays) const
57 {
58         numDisplays =  m_system->getNumDisplays();
59         return GHOST_kSuccess;
60 }
61
62
63 GHOST_TSuccess
64 GHOST_DisplayManagerX11::
65 getNumDisplaySettings(
66                 GHOST_TUns8 display,
67                 GHOST_TInt32& numSettings) const
68 {
69 #ifdef WITH_X11_XF86VMODE
70         int majorVersion, minorVersion;
71         XF86VidModeModeInfo **vidmodes;
72         Display *dpy = m_system->getXDisplay();
73
74         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
75
76         if (dpy == NULL)
77                 return GHOST_kFailure;
78
79         majorVersion = minorVersion = 0;
80         if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
81                 fprintf(stderr, "Error: XF86VidMode extension missing!\n");
82                 return GHOST_kFailure;
83         }
84
85         /* The X11 man page says vidmodes needs to be freed, but doing so causes a
86          * segfault. - z0r */
87         XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes);
88
89 #else
90         /* We only have one X11 setting at the moment. */
91         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");    
92         numSettings = GHOST_TInt32(1);
93 #endif
94
95         return GHOST_kSuccess;
96 }
97
98 GHOST_TSuccess
99 GHOST_DisplayManagerX11::
100 getDisplaySetting(
101                 GHOST_TUns8 display,
102                 GHOST_TInt32 index,
103                 GHOST_DisplaySetting& setting) const
104 {
105
106 #ifdef WITH_X11_XF86VMODE
107         int majorVersion, minorVersion;
108         XF86VidModeModeInfo **vidmodes;
109         Display *dpy = m_system->getXDisplay();
110         int numSettings;
111
112         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
113
114         if (dpy == NULL)
115                 return GHOST_kFailure;
116
117         majorVersion = minorVersion = 0;
118         if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
119                 fprintf(stderr, "Error: XF86VidMode extension missing!\n");
120                 return GHOST_kFailure;
121         }
122
123         /* The X11 man page says vidmodes needs to be freed, but doing so causes a
124          * segfault. - z0r */
125         XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes);
126         GHOST_ASSERT(index < numSettings, "Requested setting outside of valid range.\n");
127
128         setting.xPixels = vidmodes[index]->hdisplay;
129         setting.yPixels = vidmodes[index]->vdisplay;
130         setting.bpp = DefaultDepth(dpy, DefaultScreen(dpy));
131
132 #else
133         GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");    
134         GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n"); 
135         
136         Display *x_display = m_system->getXDisplay();
137
138         if (x_display == NULL) {
139                 return GHOST_kFailure;
140         }
141
142         setting.xPixels  = DisplayWidth(x_display, DefaultScreen(x_display));
143         setting.yPixels = DisplayHeight(x_display, DefaultScreen(x_display));
144         setting.bpp = DefaultDepth(x_display, DefaultScreen(x_display));
145 #endif
146
147         /* Don't think it's possible to get this value from X!
148          * So let's guess!! */
149         setting.frequency = 60;
150
151         return GHOST_kSuccess;
152 }
153         
154 GHOST_TSuccess
155 GHOST_DisplayManagerX11::
156 getCurrentDisplaySetting(
157                 GHOST_TUns8 display,
158                 GHOST_DisplaySetting& setting) const
159 {
160         /* According to the xf86vidmodegetallmodelines man page,
161          * "The first element of the array corresponds to the current video mode."
162          */
163         return getDisplaySetting(display, GHOST_TInt32(0), setting);
164 }
165
166
167 GHOST_TSuccess
168 GHOST_DisplayManagerX11::
169 setCurrentDisplaySetting(
170                 GHOST_TUns8 display,
171                 const GHOST_DisplaySetting& setting)
172 {
173 #ifdef WITH_X11_XF86VMODE
174         /* Mode switching code ported from Quake 2:
175          * ftp: ftp.idsoftware.com/idstuff/source/q2source-3.21.zip
176          * See linux/gl_glx.c:GLimp_SetMode
177          */
178         int majorVersion, minorVersion;
179         XF86VidModeModeInfo **vidmodes;
180         Display *dpy = m_system->getXDisplay();
181         int scrnum, num_vidmodes;
182         int best_fit, best_dist, dist, x, y;
183
184         if (dpy == NULL)
185                 return GHOST_kFailure;
186
187         scrnum = DefaultScreen(dpy);
188
189         /* Get video mode list */
190         majorVersion = minorVersion = 0;
191         if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
192                 fprintf(stderr, "Error: XF86VidMode extension missing!\n");
193                 return GHOST_kFailure;
194         }
195 #  ifdef _DEBUG
196         printf("Using XFree86-VidModeExtension Version %d.%d\n",
197                majorVersion, minorVersion);
198 #  endif
199
200         /* The X11 man page says vidmodes needs to be freed, but doing so causes a
201          * segfault. - z0r */
202         XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
203
204         best_dist = 9999999;
205         best_fit = -1;
206
207         for (int i = 0; i < num_vidmodes; i++) {
208                 if (setting.xPixels > vidmodes[i]->hdisplay ||
209                     setting.yPixels > vidmodes[i]->vdisplay)
210                         continue;
211
212                 x = setting.xPixels - vidmodes[i]->hdisplay;
213                 y = setting.yPixels - vidmodes[i]->vdisplay;
214                 dist = (x * x) + (y * y);
215                 if (dist < best_dist) {
216                         best_dist = dist;
217                         best_fit = i;
218                 }
219         }
220
221         if (best_fit != -1) {
222 #  ifdef _DEBUG
223                 int actualWidth, actualHeight;
224                 actualWidth = vidmodes[best_fit]->hdisplay;
225                 actualHeight = vidmodes[best_fit]->vdisplay;
226                 printf("Switching to video mode %dx%d\n",
227                        actualWidth, actualHeight);
228 #  endif
229
230                 /* change to the mode */
231                 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
232
233                 /* Move the viewport to top left */
234                 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
235         }
236         else {
237                 return GHOST_kFailure;
238         }
239
240         XFlush(dpy);
241         return GHOST_kSuccess;
242
243 #else
244         /* Just pretend the request was successful. */
245         return GHOST_kSuccess;
246 #endif
247 }
248
249
250
251