Use INVALID_FILE_ATTRIBUTES to test for failure of
[wine] / dlls / x11drv / xrandr.c
1 /*
2  * Wine X11drv Xrandr interface
3  *
4  * Copyright 2003 Alexander James Pasadyn
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include <string.h>
23 #include <stdio.h>
24
25 #ifdef HAVE_LIBXRANDR
26
27 #include "ts_xlib.h"
28
29 #include <X11/extensions/Xrandr.h>
30 #include "x11drv.h"
31
32 #include "x11ddraw.h"
33 #include "xrandr.h"
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wingdi.h"
38 #include "ddrawi.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
42
43 extern int usexrandr;
44
45 static int xrandr_event, xrandr_error, xrandr_major, xrandr_minor;
46
47 static LPDDHALMODEINFO dd_modes;
48 static unsigned int dd_mode_count;
49 static XRRScreenSize *real_xrandr_sizes;
50 static short **real_xrandr_rates;
51 static unsigned int real_xrandr_sizes_count;
52 static int *real_xrandr_rates_count;
53 static unsigned int real_xrandr_modes_count;
54
55 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
56 {
57     return 1;
58 }
59
60 static Bool in_desktop_mode;
61 static const unsigned int depths[]  = {8, 16, 32};
62
63 /* create the mode structures */
64 static void make_modes(void)
65 {
66     int i, j;
67     for (i=0; i<real_xrandr_sizes_count; i++)
68     {
69         if (real_xrandr_rates_count[i])
70         {
71             for (j=0; j < real_xrandr_rates_count[i]; j++)
72             {
73                 X11DRV_Settings_AddOneMode(real_xrandr_sizes[i].width, 
74                                            real_xrandr_sizes[i].height, 
75                                            0, real_xrandr_rates[i][j]);
76             }
77         }
78         else
79         {
80             X11DRV_Settings_AddOneMode(real_xrandr_sizes[i].width, 
81                                        real_xrandr_sizes[i].height, 
82                                        0, 0);
83         }
84     }
85 }
86
87 static int X11DRV_XRandR_GetCurrentMode(void)
88 {
89     SizeID size;
90     Rotation rot;
91     Window root;
92     XRRScreenConfiguration *sc;
93     short rate;
94     int i;
95     int res = -1;
96     
97     wine_tsx11_lock();
98     root = RootWindow (gdi_display, DefaultScreen(gdi_display));
99     sc = XRRGetScreenInfo (gdi_display, root);
100     size = XRRConfigCurrentConfiguration (sc, &rot);
101     rate = XRRConfigCurrentRate (sc);
102     for (i = 0; i < real_xrandr_modes_count; i++)
103     {
104         if ( (dd_modes[i].dwWidth      == real_xrandr_sizes[size].width ) &&
105              (dd_modes[i].dwHeight     == real_xrandr_sizes[size].height) &&
106              (dd_modes[i].wRefreshRate == rate                          ) )
107           {
108               res = i;
109           }
110     }
111     XRRFreeScreenConfigInfo(sc);
112     wine_tsx11_unlock();
113     if (res == -1)
114     {
115         ERR("In unknown mode, returning default\n");
116         res = 0;
117     }
118     return res;
119 }
120
121 static void X11DRV_XRandR_SetCurrentMode(int mode)
122 {
123     SizeID size;
124     Rotation rot;
125     Window root;
126     XRRScreenConfiguration *sc;
127     Status stat = RRSetConfigSuccess;
128     short rate;
129     int i, j;
130     DWORD dwBpp = screen_depth;
131     if (dwBpp == 24) dwBpp = 32;
132     
133     wine_tsx11_lock();
134     root = RootWindow (gdi_display, DefaultScreen(gdi_display));
135     sc = XRRGetScreenInfo (gdi_display, root);
136     size = XRRConfigCurrentConfiguration (sc, &rot);
137     if (dwBpp != dd_modes[mode].dwBPP)
138     {
139         FIXME("Cannot change screen BPP from %ld to %ld\n", dwBpp, dd_modes[mode].dwBPP);
140     }
141     mode = mode%real_xrandr_modes_count;
142     for (i = 0; i < real_xrandr_sizes_count; i++)
143     {
144         if ( (dd_modes[mode].dwWidth  == real_xrandr_sizes[i].width ) && 
145              (dd_modes[mode].dwHeight == real_xrandr_sizes[i].height) )
146         {
147             size = i;
148             if (real_xrandr_rates_count[i])
149             {
150                 for (j=0; j < real_xrandr_rates_count[i]; j++)
151                 {
152                     if (dd_modes[mode].wRefreshRate == real_xrandr_rates[i][j])
153                     {
154                         rate = real_xrandr_rates[i][j];
155                         TRACE("Resizing X display to %ldx%ld @%d Hz\n", 
156                               dd_modes[mode].dwWidth, dd_modes[mode].dwHeight, rate);
157                         stat = XRRSetScreenConfigAndRate (gdi_display, sc, root, 
158                                                           size, rot, rate, CurrentTime);
159                         FIXME("Need to update SYSMETRICS after resizing display (now %ldx%ld)\n",
160                               dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
161                     }
162                 }
163             }
164             else
165             {
166                 TRACE("Resizing X display to %ldx%ld\n", 
167                       dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
168                 stat = XRRSetScreenConfig (gdi_display, sc, root, 
169                                            size, rot, CurrentTime);
170                 FIXME("Need to update SYSMETRICS after resizing display (now %ldx%ld)\n",
171                       dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
172             }
173         }
174     }
175     if (stat != RRSetConfigSuccess)
176     {
177         ERR("Resolution change not successful -- perhaps display has chaned?");
178     }
179     XRRFreeScreenConfigInfo(sc);
180     wine_tsx11_unlock();
181 }
182
183 void X11DRV_XRandR_Init(void)
184 {
185     Bool ok;
186     int nmodes = 0;
187     int i;
188     in_desktop_mode = (root_window != DefaultRootWindow(gdi_display));
189
190     if (xrandr_major) return; /* already initialized? */
191     if (!usexrandr) return; /* disabled in config */
192     if (in_desktop_mode) return; /* not compatible with desktop mode */
193
194     /* see if Xrandr is available */
195     wine_tsx11_lock();
196     ok = XRRQueryExtension(gdi_display, &xrandr_event, &xrandr_error);
197     if (ok)
198     {
199         X11DRV_expect_error(gdi_display, XRandRErrorHandler, NULL);
200         ok = XRRQueryVersion(gdi_display, &xrandr_major, &xrandr_minor);
201         if (X11DRV_check_error()) ok = FALSE;
202     }
203     if (ok)
204     {
205         TRACE("Found XRandR - major: %d, minor: %d\n", xrandr_major, xrandr_minor);
206         /* retrieve modes */
207         real_xrandr_sizes = XRRSizes(gdi_display, DefaultScreen(gdi_display), &real_xrandr_sizes_count);
208         ok = (real_xrandr_sizes_count>0);
209     }
210     if (ok)
211     {
212         real_xrandr_rates = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(short *) * real_xrandr_sizes_count);
213         real_xrandr_rates_count = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(int) * real_xrandr_sizes_count);
214         for (i=0; i < real_xrandr_sizes_count; i++)
215         {
216             real_xrandr_rates[i] = XRRRates (gdi_display, DefaultScreen(gdi_display), i, &(real_xrandr_rates_count[i]));
217             if (real_xrandr_rates_count[i])
218             {
219                 nmodes += real_xrandr_rates_count[i];
220             }
221             else
222             {
223                 nmodes++;
224             }
225         }
226     }
227     wine_tsx11_unlock();
228     if (!ok) return;
229
230     real_xrandr_modes_count = nmodes;
231     TRACE("XRandR modes: count=%d\n", nmodes);
232
233     dd_modes = X11DRV_Settings_SetHandlers("XRandR", 
234                                            X11DRV_XRandR_GetCurrentMode, 
235                                            X11DRV_XRandR_SetCurrentMode, 
236                                            nmodes, 1);
237     make_modes();
238     X11DRV_Settings_AddDepthModes();
239     dd_mode_count = X11DRV_Settings_GetModeCount();
240     X11DRV_Settings_SetDefaultMode(0);
241
242     TRACE("Available DD modes: count=%d\n", dd_mode_count);
243     TRACE("Enabling XRandR\n");
244 }
245
246 void X11DRV_XRandR_Cleanup(void)
247 {
248     if (real_xrandr_rates)
249     {
250         HeapFree(GetProcessHeap(), 0, real_xrandr_rates);
251         real_xrandr_rates = NULL;
252     }
253     if (real_xrandr_rates_count)
254     {
255         HeapFree(GetProcessHeap(), 0, real_xrandr_rates_count);
256         real_xrandr_rates_count = NULL;
257     }
258 }
259
260 #endif /* HAVE_LIBXRANDR */