2 * Wine X11drv display settings functions
4 * Copyright 2003 Alexander James Pasadyn
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(x11settings
);
40 * The DDHALMODEINFO type is used to hold all the mode information.
41 * This is done because the array of DDHALMODEINFO structures must be
42 * created for use by DirectDraw anyway.
44 static LPDDHALMODEINFO dd_modes
= NULL
;
45 static unsigned int dd_mode_count
= 0;
46 static unsigned int dd_max_modes
= 0;
47 static int dd_mode_default
= 0;
48 static const unsigned int depths
[] = {8, 16, 32};
50 /* pointers to functions that actually do the hard stuff */
51 static int (*pGetCurrentMode
)(void);
52 static LONG (*pSetCurrentMode
)(int mode
);
53 static const char *handler_name
;
56 * Set the handlers for resolution changing functions
57 * and initialize the master list of modes
59 LPDDHALMODEINFO
X11DRV_Settings_SetHandlers(const char *name
,
66 pGetCurrentMode
= pNewGCM
;
67 pSetCurrentMode
= pNewSCM
;
68 TRACE("Resolution settings now handled by: %s\n", name
);
70 /* leave room for other depths */
71 dd_max_modes
= (3+1)*(nmodes
);
73 dd_max_modes
= nmodes
;
77 TRACE("Destroying old display modes array\n");
78 HeapFree(GetProcessHeap(), 0, dd_modes
);
80 dd_modes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DDHALMODEINFO
) * dd_max_modes
);
82 TRACE("Initialized new display modes array\n");
86 /* Add one mode to the master list */
87 void X11DRV_Settings_AddOneMode(unsigned int width
, unsigned int height
, unsigned int bpp
, unsigned int freq
)
89 LPDDHALMODEINFO info
= &(dd_modes
[dd_mode_count
]);
90 DWORD dwBpp
= screen_depth
;
91 if (dd_mode_count
>= dd_max_modes
)
93 ERR("Maximum modes (%d) exceeded\n", dd_max_modes
);
96 if (dwBpp
== 24) dwBpp
= 32;
97 if (bpp
== 0) bpp
= dwBpp
;
98 info
->dwWidth
= width
;
99 info
->dwHeight
= height
;
100 info
->wRefreshRate
= freq
;
104 info
->dwRBitMask
= 0;
105 info
->dwGBitMask
= 0;
106 info
->dwBBitMask
= 0;
107 info
->dwAlphaBitMask
= 0;
108 TRACE("initialized mode %d: %dx%dx%d @%d Hz (%s)\n",
109 dd_mode_count
, width
, height
, bpp
, freq
, handler_name
);
113 /* copy all the current modes using the other color depths */
114 void X11DRV_Settings_AddDepthModes(void)
117 int existing_modes
= dd_mode_count
;
118 DWORD dwBpp
= screen_depth
;
119 if (dwBpp
== 24) dwBpp
= 32;
122 if (depths
[j
] != dwBpp
)
124 for (i
=0; i
< existing_modes
; i
++)
126 X11DRV_Settings_AddOneMode(dd_modes
[i
].dwWidth
, dd_modes
[i
].dwHeight
,
127 depths
[j
], dd_modes
[i
].wRefreshRate
);
133 /* set the default mode */
134 void X11DRV_Settings_SetDefaultMode(int mode
)
136 dd_mode_default
= mode
;
139 /* return the number of modes that are initialized */
140 unsigned int X11DRV_Settings_GetModeCount(void)
142 return dd_mode_count
;
145 /***********************************************************************
146 * Default handlers if resolution switching is not enabled
149 static int X11DRV_nores_GetCurrentMode(void)
154 static LONG
X11DRV_nores_SetCurrentMode(int mode
)
156 TRACE("Ignoring mode change request\n");
157 return DISP_CHANGE_FAILED
;
160 /* default handler only gets the current X desktop resolution */
161 void X11DRV_Settings_Init(void)
163 X11DRV_Settings_SetHandlers("NoRes",
164 X11DRV_nores_GetCurrentMode
,
165 X11DRV_nores_SetCurrentMode
,
167 X11DRV_Settings_AddOneMode(screen_width
, screen_height
, 0, 60);
170 static BOOL
get_display_device_reg_key(char *key
, unsigned len
)
172 static const char display_device_guid_prop
[] = "__wine_display_device_guid";
173 static const char video_path
[] = "System\\CurrentControlSet\\Control\\Video\\{";
174 static const char display0
[] = "}\\0000";
177 assert(len
>= sizeof(video_path
) + sizeof(display0
) + 40);
179 guid_atom
= HandleToULong(GetPropA(GetDesktopWindow(), display_device_guid_prop
));
180 if (!guid_atom
) return FALSE
;
182 memcpy(key
, video_path
, sizeof(video_path
));
184 if (!GlobalGetAtomNameA(guid_atom
, key
+ strlen(key
), 40))
187 strcat(key
, display0
);
189 TRACE("display device key %s\n", wine_dbgstr_a(key
));
193 static BOOL
read_registry_settings(DEVMODEW
*dm
)
195 char wine_x11_reg_key
[128];
200 if (!get_display_device_reg_key(wine_x11_reg_key
, sizeof(wine_x11_reg_key
)))
203 if (RegOpenKeyExA(HKEY_CURRENT_CONFIG
, wine_x11_reg_key
, 0, KEY_READ
, &hkey
))
206 #define query_value(name, data) \
207 size = sizeof(DWORD); \
208 if (RegQueryValueExA(hkey, name, 0, &type, (LPBYTE)(data), &size) || \
209 type != REG_DWORD || size != sizeof(DWORD)) \
212 query_value("DefaultSettings.BitsPerPel", &dm
->dmBitsPerPel
);
213 query_value("DefaultSettings.XResolution", &dm
->dmPelsWidth
);
214 query_value("DefaultSettings.YResolution", &dm
->dmPelsHeight
);
215 query_value("DefaultSettings.VRefresh", &dm
->dmDisplayFrequency
);
216 query_value("DefaultSettings.Flags", &dm
->u2
.dmDisplayFlags
);
217 query_value("DefaultSettings.XPanning", &dm
->u1
.s2
.dmPosition
.x
);
218 query_value("DefaultSettings.YPanning", &dm
->u1
.s2
.dmPosition
.y
);
219 query_value("DefaultSettings.Orientation", &dm
->u1
.s2
.dmDisplayOrientation
);
220 query_value("DefaultSettings.FixedOutput", &dm
->u1
.s2
.dmDisplayFixedOutput
);
228 static BOOL
write_registry_settings(const DEVMODEW
*dm
)
230 char wine_x11_reg_key
[128];
234 if (!get_display_device_reg_key(wine_x11_reg_key
, sizeof(wine_x11_reg_key
)))
237 if (RegCreateKeyExA(HKEY_CURRENT_CONFIG
, wine_x11_reg_key
, 0, NULL
,
238 REG_OPTION_VOLATILE
, KEY_WRITE
, NULL
, &hkey
, NULL
))
241 #define set_value(name, data) \
242 if (RegSetValueExA(hkey, name, 0, REG_DWORD, (LPBYTE)(data), sizeof(DWORD))) \
245 set_value("DefaultSettings.BitsPerPel", &dm
->dmBitsPerPel
);
246 set_value("DefaultSettings.XResolution", &dm
->dmPelsWidth
);
247 set_value("DefaultSettings.YResolution", &dm
->dmPelsHeight
);
248 set_value("DefaultSettings.VRefresh", &dm
->dmDisplayFrequency
);
249 set_value("DefaultSettings.Flags", &dm
->u2
.dmDisplayFlags
);
250 set_value("DefaultSettings.XPanning", &dm
->u1
.s2
.dmPosition
.x
);
251 set_value("DefaultSettings.YPanning", &dm
->u1
.s2
.dmPosition
.y
);
252 set_value("DefaultSettings.Orientation", &dm
->u1
.s2
.dmDisplayOrientation
);
253 set_value("DefaultSettings.FixedOutput", &dm
->u1
.s2
.dmDisplayFixedOutput
);
261 /***********************************************************************
262 * EnumDisplaySettingsEx (X11DRV.@)
265 BOOL
X11DRV_EnumDisplaySettingsEx( LPCWSTR name
, DWORD n
, LPDEVMODEW devmode
, DWORD flags
)
267 static const WCHAR dev_name
[CCHDEVICENAME
] =
268 { 'W','i','n','e',' ','X','1','1',' ','d','r','i','v','e','r',0 };
271 dwBpp
= screen_depth
;
272 if (dwBpp
== 24) dwBpp
= 32;
274 devmode
->dmSize
= sizeof(DEVMODEW
);
275 devmode
->dmSpecVersion
= MAKEWORD(1,4);
276 devmode
->dmDriverVersion
= MAKEWORD(1,4);
277 memcpy(devmode
->dmDeviceName
, dev_name
, sizeof(dev_name
));
278 devmode
->dmDriverExtra
= 0;
279 devmode
->u2
.dmDisplayFlags
= 0;
280 devmode
->dmDisplayFrequency
= 0;
281 devmode
->u1
.s2
.dmPosition
.x
= 0;
282 devmode
->u1
.s2
.dmPosition
.y
= 0;
283 devmode
->u1
.s2
.dmDisplayOrientation
= 0;
284 devmode
->u1
.s2
.dmDisplayFixedOutput
= 0;
286 if (n
== ENUM_CURRENT_SETTINGS
)
288 TRACE("mode %d (current) -- getting current mode (%s)\n", n
, handler_name
);
289 n
= pGetCurrentMode();
291 if (n
== ENUM_REGISTRY_SETTINGS
)
293 TRACE("mode %d (registry) -- getting default mode (%s)\n", n
, handler_name
);
294 return read_registry_settings(devmode
);
296 if (n
< dd_mode_count
)
298 devmode
->dmPelsWidth
= dd_modes
[n
].dwWidth
;
299 devmode
->dmPelsHeight
= dd_modes
[n
].dwHeight
;
300 devmode
->dmBitsPerPel
= dd_modes
[n
].dwBPP
;
301 devmode
->dmDisplayFrequency
= dd_modes
[n
].wRefreshRate
;
302 devmode
->dmFields
= (DM_PELSWIDTH
|DM_PELSHEIGHT
|DM_BITSPERPEL
);
303 if (devmode
->dmDisplayFrequency
)
305 devmode
->dmFields
|= DM_DISPLAYFREQUENCY
;
306 TRACE("mode %d -- %dx%dx%dbpp @%d Hz (%s)\n", n
,
307 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, devmode
->dmBitsPerPel
,
308 devmode
->dmDisplayFrequency
, handler_name
);
312 TRACE("mode %d -- %dx%dx%dbpp (%s)\n", n
,
313 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, devmode
->dmBitsPerPel
,
318 TRACE("mode %d -- not present (%s)\n", n
, handler_name
);
322 #define _X_FIELD(prefix, bits) if ((fields) & prefix##_##bits) {p+=sprintf(p, "%s%s", first ? "" : ",", #bits); first=FALSE;}
323 static const char * _CDS_flags(DWORD fields
)
328 _X_FIELD(CDS
,UPDATEREGISTRY
);_X_FIELD(CDS
,TEST
);_X_FIELD(CDS
,FULLSCREEN
);
329 _X_FIELD(CDS
,GLOBAL
);_X_FIELD(CDS
,SET_PRIMARY
);_X_FIELD(CDS
,RESET
);
330 _X_FIELD(CDS
,SETRECT
);_X_FIELD(CDS
,NORESET
);
332 return wine_dbg_sprintf("%s", buf
);
334 static const char * _DM_fields(DWORD fields
)
339 _X_FIELD(DM
,BITSPERPEL
);_X_FIELD(DM
,PELSWIDTH
);_X_FIELD(DM
,PELSHEIGHT
);
340 _X_FIELD(DM
,DISPLAYFLAGS
);_X_FIELD(DM
,DISPLAYFREQUENCY
);_X_FIELD(DM
,POSITION
);
342 return wine_dbg_sprintf("%s", buf
);
346 /***********************************************************************
347 * ChangeDisplaySettingsEx (X11DRV.@)
350 LONG
X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname
, LPDEVMODEW devmode
,
351 HWND hwnd
, DWORD flags
, LPVOID lpvoid
)
355 BOOL def_mode
= TRUE
;
357 TRACE("(%s,%p,%p,0x%08x,%p)\n",debugstr_w(devname
),devmode
,hwnd
,flags
,lpvoid
);
358 TRACE("flags=%s\n",_CDS_flags(flags
));
361 TRACE("DM_fields=%s\n",_DM_fields(devmode
->dmFields
));
362 TRACE("width=%d height=%d bpp=%d freq=%d (%s)\n",
363 devmode
->dmPelsWidth
,devmode
->dmPelsHeight
,
364 devmode
->dmBitsPerPel
,devmode
->dmDisplayFrequency
, handler_name
);
366 dwBpp
= (devmode
->dmBitsPerPel
== 24) ? 32 : devmode
->dmBitsPerPel
;
367 if (devmode
->dmFields
& DM_BITSPERPEL
) def_mode
&= !dwBpp
;
368 if (devmode
->dmFields
& DM_PELSWIDTH
) def_mode
&= !devmode
->dmPelsWidth
;
369 if (devmode
->dmFields
& DM_PELSHEIGHT
) def_mode
&= !devmode
->dmPelsHeight
;
370 if (devmode
->dmFields
& DM_DISPLAYFREQUENCY
) def_mode
&= !devmode
->dmDisplayFrequency
;
375 TRACE("Return to original display mode (%s)\n", handler_name
);
376 if (!X11DRV_EnumDisplaySettingsEx(devname
, dd_mode_default
, &dm
, 0))
378 ERR("Default mode not found!\n");
379 return DISP_CHANGE_BADMODE
;
383 dwBpp
= !dwBpp
? dd_modes
[dd_mode_default
].dwBPP
: dwBpp
;
385 if ((devmode
->dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
)) != (DM_PELSWIDTH
| DM_PELSHEIGHT
))
386 return DISP_CHANGE_BADMODE
;
388 for (i
= 0; i
< dd_mode_count
; i
++)
390 if (devmode
->dmFields
& DM_BITSPERPEL
)
392 if (dwBpp
!= dd_modes
[i
].dwBPP
)
395 if (devmode
->dmFields
& DM_PELSWIDTH
)
397 if (devmode
->dmPelsWidth
!= dd_modes
[i
].dwWidth
)
400 if (devmode
->dmFields
& DM_PELSHEIGHT
)
402 if (devmode
->dmPelsHeight
!= dd_modes
[i
].dwHeight
)
405 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) && (dd_modes
[i
].wRefreshRate
!= 0) &&
406 devmode
->dmDisplayFrequency
!= 0)
408 if (devmode
->dmDisplayFrequency
!= dd_modes
[i
].wRefreshRate
)
411 /* we have a valid mode */
412 TRACE("Requested display settings match mode %d (%s)\n", i
, handler_name
);
414 if (flags
& CDS_UPDATEREGISTRY
)
415 write_registry_settings(devmode
);
417 if (!(flags
& (CDS_TEST
| CDS_NORESET
)))
418 return pSetCurrentMode(i
);
419 return DISP_CHANGE_SUCCESSFUL
;
422 /* no valid modes found */
423 ERR("No matching mode found(%dx%dx%d)! (%s)\n",
424 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
,
425 devmode
->dmBitsPerPel
, handler_name
);
426 return DISP_CHANGE_BADMODE
;
432 /***********************************************************************
433 * DirectDraw HAL interface
436 static DWORD PASCAL
X11DRV_Settings_SetMode(LPDDHAL_SETMODEDATA data
)
438 TRACE("Mode %d requested by DDHAL (%s)\n", data
->dwModeIndex
, handler_name
);
439 switch (pSetCurrentMode(data
->dwModeIndex
))
441 case DISP_CHANGE_SUCCESSFUL
:
442 X11DRV_DDHAL_SwitchMode(data
->dwModeIndex
, NULL
, NULL
);
443 data
->ddRVal
= DD_OK
;
445 case DISP_CHANGE_BADMODE
:
446 data
->ddRVal
= DDERR_WRONGMODE
;
449 data
->ddRVal
= DDERR_UNSUPPORTEDMODE
;
451 return DDHAL_DRIVER_HANDLED
;
453 int X11DRV_Settings_CreateDriver(LPDDHALINFO info
)
455 if (!dd_mode_count
) return 0; /* no settings defined */
457 TRACE("Setting up display settings for DDRAW (%s)\n", handler_name
);
458 info
->dwNumModes
= dd_mode_count
;
459 info
->lpModeInfo
= dd_modes
;
460 X11DRV_DDHAL_SwitchMode(pGetCurrentMode(), NULL
, NULL
);
461 info
->lpDDCallbacks
->SetMode
= X11DRV_Settings_SetMode
;