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