Fix subclassing to support nested messages.
[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 <X11/Xlib.h>
28 #include <X11/extensions/Xrandr.h>
29 #include "x11drv.h"
30
31 #include "x11ddraw.h"
32 #include "xrandr.h"
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "ddrawi.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(xrandr);
41
42 extern int usexrandr;
43
44 static int xrandr_event, xrandr_error, xrandr_major, xrandr_minor;
45
46 static LPDDHALMODEINFO dd_modes;
47 static unsigned int dd_mode_count;
48 static XRRScreenSize *real_xrandr_sizes;
49 static short **real_xrandr_rates;
50 static unsigned int real_xrandr_sizes_count;
51 static int *real_xrandr_rates_count;
52 static unsigned int real_xrandr_modes_count;
53
54 static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
55 {
56     return 1;
57 }
58
59
60 /* create the mode structures */
61 static void make_modes(void)
62 {
63     int i, j;
64     for (i=0; i<real_xrandr_sizes_count; i++)
65     {
66         if (real_xrandr_rates_count[i])
67         {
68             for (j=0; j < real_xrandr_rates_count[i]; j++)
69             {
70                 X11DRV_Settings_AddOneMode(real_xrandr_sizes[i].width, 
71                                            real_xrandr_sizes[i].height, 
72                                            0, real_xrandr_rates[i][j]);
73             }
74         }
75         else
76         {
77             X11DRV_Settings_AddOneMode(real_xrandr_sizes[i].width, 
78                                        real_xrandr_sizes[i].height, 
79                                        0, 0);
80         }
81     }
82 }
83
84 static int X11DRV_XRandR_GetCurrentMode(void)
85 {
86     SizeID size;
87     Rotation rot;
88     Window root;
89     XRRScreenConfiguration *sc;
90     short rate;
91     int i;
92     int res = -1;
93     
94     wine_tsx11_lock();
95     root = RootWindow (gdi_display, DefaultScreen(gdi_display));
96     sc = XRRGetScreenInfo (gdi_display, root);
97     size = XRRConfigCurrentConfiguration (sc, &rot);
98     rate = XRRConfigCurrentRate (sc);
99     for (i = 0; i < real_xrandr_modes_count; i++)
100     {
101         if ( (dd_modes[i].dwWidth      == real_xrandr_sizes[size].width ) &&
102              (dd_modes[i].dwHeight     == real_xrandr_sizes[size].height) &&
103              (dd_modes[i].wRefreshRate == rate                          ) )
104           {
105               res = i;
106           }
107     }
108     XRRFreeScreenConfigInfo(sc);
109     wine_tsx11_unlock();
110     if (res == -1)
111     {
112         ERR("In unknown mode, returning default\n");
113         res = 0;
114     }
115     return res;
116 }
117
118 static void X11DRV_XRandR_SetCurrentMode(int mode)
119 {
120     SizeID size;
121     Rotation rot;
122     Window root;
123     XRRScreenConfiguration *sc;
124     Status stat = RRSetConfigSuccess;
125     short rate;
126     int i, j;
127     DWORD dwBpp = screen_depth;
128     if (dwBpp == 24) dwBpp = 32;
129     
130     wine_tsx11_lock();
131     root = RootWindow (gdi_display, DefaultScreen(gdi_display));
132     sc = XRRGetScreenInfo (gdi_display, root);
133     size = XRRConfigCurrentConfiguration (sc, &rot);
134     if (dwBpp != dd_modes[mode].dwBPP)
135     {
136         FIXME("Cannot change screen BPP from %ld to %ld\n", dwBpp, dd_modes[mode].dwBPP);
137     }
138     mode = mode%real_xrandr_modes_count;
139     for (i = 0; i < real_xrandr_sizes_count; i++)
140     {
141         if ( (dd_modes[mode].dwWidth  == real_xrandr_sizes[i].width ) && 
142              (dd_modes[mode].dwHeight == real_xrandr_sizes[i].height) )
143         {
144             size = i;
145             if (real_xrandr_rates_count[i])
146             {
147                 for (j=0; j < real_xrandr_rates_count[i]; j++)
148                 {
149                     if (dd_modes[mode].wRefreshRate == real_xrandr_rates[i][j])
150                     {
151                         rate = real_xrandr_rates[i][j];
152                         TRACE("Resizing X display to %ldx%ld @%d Hz\n", 
153                               dd_modes[mode].dwWidth, dd_modes[mode].dwHeight, rate);
154                         stat = XRRSetScreenConfigAndRate (gdi_display, sc, root, 
155                                                           size, rot, rate, CurrentTime);
156                     }
157                 }
158             }
159             else
160             {
161                 TRACE("Resizing X display to %ldx%ld\n", 
162                       dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
163                 stat = XRRSetScreenConfig (gdi_display, sc, root, 
164                                            size, rot, CurrentTime);
165             }
166         }
167     }
168     XRRFreeScreenConfigInfo(sc);
169     wine_tsx11_unlock();
170     if (stat == RRSetConfigSuccess)
171         X11DRV_handle_desktop_resize( dd_modes[mode].dwWidth, dd_modes[mode].dwHeight );
172     else
173         ERR("Resolution change not successful -- perhaps display has changed?\n");
174 }
175
176 void X11DRV_XRandR_Init(void)
177 {
178     Bool ok;
179     int nmodes = 0;
180     int i;
181
182     if (xrandr_major) return; /* already initialized? */
183     if (!usexrandr) return; /* disabled in config */
184     if (using_wine_desktop) return; /* not compatible with desktop mode */
185
186     /* see if Xrandr is available */
187     wine_tsx11_lock();
188     ok = XRRQueryExtension(gdi_display, &xrandr_event, &xrandr_error);
189     if (ok)
190     {
191         X11DRV_expect_error(gdi_display, XRandRErrorHandler, NULL);
192         ok = XRRQueryVersion(gdi_display, &xrandr_major, &xrandr_minor);
193         if (X11DRV_check_error()) ok = FALSE;
194     }
195     if (ok)
196     {
197         TRACE("Found XRandR - major: %d, minor: %d\n", xrandr_major, xrandr_minor);
198         /* retrieve modes */
199         real_xrandr_sizes = XRRSizes(gdi_display, DefaultScreen(gdi_display), &real_xrandr_sizes_count);
200         ok = (real_xrandr_sizes_count>0);
201     }
202     if (ok)
203     {
204         real_xrandr_rates = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(short *) * real_xrandr_sizes_count);
205         real_xrandr_rates_count = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(int) * real_xrandr_sizes_count);
206         for (i=0; i < real_xrandr_sizes_count; i++)
207         {
208             real_xrandr_rates[i] = XRRRates (gdi_display, DefaultScreen(gdi_display), i, &(real_xrandr_rates_count[i]));
209             if (real_xrandr_rates_count[i])
210             {
211                 nmodes += real_xrandr_rates_count[i];
212             }
213             else
214             {
215                 nmodes++;
216             }
217         }
218     }
219     wine_tsx11_unlock();
220     if (!ok) return;
221
222     real_xrandr_modes_count = nmodes;
223     TRACE("XRandR modes: count=%d\n", nmodes);
224
225     dd_modes = X11DRV_Settings_SetHandlers("XRandR", 
226                                            X11DRV_XRandR_GetCurrentMode, 
227                                            X11DRV_XRandR_SetCurrentMode, 
228                                            nmodes, 1);
229     make_modes();
230     X11DRV_Settings_AddDepthModes();
231     dd_mode_count = X11DRV_Settings_GetModeCount();
232     X11DRV_Settings_SetDefaultMode(0);
233
234     TRACE("Available DD modes: count=%d\n", dd_mode_count);
235     TRACE("Enabling XRandR\n");
236 }
237
238 void X11DRV_XRandR_Cleanup(void)
239 {
240     if (real_xrandr_rates)
241     {
242         HeapFree(GetProcessHeap(), 0, real_xrandr_rates);
243         real_xrandr_rates = NULL;
244     }
245     if (real_xrandr_rates_count)
246     {
247         HeapFree(GetProcessHeap(), 0, real_xrandr_rates_count);
248         real_xrandr_rates_count = NULL;
249     }
250 }
251
252 #endif /* HAVE_LIBXRANDR */