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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(x11settings
);
38 static struct x11drv_mode_info
*dd_modes
= NULL
;
39 static unsigned int dd_mode_count
= 0;
40 static unsigned int dd_max_modes
= 0;
41 /* All Windows drivers seen so far either support 32 bit depths, or 24 bit depths, but never both. So if we have
42 * a 32 bit framebuffer, report 32 bit bpps, otherwise 24 bit ones.
44 static const unsigned int depths_24
[] = {8, 16, 24};
45 static const unsigned int depths_32
[] = {8, 16, 32};
47 /* pointers to functions that actually do the hard stuff */
48 static int (*pGetCurrentMode
)(void);
49 static LONG (*pSetCurrentMode
)(int mode
);
50 static const char *handler_name
;
53 * Set the handlers for resolution changing functions
54 * and initialize the master list of modes
56 struct x11drv_mode_info
*X11DRV_Settings_SetHandlers(const char *name
,
63 pGetCurrentMode
= pNewGCM
;
64 pSetCurrentMode
= pNewSCM
;
65 TRACE("Resolution settings now handled by: %s\n", name
);
67 /* leave room for other depths */
68 dd_max_modes
= (3+1)*(nmodes
);
70 dd_max_modes
= nmodes
;
74 TRACE("Destroying old display modes array\n");
75 HeapFree(GetProcessHeap(), 0, dd_modes
);
77 dd_modes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*dd_modes
) * dd_max_modes
);
79 TRACE("Initialized new display modes array\n");
83 /* Add one mode to the master list */
84 void X11DRV_Settings_AddOneMode(unsigned int width
, unsigned int height
, unsigned int bpp
, unsigned int freq
)
86 struct x11drv_mode_info
*info
= &dd_modes
[dd_mode_count
];
87 DWORD dwBpp
= screen_bpp
;
88 if (dd_mode_count
>= dd_max_modes
)
90 ERR("Maximum modes (%d) exceeded\n", dd_max_modes
);
93 if (bpp
== 0) bpp
= dwBpp
;
95 info
->height
= height
;
96 info
->refresh_rate
= freq
;
98 TRACE("initialized mode %d: %dx%dx%d @%d Hz (%s)\n",
99 dd_mode_count
, width
, height
, bpp
, freq
, handler_name
);
103 /* copy all the current modes using the other color depths */
104 void X11DRV_Settings_AddDepthModes(void)
107 int existing_modes
= dd_mode_count
;
108 DWORD dwBpp
= screen_bpp
;
109 const DWORD
*depths
= screen_bpp
== 32 ? depths_32
: depths_24
;
113 if (depths
[j
] != dwBpp
)
115 for (i
=0; i
< existing_modes
; i
++)
117 X11DRV_Settings_AddOneMode(dd_modes
[i
].width
, dd_modes
[i
].height
,
118 depths
[j
], dd_modes
[i
].refresh_rate
);
124 /* return the number of modes that are initialized */
125 unsigned int X11DRV_Settings_GetModeCount(void)
127 return dd_mode_count
;
130 /***********************************************************************
131 * Default handlers if resolution switching is not enabled
134 static int X11DRV_nores_GetCurrentMode(void)
139 static LONG
X11DRV_nores_SetCurrentMode(int mode
)
141 if (mode
== 0) return DISP_CHANGE_SUCCESSFUL
;
142 TRACE("Ignoring mode change request mode=%d\n", mode
);
143 return DISP_CHANGE_FAILED
;
146 /* default handler only gets the current X desktop resolution */
147 void X11DRV_Settings_Init(void)
149 RECT primary
= get_primary_monitor_rect();
150 X11DRV_Settings_SetHandlers("NoRes",
151 X11DRV_nores_GetCurrentMode
,
152 X11DRV_nores_SetCurrentMode
,
154 X11DRV_Settings_AddOneMode( primary
.right
- primary
.left
, primary
.bottom
- primary
.top
, 0, 60);
157 static BOOL
get_display_device_reg_key(char *key
, unsigned len
)
159 static const char display_device_guid_prop
[] = "__wine_display_device_guid";
160 static const char video_path
[] = "System\\CurrentControlSet\\Control\\Video\\{";
161 static const char display0
[] = "}\\0000";
164 assert(len
>= sizeof(video_path
) + sizeof(display0
) + 40);
166 guid_atom
= HandleToULong(GetPropA(GetDesktopWindow(), display_device_guid_prop
));
167 if (!guid_atom
) return FALSE
;
169 memcpy(key
, video_path
, sizeof(video_path
));
171 if (!GlobalGetAtomNameA(guid_atom
, key
+ strlen(key
), 40))
174 strcat(key
, display0
);
176 TRACE("display device key %s\n", wine_dbgstr_a(key
));
180 static BOOL
read_registry_settings(DEVMODEW
*dm
)
182 char wine_x11_reg_key
[128];
189 if (!get_display_device_reg_key(wine_x11_reg_key
, sizeof(wine_x11_reg_key
)))
192 if (RegOpenKeyExA(HKEY_CURRENT_CONFIG
, wine_x11_reg_key
, 0, KEY_READ
, &hkey
))
195 #define query_value(name, data) \
196 size = sizeof(DWORD); \
197 if (RegQueryValueExA(hkey, name, 0, &type, (LPBYTE)(data), &size) || \
198 type != REG_DWORD || size != sizeof(DWORD)) \
201 query_value("DefaultSettings.BitsPerPel", &dm
->dmBitsPerPel
);
202 dm
->dmFields
|= DM_BITSPERPEL
;
203 query_value("DefaultSettings.XResolution", &dm
->dmPelsWidth
);
204 dm
->dmFields
|= DM_PELSWIDTH
;
205 query_value("DefaultSettings.YResolution", &dm
->dmPelsHeight
);
206 dm
->dmFields
|= DM_PELSHEIGHT
;
207 query_value("DefaultSettings.VRefresh", &dm
->dmDisplayFrequency
);
208 dm
->dmFields
|= DM_DISPLAYFREQUENCY
;
209 query_value("DefaultSettings.Flags", &dm
->u2
.dmDisplayFlags
);
210 dm
->dmFields
|= DM_DISPLAYFLAGS
;
211 query_value("DefaultSettings.XPanning", &dm
->u1
.s2
.dmPosition
.x
);
212 query_value("DefaultSettings.YPanning", &dm
->u1
.s2
.dmPosition
.y
);
213 query_value("DefaultSettings.Orientation", &dm
->u1
.s2
.dmDisplayOrientation
);
214 query_value("DefaultSettings.FixedOutput", &dm
->u1
.s2
.dmDisplayFixedOutput
);
222 static BOOL
write_registry_settings(const DEVMODEW
*dm
)
224 char wine_x11_reg_key
[128];
228 if (!get_display_device_reg_key(wine_x11_reg_key
, sizeof(wine_x11_reg_key
)))
231 if (RegCreateKeyExA(HKEY_CURRENT_CONFIG
, wine_x11_reg_key
, 0, NULL
,
232 REG_OPTION_VOLATILE
, KEY_WRITE
, NULL
, &hkey
, NULL
))
235 #define set_value(name, data) \
236 if (RegSetValueExA(hkey, name, 0, REG_DWORD, (const BYTE*)(data), sizeof(DWORD))) \
239 set_value("DefaultSettings.BitsPerPel", &dm
->dmBitsPerPel
);
240 set_value("DefaultSettings.XResolution", &dm
->dmPelsWidth
);
241 set_value("DefaultSettings.YResolution", &dm
->dmPelsHeight
);
242 set_value("DefaultSettings.VRefresh", &dm
->dmDisplayFrequency
);
243 set_value("DefaultSettings.Flags", &dm
->u2
.dmDisplayFlags
);
244 set_value("DefaultSettings.XPanning", &dm
->u1
.s2
.dmPosition
.x
);
245 set_value("DefaultSettings.YPanning", &dm
->u1
.s2
.dmPosition
.y
);
246 set_value("DefaultSettings.Orientation", &dm
->u1
.s2
.dmDisplayOrientation
);
247 set_value("DefaultSettings.FixedOutput", &dm
->u1
.s2
.dmDisplayFixedOutput
);
255 /***********************************************************************
256 * EnumDisplaySettingsEx (X11DRV.@)
259 BOOL CDECL
X11DRV_EnumDisplaySettingsEx( LPCWSTR name
, DWORD n
, LPDEVMODEW devmode
, DWORD flags
)
261 static const WCHAR dev_name
[CCHDEVICENAME
] =
262 { 'W','i','n','e',' ','X','1','1',' ','d','r','i','v','e','r',0 };
264 devmode
->dmSize
= FIELD_OFFSET(DEVMODEW
, dmICMMethod
);
265 devmode
->dmSpecVersion
= DM_SPECVERSION
;
266 devmode
->dmDriverVersion
= DM_SPECVERSION
;
267 memcpy(devmode
->dmDeviceName
, dev_name
, sizeof(dev_name
));
268 devmode
->dmDriverExtra
= 0;
269 devmode
->u2
.dmDisplayFlags
= 0;
270 devmode
->dmDisplayFrequency
= 0;
271 devmode
->u1
.s2
.dmPosition
.x
= 0;
272 devmode
->u1
.s2
.dmPosition
.y
= 0;
273 devmode
->u1
.s2
.dmDisplayOrientation
= 0;
274 devmode
->u1
.s2
.dmDisplayFixedOutput
= 0;
276 if (n
== ENUM_CURRENT_SETTINGS
)
278 TRACE("mode %d (current) -- getting current mode (%s)\n", n
, handler_name
);
279 n
= pGetCurrentMode();
281 if (n
== ENUM_REGISTRY_SETTINGS
)
283 TRACE("mode %d (registry) -- getting default mode (%s)\n", n
, handler_name
);
284 return read_registry_settings(devmode
);
286 if (n
< dd_mode_count
)
288 devmode
->dmPelsWidth
= dd_modes
[n
].width
;
289 devmode
->dmPelsHeight
= dd_modes
[n
].height
;
290 devmode
->dmBitsPerPel
= dd_modes
[n
].bpp
;
291 devmode
->dmDisplayFrequency
= dd_modes
[n
].refresh_rate
;
292 devmode
->dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
|
294 if (devmode
->dmDisplayFrequency
)
296 devmode
->dmFields
|= DM_DISPLAYFREQUENCY
;
297 TRACE("mode %d -- %dx%dx%dbpp @%d Hz (%s)\n", n
,
298 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, devmode
->dmBitsPerPel
,
299 devmode
->dmDisplayFrequency
, handler_name
);
303 TRACE("mode %d -- %dx%dx%dbpp (%s)\n", n
,
304 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, devmode
->dmBitsPerPel
,
309 TRACE("mode %d -- not present (%s)\n", n
, handler_name
);
310 SetLastError(ERROR_NO_MORE_FILES
);
314 #define _X_FIELD(prefix, bits) if ((fields) & prefix##_##bits) {p+=sprintf(p, "%s%s", first ? "" : ",", #bits); first=FALSE;}
315 static const char * _CDS_flags(DWORD fields
)
320 _X_FIELD(CDS
,UPDATEREGISTRY
);_X_FIELD(CDS
,TEST
);_X_FIELD(CDS
,FULLSCREEN
);
321 _X_FIELD(CDS
,GLOBAL
);_X_FIELD(CDS
,SET_PRIMARY
);_X_FIELD(CDS
,RESET
);
322 _X_FIELD(CDS
,SETRECT
);_X_FIELD(CDS
,NORESET
);
324 return wine_dbg_sprintf("%s", buf
);
326 static const char * _DM_fields(DWORD fields
)
331 _X_FIELD(DM
,BITSPERPEL
);_X_FIELD(DM
,PELSWIDTH
);_X_FIELD(DM
,PELSHEIGHT
);
332 _X_FIELD(DM
,DISPLAYFLAGS
);_X_FIELD(DM
,DISPLAYFREQUENCY
);_X_FIELD(DM
,POSITION
);
334 return wine_dbg_sprintf("%s", buf
);
338 /***********************************************************************
339 * ChangeDisplaySettingsEx (X11DRV.@)
342 LONG CDECL
X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname
, LPDEVMODEW devmode
,
343 HWND hwnd
, DWORD flags
, LPVOID lpvoid
)
347 BOOL def_mode
= TRUE
;
348 char bpp_buffer
[16], freq_buffer
[18];
350 TRACE("(%s,%p,%p,0x%08x,%p)\n",debugstr_w(devname
),devmode
,hwnd
,flags
,lpvoid
);
351 TRACE("flags=%s\n",_CDS_flags(flags
));
354 /* this is the minimal dmSize that XP accepts */
355 if (devmode
->dmSize
< FIELD_OFFSET(DEVMODEW
, dmFields
))
356 return DISP_CHANGE_FAILED
;
358 TRACE("DM_fields=%s\n",_DM_fields(devmode
->dmFields
));
359 TRACE("width=%d height=%d bpp=%d freq=%d (%s)\n",
360 devmode
->dmPelsWidth
,devmode
->dmPelsHeight
,
361 devmode
->dmBitsPerPel
,devmode
->dmDisplayFrequency
, handler_name
);
363 dwBpp
= devmode
->dmBitsPerPel
;
364 if (devmode
->dmFields
& DM_BITSPERPEL
) def_mode
&= !dwBpp
;
365 if (devmode
->dmFields
& DM_PELSWIDTH
) def_mode
&= !devmode
->dmPelsWidth
;
366 if (devmode
->dmFields
& DM_PELSHEIGHT
) def_mode
&= !devmode
->dmPelsHeight
;
367 if (devmode
->dmFields
& DM_DISPLAYFREQUENCY
) def_mode
&= !devmode
->dmDisplayFrequency
;
370 if (def_mode
|| !dwBpp
)
372 if (!X11DRV_EnumDisplaySettingsEx(devname
, ENUM_REGISTRY_SETTINGS
, &dm
, 0))
374 ERR("Default mode not found!\n");
375 return DISP_CHANGE_BADMODE
;
379 TRACE("Return to original display mode (%s)\n", handler_name
);
382 dwBpp
= dm
.dmBitsPerPel
;
385 if ((devmode
->dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
)) != (DM_PELSWIDTH
| DM_PELSHEIGHT
))
387 WARN("devmode doesn't specify the resolution: %04x\n", devmode
->dmFields
);
388 return DISP_CHANGE_BADMODE
;
391 for (i
= 0; i
< dd_mode_count
; i
++)
393 if (devmode
->dmFields
& DM_BITSPERPEL
)
395 if (dwBpp
!= dd_modes
[i
].bpp
)
398 if (devmode
->dmFields
& DM_PELSWIDTH
)
400 if (devmode
->dmPelsWidth
!= dd_modes
[i
].width
)
403 if (devmode
->dmFields
& DM_PELSHEIGHT
)
405 if (devmode
->dmPelsHeight
!= dd_modes
[i
].height
)
408 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) && (dd_modes
[i
].refresh_rate
!= 0) &&
409 devmode
->dmDisplayFrequency
!= 0)
411 if (devmode
->dmDisplayFrequency
!= dd_modes
[i
].refresh_rate
)
414 /* we have a valid mode */
415 TRACE("Requested display settings match mode %d (%s)\n", i
, handler_name
);
417 if (flags
& CDS_UPDATEREGISTRY
)
418 write_registry_settings(devmode
);
420 if (!(flags
& (CDS_TEST
| CDS_NORESET
)))
421 return pSetCurrentMode(i
);
423 return DISP_CHANGE_SUCCESSFUL
;
426 /* no valid modes found, only print the fields we were trying to matching against */
427 bpp_buffer
[0] = freq_buffer
[0] = 0;
428 if (devmode
->dmFields
& DM_BITSPERPEL
)
429 sprintf(bpp_buffer
, "bpp=%u ", devmode
->dmBitsPerPel
);
430 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) && (devmode
->dmDisplayFrequency
!= 0))
431 sprintf(freq_buffer
, "freq=%u ", devmode
->dmDisplayFrequency
);
432 ERR("No matching mode found: width=%d height=%d %s%s(%s)\n",
433 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, bpp_buffer
, freq_buffer
, handler_name
);
435 return DISP_CHANGE_BADMODE
;