[USER32] Add support for navigating a group of radio buttons using a keyboard.
[reactos.git] / win32ss / user / user32 / misc / display.c
1 /*
2 * PROJECT: ReactOS user32.dll
3 * FILE: win32ss/user/user32/misc/display.c
4 * PURPOSE: DDE
5 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 */
7
8 #include <user32.h>
9
10 WINE_DEFAULT_DEBUG_CHANNEL(user32);
11
12 #define SIZEOF_DEVMODEA_300 124
13 #define SIZEOF_DEVMODEA_400 148
14 #define SIZEOF_DEVMODEA_500 156
15 #define SIZEOF_DEVMODEW_300 188
16 #define SIZEOF_DEVMODEW_400 212
17 #define SIZEOF_DEVMODEW_500 220
18
19 /*
20 * @implemented
21 */
22 BOOL WINAPI
23 EnumDisplayDevicesA(
24 LPCSTR lpDevice,
25 DWORD iDevNum,
26 PDISPLAY_DEVICEA lpDisplayDevice,
27 DWORD dwFlags)
28 {
29 BOOL rc;
30 UNICODE_STRING Device;
31 DISPLAY_DEVICEW DisplayDeviceW;
32
33 if (!RtlCreateUnicodeStringFromAsciiz(&Device, (PCSZ)lpDevice))
34 {
35 SetLastError(ERROR_OUTOFMEMORY);
36 return FALSE;
37 }
38
39 RtlZeroMemory(&DisplayDeviceW, sizeof(DISPLAY_DEVICEW));
40 DisplayDeviceW.cb = sizeof(DISPLAY_DEVICEW);
41 rc = NtUserEnumDisplayDevices(&Device,
42 iDevNum,
43 &DisplayDeviceW,
44 dwFlags);
45 if (rc)
46 {
47 /* Copy result from DisplayDeviceW to lpDisplayDevice. Buffers have the same size so result is always NULL terminated. */
48 lpDisplayDevice->StateFlags = DisplayDeviceW.StateFlags;
49 WideCharToMultiByte(CP_ACP, 0, DisplayDeviceW.DeviceName, -1,
50 lpDisplayDevice->DeviceName,
51 sizeof(lpDisplayDevice->DeviceName) / sizeof(lpDisplayDevice->DeviceName[0]),
52 NULL, NULL);
53 WideCharToMultiByte(CP_ACP, 0, DisplayDeviceW.DeviceString, -1,
54 lpDisplayDevice->DeviceString,
55 sizeof(lpDisplayDevice->DeviceString) / sizeof(lpDisplayDevice->DeviceString[0]),
56 NULL, NULL);
57 WideCharToMultiByte(CP_ACP, 0, DisplayDeviceW.DeviceID, -1,
58 lpDisplayDevice->DeviceID,
59 sizeof(lpDisplayDevice->DeviceID) / sizeof(lpDisplayDevice->DeviceID[0]),
60 NULL, NULL);
61 WideCharToMultiByte(CP_ACP, 0, DisplayDeviceW.DeviceKey, -1,
62 lpDisplayDevice->DeviceKey,
63 sizeof(lpDisplayDevice->DeviceKey) / sizeof(lpDisplayDevice->DeviceKey[0]),
64 NULL, NULL);
65 }
66
67 RtlFreeUnicodeString(&Device);
68
69 return rc;
70 }
71
72
73 /*
74 * @implemented
75 */
76 BOOL
77 WINAPI
78 EnumDisplayDevicesW(
79 LPCWSTR lpDevice,
80 DWORD iDevNum,
81 PDISPLAY_DEVICEW lpDisplayDevice,
82 DWORD dwFlags)
83 {
84 UNICODE_STRING Device;
85 BOOL rc;
86
87 RtlInitUnicodeString(&Device, lpDevice);
88
89 rc = NtUserEnumDisplayDevices(
90 &Device,
91 iDevNum,
92 lpDisplayDevice,
93 dwFlags);
94
95 return rc;
96 }
97
98
99 /*
100 * @implemented
101 */
102 BOOL
103 WINAPI
104 EnumDisplayMonitors(
105 HDC hdc,
106 LPCRECT lprcClip,
107 MONITORENUMPROC lpfnEnum,
108 LPARAM dwData)
109 {
110 INT iCount, i;
111 HMONITOR *hMonitorList;
112 LPRECT pRectList;
113 HANDLE hHeap;
114 BOOL ret = FALSE;
115
116 /* get list of monitors/rects */
117 iCount = NtUserEnumDisplayMonitors(hdc, lprcClip, NULL, NULL, 0);
118 if (iCount < 0)
119 {
120 /* FIXME: SetLastError() */
121 return FALSE;
122 }
123 if (iCount == 0)
124 {
125 return TRUE;
126 }
127
128 hHeap = GetProcessHeap();
129 hMonitorList = HeapAlloc(hHeap, 0, sizeof (HMONITOR) * iCount);
130 if (hMonitorList == NULL)
131 {
132 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
133 return FALSE;
134 }
135 pRectList = HeapAlloc(hHeap, 0, sizeof (RECT) * iCount);
136 if (pRectList == NULL)
137 {
138 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
139 goto cleanup;
140 }
141
142 iCount = NtUserEnumDisplayMonitors(hdc, lprcClip, hMonitorList, pRectList, iCount);
143 if (iCount <= 0)
144 {
145 /* FIXME: SetLastError() */
146 goto cleanup;
147 }
148
149 /* enumerate list */
150 for (i = 0; i < iCount; i++)
151 {
152 HMONITOR hMonitor = hMonitorList[i];
153 LPRECT pMonitorRect = pRectList + i;
154 HDC hMonitorDC = NULL;
155
156 if (hdc != NULL)
157 {
158 /* make monitor DC */
159 hMonitorDC = hdc;
160 }
161
162 if (!lpfnEnum(hMonitor, hMonitorDC, pMonitorRect, dwData))
163 goto cleanup; /* return FALSE */
164 }
165
166 ret = TRUE;
167
168 cleanup:
169 if(hMonitorList)
170 HeapFree(hHeap, 0, hMonitorList);
171 if(pRectList)
172 HeapFree(hHeap, 0, pRectList);
173 return ret;
174 }
175
176
177 /*
178 * @implemented
179 */
180 BOOL
181 WINAPI
182 EnumDisplaySettingsExA(
183 LPCSTR lpszDeviceName,
184 DWORD iModeNum,
185 LPDEVMODEA lpDevMode,
186 DWORD dwFlags)
187 {
188 NTSTATUS Status;
189 UNICODE_STRING usDeviceName;
190 PUNICODE_STRING pusDeviceName = NULL;
191 LPDEVMODEW lpExtendedDevMode;
192 BOOL Result = FALSE;
193
194 if (lpszDeviceName)
195 {
196 if (!RtlCreateUnicodeStringFromAsciiz(&usDeviceName, (PCSZ)lpszDeviceName))
197 {
198 SetLastError(ERROR_OUTOFMEMORY);
199 return FALSE;
200 }
201 pusDeviceName = &usDeviceName;
202 }
203
204 /* Allocate memory for DEVMODEW and extra data */
205 lpExtendedDevMode = RtlAllocateHeap(RtlGetProcessHeap(),
206 HEAP_ZERO_MEMORY,
207 sizeof(DEVMODEW) + lpDevMode->dmDriverExtra);
208 if (!lpExtendedDevMode)
209 {
210 if (pusDeviceName)
211 RtlFreeUnicodeString(&usDeviceName);
212
213 return FALSE;
214 }
215
216 /* Initialize structure fields */
217 lpExtendedDevMode->dmSize = sizeof(DEVMODEW);
218 lpExtendedDevMode->dmDriverExtra = lpDevMode->dmDriverExtra;
219
220 Status = NtUserEnumDisplaySettings(pusDeviceName, iModeNum, lpExtendedDevMode, dwFlags);
221
222 if (pusDeviceName)
223 RtlFreeUnicodeString(&usDeviceName);
224
225 if (NT_SUCCESS(Status))
226 {
227 /* Store old structure size */
228 WORD OldSize = lpDevMode->dmSize;
229
230 #define COPYS(f,len) WideCharToMultiByte(CP_THREAD_ACP, 0, lpExtendedDevMode->f, len, (LPSTR)lpDevMode->f, len, NULL, NULL)
231 #define COPYN(f) lpDevMode->f = lpExtendedDevMode->f
232
233 COPYS(dmDeviceName, CCHDEVICENAME);
234 COPYN(dmSpecVersion);
235 COPYN(dmDriverVersion);
236 COPYN(dmFields);
237 COPYN(dmPosition.x);
238 COPYN(dmPosition.y);
239 COPYN(dmScale);
240 COPYN(dmCopies);
241 COPYN(dmDefaultSource);
242 COPYN(dmPrintQuality);
243 COPYN(dmColor);
244 COPYN(dmDuplex);
245 COPYN(dmYResolution);
246 COPYN(dmTTOption);
247 COPYN(dmCollate);
248 COPYS(dmFormName,CCHFORMNAME);
249 COPYN(dmLogPixels);
250 COPYN(dmBitsPerPel);
251 COPYN(dmPelsWidth);
252 COPYN(dmPelsHeight);
253 COPYN(dmDisplayFlags); // aka dmNup
254 COPYN(dmDisplayFrequency);
255
256 /* we're done with 0x300 fields */
257 if (OldSize > SIZEOF_DEVMODEA_300)
258 {
259 COPYN(dmICMMethod);
260 COPYN(dmICMIntent);
261 COPYN(dmMediaType);
262 COPYN(dmDitherType);
263 COPYN(dmReserved1);
264 COPYN(dmReserved2);
265
266 /* we're done with 0x400 fields */
267 if (OldSize > SIZEOF_DEVMODEA_400)
268 {
269 COPYN(dmPanningWidth);
270 COPYN(dmPanningHeight);
271 }
272 }
273
274 /* Restore old size */
275 lpDevMode->dmSize = OldSize;
276
277 /* Extra data presented? */
278 if (lpDevMode->dmDriverExtra && lpExtendedDevMode->dmDriverExtra)
279 {
280 /* We choose the smallest size */
281 if (lpDevMode->dmDriverExtra > lpExtendedDevMode->dmDriverExtra)
282 lpDevMode->dmDriverExtra = lpExtendedDevMode->dmDriverExtra;
283
284 /* Copy extra data */
285 RtlCopyMemory((PUCHAR)lpDevMode + OldSize,
286 lpExtendedDevMode + 1,
287 lpDevMode->dmDriverExtra);
288 }
289
290 /* If the size of source structure is less, than used, we clean unsupported flags */
291 if (OldSize < FIELD_OFFSET(DEVMODEA, dmPanningHeight))
292 lpDevMode->dmFields &= ~DM_PANNINGHEIGHT;
293
294 if (OldSize < FIELD_OFFSET(DEVMODEA, dmPanningWidth))
295 lpDevMode->dmFields &= ~DM_PANNINGWIDTH;
296
297 Result = TRUE;
298 }
299
300 /* Free memory */
301 RtlFreeHeap(RtlGetProcessHeap(), 0, lpExtendedDevMode);
302
303 return Result;
304 }
305
306
307 /*
308 * @implemented
309 */
310 BOOL
311 WINAPI
312 EnumDisplaySettingsA(
313 LPCSTR lpszDeviceName,
314 DWORD iModeNum,
315 LPDEVMODEA lpDevMode)
316 {
317 /* Fixup sizes */
318 lpDevMode->dmSize = FIELD_OFFSET(DEVMODEA, dmICMMethod);
319 lpDevMode->dmDriverExtra = 0;
320
321 return EnumDisplaySettingsExA(lpszDeviceName, iModeNum, lpDevMode, 0);
322 }
323
324
325 /*
326 * @implemented
327 */
328 BOOL
329 WINAPI
330 EnumDisplaySettingsExW(
331 LPCWSTR lpszDeviceName,
332 DWORD iModeNum,
333 LPDEVMODEW lpDevMode,
334 DWORD dwFlags)
335 {
336 NTSTATUS Status;
337 UNICODE_STRING usDeviceName;
338 PUNICODE_STRING pusDeviceName = NULL;
339 LPDEVMODEW lpExtendedDevMode;
340 BOOL Result = FALSE;
341
342 if (lpszDeviceName)
343 {
344 RtlInitUnicodeString(&usDeviceName, lpszDeviceName);
345 pusDeviceName = &usDeviceName;
346 }
347
348 /* Allocate memory for DEVMODEW and extra data */
349 lpExtendedDevMode = RtlAllocateHeap(RtlGetProcessHeap(),
350 HEAP_ZERO_MEMORY,
351 sizeof(DEVMODEW) + lpDevMode->dmDriverExtra);
352 if (!lpExtendedDevMode)
353 return FALSE;
354
355 /* Initialize structure fields */
356 lpExtendedDevMode->dmSize = sizeof(DEVMODEW);
357 lpExtendedDevMode->dmDriverExtra = lpDevMode->dmDriverExtra;
358
359 Status = NtUserEnumDisplaySettings(pusDeviceName, iModeNum, lpExtendedDevMode, dwFlags);
360 if (NT_SUCCESS(Status))
361 {
362 /* Store old structure sizes */
363 WORD OldSize = lpDevMode->dmSize;
364 WORD OldDriverExtra = lpDevMode->dmDriverExtra;
365
366 /* Copy general data */
367 RtlCopyMemory(lpDevMode, lpExtendedDevMode, OldSize);
368
369 /* Restore old sizes */
370 lpDevMode->dmSize = OldSize;
371 lpDevMode->dmDriverExtra = OldDriverExtra;
372
373 /* Extra data presented? */
374 if (lpDevMode->dmDriverExtra && lpExtendedDevMode->dmDriverExtra)
375 {
376 /* We choose the smallest size */
377 if (lpDevMode->dmDriverExtra > lpExtendedDevMode->dmDriverExtra)
378 lpDevMode->dmDriverExtra = lpExtendedDevMode->dmDriverExtra;
379
380 /* Copy extra data */
381 RtlCopyMemory((PUCHAR)lpDevMode + OldSize,
382 lpExtendedDevMode + 1,
383 lpDevMode->dmDriverExtra);
384 }
385
386 /* If the size of source structure is less, than used, we clean unsupported flags */
387 if (OldSize < FIELD_OFFSET(DEVMODEW, dmPanningHeight))
388 lpDevMode->dmFields &= ~DM_PANNINGHEIGHT;
389
390 if (OldSize < FIELD_OFFSET(DEVMODEW, dmPanningWidth))
391 lpDevMode->dmFields &= ~DM_PANNINGWIDTH;
392
393 Result = TRUE;
394 }
395
396 /* Free memory */
397 RtlFreeHeap(RtlGetProcessHeap(), 0, lpExtendedDevMode);
398
399 return Result;
400 }
401
402
403 /*
404 * @implemented
405 */
406 BOOL
407 WINAPI
408 EnumDisplaySettingsW(
409 LPCWSTR lpszDeviceName,
410 DWORD iModeNum,
411 LPDEVMODEW lpDevMode)
412 {
413 /* Fixup sizes */
414 lpDevMode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
415 lpDevMode->dmDriverExtra = 0;
416
417 return EnumDisplaySettingsExW(lpszDeviceName, iModeNum, lpDevMode, 0);
418 }
419
420
421 /*
422 * @implemented
423 */
424 BOOL
425 WINAPI
426 GetMonitorInfoA(
427 HMONITOR hMonitor,
428 LPMONITORINFO lpmi)
429 {
430 if (lpmi->cbSize == sizeof (MONITORINFO))
431 {
432 return NtUserGetMonitorInfo(hMonitor, lpmi);
433 }
434 else if (lpmi->cbSize != sizeof (MONITORINFOEXA))
435 {
436 SetLastError(ERROR_INVALID_PARAMETER);
437 return FALSE;
438 }
439 else
440 {
441 MONITORINFOEXW miExW;
442 INT res;
443
444 miExW.cbSize = sizeof (MONITORINFOEXW);
445 if (!NtUserGetMonitorInfo(hMonitor, (LPMONITORINFO)&miExW))
446 {
447 return FALSE;
448 }
449 memcpy(lpmi, &miExW, sizeof (MONITORINFO));
450 res = WideCharToMultiByte(CP_THREAD_ACP, 0, miExW.szDevice, -1,
451 ((LPMONITORINFOEXA)lpmi)->szDevice, CCHDEVICENAME,
452 NULL, NULL);
453 if (res == 0)
454 {
455 WARN("WideCharToMultiByte() failed!\n");
456 return FALSE;
457 }
458 }
459
460 return TRUE;
461 }
462
463
464 /*
465 * @implemented
466 */
467 BOOL
468 WINAPI
469 GetMonitorInfoW(
470 HMONITOR hMonitor,
471 LPMONITORINFO lpmi)
472 {
473 return NtUserGetMonitorInfo(hMonitor, lpmi);
474 }
475
476
477 /*
478 * @implemented
479 */
480 HMONITOR
481 WINAPI
482 MonitorFromPoint(
483 IN POINT ptPoint,
484 IN DWORD dwFlags )
485 {
486 return NtUserMonitorFromPoint(ptPoint, dwFlags);
487 }
488
489
490 /*
491 * @implemented
492 */
493 HMONITOR
494 WINAPI
495 MonitorFromRect(
496 IN LPCRECT lpcRect,
497 IN DWORD dwFlags )
498 {
499 return NtUserMonitorFromRect(lpcRect, dwFlags);
500 }
501
502
503 /*
504 * @implemented
505 */
506 HMONITOR
507 WINAPI
508 MonitorFromWindow(
509 IN HWND hWnd,
510 IN DWORD dwFlags )
511 {
512 return NtUserMonitorFromWindow(hWnd, dwFlags);
513 }
514
515
516 /*
517 * @implemented
518 */
519 LONG
520 WINAPI
521 ChangeDisplaySettingsExA(
522 LPCSTR lpszDeviceName,
523 LPDEVMODEA lpDevMode,
524 HWND hwnd,
525 DWORD dwflags,
526 LPVOID lParam)
527 {
528 LONG rc;
529 UNICODE_STRING DeviceName;
530 PUNICODE_STRING pDeviceName = &DeviceName;
531
532 if (lpszDeviceName != NULL)
533 {
534 if (!RtlCreateUnicodeStringFromAsciiz(pDeviceName, (PCSZ)lpszDeviceName))
535 {
536 SetLastError(ERROR_OUTOFMEMORY);
537 return DISP_CHANGE_BADPARAM; /* FIXME what to return? */
538 }
539 }
540 else
541 pDeviceName = NULL;
542
543 if (lpDevMode != NULL)
544 {
545 LPDEVMODEW pDevModeW;
546 pDevModeW = GdiConvertToDevmodeW(lpDevMode);
547 if(pDevModeW)
548 {
549 rc = NtUserChangeDisplaySettings(pDeviceName, pDevModeW, dwflags, lParam);
550 RtlFreeHeap(GetProcessHeap(), 0, pDevModeW);
551 }
552 else
553 rc = DISP_CHANGE_SUCCESSFUL;
554 }
555 else
556 rc = NtUserChangeDisplaySettings(pDeviceName, NULL, dwflags, lParam);
557
558 if (lpszDeviceName != NULL)
559 RtlFreeUnicodeString(&DeviceName);
560
561 return rc;
562 }
563
564
565 /*
566 * @implemented
567 */
568 LONG
569 WINAPI
570 ChangeDisplaySettingsA(
571 LPDEVMODEA lpDevMode,
572 DWORD dwflags)
573 {
574 if(lpDevMode)
575 lpDevMode->dmDriverExtra = 0;
576 return ChangeDisplaySettingsExA ( NULL, lpDevMode, NULL, dwflags, 0 );
577 }
578
579
580 /*
581 * @implemented
582 */
583 LONG
584 WINAPI
585 ChangeDisplaySettingsExW(
586 LPCWSTR lpszDeviceName,
587 LPDEVMODEW lpDevMode,
588 HWND hwnd,
589 DWORD dwflags,
590 LPVOID lParam)
591 {
592 LONG rc;
593 UNICODE_STRING DeviceName;
594 PUNICODE_STRING pDeviceName = &DeviceName;
595
596 if (lpszDeviceName != NULL)
597 RtlInitUnicodeString(pDeviceName, lpszDeviceName);
598 else
599 pDeviceName = NULL;
600
601 rc = NtUserChangeDisplaySettings(pDeviceName, lpDevMode, dwflags, lParam);
602
603 return rc;
604 }
605
606
607 /*
608 * @implemented
609 */
610 LONG
611 WINAPI
612 ChangeDisplaySettingsW(
613 LPDEVMODEW lpDevMode,
614 DWORD dwflags)
615 {
616 if(lpDevMode)
617 lpDevMode->dmDriverExtra = 0;
618 return ChangeDisplaySettingsExW(NULL, lpDevMode, NULL, dwflags, 0);
619 }