rename DCs pDc_Attr to pdcattr, like in gdikdx.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dc.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * DC.C - Device context functions
21 *
22 */
23
24 #include <w32k.h>
25 #include <bugcodes.h>
26
27 #define NDEBUG
28 #include <debug.h>
29
30 // --------------------------------------------------------- File Statics
31
32 static GDIDEVICE PrimarySurface;
33 PGDIDEVICE pPrimarySurface = &PrimarySurface;
34 static KEVENT VideoDriverNeedsPreparation;
35 static KEVENT VideoDriverPrepared;
36 PDC defaultDCstate = NULL;
37
38
39 NTSTATUS FASTCALL
40 InitDcImpl(VOID)
41 {
42 KeInitializeEvent(&VideoDriverNeedsPreparation, SynchronizationEvent, TRUE);
43 KeInitializeEvent(&VideoDriverPrepared, NotificationEvent, FALSE);
44 return STATUS_SUCCESS;
45 }
46
47 /* FIXME: DCs should probably be thread safe */
48
49 // ----------------------------------------------------- Public Functions
50
51 BOOL APIENTRY
52 NtGdiCancelDC(HDC hDC)
53 {
54 UNIMPLEMENTED;
55 return FALSE;
56 }
57
58 HDC APIENTRY
59 NtGdiCreateCompatibleDC(HDC hDC)
60 {
61 PDC NewDC, OrigDC;
62 PDC_ATTR nDc_Attr, oDc_Attr;
63 HDC hNewDC, DisplayDC = NULL;
64 HRGN hVisRgn;
65 UNICODE_STRING DriverName;
66 DWORD Layout = 0;
67
68 if (hDC == NULL)
69 {
70 RtlInitUnicodeString(&DriverName, L"DISPLAY");
71 DisplayDC = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, TRUE);
72 if (NULL == DisplayDC)
73 {
74 DPRINT1("Failed to create DisplayDC\n");
75 return NULL;
76 }
77 hDC = DisplayDC;
78 }
79
80 /* Allocate a new DC based on the original DC's device */
81 OrigDC = DC_LockDc(hDC);
82 if (NULL == OrigDC)
83 {
84 if (NULL != DisplayDC)
85 {
86 NtGdiDeleteObjectApp(DisplayDC);
87 }
88 DPRINT1("Failed to lock hDC\n");
89 return NULL;
90 }
91 hNewDC = DC_AllocDC(&OrigDC->rosdc.DriverName);
92 if (NULL == hNewDC)
93 {
94 DPRINT1("Failed to create hNewDC\n");
95 DC_UnlockDc(OrigDC);
96 if (NULL != DisplayDC)
97 {
98 NtGdiDeleteObjectApp(DisplayDC);
99 }
100 return NULL;
101 }
102 NewDC = DC_LockDc( hNewDC );
103
104 if(!NewDC)
105 {
106 DPRINT1("Failed to lock hNewDC\n");
107 NtGdiDeleteObjectApp(hNewDC);
108 return NULL;
109 }
110
111 oDc_Attr = OrigDC->pdcattr;
112 nDc_Attr = NewDC->pdcattr;
113
114 /* Copy information from original DC to new DC */
115 NewDC->DcLevel.hdcSave = hNewDC;
116
117 NewDC->dhpdev = OrigDC->dhpdev;
118
119 NewDC->rosdc.bitsPerPixel = OrigDC->rosdc.bitsPerPixel;
120
121 /* DriverName is copied in the AllocDC routine */
122 nDc_Attr->ptlWindowOrg = oDc_Attr->ptlWindowOrg;
123 nDc_Attr->szlWindowExt = oDc_Attr->szlWindowExt;
124 nDc_Attr->ptlViewportOrg = oDc_Attr->ptlViewportOrg;
125 nDc_Attr->szlViewportExt = oDc_Attr->szlViewportExt;
126
127 NewDC->dctype = DC_TYPE_MEMORY; // Always!
128 NewDC->rosdc.hBitmap = NtGdiGetStockObject(DEFAULT_BITMAP);
129 NewDC->ppdev = OrigDC->ppdev;
130 NewDC->DcLevel.hpal = OrigDC->DcLevel.hpal;
131
132 nDc_Attr->lTextAlign = oDc_Attr->lTextAlign;
133 nDc_Attr->lBkMode = oDc_Attr->lBkMode;
134 nDc_Attr->jBkMode = oDc_Attr->jBkMode;
135 nDc_Attr->jROP2 = oDc_Attr->jROP2;
136 nDc_Attr->dwLayout = oDc_Attr->dwLayout;
137 if (oDc_Attr->dwLayout & LAYOUT_ORIENTATIONMASK) Layout = oDc_Attr->dwLayout;
138 NewDC->DcLevel.flPath = OrigDC->DcLevel.flPath;
139 nDc_Attr->ulDirty_ = oDc_Attr->ulDirty_;
140 nDc_Attr->iCS_CP = oDc_Attr->iCS_CP;
141
142 NewDC->erclWindow = (RECTL){0,0,1,1};
143
144 DC_UnlockDc(NewDC);
145 DC_UnlockDc(OrigDC);
146 if (NULL != DisplayDC)
147 {
148 NtGdiDeleteObjectApp(DisplayDC);
149 }
150
151 hVisRgn = NtGdiCreateRectRgn(0, 0, 1, 1);
152 if (hVisRgn)
153 {
154 GdiSelectVisRgn(hNewDC, hVisRgn);
155 NtGdiDeleteObject(hVisRgn);
156 }
157 if (Layout) NtGdiSetLayout( hNewDC, -1, Layout);
158
159 DC_InitDC(hNewDC);
160 return hNewDC;
161 }
162
163 static BOOLEAN FASTCALL
164 GetRegistryPath(PUNICODE_STRING RegistryPath, ULONG DisplayNumber)
165 {
166 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
167 WCHAR DeviceNameBuffer[20];
168 NTSTATUS Status;
169
170 swprintf(DeviceNameBuffer, L"\\Device\\Video%lu", DisplayNumber);
171 RtlInitUnicodeString(RegistryPath, NULL);
172 RtlZeroMemory(QueryTable, sizeof(QueryTable));
173 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
174 QueryTable[0].Name = DeviceNameBuffer;
175 QueryTable[0].EntryContext = RegistryPath;
176
177 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
178 L"VIDEO",
179 QueryTable,
180 NULL,
181 NULL);
182 if (! NT_SUCCESS(Status))
183 {
184 DPRINT1("No \\Device\\Video%lu value in DEVICEMAP\\VIDEO found\n", DisplayNumber);
185 return FALSE;
186 }
187
188 DPRINT("RegistryPath %wZ\n", RegistryPath);
189
190 return TRUE;
191 }
192
193 static BOOL FASTCALL
194 FindDriverFileNames(PUNICODE_STRING DriverFileNames, ULONG DisplayNumber)
195 {
196 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
197 UNICODE_STRING RegistryPath;
198 NTSTATUS Status;
199
200 if (! GetRegistryPath(&RegistryPath, DisplayNumber))
201 {
202 DPRINT("GetRegistryPath failed\n");
203 return FALSE;
204 }
205
206 RtlZeroMemory(QueryTable, sizeof(QueryTable));
207 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
208 QueryTable[0].Name = L"InstalledDisplayDrivers";
209 QueryTable[0].EntryContext = DriverFileNames;
210
211 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
212 RegistryPath.Buffer,
213 QueryTable,
214 NULL,
215 NULL);
216 ExFreePoolWithTag(RegistryPath.Buffer, TAG_RTLREGISTRY);
217 if (! NT_SUCCESS(Status))
218 {
219 DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
220 return FALSE;
221 }
222
223 DPRINT("DriverFileNames %S\n", DriverFileNames->Buffer);
224
225 return TRUE;
226 }
227
228 static NTSTATUS APIENTRY
229 DevModeCallback(IN PWSTR ValueName,
230 IN ULONG ValueType,
231 IN PVOID ValueData,
232 IN ULONG ValueLength,
233 IN PVOID Context,
234 IN PVOID EntryContext)
235 {
236 PDEVMODEW DevMode = (PDEVMODEW) Context;
237
238 DPRINT("Found registry value for name %S: type %d, length %d\n",
239 ValueName, ValueType, ValueLength);
240
241 if (REG_DWORD == ValueType && sizeof(DWORD) == ValueLength)
242 {
243 if (0 == _wcsicmp(ValueName, L"DefaultSettings.BitsPerPel"))
244 {
245 DevMode->dmBitsPerPel = *((DWORD *) ValueData);
246 }
247 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.Flags"))
248 {
249 DevMode->dmDisplayFlags = *((DWORD *) ValueData);
250 }
251 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.VRefresh"))
252 {
253 DevMode->dmDisplayFrequency = *((DWORD *) ValueData);
254 }
255 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XPanning"))
256 {
257 DevMode->dmPanningWidth = *((DWORD *) ValueData);
258 }
259 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XResolution"))
260 {
261 DevMode->dmPelsWidth = *((DWORD *) ValueData);
262 }
263 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YPanning"))
264 {
265 DevMode->dmPanningHeight = *((DWORD *) ValueData);
266 }
267 else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YResolution"))
268 {
269 DevMode->dmPelsHeight = *((DWORD *) ValueData);
270 }
271 }
272
273 return STATUS_SUCCESS;
274 }
275
276 static BOOL FASTCALL
277 SetupDevMode(PDEVMODEW DevMode, ULONG DisplayNumber)
278 {
279 UNICODE_STRING RegistryPath;
280 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
281 NTSTATUS Status;
282 BOOLEAN Valid = TRUE;
283
284 if (!GetRegistryPath(&RegistryPath, DisplayNumber))
285 {
286 DPRINT("GetRegistryPath failed\n");
287 return FALSE;
288 }
289
290 RtlZeroMemory(QueryTable, sizeof(QueryTable));
291 QueryTable[0].QueryRoutine = DevModeCallback;
292 QueryTable[0].Flags = 0;
293 QueryTable[0].Name = NULL;
294 QueryTable[0].EntryContext = NULL;
295 QueryTable[0].DefaultType = REG_NONE;
296 QueryTable[0].DefaultData = NULL;
297 QueryTable[0].DefaultLength = 0;
298
299 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
300 RegistryPath.Buffer,
301 QueryTable,
302 DevMode,
303 NULL);
304 if (! NT_SUCCESS(Status))
305 {
306 DPRINT("RtlQueryRegistryValues for %wZ failed with status 0x%08x\n",
307 &RegistryPath, Status);
308 Valid = FALSE;
309 }
310 else
311 {
312 DPRINT("dmBitsPerPel %d dmDisplayFrequency %d dmPelsWidth %d dmPelsHeight %d\n",
313 DevMode->dmBitsPerPel, DevMode->dmDisplayFrequency,
314 DevMode->dmPelsWidth, DevMode->dmPelsHeight);
315 if (0 == DevMode->dmBitsPerPel || 0 == DevMode->dmDisplayFrequency
316 || 0 == DevMode->dmPelsWidth || 0 == DevMode->dmPelsHeight)
317 {
318 DPRINT("Not all required devmode members are set\n");
319 Valid = FALSE;
320 }
321 }
322
323 ExFreePoolWithTag(RegistryPath.Buffer, TAG_RTLREGISTRY);
324
325 if (! Valid)
326 {
327 RtlZeroMemory(DevMode, sizeof(DEVMODEW));
328 }
329
330 return Valid;
331 }
332
333 static BOOL FASTCALL
334 IntPrepareDriver()
335 {
336 PGD_ENABLEDRIVER GDEnableDriver;
337 DRVENABLEDATA DED;
338 UNICODE_STRING DriverFileNames;
339 PWSTR CurrentName;
340 BOOL GotDriver;
341 BOOL DoDefault;
342 ULONG DisplayNumber;
343 LARGE_INTEGER Zero;
344 BOOLEAN ret = FALSE;
345
346 Zero.QuadPart = 0;
347 if (STATUS_SUCCESS != KeWaitForSingleObject(&VideoDriverNeedsPreparation, Executive, KernelMode, TRUE, &Zero))
348 {
349 /* Concurrent access. Wait for VideoDriverPrepared event */
350 if (STATUS_SUCCESS == KeWaitForSingleObject(&VideoDriverPrepared, Executive, KernelMode, TRUE, NULL))
351 ret = PrimarySurface.PreparedDriver;
352 goto cleanup;
353 }
354 // HAX! Fixme so I can support more than one! So how many?
355 for (DisplayNumber = 0; ; DisplayNumber++)
356 {
357 DPRINT("Trying to load display driver no. %d\n", DisplayNumber);
358
359 RtlZeroMemory(&PrimarySurface, sizeof(PrimarySurface));
360
361 // if (!pPrimarySurface) pPrimarySurface = ExAllocatePoolWithTag(PagedPool, sizeof(GDIDEVICE), TAG_GDIPDEV);
362
363 PrimarySurface.VideoFileObject = DRIVER_FindMPDriver(DisplayNumber);
364
365 /* Open the miniport driver */
366 if (PrimarySurface.VideoFileObject == NULL)
367 {
368 DPRINT1("FindMPDriver failed\n");
369 goto cleanup;
370 }
371
372 /* Retrieve DDI driver names from registry */
373 RtlInitUnicodeString(&DriverFileNames, NULL);
374 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
375 {
376 DPRINT1("FindDriverFileNames failed\n");
377 continue;
378 }
379
380 /*
381 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
382 * scan all of them until a good one found.
383 */
384 CurrentName = DriverFileNames.Buffer;
385 GotDriver = FALSE;
386 while (!GotDriver &&
387 CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
388 {
389 /* Get the DDI driver's entry point */
390 GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
391 if (NULL == GDEnableDriver)
392 {
393 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
394 }
395 else
396 {
397 /* Call DDI driver's EnableDriver function */
398 RtlZeroMemory(&DED, sizeof(DED));
399
400 if (! GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof(DED), &DED))
401 {
402 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
403 }
404 else
405 {
406 GotDriver = TRUE;
407 }
408 }
409
410 if (! GotDriver)
411 {
412 /* Skip to the next name but never get past the Unicode string */
413 while (L'\0' != *CurrentName &&
414 CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
415 {
416 CurrentName++;
417 }
418 if (CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
419 {
420 CurrentName++;
421 }
422 }
423 }
424
425 if (!GotDriver)
426 {
427 ObDereferenceObject(PrimarySurface.VideoFileObject);
428 ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
429 DPRINT1("No suitable DDI driver found\n");
430 continue;
431 }
432
433 DPRINT("Display driver %S loaded\n", CurrentName);
434
435 ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
436
437 DPRINT("Building DDI Functions\n");
438
439 /* Construct DDI driver function dispatch table */
440 if (!DRIVER_BuildDDIFunctions(&DED, &PrimarySurface.DriverFunctions))
441 {
442 ObDereferenceObject(PrimarySurface.VideoFileObject);
443 DPRINT1("BuildDDIFunctions failed\n");
444 goto cleanup;
445 }
446
447 /* Allocate a phyical device handle from the driver */
448 // Support DMW.dmSize + DMW.dmDriverExtra & Alloc DMW then set prt pdmwDev.
449 PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
450 if (SetupDevMode(&PrimarySurface.DMW, DisplayNumber))
451 {
452 PrimarySurface.hPDev = PrimarySurface.DriverFunctions.EnablePDEV(
453 &PrimarySurface.DMW,
454 L"",
455 HS_DDI_MAX,
456 PrimarySurface.FillPatterns,
457 sizeof(PrimarySurface.GDIInfo),
458 (ULONG *) &PrimarySurface.GDIInfo,
459 sizeof(PrimarySurface.DevInfo),
460 &PrimarySurface.DevInfo,
461 NULL,
462 L"",
463 (HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
464 DoDefault = (NULL == PrimarySurface.hPDev);
465 if (DoDefault)
466 {
467 DPRINT1("DrvEnablePDev with registry parameters failed\n");
468 }
469 }
470 else
471 {
472 DoDefault = TRUE;
473 }
474
475 if (DoDefault)
476 {
477 RtlZeroMemory(&(PrimarySurface.DMW), sizeof(DEVMODEW));
478 PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
479 PrimarySurface.hPDev = PrimarySurface.DriverFunctions.EnablePDEV(
480 &PrimarySurface.DMW,
481 L"",
482 HS_DDI_MAX,
483 PrimarySurface.FillPatterns,
484 sizeof(PrimarySurface.GDIInfo),
485 (ULONG *) &PrimarySurface.GDIInfo,
486 sizeof(PrimarySurface.DevInfo),
487 &PrimarySurface.DevInfo,
488 NULL,
489 L"",
490 (HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
491
492 if (NULL == PrimarySurface.hPDev)
493 {
494 ObDereferenceObject(PrimarySurface.VideoFileObject);
495 DPRINT1("DrvEnablePDEV with default parameters failed\n");
496 DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
497 continue;
498 }
499
500 // Update the primary surface with what we really got
501 PrimarySurface.DMW.dmPelsWidth = PrimarySurface.GDIInfo.ulHorzRes;
502 PrimarySurface.DMW.dmPelsHeight = PrimarySurface.GDIInfo.ulVertRes;
503 PrimarySurface.DMW.dmBitsPerPel = PrimarySurface.GDIInfo.cBitsPixel;
504 PrimarySurface.DMW.dmDisplayFrequency = PrimarySurface.GDIInfo.ulVRefresh;
505 }
506
507 if (!PrimarySurface.DMW.dmDriverExtra)
508 {
509 PrimarySurface.pdmwDev = &PrimarySurface.DMW; // HAX!
510 }
511 else
512 {
513 DPRINT1("WARNING!!! Need to Alloc DMW !!!!!!\n");
514 }
515 // Dont remove until we finish testing other drivers.
516 if (PrimarySurface.DMW.dmDriverExtra != 0)
517 {
518 DPRINT1("**** DMW extra = %u bytes. Please report to ros-dev@reactos.org ****\n", PrimarySurface.DMW.dmDriverExtra);
519 }
520
521 if (0 == PrimarySurface.GDIInfo.ulLogPixelsX)
522 {
523 DPRINT("Adjusting GDIInfo.ulLogPixelsX\n");
524 PrimarySurface.GDIInfo.ulLogPixelsX = 96;
525 }
526 if (0 == PrimarySurface.GDIInfo.ulLogPixelsY)
527 {
528 DPRINT("Adjusting GDIInfo.ulLogPixelsY\n");
529 PrimarySurface.GDIInfo.ulLogPixelsY = 96;
530 }
531
532 PrimarySurface.Pointer.Exclude.right = -1;
533
534 DPRINT("calling completePDev\n");
535
536 /* Complete initialization of the physical device */
537 PrimarySurface.DriverFunctions.CompletePDEV(
538 PrimarySurface.hPDev,
539 (HDEV)&PrimarySurface);
540
541 DPRINT("calling DRIVER_ReferenceDriver\n");
542
543 DRIVER_ReferenceDriver(L"DISPLAY");
544
545 PrimarySurface.PreparedDriver = TRUE;
546 PrimarySurface.DisplayNumber = DisplayNumber;
547 PrimarySurface.flFlags = PDEV_DISPLAY; // Hard set,, add more flags.
548 PrimarySurface.hsemDevLock = (PERESOURCE)EngCreateSemaphore();
549 // Should be null,, but make sure for now.
550 PrimarySurface.pvGammaRamp = NULL;
551 PrimarySurface.ppdevNext = NULL; // Fixme! We need to support more than display drvs.
552 PrimarySurface.ppdevParent = NULL; // Always NULL if primary.
553 PrimarySurface.pGraphicsDev = NULL; // Fixme!
554 PrimarySurface.pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), TAG_EDDGBL);
555 if (PrimarySurface.pEDDgpl)
556 {
557 RtlZeroMemory( PrimarySurface.pEDDgpl ,sizeof(EDD_DIRECTDRAW_GLOBAL));
558 ret = TRUE;
559 }
560 goto cleanup;
561 }
562
563 cleanup:
564 KeSetEvent(&VideoDriverPrepared, 1, FALSE);
565 return ret;
566 }
567
568 static BOOL FASTCALL
569 IntPrepareDriverIfNeeded()
570 {
571 return (PrimarySurface.PreparedDriver ? TRUE : IntPrepareDriver());
572 }
573
574 static BOOL FASTCALL
575 PrepareVideoPrt()
576 {
577 PIRP Irp;
578 NTSTATUS Status;
579 IO_STATUS_BLOCK Iosb;
580 BOOL Prepare = TRUE;
581 ULONG Length = sizeof(BOOL);
582 PIO_STACK_LOCATION StackPtr;
583 LARGE_INTEGER StartOffset;
584 PFILE_OBJECT FileObject = PrimarySurface.VideoFileObject;
585 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
586
587 DPRINT("PrepareVideoPrt() called\n");
588
589 KeClearEvent(&PrimarySurface.VideoFileObject->Event);
590
591 ObReferenceObjectByPointer(FileObject, 0, IoFileObjectType, KernelMode);
592
593 StartOffset.QuadPart = 0;
594 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
595 DeviceObject,
596 (PVOID) &Prepare,
597 Length,
598 &StartOffset,
599 NULL,
600 &Iosb);
601 if (NULL == Irp)
602 {
603 return FALSE;
604 }
605
606 /* Set up IRP Data */
607 Irp->Tail.Overlay.OriginalFileObject = FileObject;
608 Irp->RequestorMode = KernelMode;
609 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
610 Irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
611 Irp->Flags |= IRP_WRITE_OPERATION;
612
613 /* Setup Stack Data */
614 StackPtr = IoGetNextIrpStackLocation(Irp);
615 StackPtr->FileObject = PrimarySurface.VideoFileObject;
616 StackPtr->Parameters.Write.Key = 0;
617
618 Status = IoCallDriver(DeviceObject, Irp);
619
620 if (STATUS_PENDING == Status)
621 {
622 KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, TRUE, 0);
623 Status = Iosb.Status;
624 }
625
626 return NT_SUCCESS(Status);
627 }
628
629
630 BOOL FASTCALL
631 IntCreatePrimarySurface()
632 {
633 SIZEL SurfSize;
634 RECTL SurfaceRect;
635 SURFOBJ *SurfObj;
636 BOOL calledFromUser;
637
638 if (! IntPrepareDriverIfNeeded())
639 {
640 return FALSE;
641 }
642
643 if (! PrepareVideoPrt())
644 {
645 return FALSE;
646 }
647
648 DPRINT("calling EnableSurface\n");
649 /* Enable the drawing surface */
650 PrimarySurface.pSurface =
651 PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.hPDev);
652 if (NULL == PrimarySurface.pSurface)
653 {
654 /* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.hPDev, FALSE);*/
655 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.hPDev);
656 ObDereferenceObject(PrimarySurface.VideoFileObject);
657 DPRINT1("DrvEnableSurface failed\n");
658 return FALSE;
659 }
660
661 PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.hPDev, TRUE);
662
663 calledFromUser = UserIsEntered(); //fixme: possibly upgrade a shared lock
664 if (!calledFromUser){
665 UserEnterExclusive();
666 }
667
668 /* attach monitor */
669 IntAttachMonitor(&PrimarySurface, PrimarySurface.DisplayNumber);
670
671 SurfObj = EngLockSurface(PrimarySurface.pSurface);
672 SurfObj->dhpdev = PrimarySurface.hPDev;
673 SurfSize = SurfObj->sizlBitmap;
674 SurfaceRect.left = SurfaceRect.top = 0;
675 SurfaceRect.right = SurfObj->sizlBitmap.cx;
676 SurfaceRect.bottom = SurfObj->sizlBitmap.cy;
677 /* FIXME - why does EngEraseSurface() sometimes crash?
678 EngEraseSurface(SurfObj, &SurfaceRect, 0); */
679
680 /* Put the pointer in the center of the screen */
681 gpsi->ptCursor.x = (SurfaceRect.right - SurfaceRect.left) / 2;
682 gpsi->ptCursor.y = (SurfaceRect.bottom - SurfaceRect.top) / 2;
683
684 EngUnlockSurface(SurfObj);
685 co_IntShowDesktop(IntGetActiveDesktop(), SurfSize.cx, SurfSize.cy);
686
687 // Init Primary Displays Device Capabilities.
688 IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
689
690 if (!calledFromUser){
691 UserLeave();
692 }
693
694 return TRUE;
695 }
696
697 VOID FASTCALL
698 IntDestroyPrimarySurface()
699 {
700 BOOL calledFromUser;
701
702 DRIVER_UnreferenceDriver(L"DISPLAY");
703
704 calledFromUser = UserIsEntered();
705 if (!calledFromUser){
706 UserEnterExclusive();
707 }
708
709 /* detach monitor */
710 IntDetachMonitor(&PrimarySurface);
711
712 if (!calledFromUser){
713 UserLeave();
714 }
715
716 /*
717 * FIXME: Hide a mouse pointer there. Also because we have to prevent
718 * memory leaks with the Eng* mouse routines.
719 */
720
721 DPRINT("Reseting display\n" );
722 PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.hPDev, FALSE);
723 PrimarySurface.DriverFunctions.DisableSurface(PrimarySurface.hPDev);
724 PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.hPDev);
725 PrimarySurface.PreparedDriver = FALSE;
726 KeSetEvent(&VideoDriverNeedsPreparation, 1, FALSE);
727 KeResetEvent(&VideoDriverPrepared);
728
729 DceEmptyCache();
730
731 ObDereferenceObject(PrimarySurface.VideoFileObject);
732 }
733
734 HDC FASTCALL
735 IntGdiCreateDC(PUNICODE_STRING Driver,
736 PUNICODE_STRING Device,
737 PVOID pUMdhpdev,
738 CONST PDEVMODEW InitData,
739 BOOL CreateAsIC)
740 {
741 HDC hNewDC;
742 PDC NewDC;
743 PDC_ATTR nDc_Attr;
744 HDC hDC = NULL;
745 HRGN hVisRgn;
746 UNICODE_STRING StdDriver;
747 BOOL calledFromUser;
748
749 RtlInitUnicodeString(&StdDriver, L"DISPLAY");
750
751 DPRINT("DriverName: %wZ, DeviceName: %wZ\n", Driver, Device);
752
753 if (NULL == Driver || 0 == RtlCompareUnicodeString(Driver, &StdDriver, TRUE))
754 {
755 if (CreateAsIC)
756 {
757 if (! IntPrepareDriverIfNeeded())
758 {
759 /* Here, we have two possibilities:
760 * a) return NULL, and hope that the caller
761 * won't call us in a loop
762 * b) bugcheck, but caller is unable to
763 * react on the problem
764 */
765 /*DPRINT1("Unable to prepare graphics driver, returning NULL ic\n");
766 return NULL;*/
767 KeBugCheck(VIDEO_DRIVER_INIT_FAILURE);
768 }
769 }
770 else
771 {
772 calledFromUser = UserIsEntered();
773 if (!calledFromUser){
774 UserEnterExclusive();
775 }
776
777 if (! co_IntGraphicsCheck(TRUE))
778 {
779 if (!calledFromUser){
780 UserLeave();
781 }
782 DPRINT1("Unable to initialize graphics, returning NULL dc\n");
783 return NULL;
784 }
785
786 if (!calledFromUser){
787 UserLeave();
788 }
789
790 }
791 }
792
793 /* Check for existing DC object */
794 if ((hNewDC = DC_FindOpenDC(Driver)) != NULL)
795 {
796 hDC = NtGdiCreateCompatibleDC(hNewDC);
797 if (!hDC)
798 DPRINT1("NtGdiCreateCompatibleDC() failed\n");
799 return hDC;
800 }
801
802 /* Allocate a DC object */
803 if ((hNewDC = DC_AllocDC(Driver)) == NULL)
804 {
805 DPRINT1("DC_AllocDC() failed\n");
806 return NULL;
807 }
808
809 NewDC = DC_LockDc( hNewDC );
810 if ( !NewDC )
811 {
812 DC_FreeDC( hNewDC );
813 DPRINT1("DC_LockDc() failed\n");
814 return NULL;
815 }
816
817 nDc_Attr = NewDC->pdcattr;
818
819 NewDC->dctype = DC_TYPE_DIRECT;
820
821 NewDC->dhpdev = PrimarySurface.hPDev;
822 if(pUMdhpdev) pUMdhpdev = NewDC->dhpdev; // set DHPDEV for device.
823 NewDC->ppdev = (PVOID)&PrimarySurface;
824 NewDC->rosdc.hBitmap = (HBITMAP)PrimarySurface.pSurface;
825 // ATM we only have one display.
826 nDc_Attr->ulDirty_ |= DC_PRIMARY_DISPLAY;
827
828 NewDC->rosdc.bitsPerPixel = ((PGDIDEVICE)NewDC->ppdev)->GDIInfo.cBitsPixel *
829 ((PGDIDEVICE)NewDC->ppdev)->GDIInfo.cPlanes;
830 DPRINT("Bits per pel: %u\n", NewDC->rosdc.bitsPerPixel);
831
832 NewDC->flGraphicsCaps = PrimarySurface.DevInfo.flGraphicsCaps;
833 NewDC->flGraphicsCaps2 = PrimarySurface.DevInfo.flGraphicsCaps2;
834
835 NewDC->DcLevel.hpal = NtGdiGetStockObject(DEFAULT_PALETTE);
836
837 nDc_Attr->jROP2 = R2_COPYPEN;
838
839 NewDC->erclWindow.top = NewDC->erclWindow.left = 0;
840 NewDC->erclWindow.right = ((PGDIDEVICE)NewDC->ppdev)->GDIInfo.ulHorzRes;
841 NewDC->erclWindow.bottom = ((PGDIDEVICE)NewDC->ppdev)->GDIInfo.ulVertRes;
842 NewDC->DcLevel.flPath &= ~DCPATH_CLOCKWISE; // Default is CCW.
843
844 nDc_Attr->iCS_CP = ftGdiGetTextCharsetInfo(NewDC,NULL,0);
845
846 hVisRgn = NtGdiCreateRectRgn(0, 0, ((PGDIDEVICE)NewDC->ppdev)->GDIInfo.ulHorzRes,
847 ((PGDIDEVICE)NewDC->ppdev)->GDIInfo.ulVertRes);
848
849 if (!CreateAsIC)
850 {
851 NewDC->pSurfInfo = NULL;
852 // NewDC->DcLevel.pSurface =
853 DC_UnlockDc( NewDC );
854
855 /* Initialize the DC state */
856 DC_InitDC(hNewDC);
857 IntGdiSetTextColor(hNewDC, RGB(0, 0, 0));
858 IntGdiSetBkColor(hNewDC, RGB(255, 255, 255));
859 }
860 else
861 {
862 /* From MSDN2:
863 The CreateIC function creates an information context for the specified device.
864 The information context provides a fast way to get information about the
865 device without creating a device context (DC). However, GDI drawing functions
866 cannot accept a handle to an information context.
867 */
868 NewDC->dctype = DC_TYPE_INFO;
869 // NewDC->pSurfInfo =
870 NewDC->DcLevel.pSurface = NULL;
871 nDc_Attr->crBackgroundClr = nDc_Attr->ulBackgroundClr = RGB(255, 255, 255);
872 nDc_Attr->crForegroundClr = RGB(0, 0, 0);
873 DC_UnlockDc( NewDC );
874 }
875
876 if (hVisRgn)
877 {
878 GdiSelectVisRgn(hNewDC, hVisRgn);
879 NtGdiDeleteObject(hVisRgn);
880 }
881
882 IntGdiSetTextAlign(hNewDC, TA_TOP);
883 IntGdiSetBkMode(hNewDC, OPAQUE);
884
885 return hNewDC;
886 }
887
888 HDC APIENTRY
889 NtGdiOpenDCW( PUNICODE_STRING Device,
890 DEVMODEW *InitData,
891 PUNICODE_STRING pustrLogAddr,
892 ULONG iType,
893 HANDLE hspool,
894 VOID *pDriverInfo2,
895 VOID *pUMdhpdev )
896 {
897 UNICODE_STRING SafeDevice;
898 DEVMODEW SafeInitData;
899 PVOID Dhpdev;
900 HDC Ret;
901 NTSTATUS Status = STATUS_SUCCESS;
902
903 if(InitData)
904 {
905 _SEH2_TRY
906 {
907 if (pUMdhpdev)
908 {
909 ProbeForWrite(pUMdhpdev,
910 sizeof(PVOID),
911 1);
912 }
913 ProbeForRead(InitData,
914 sizeof(DEVMODEW),
915 1);
916 RtlCopyMemory(&SafeInitData,
917 InitData,
918 sizeof(DEVMODEW));
919 }
920 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
921 {
922 Status = _SEH2_GetExceptionCode();
923 }
924 _SEH2_END;
925 if(!NT_SUCCESS(Status))
926 {
927 SetLastNtError(Status);
928 return NULL;
929 }
930 /* FIXME - InitData can have some more bytes! */
931 }
932
933 if(Device)
934 {
935 Status = IntSafeCopyUnicodeString(&SafeDevice, Device);
936 if(!NT_SUCCESS(Status))
937 {
938 SetLastNtError(Status);
939 return NULL;
940 }
941 }
942
943 Ret = IntGdiCreateDC(Device ? &SafeDevice : NULL,
944 NULL,
945 pUMdhpdev ? &Dhpdev : NULL,
946 InitData ? &SafeInitData : NULL,
947 (BOOL) iType); // FALSE 0 DCW, TRUE 1 ICW
948
949 if (pUMdhpdev) pUMdhpdev = Dhpdev;
950
951 return Ret;
952
953 }
954
955
956 HDC FASTCALL
957 IntGdiCreateDisplayDC(HDEV hDev, ULONG DcType, BOOL EmptyDC)
958 {
959 HDC hDC;
960 UNICODE_STRING DriverName;
961 RtlInitUnicodeString(&DriverName, L"DISPLAY");
962
963 if (DcType != DC_TYPE_MEMORY)
964 hDC = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, (DcType == DC_TYPE_INFO));
965 else
966 hDC = NtGdiCreateCompatibleDC(NULL); // OH~ Yuck! I think I taste vomit in my mouth!
967 //
968 // There is room to grow here~
969 //
970
971 //
972 // If NULL, first time through! Build the default (was window) dc!
973 //
974 if (hDC && !defaultDCstate) // Ultra HAX! Dedicated to GvG!
975 { // This is a cheesy way to do this.
976 PDC dc = DC_LockDc ( hDC );
977 defaultDCstate = ExAllocatePoolWithTag(PagedPool, sizeof(DC), TAG_DC);
978 if (!defaultDCstate)
979 {
980 DC_UnlockDc( dc );
981 return NULL;
982 }
983 RtlZeroMemory(defaultDCstate, sizeof(DC));
984 defaultDCstate->pdcattr = &defaultDCstate->Dc_Attr;
985 IntGdiCopyToSaveState(dc, defaultDCstate);
986 DC_UnlockDc( dc );
987 }
988 return hDC;
989 }
990
991 BOOL FASTCALL
992 IntGdiCleanDC(HDC hDC)
993 {
994 PDC dc;
995 if (!hDC) return FALSE;
996 dc = DC_LockDc ( hDC );
997 if (!dc) return FALSE;
998 // Clean the DC
999 if (defaultDCstate) IntGdiCopyFromSaveState(dc, defaultDCstate, hDC );
1000 return TRUE;
1001 }
1002
1003 //
1004 //
1005 //
1006 BOOL
1007 FASTCALL
1008 IntGdiDeleteDC(HDC hDC, BOOL Force)
1009 {
1010 PDC DCToDelete = DC_LockDc(hDC);
1011
1012 if (DCToDelete == NULL)
1013 {
1014 SetLastWin32Error(ERROR_INVALID_HANDLE);
1015 return FALSE;
1016 }
1017
1018 if(!Force)
1019 {
1020 if (DCToDelete->fs & DC_FLAG_PERMANENT)
1021 {
1022 DPRINT1("No! You Naughty Application!\n");
1023 DC_UnlockDc( DCToDelete );
1024 return UserReleaseDC(NULL, hDC, FALSE);
1025 }
1026 }
1027
1028 /* First delete all saved DCs */
1029 while (DCToDelete->DcLevel.lSaveDepth)
1030 {
1031 PDC savedDC;
1032 HDC savedHDC;
1033
1034 savedHDC = DC_GetNextDC (DCToDelete);
1035 savedDC = DC_LockDc (savedHDC);
1036 if (savedDC == NULL)
1037 {
1038 break;
1039 }
1040 DC_SetNextDC (DCToDelete, DC_GetNextDC (savedDC));
1041 DCToDelete->DcLevel.lSaveDepth--;
1042 DC_UnlockDc( savedDC );
1043 IntGdiDeleteDC(savedHDC, Force);
1044 }
1045
1046 /* Free GDI resources allocated to this DC */
1047 if (!(DCToDelete->DcLevel.flPath & DCPATH_SAVESTATE))
1048 {
1049 /*
1050 NtGdiSelectPen (DCHandle, STOCK_BLACK_PEN);
1051 NtGdiSelectBrush (DCHandle, STOCK_WHITE_BRUSH);
1052 NtGdiSelectFont (DCHandle, STOCK_SYSTEM_FONT);
1053 DC_LockDC (DCHandle); NtGdiSelectXxx does not recognize stock objects yet */
1054 if (DCToDelete->rosdc.XlateBrush != NULL)
1055 EngDeleteXlate(DCToDelete->rosdc.XlateBrush);
1056 if (DCToDelete->rosdc.XlatePen != NULL)
1057 EngDeleteXlate(DCToDelete->rosdc.XlatePen);
1058 }
1059 if (DCToDelete->rosdc.hClipRgn)
1060 {
1061 NtGdiDeleteObject (DCToDelete->rosdc.hClipRgn);
1062 }
1063 if (DCToDelete->rosdc.hVisRgn)
1064 {
1065 NtGdiDeleteObject (DCToDelete->rosdc.hVisRgn);
1066 }
1067 if (NULL != DCToDelete->rosdc.CombinedClip)
1068 {
1069 IntEngDeleteClipRegion(DCToDelete->rosdc.CombinedClip);
1070 }
1071 if (DCToDelete->rosdc.hGCClipRgn)
1072 {
1073 NtGdiDeleteObject (DCToDelete->rosdc.hGCClipRgn);
1074 }
1075 PATH_Delete(DCToDelete->DcLevel.hPath);
1076
1077 DC_UnlockDc( DCToDelete );
1078 DC_FreeDC ( hDC );
1079 return TRUE;
1080 }
1081
1082 BOOL
1083 APIENTRY
1084 NtGdiDeleteObjectApp(HANDLE DCHandle)
1085 {
1086 /* Complete all pending operations */
1087 NtGdiFlushUserBatch();
1088
1089 if (GDI_HANDLE_IS_STOCKOBJ(DCHandle)) return TRUE;
1090
1091 if (GDI_HANDLE_GET_TYPE(DCHandle) != GDI_OBJECT_TYPE_DC)
1092 return NtGdiDeleteObject((HGDIOBJ) DCHandle);
1093
1094 if(IsObjectDead((HGDIOBJ)DCHandle)) return TRUE;
1095
1096 if (!GDIOBJ_OwnedByCurrentProcess(DCHandle))
1097 {
1098 SetLastWin32Error(ERROR_INVALID_HANDLE);
1099 return FALSE;
1100 }
1101
1102 return IntGdiDeleteDC(DCHandle, FALSE);
1103 }
1104
1105 INT
1106 APIENTRY
1107 NtGdiDrawEscape(
1108 IN HDC hdc,
1109 IN INT iEsc,
1110 IN INT cjIn,
1111 IN OPTIONAL LPSTR pjIn)
1112 {
1113 UNIMPLEMENTED;
1114 return 0;
1115 }
1116
1117 ULONG
1118 APIENTRY
1119 NtGdiEnumObjects(
1120 IN HDC hdc,
1121 IN INT iObjectType,
1122 IN ULONG cjBuf,
1123 OUT OPTIONAL PVOID pvBuf)
1124 {
1125 UNIMPLEMENTED;
1126 return 0;
1127 }
1128
1129 HANDLE
1130 APIENTRY
1131 NtGdiGetDCObject(HDC hDC, INT ObjectType)
1132 {
1133 HGDIOBJ SelObject;
1134 DC *dc;
1135 PDC_ATTR pdcattr;
1136
1137 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
1138 if(!hDC) return NULL;
1139
1140 if(!(dc = DC_LockDc(hDC)))
1141 {
1142 SetLastWin32Error(ERROR_INVALID_HANDLE);
1143 return NULL;
1144 }
1145 pdcattr = dc->pdcattr;
1146
1147 if (pdcattr->ulDirty_ & DC_BRUSH_DIRTY)
1148 IntGdiSelectBrush(dc,pdcattr->hbrush);
1149
1150 if (pdcattr->ulDirty_ & DC_PEN_DIRTY)
1151 IntGdiSelectPen(dc,pdcattr->hpen);
1152
1153 switch(ObjectType)
1154 {
1155 case GDI_OBJECT_TYPE_EXTPEN:
1156 case GDI_OBJECT_TYPE_PEN:
1157 SelObject = pdcattr->hpen;
1158 break;
1159 case GDI_OBJECT_TYPE_BRUSH:
1160 SelObject = pdcattr->hbrush;
1161 break;
1162 case GDI_OBJECT_TYPE_PALETTE:
1163 SelObject = dc->DcLevel.hpal;
1164 break;
1165 case GDI_OBJECT_TYPE_FONT:
1166 SelObject = pdcattr->hlfntNew;
1167 break;
1168 case GDI_OBJECT_TYPE_BITMAP:
1169 SelObject = dc->rosdc.hBitmap;
1170 break;
1171 case GDI_OBJECT_TYPE_COLORSPACE:
1172 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
1173 // SelObject = dc->DcLevel.pColorSpace.BaseObject.hHmgr; ?
1174 SelObject = NULL;
1175 break;
1176 default:
1177 SelObject = NULL;
1178 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1179 break;
1180 }
1181
1182 DC_UnlockDc(dc);
1183 return SelObject;
1184 }
1185
1186 LONG FASTCALL
1187 IntCalcFillOrigin(PDC pdc)
1188 {
1189 pdc->ptlFillOrigin.x = pdc->DcLevel.ptlBrushOrigin.x + pdc->ptlDCOrig.x;
1190 pdc->ptlFillOrigin.y = pdc->DcLevel.ptlBrushOrigin.y + pdc->ptlDCOrig.y;
1191
1192 return pdc->ptlFillOrigin.y;
1193 }
1194
1195 VOID
1196 APIENTRY
1197 GdiSetDCOrg(HDC hDC, LONG Left, LONG Top, PRECTL prc)
1198 {
1199 PDC pdc;
1200
1201 pdc = DC_LockDc(hDC);
1202 if (!pdc) return;
1203
1204 pdc->ptlDCOrig.x = Left;
1205 pdc->ptlDCOrig.y = Top;
1206
1207 IntCalcFillOrigin(pdc);
1208
1209 if (prc) pdc->erclWindow = *prc;
1210
1211 DC_UnlockDc(pdc);
1212 }
1213
1214
1215 BOOL FASTCALL
1216 IntGdiGetDCOrg(PDC pDc, PPOINTL ppt)
1217 {
1218 *ppt = pDc->ptlDCOrig;
1219 return TRUE;
1220 }
1221
1222 BOOL APIENTRY
1223 GdiGetDCOrgEx(HDC hDC, PPOINTL ppt, PRECTL prc)
1224 {
1225 PDC pdc;
1226
1227 pdc = DC_LockDc(hDC);
1228 if (!pdc) return FALSE;
1229
1230 *prc = pdc->erclWindow;
1231 *ppt = pdc->ptlDCOrig;
1232
1233 DC_UnlockDc(pdc);
1234 return TRUE;
1235 }
1236
1237 BOOL FASTCALL
1238 IntGetAspectRatioFilter(PDC pDC,
1239 LPSIZE AspectRatio)
1240 {
1241 PDC_ATTR pdcattr;
1242
1243 pdcattr = pDC->pdcattr;
1244
1245 if ( pdcattr->flFontMapper & 1 ) // TRUE assume 1.
1246 {
1247 // "This specifies that Windows should only match fonts that have the
1248 // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1249 AspectRatio->cx = ((PGDIDEVICE)pDC->ppdev)->GDIInfo.ulLogPixelsX;
1250 AspectRatio->cy = ((PGDIDEVICE)pDC->ppdev)->GDIInfo.ulLogPixelsY;
1251 }
1252 else
1253 {
1254 AspectRatio->cx = 0;
1255 AspectRatio->cy = 0;
1256 }
1257 return TRUE;
1258 }
1259
1260 VOID
1261 FASTCALL
1262 IntGetViewportExtEx(PDC pdc, LPSIZE pSize)
1263 {
1264 PDC_ATTR pdcattr;
1265
1266 /* Get a pointer to the dc attribute */
1267 pdcattr = pdc->pdcattr;
1268
1269 /* Check if we need to recalculate */
1270 if (pdcattr->flXform & PAGE_EXTENTS_CHANGED)
1271 {
1272 /* Check if we need to do isotropic fixup */
1273 if (pdcattr->iMapMode == MM_ISOTROPIC)
1274 {
1275 IntFixIsotropicMapping(pdc);
1276 }
1277
1278 /* Update xforms, CHECKME: really done here? */
1279 DC_UpdateXforms(pdc);
1280 }
1281
1282 /* Copy the viewport extension */
1283 *pSize = pdcattr->szlViewportExt;
1284 }
1285
1286 BOOL APIENTRY
1287 NtGdiGetDCPoint( HDC hDC, UINT iPoint, PPOINTL Point)
1288 {
1289 BOOL Ret = TRUE;
1290 DC *dc;
1291 POINTL SafePoint;
1292 SIZE Size;
1293 NTSTATUS Status = STATUS_SUCCESS;
1294
1295 if(!Point)
1296 {
1297 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1298 return FALSE;
1299 }
1300
1301 RtlZeroMemory(&SafePoint, sizeof(POINT));
1302
1303 dc = DC_LockDc(hDC);
1304 if(!dc)
1305 {
1306 SetLastWin32Error(ERROR_INVALID_HANDLE);
1307 return FALSE;
1308 }
1309
1310 switch (iPoint)
1311 {
1312 case GdiGetViewPortExt:
1313 IntGetViewportExtEx(dc, &Size);
1314 SafePoint.x = Size.cx;
1315 SafePoint.y = Size.cy;
1316 break;
1317 case GdiGetWindowExt:
1318 IntGetWindowExtEx(dc, &Size);
1319 SafePoint.x = Size.cx;
1320 SafePoint.y = Size.cy;
1321 break;
1322 case GdiGetViewPortOrg:
1323 IntGetViewportOrgEx(dc, &SafePoint);
1324 break;
1325 case GdiGetWindowOrg:
1326 IntGetWindowOrgEx(dc, &SafePoint);
1327 break;
1328 case GdiGetDCOrg:
1329 Ret = IntGdiGetDCOrg(dc, &SafePoint);
1330 break;
1331 case GdiGetAspectRatioFilter:
1332 Ret = IntGetAspectRatioFilter(dc, &Size);
1333 SafePoint.x = Size.cx;
1334 SafePoint.y = Size.cy;
1335 break;
1336 default:
1337 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1338 Ret = FALSE;
1339 break;
1340 }
1341
1342 if (Ret)
1343 {
1344 _SEH2_TRY
1345 {
1346 ProbeForWrite(Point,
1347 sizeof(POINT),
1348 1);
1349 *Point = SafePoint;
1350 }
1351 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1352 {
1353 Status = _SEH2_GetExceptionCode();
1354 }
1355 _SEH2_END;
1356 }
1357
1358 if(!NT_SUCCESS(Status))
1359 {
1360 SetLastNtError(Status);
1361 DC_UnlockDc(dc);
1362 return FALSE;
1363 }
1364
1365 DC_UnlockDc(dc);
1366 return Ret;
1367 }
1368
1369 VOID
1370 FASTCALL
1371 IntGdiCopyToSaveState(PDC dc, PDC newdc)
1372 {
1373 PDC_ATTR pdcattr, nDc_Attr;
1374
1375 pdcattr = dc->pdcattr;
1376 nDc_Attr = newdc->pdcattr;
1377
1378 newdc->DcLevel.flPath = dc->DcLevel.flPath | DCPATH_SAVESTATE;
1379
1380 nDc_Attr->dwLayout = pdcattr->dwLayout;
1381 nDc_Attr->hpen = pdcattr->hpen;
1382 nDc_Attr->hbrush = pdcattr->hbrush;
1383 nDc_Attr->hlfntNew = pdcattr->hlfntNew;
1384 newdc->rosdc.hBitmap = dc->rosdc.hBitmap;
1385 newdc->DcLevel.hpal = dc->DcLevel.hpal;
1386 newdc->rosdc.bitsPerPixel = dc->rosdc.bitsPerPixel;
1387 nDc_Attr->jROP2 = pdcattr->jROP2;
1388 nDc_Attr->jFillMode = pdcattr->jFillMode;
1389 nDc_Attr->jStretchBltMode = pdcattr->jStretchBltMode;
1390 nDc_Attr->lRelAbs = pdcattr->lRelAbs;
1391 nDc_Attr->jBkMode = pdcattr->jBkMode;
1392 nDc_Attr->lBkMode = pdcattr->lBkMode;
1393 nDc_Attr->crBackgroundClr = pdcattr->crBackgroundClr;
1394 nDc_Attr->crForegroundClr = pdcattr->crForegroundClr;
1395 nDc_Attr->ulBackgroundClr = pdcattr->ulBackgroundClr;
1396 nDc_Attr->ulForegroundClr = pdcattr->ulForegroundClr;
1397 nDc_Attr->ptlBrushOrigin = pdcattr->ptlBrushOrigin;
1398 nDc_Attr->lTextAlign = pdcattr->lTextAlign;
1399 nDc_Attr->lTextExtra = pdcattr->lTextExtra;
1400 nDc_Attr->cBreak = pdcattr->cBreak;
1401 nDc_Attr->lBreakExtra = pdcattr->lBreakExtra;
1402 nDc_Attr->iMapMode = pdcattr->iMapMode;
1403 nDc_Attr->iGraphicsMode = pdcattr->iGraphicsMode;
1404 #if 0
1405 /* Apparently, the DC origin is not changed by [GS]etDCState */
1406 newdc->ptlDCOrig.x = dc->ptlDCOrig.x;
1407 newdc->ptlDCOrig.y = dc->ptlDCOrig.y;
1408 #endif
1409 nDc_Attr->ptlCurrent = pdcattr->ptlCurrent;
1410 nDc_Attr->ptfxCurrent = pdcattr->ptfxCurrent;
1411 newdc->DcLevel.mxWorldToDevice = dc->DcLevel.mxWorldToDevice;
1412 newdc->DcLevel.mxDeviceToWorld = dc->DcLevel.mxDeviceToWorld;
1413 newdc->DcLevel.mxWorldToPage = dc->DcLevel.mxWorldToPage;
1414 nDc_Attr->flXform = pdcattr->flXform;
1415 nDc_Attr->ptlWindowOrg = pdcattr->ptlWindowOrg;
1416 nDc_Attr->szlWindowExt = pdcattr->szlWindowExt;
1417 nDc_Attr->ptlViewportOrg = pdcattr->ptlViewportOrg;
1418 nDc_Attr->szlViewportExt = pdcattr->szlViewportExt;
1419
1420 newdc->DcLevel.lSaveDepth = 0;
1421 newdc->dctype = dc->dctype;
1422
1423 #if 0
1424 PATH_InitGdiPath( &newdc->DcLevel.hPath );
1425 #endif
1426
1427 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
1428
1429 newdc->rosdc.hGCClipRgn = newdc->rosdc.hVisRgn = 0;
1430 if (dc->rosdc.hClipRgn)
1431 {
1432 newdc->rosdc.hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
1433 NtGdiCombineRgn( newdc->rosdc.hClipRgn, dc->rosdc.hClipRgn, 0, RGN_COPY );
1434 }
1435 }
1436
1437
1438 VOID
1439 FASTCALL
1440 IntGdiCopyFromSaveState(PDC dc, PDC dcs, HDC hDC)
1441 {
1442 PDC_ATTR pdcattr, sDc_Attr;
1443
1444 pdcattr = dc->pdcattr;
1445 sDc_Attr = dcs->pdcattr;
1446
1447 dc->DcLevel.flPath = dcs->DcLevel.flPath & ~DCPATH_SAVESTATE;
1448
1449 pdcattr->dwLayout = sDc_Attr->dwLayout;
1450 pdcattr->jROP2 = sDc_Attr->jROP2;
1451 pdcattr->jFillMode = sDc_Attr->jFillMode;
1452 pdcattr->jStretchBltMode = sDc_Attr->jStretchBltMode;
1453 pdcattr->lRelAbs = sDc_Attr->lRelAbs;
1454 pdcattr->jBkMode = sDc_Attr->jBkMode;
1455 pdcattr->crBackgroundClr = sDc_Attr->crBackgroundClr;
1456 pdcattr->crForegroundClr = sDc_Attr->crForegroundClr;
1457 pdcattr->lBkMode = sDc_Attr->lBkMode;
1458 pdcattr->ulBackgroundClr = sDc_Attr->ulBackgroundClr;
1459 pdcattr->ulForegroundClr = sDc_Attr->ulForegroundClr;
1460 pdcattr->ptlBrushOrigin = sDc_Attr->ptlBrushOrigin;
1461
1462 pdcattr->lTextAlign = sDc_Attr->lTextAlign;
1463 pdcattr->lTextExtra = sDc_Attr->lTextExtra;
1464 pdcattr->cBreak = sDc_Attr->cBreak;
1465 pdcattr->lBreakExtra = sDc_Attr->lBreakExtra;
1466 pdcattr->iMapMode = sDc_Attr->iMapMode;
1467 pdcattr->iGraphicsMode = sDc_Attr->iGraphicsMode;
1468 #if 0
1469 /* Apparently, the DC origin is not changed by [GS]etDCState */
1470 dc->ptlDCOrig.x = dcs->ptlDCOrig.x;
1471 dc->ptlDCOrig.y = dcs->ptlDCOrig.y;
1472 #endif
1473 pdcattr->ptlCurrent = sDc_Attr->ptlCurrent;
1474 pdcattr->ptfxCurrent = sDc_Attr->ptfxCurrent;
1475 dc->DcLevel.mxWorldToDevice = dcs->DcLevel.mxWorldToDevice;
1476 dc->DcLevel.mxDeviceToWorld = dcs->DcLevel.mxDeviceToWorld;
1477 dc->DcLevel.mxWorldToPage = dcs->DcLevel.mxWorldToPage;
1478 pdcattr->flXform = sDc_Attr->flXform;
1479 pdcattr->ptlWindowOrg = sDc_Attr->ptlWindowOrg;
1480 pdcattr->szlWindowExt = sDc_Attr->szlWindowExt;
1481 pdcattr->ptlViewportOrg = sDc_Attr->ptlViewportOrg;
1482 pdcattr->szlViewportExt = sDc_Attr->szlViewportExt;
1483
1484 if (dc->dctype != DC_TYPE_MEMORY)
1485 {
1486 dc->rosdc.bitsPerPixel = dcs->rosdc.bitsPerPixel;
1487 }
1488
1489 #if 0
1490 if (dcs->rosdc.hClipRgn)
1491 {
1492 if (!dc->rosdc.hClipRgn)
1493 {
1494 dc->rosdc.hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
1495 }
1496 NtGdiCombineRgn( dc->rosdc.hClipRgn, dcs->rosdc.hClipRgn, 0, RGN_COPY );
1497 }
1498 else
1499 {
1500 if (dc->rosdc.hClipRgn)
1501 {
1502 NtGdiDeleteObject( dc->rosdc.hClipRgn );
1503 }
1504 dc->rosdc.hClipRgn = 0;
1505 }
1506 {
1507 int res;
1508 res = CLIPPING_UpdateGCRegion( dc );
1509 ASSERT ( res != ERROR );
1510 }
1511 DC_UnlockDc ( dc );
1512 #else
1513 GdiExtSelectClipRgn(dc, dcs->rosdc.hClipRgn, RGN_COPY);
1514 DC_UnlockDc ( dc );
1515 #endif
1516 if(!hDC) return; // Not a MemoryDC or SaveLevel DC, return.
1517
1518 NtGdiSelectBitmap( hDC, dcs->rosdc.hBitmap );
1519 NtGdiSelectBrush( hDC, sDc_Attr->hbrush );
1520 NtGdiSelectFont( hDC, sDc_Attr->hlfntNew );
1521 NtGdiSelectPen( hDC, sDc_Attr->hpen );
1522
1523 IntGdiSetBkColor( hDC, sDc_Attr->crBackgroundClr);
1524 IntGdiSetTextColor( hDC, sDc_Attr->crForegroundClr);
1525
1526 GdiSelectPalette( hDC, dcs->DcLevel.hpal, FALSE );
1527
1528 #if 0
1529 GDISelectPalette16( hDC, dcs->DcLevel.hpal, FALSE );
1530 #endif
1531 }
1532
1533 HDC APIENTRY
1534 IntGdiGetDCState(HDC hDC)
1535 {
1536 PDC newdc, dc;
1537 HDC hnewdc;
1538
1539 dc = DC_LockDc(hDC);
1540 if (dc == NULL)
1541 {
1542 SetLastWin32Error(ERROR_INVALID_HANDLE);
1543 return 0;
1544 }
1545
1546 hnewdc = DC_AllocDC(NULL);
1547 if (hnewdc == NULL)
1548 {
1549 DC_UnlockDc(dc);
1550 return 0;
1551 }
1552 newdc = DC_LockDc( hnewdc );
1553 /* FIXME - newdc can be NULL!!!! Don't assert here!!! */
1554 ASSERT( newdc );
1555
1556 newdc->DcLevel.hdcSave = hnewdc;
1557 IntGdiCopyToSaveState( dc, newdc);
1558
1559 DC_UnlockDc( newdc );
1560 DC_UnlockDc( dc );
1561 return hnewdc;
1562 }
1563
1564
1565 VOID
1566 APIENTRY
1567 IntGdiSetDCState ( HDC hDC, HDC hDCSave )
1568 {
1569 PDC dc, dcs;
1570
1571 dc = DC_LockDc ( hDC );
1572 if ( dc )
1573 {
1574 dcs = DC_LockDc ( hDCSave );
1575 if ( dcs )
1576 {
1577 if ( dcs->DcLevel.flPath & DCPATH_SAVESTATE )
1578 {
1579 IntGdiCopyFromSaveState( dc, dcs, dc->DcLevel.hdcSave);
1580 }
1581 else
1582 {
1583 DC_UnlockDc(dc);
1584 }
1585 DC_UnlockDc ( dcs );
1586 }
1587 else
1588 {
1589 DC_UnlockDc ( dc );
1590 SetLastWin32Error(ERROR_INVALID_HANDLE);
1591 }
1592 }
1593 else
1594 SetLastWin32Error(ERROR_INVALID_HANDLE);
1595 }
1596
1597 INT
1598 FASTCALL
1599 IntcFonts(PGDIDEVICE pDevObj)
1600 {
1601 ULONG_PTR Junk;
1602 // Msdn DrvQueryFont:
1603 // If the number of fonts in DEVINFO is -1 and iFace is zero, the driver
1604 // should return the number of fonts it supports.
1605 if ( pDevObj->DevInfo.cFonts == -1)
1606 {
1607 if (pDevObj->DriverFunctions.QueryFont)
1608 pDevObj->DevInfo.cFonts =
1609 (ULONG)pDevObj->DriverFunctions.QueryFont(pDevObj->hPDev, 0, 0, &Junk);
1610 else
1611 pDevObj->DevInfo.cFonts = 0;
1612 }
1613 return pDevObj->DevInfo.cFonts;
1614 }
1615
1616 INT
1617 FASTCALL
1618 IntGetColorManagementCaps(PGDIDEVICE pDevObj)
1619 {
1620 INT ret = CM_NONE;
1621
1622 if ( pDevObj->flFlags & PDEV_DISPLAY)
1623 {
1624 if ( pDevObj->DevInfo.iDitherFormat == BMF_8BPP ||
1625 pDevObj->DevInfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP)
1626 ret = CM_GAMMA_RAMP;
1627 }
1628 if (pDevObj->DevInfo.flGraphicsCaps & GCAPS_CMYKCOLOR)
1629 ret |= CM_CMYK_COLOR;
1630 if (pDevObj->DevInfo.flGraphicsCaps & GCAPS_ICM)
1631 ret |= CM_DEVICE_ICM;
1632 return ret;
1633 }
1634
1635 INT FASTCALL
1636 IntGdiGetDeviceCaps(PDC dc, INT Index)
1637 {
1638 INT ret = 0;
1639 PGDIDEVICE ppdev = dc->ppdev;
1640 /* Retrieve capability */
1641 switch (Index)
1642 {
1643 case DRIVERVERSION:
1644 ret = ppdev->GDIInfo.ulVersion;
1645 break;
1646
1647 case TECHNOLOGY:
1648 ret = ppdev->GDIInfo.ulTechnology;
1649 break;
1650
1651 case HORZSIZE:
1652 ret = ppdev->GDIInfo.ulHorzSize;
1653 break;
1654
1655 case VERTSIZE:
1656 ret = ppdev->GDIInfo.ulVertSize;
1657 break;
1658
1659 case HORZRES:
1660 ret = ppdev->GDIInfo.ulHorzRes;
1661 break;
1662
1663 case VERTRES:
1664 ret = ppdev->GDIInfo.ulVertRes;
1665 break;
1666
1667 case LOGPIXELSX:
1668 ret = ppdev->GDIInfo.ulLogPixelsX;
1669 break;
1670
1671 case LOGPIXELSY:
1672 ret = ppdev->GDIInfo.ulLogPixelsY;
1673 break;
1674
1675 case CAPS1:
1676 if ( ppdev->pGraphicsDev &&
1677 (((PGRAPHICS_DEVICE)ppdev->pGraphicsDev)->StateFlags &
1678 DISPLAY_DEVICE_MIRRORING_DRIVER))
1679 ret = C1_MIRRORING;
1680 break;
1681
1682 case BITSPIXEL:
1683 ret = ppdev->GDIInfo.cBitsPixel;
1684 break;
1685
1686 case PLANES:
1687 ret = ppdev->GDIInfo.cPlanes;
1688 break;
1689
1690 case NUMBRUSHES:
1691 ret = -1;
1692 break;
1693
1694 case NUMPENS:
1695 ret = ppdev->GDIInfo.ulNumColors;
1696 if ( ret != -1 ) ret *= 5;
1697 break;
1698
1699 case NUMFONTS:
1700 ret = IntcFonts(ppdev);
1701 break;
1702
1703 case NUMCOLORS:
1704 ret = ppdev->GDIInfo.ulNumColors;
1705 break;
1706
1707 case ASPECTX:
1708 ret = ppdev->GDIInfo.ulAspectX;
1709 break;
1710
1711 case ASPECTY:
1712 ret = ppdev->GDIInfo.ulAspectY;
1713 break;
1714
1715 case ASPECTXY:
1716 ret = ppdev->GDIInfo.ulAspectXY;
1717 break;
1718
1719 case CLIPCAPS:
1720 ret = CP_RECTANGLE;
1721 break;
1722
1723 case SIZEPALETTE:
1724 ret = ppdev->GDIInfo.ulNumPalReg;
1725 break;
1726
1727 case NUMRESERVED:
1728 ret = 20;
1729 break;
1730
1731 case COLORRES:
1732 ret = ppdev->GDIInfo.ulDACRed +
1733 ppdev->GDIInfo.ulDACGreen +
1734 ppdev->GDIInfo.ulDACBlue;
1735 break;
1736
1737 case DESKTOPVERTRES:
1738 ret = ppdev->GDIInfo.ulVertRes;
1739 break;
1740
1741 case DESKTOPHORZRES:
1742 ret = ppdev->GDIInfo.ulHorzRes;
1743 break;
1744
1745 case BLTALIGNMENT:
1746 ret = ppdev->GDIInfo.ulBltAlignment;
1747 break;
1748
1749 case SHADEBLENDCAPS:
1750 ret = ppdev->GDIInfo.flShadeBlend;
1751 break;
1752
1753 case COLORMGMTCAPS:
1754 ret = IntGetColorManagementCaps(ppdev);
1755 break;
1756
1757 case PHYSICALWIDTH:
1758 ret = ppdev->GDIInfo.szlPhysSize.cx;
1759 break;
1760
1761 case PHYSICALHEIGHT:
1762 ret = ppdev->GDIInfo.szlPhysSize.cy;
1763 break;
1764
1765 case PHYSICALOFFSETX:
1766 ret = ppdev->GDIInfo.ptlPhysOffset.x;
1767 break;
1768
1769 case PHYSICALOFFSETY:
1770 ret = ppdev->GDIInfo.ptlPhysOffset.y;
1771 break;
1772
1773 case VREFRESH:
1774 ret = ppdev->GDIInfo.ulVRefresh;
1775 break;
1776
1777 case RASTERCAPS:
1778 ret = ppdev->GDIInfo.flRaster;
1779 break;
1780
1781 case CURVECAPS:
1782 ret = (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
1783 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
1784 break;
1785
1786 case LINECAPS:
1787 ret = (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
1788 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
1789 break;
1790
1791 case POLYGONALCAPS:
1792 ret = (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
1793 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
1794 break;
1795
1796 case TEXTCAPS:
1797 ret = ppdev->GDIInfo.flTextCaps;
1798 if (ppdev->GDIInfo.ulTechnology) ret |= TC_VA_ABLE;
1799 ret |= (TC_SO_ABLE|TC_UA_ABLE);
1800 break;
1801
1802 case PDEVICESIZE:
1803 case SCALINGFACTORX:
1804 case SCALINGFACTORY:
1805 default:
1806 ret = 0;
1807 break;
1808 }
1809
1810 return ret;
1811 }
1812
1813 INT APIENTRY
1814 NtGdiGetDeviceCaps(HDC hDC,
1815 INT Index)
1816 {
1817 PDC dc;
1818 INT ret;
1819
1820 dc = DC_LockDc(hDC);
1821 if (dc == NULL)
1822 {
1823 SetLastWin32Error(ERROR_INVALID_HANDLE);
1824 return 0;
1825 }
1826
1827 ret = IntGdiGetDeviceCaps(dc, Index);
1828
1829 DPRINT("(%04x,%d): returning %d\n", hDC, Index, ret);
1830
1831 DC_UnlockDc( dc );
1832 return ret;
1833 }
1834
1835 VOID
1836 FASTCALL
1837 IntvGetDeviceCaps(
1838 PGDIDEVICE pDevObj,
1839 PDEVCAPS pDevCaps)
1840 {
1841 ULONG Tmp = 0;
1842 PGDIINFO pGdiInfo = &pDevObj->GDIInfo;
1843
1844 pDevCaps->ulVersion = pGdiInfo->ulVersion;
1845 pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
1846 pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000;
1847 pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000;
1848 pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize;
1849 pDevCaps->ulVertSize = pGdiInfo->ulVertSize;
1850 pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes;
1851 pDevCaps->ulVertRes = pGdiInfo->ulVertRes;
1852 pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh;
1853 pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes;
1854 pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes;
1855 pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
1856 pDevCaps->ulPlanes = pGdiInfo->cPlanes;
1857
1858 pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel;
1859 if (pGdiInfo->cBitsPixel == 15) pDevCaps->ulBitsPixel = 16;
1860
1861 Tmp = pGdiInfo->ulNumColors;
1862 if ( Tmp != -1 ) Tmp *= 5;
1863 pDevCaps->ulNumPens = Tmp;
1864 pDevCaps->ulNumColors = pGdiInfo->ulNumColors;
1865
1866 pDevCaps->ulNumFonts = IntcFonts(pDevObj);
1867
1868 pDevCaps->ulRasterCaps = pGdiInfo->flRaster;
1869 pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend;
1870 pDevCaps->ulAspectX = pGdiInfo->ulAspectX;
1871 pDevCaps->ulAspectY = pGdiInfo->ulAspectY;
1872 pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY;
1873 pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX;
1874 pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY;
1875 pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg;
1876 pDevCaps->ulColorRes = pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue;
1877 pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx;
1878 pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy;
1879 pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x;
1880 pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
1881 pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes;
1882 pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes;
1883 pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment;
1884 pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment;
1885
1886 Tmp = 0;
1887 Tmp = pGdiInfo->flTextCaps | (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
1888
1889 pDevCaps->ulTextCaps = pGdiInfo->flTextCaps | (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
1890
1891 if (pGdiInfo->ulTechnology)
1892 pDevCaps->ulTextCaps = Tmp | TC_VA_ABLE;
1893
1894 pDevCaps->ulColorMgmtCaps = IntGetColorManagementCaps(pDevObj);
1895
1896 return;
1897 }
1898
1899 /*
1900 * @implemented
1901 */
1902 BOOL
1903 APIENTRY
1904 NtGdiGetDeviceCapsAll (
1905 IN HDC hDC,
1906 OUT PDEVCAPS pDevCaps)
1907 {
1908 PDC dc;
1909 PDEVCAPS pSafeDevCaps;
1910 NTSTATUS Status = STATUS_SUCCESS;
1911
1912 dc = DC_LockDc(hDC);
1913 if (!dc)
1914 {
1915 SetLastWin32Error(ERROR_INVALID_HANDLE);
1916 return FALSE;
1917 }
1918
1919 pSafeDevCaps = ExAllocatePoolWithTag(PagedPool, sizeof(DEVCAPS), TAG_TEMP);
1920
1921 if (!pSafeDevCaps)
1922 {
1923 DC_UnlockDc(dc);
1924 return FALSE;
1925 }
1926
1927 IntvGetDeviceCaps(dc->ppdev, pSafeDevCaps);
1928
1929 _SEH2_TRY
1930 {
1931 ProbeForWrite(pDevCaps,
1932 sizeof(DEVCAPS),
1933 1);
1934 RtlCopyMemory(pDevCaps, pSafeDevCaps, sizeof(DEVCAPS));
1935 }
1936 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1937 {
1938 Status = _SEH2_GetExceptionCode();
1939 }
1940 _SEH2_END;
1941
1942 ExFreePoolWithTag(pSafeDevCaps, TAG_TEMP);
1943 DC_UnlockDc(dc);
1944
1945 if (!NT_SUCCESS(Status))
1946 {
1947 SetLastNtError(Status);
1948 return FALSE;
1949 }
1950 return TRUE;
1951 }
1952
1953
1954
1955 BOOL
1956 APIENTRY
1957 NtGdiResetDC(
1958 IN HDC hdc,
1959 IN LPDEVMODEW pdm,
1960 OUT PBOOL pbBanding,
1961 IN OPTIONAL VOID *pDriverInfo2,
1962 OUT VOID *ppUMdhpdev)
1963 {
1964 UNIMPLEMENTED;
1965 return 0;
1966 }
1967
1968 BOOL APIENTRY
1969 NtGdiRestoreDC(HDC hDC, INT SaveLevel)
1970 {
1971 PDC dc, dcs;
1972 BOOL success;
1973
1974 DPRINT("NtGdiRestoreDC(%lx, %d)\n", hDC, SaveLevel);
1975
1976 dc = DC_LockDc(hDC);
1977 if (!dc)
1978 {
1979 SetLastWin32Error(ERROR_INVALID_HANDLE);
1980 return FALSE;
1981 }
1982
1983 if (SaveLevel < 0)
1984 SaveLevel = dc->DcLevel.lSaveDepth + SaveLevel + 1;
1985
1986 if(SaveLevel < 0 || dc->DcLevel.lSaveDepth<SaveLevel)
1987 {
1988 DC_UnlockDc(dc);
1989 return FALSE;
1990 }
1991
1992 success=TRUE;
1993 while (dc->DcLevel.lSaveDepth >= SaveLevel)
1994 {
1995 HDC hdcs = DC_GetNextDC (dc);
1996
1997 dcs = DC_LockDc (hdcs);
1998 if (dcs == NULL)
1999 {
2000 DC_UnlockDc(dc);
2001 return FALSE;
2002 }
2003
2004 DC_SetNextDC (dc, DC_GetNextDC (dcs));
2005 dcs->hdcNext = 0;
2006
2007 if (--dc->DcLevel.lSaveDepth < SaveLevel)
2008 {
2009 DC_UnlockDc( dc );
2010 DC_UnlockDc( dcs );
2011
2012 IntGdiSetDCState(hDC, hdcs);
2013
2014 dc = DC_LockDc(hDC);
2015 if(!dc)
2016 {
2017 return FALSE;
2018 }
2019 // Restore Path by removing it, if the Save flag is set.
2020 // BeginPath will takecare of the rest.
2021 if ( dc->DcLevel.hPath && dc->DcLevel.flPath & DCPATH_SAVE)
2022 {
2023 PATH_Delete(dc->DcLevel.hPath);
2024 dc->DcLevel.hPath = 0;
2025 dc->DcLevel.flPath &= ~DCPATH_SAVE;
2026 }
2027 }
2028 else
2029 {
2030 DC_UnlockDc( dcs );
2031 }
2032 NtGdiDeleteObjectApp (hdcs);
2033 }
2034 DC_UnlockDc( dc );
2035 return success;
2036 }
2037
2038
2039 INT APIENTRY
2040 NtGdiSaveDC(HDC hDC)
2041 {
2042 HDC hdcs;
2043 PDC dc, dcs;
2044 INT ret;
2045
2046 DPRINT("NtGdiSaveDC(%lx)\n", hDC);
2047
2048 if (!(hdcs = IntGdiGetDCState(hDC)))
2049 {
2050 return 0;
2051 }
2052
2053 dcs = DC_LockDc (hdcs);
2054 if (dcs == NULL)
2055 {
2056 SetLastWin32Error(ERROR_INVALID_HANDLE);
2057 return 0;
2058 }
2059 dc = DC_LockDc (hDC);
2060 if (dc == NULL)
2061 {
2062 DC_UnlockDc(dcs);
2063 SetLastWin32Error(ERROR_INVALID_HANDLE);
2064 return 0;
2065 }
2066
2067 /*
2068 * Copy path.
2069 */
2070 dcs->DcLevel.hPath = dc->DcLevel.hPath;
2071 if (dcs->DcLevel.hPath) dcs->DcLevel.flPath |= DCPATH_SAVE;
2072
2073 DC_SetNextDC (dcs, DC_GetNextDC (dc));
2074 DC_SetNextDC (dc, hdcs);
2075 ret = ++dc->DcLevel.lSaveDepth;
2076 DC_UnlockDc( dcs );
2077 DC_UnlockDc( dc );
2078
2079 return ret;
2080 }
2081
2082
2083 HPALETTE
2084 FASTCALL
2085 GdiSelectPalette(HDC hDC,
2086 HPALETTE hpal,
2087 BOOL ForceBackground)
2088 {
2089 PDC dc;
2090 HPALETTE oldPal = NULL;
2091 PPALGDI PalGDI;
2092
2093 // FIXME: mark the palette as a [fore\back]ground pal
2094 dc = DC_LockDc(hDC);
2095 if (!dc)
2096 {
2097 return NULL;
2098 }
2099
2100 /* Check if this is a valid palette handle */
2101 PalGDI = PALETTE_LockPalette(hpal);
2102 if (!PalGDI)
2103 {
2104 DC_UnlockDc(dc);
2105 return NULL;
2106 }
2107
2108 /* Is this a valid palette for this depth? */
2109 if ((dc->rosdc.bitsPerPixel <= 8 && PalGDI->Mode == PAL_INDEXED) ||
2110 (dc->rosdc.bitsPerPixel > 8 && PalGDI->Mode != PAL_INDEXED))
2111 {
2112 oldPal = dc->DcLevel.hpal;
2113 dc->DcLevel.hpal = hpal;
2114 }
2115 else if (8 < dc->rosdc.bitsPerPixel && PAL_INDEXED == PalGDI->Mode)
2116 {
2117 oldPal = dc->DcLevel.hpal;
2118 dc->DcLevel.hpal = hpal;
2119 }
2120
2121 PALETTE_UnlockPalette(PalGDI);
2122 DC_UnlockDc(dc);
2123
2124 return oldPal;
2125 }
2126
2127 WORD APIENTRY
2128 IntGdiSetHookFlags(HDC hDC, WORD Flags)
2129 {
2130 WORD wRet;
2131 DC *dc = DC_LockDc(hDC);
2132
2133 if (NULL == dc)
2134 {
2135 SetLastWin32Error(ERROR_INVALID_HANDLE);
2136 return 0;
2137 }
2138
2139 wRet = dc->fs & DC_FLAG_DIRTY_RAO; // Fixme wrong flag!
2140
2141 /* "Undocumented Windows" info is slightly confusing.
2142 */
2143
2144 DPRINT("DC %p, Flags %04x\n", hDC, Flags);
2145
2146 if (Flags & DCHF_INVALIDATEVISRGN)
2147 { /* hVisRgn has to be updated */
2148 dc->fs |= DC_FLAG_DIRTY_RAO;
2149 }
2150 else if (Flags & DCHF_VALIDATEVISRGN || 0 == Flags)
2151 {
2152 dc->fs &= ~DC_FLAG_DIRTY_RAO;
2153 }
2154
2155 DC_UnlockDc(dc);
2156
2157 return wRet;
2158 }
2159
2160
2161 BOOL
2162 APIENTRY
2163 NtGdiGetDCDword(
2164 HDC hDC,
2165 UINT u,
2166 DWORD *Result
2167 )
2168 {
2169 BOOL Ret = TRUE;
2170 PDC dc;
2171 PDC_ATTR pdcattr;
2172
2173 DWORD SafeResult = 0;
2174 NTSTATUS Status = STATUS_SUCCESS;
2175
2176 if(!Result)
2177 {
2178 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2179 return FALSE;
2180 }
2181
2182 dc = DC_LockDc(hDC);
2183 if(!dc)
2184 {
2185 SetLastWin32Error(ERROR_INVALID_HANDLE);
2186 return FALSE;
2187 }
2188 pdcattr = dc->pdcattr;
2189
2190 switch (u)
2191 {
2192 case GdiGetJournal:
2193 break;
2194 case GdiGetRelAbs:
2195 SafeResult = pdcattr->lRelAbs;
2196 break;
2197 case GdiGetBreakExtra:
2198 SafeResult = pdcattr->lBreakExtra;
2199 break;
2200 case GdiGerCharBreak:
2201 SafeResult = pdcattr->cBreak;
2202 break;
2203 case GdiGetArcDirection:
2204 if (pdcattr->dwLayout & LAYOUT_RTL)
2205 SafeResult = AD_CLOCKWISE - ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0);
2206 else
2207 SafeResult = ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0) + AD_COUNTERCLOCKWISE;
2208 break;
2209 case GdiGetEMFRestorDc:
2210 break;
2211 case GdiGetFontLanguageInfo:
2212 SafeResult = IntGetFontLanguageInfo(dc);
2213 break;
2214 case GdiGetIsMemDc:
2215 SafeResult = dc->dctype;
2216 break;
2217 case GdiGetMapMode:
2218 SafeResult = pdcattr->iMapMode;
2219 break;
2220 case GdiGetTextCharExtra:
2221 SafeResult = pdcattr->lTextExtra;
2222 break;
2223 default:
2224 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2225 Ret = FALSE;
2226 break;
2227 }
2228
2229 if (Ret)
2230 {
2231 _SEH2_TRY
2232 {
2233 ProbeForWrite(Result,
2234 sizeof(DWORD),
2235 1);
2236 *Result = SafeResult;
2237 }
2238 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2239 {
2240 Status = _SEH2_GetExceptionCode();
2241 }
2242 _SEH2_END;
2243 }
2244
2245 if(!NT_SUCCESS(Status))
2246 {
2247 SetLastNtError(Status);
2248 DC_UnlockDc(dc);
2249 return FALSE;
2250 }
2251
2252 DC_UnlockDc(dc);
2253 return Ret;
2254 }
2255
2256 BOOL
2257 APIENTRY
2258 NtGdiGetAndSetDCDword(
2259 HDC hDC,
2260 UINT u,
2261 DWORD dwIn,
2262 DWORD *Result
2263 )
2264 {
2265 BOOL Ret = TRUE;
2266 PDC dc;
2267 PDC_ATTR pdcattr;
2268
2269 DWORD SafeResult = 0;
2270 NTSTATUS Status = STATUS_SUCCESS;
2271
2272 if(!Result)
2273 {
2274 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2275 return FALSE;
2276 }
2277
2278 dc = DC_LockDc(hDC);
2279 if(!dc)
2280 {
2281 SetLastWin32Error(ERROR_INVALID_HANDLE);
2282 return FALSE;
2283 }
2284 pdcattr = dc->pdcattr;
2285
2286 switch (u)
2287 {
2288 case GdiGetSetCopyCount:
2289 SafeResult = dc->ulCopyCount;
2290 dc->ulCopyCount = dwIn;
2291 break;
2292 case GdiGetSetTextAlign:
2293 SafeResult = pdcattr->lTextAlign;
2294 pdcattr->lTextAlign = dwIn;
2295 // pdcattr->flTextAlign = dwIn; // Flags!
2296 break;
2297 case GdiGetSetRelAbs:
2298 SafeResult = pdcattr->lRelAbs;
2299 pdcattr->lRelAbs = dwIn;
2300 break;
2301 case GdiGetSetTextCharExtra:
2302 SafeResult = pdcattr->lTextExtra;
2303 pdcattr->lTextExtra = dwIn;
2304 break;
2305 case GdiGetSetSelectFont:
2306 break;
2307 case GdiGetSetMapperFlagsInternal:
2308 if (dwIn & ~1)
2309 {
2310 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2311 Ret = FALSE;
2312 break;
2313 }
2314 SafeResult = pdcattr->flFontMapper;
2315 pdcattr->flFontMapper = dwIn;
2316 break;
2317 case GdiGetSetMapMode:
2318 SafeResult = IntGdiSetMapMode( dc, dwIn);
2319 break;
2320 case GdiGetSetArcDirection:
2321 if (dwIn != AD_COUNTERCLOCKWISE && dwIn != AD_CLOCKWISE)
2322 {
2323 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2324 Ret = FALSE;
2325 break;
2326 }
2327 if ( pdcattr->dwLayout & LAYOUT_RTL ) // Right to Left
2328 {
2329 SafeResult = AD_CLOCKWISE - ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0);
2330 if ( dwIn == AD_CLOCKWISE )
2331 {
2332 dc->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
2333 break;
2334 }
2335 dc->DcLevel.flPath |= DCPATH_CLOCKWISE;
2336 }
2337 else // Left to Right
2338 {
2339 SafeResult = ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0) + AD_COUNTERCLOCKWISE;
2340 if ( dwIn == AD_COUNTERCLOCKWISE)
2341 {
2342 dc->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
2343 break;
2344 }
2345 dc->DcLevel.flPath |= DCPATH_CLOCKWISE;
2346 }
2347 break;
2348 default:
2349 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2350 Ret = FALSE;
2351 break;
2352 }
2353
2354 if (Ret)
2355 {
2356 _SEH2_TRY
2357 {
2358 ProbeForWrite(Result,
2359 sizeof(DWORD),
2360 1);
2361 *Result = SafeResult;
2362 }
2363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2364 {
2365 Status = _SEH2_GetExceptionCode();
2366 }
2367 _SEH2_END;
2368 }
2369
2370 if(!NT_SUCCESS(Status))
2371 {
2372 SetLastNtError(Status);
2373 DC_UnlockDc(dc);
2374 return FALSE;
2375 }
2376
2377 DC_UnlockDc(dc);
2378 return Ret;
2379 }
2380
2381 // ---------------------------------------------------- Private Interface
2382
2383 HDC FASTCALL
2384 DC_AllocDC(PUNICODE_STRING Driver)
2385 {
2386 PDC NewDC;
2387 PDC_ATTR pdcattr;
2388 HDC hDC;
2389 PWSTR Buf = NULL;
2390 XFORM xformTemplate;
2391
2392 if (Driver != NULL)
2393 {
2394 Buf = ExAllocatePoolWithTag(PagedPool, Driver->MaximumLength, TAG_DC);
2395 if(!Buf)
2396 {
2397 DPRINT1("ExAllocatePoolWithTag failed\n");
2398 return NULL;
2399 }
2400 RtlCopyMemory(Buf, Driver->Buffer, Driver->MaximumLength);
2401 }
2402
2403 NewDC = (PDC)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_DC);
2404 if(!NewDC)
2405 {
2406 if(Buf)
2407 {
2408 ExFreePoolWithTag(Buf, TAG_DC);
2409 }
2410 DPRINT1("GDIOBJ_AllocObjWithHandle failed\n");
2411 return NULL;
2412 }
2413
2414 hDC = NewDC->BaseObject.hHmgr;
2415
2416 NewDC->pdcattr = &NewDC->Dc_Attr;
2417 DC_AllocateDcAttr(hDC);
2418
2419 if (Driver != NULL)
2420 {
2421 RtlCopyMemory(&NewDC->rosdc.DriverName, Driver, sizeof(UNICODE_STRING));
2422 NewDC->rosdc.DriverName.Buffer = Buf;
2423 }
2424 pdcattr = NewDC->pdcattr;
2425
2426 NewDC->BaseObject.hHmgr = (HGDIOBJ) hDC; // Save the handle for this DC object.
2427
2428 xformTemplate.eM11 = 1.0f;
2429 xformTemplate.eM12 = 0.0f;
2430 xformTemplate.eM21 = 0.0f;
2431 xformTemplate.eM22 = 1.0f;
2432 xformTemplate.eDx = 0.0f;
2433 xformTemplate.eDy = 0.0f;
2434 XForm2MatrixS(&NewDC->DcLevel.mxWorldToDevice, &xformTemplate);
2435 XForm2MatrixS(&NewDC->DcLevel.mxDeviceToWorld, &xformTemplate);
2436 XForm2MatrixS(&NewDC->DcLevel.mxWorldToPage, &xformTemplate);
2437
2438 // Setup syncing bits for the dcattr data packets.
2439 pdcattr->flXform = DEVICE_TO_PAGE_INVALID;
2440
2441 pdcattr->ulDirty_ = 0; // Server side
2442
2443 pdcattr->iMapMode = MM_TEXT;
2444 pdcattr->iGraphicsMode = GM_COMPATIBLE;
2445 pdcattr->jFillMode = ALTERNATE;
2446
2447 pdcattr->szlWindowExt.cx = 1; // Float to Int,,, WRONG!
2448 pdcattr->szlWindowExt.cy = 1;
2449 pdcattr->szlViewportExt.cx = 1;
2450 pdcattr->szlViewportExt.cy = 1;
2451
2452 pdcattr->crForegroundClr = 0;
2453 pdcattr->ulForegroundClr = 0;
2454
2455 pdcattr->ulBackgroundClr = 0xffffff;
2456 pdcattr->crBackgroundClr = 0xffffff;
2457
2458 pdcattr->ulPenClr = RGB( 0, 0, 0 );
2459 pdcattr->crPenClr = RGB( 0, 0, 0 );
2460
2461 pdcattr->ulBrushClr = RGB( 255, 255, 255 ); // Do this way too.
2462 pdcattr->crBrushClr = RGB( 255, 255, 255 );
2463
2464 //// This fixes the default brush and pen settings. See DC_InitDC.
2465 pdcattr->hbrush = NtGdiGetStockObject( WHITE_BRUSH );
2466 pdcattr->hpen = NtGdiGetStockObject( BLACK_PEN );
2467 ////
2468 pdcattr->hlfntNew = NtGdiGetStockObject(SYSTEM_FONT);
2469 TextIntRealizeFont(pdcattr->hlfntNew,NULL);
2470
2471 NewDC->DcLevel.hpal = NtGdiGetStockObject(DEFAULT_PALETTE);
2472 NewDC->DcLevel.laPath.eMiterLimit = 10.0;
2473
2474 DC_UnlockDc(NewDC);
2475
2476 return hDC;
2477 }
2478
2479 HDC FASTCALL
2480 DC_FindOpenDC(PUNICODE_STRING Driver)
2481 {
2482 return NULL;
2483 }
2484
2485 /*!
2486 * Initialize some common fields in the Device Context structure.
2487 */
2488 VOID FASTCALL
2489 DC_InitDC(HDC DCHandle)
2490 {
2491 // NtGdiRealizeDefaultPalette(DCHandle);
2492
2493 //// Removed for now.. See above brush and pen.
2494 // NtGdiSelectBrush(DCHandle, NtGdiGetStockObject( WHITE_BRUSH ));
2495 // NtGdiSelectPen(DCHandle, NtGdiGetStockObject( BLACK_PEN ));
2496 ////
2497 //NtGdiSelectFont(DCHandle, hFont);
2498
2499 /*
2500 {
2501 int res;
2502 res = CLIPPING_UpdateGCRegion(DCToInit);
2503 ASSERT ( res != ERROR );
2504 }
2505 */
2506 }
2507
2508 VOID
2509 FASTCALL
2510 DC_AllocateDcAttr(HDC hDC)
2511 {
2512 PVOID NewMem = NULL;
2513 PDC pDC;
2514 HANDLE Pid = NtCurrentProcess();
2515 ULONG MemSize = sizeof(DC_ATTR); //PAGE_SIZE it will allocate that size
2516
2517 NTSTATUS Status = ZwAllocateVirtualMemory(Pid,
2518 &NewMem,
2519 0,
2520 &MemSize,
2521 MEM_COMMIT|MEM_RESERVE,
2522 PAGE_READWRITE);
2523 KeEnterCriticalRegion();
2524 {
2525 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hDC);
2526 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
2527 // FIXME: dc could have been deleted!!! use GDIOBJ_InsertUserData
2528 if (NT_SUCCESS(Status))
2529 {
2530 RtlZeroMemory(NewMem, MemSize);
2531 Entry->UserData = NewMem;
2532 DPRINT("DC_ATTR allocated! 0x%x\n",NewMem);
2533 }
2534 else
2535 {
2536 DPRINT("DC_ATTR not allocated!\n");
2537 }
2538 }
2539 KeLeaveCriticalRegion();
2540 pDC = DC_LockDc(hDC);
2541 ASSERT(pDC->pdcattr == &pDC->Dc_Attr);
2542 if(NewMem)
2543 {
2544 pDC->pdcattr = NewMem; // Store pointer
2545 }
2546 DC_UnlockDc(pDC);
2547 }
2548
2549 VOID
2550 FASTCALL
2551 DC_FreeDcAttr(HDC DCToFree )
2552 {
2553 HANDLE Pid = NtCurrentProcess();
2554 PDC pDC = DC_LockDc(DCToFree);
2555 if (pDC->pdcattr == &pDC->Dc_Attr) return; // Internal DC object!
2556 pDC->pdcattr = &pDC->Dc_Attr;
2557 DC_UnlockDc(pDC);
2558
2559 KeEnterCriticalRegion();
2560 {
2561 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)DCToFree);
2562 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
2563 if(Entry->UserData)
2564 {
2565 ULONG MemSize = sizeof(DC_ATTR); //PAGE_SIZE;
2566 NTSTATUS Status = ZwFreeVirtualMemory(Pid,
2567 &Entry->UserData,
2568 &MemSize,
2569 MEM_RELEASE);
2570 if (NT_SUCCESS(Status))
2571 {
2572 DPRINT("DC_FreeDC DC_ATTR 0x%x\n", Entry->UserData);
2573 Entry->UserData = NULL;
2574 }
2575 }
2576 }
2577 KeLeaveCriticalRegion();
2578 }
2579
2580 VOID FASTCALL
2581 DC_FreeDC(HDC DCToFree)
2582 {
2583 DC_FreeDcAttr(DCToFree);
2584 if(!IsObjectDead( DCToFree ))
2585 {
2586 if (!GDIOBJ_FreeObjByHandle(DCToFree, GDI_OBJECT_TYPE_DC))
2587 {
2588 DPRINT1("DC_FreeDC failed\n");
2589 }
2590 }
2591 else
2592 {
2593 DPRINT1("Attempted to Delete 0x%x currently being destroyed!!!\n",DCToFree);
2594 }
2595 }
2596
2597 BOOL INTERNAL_CALL
2598 DC_Cleanup(PVOID ObjectBody)
2599 {
2600 PDC pDC = (PDC)ObjectBody;
2601 if (pDC->rosdc.DriverName.Buffer)
2602 ExFreePoolWithTag(pDC->rosdc.DriverName.Buffer, TAG_DC);
2603 return TRUE;
2604 }
2605
2606 HDC FASTCALL
2607 DC_GetNextDC (PDC pDC)
2608 {
2609 return pDC->hdcNext;
2610 }
2611
2612 VOID FASTCALL
2613 DC_SetNextDC (PDC pDC, HDC hNextDC)
2614 {
2615 pDC->hdcNext = hNextDC;
2616 }
2617
2618 VOID FASTCALL
2619 DC_UpdateXforms(PDC dc)
2620 {
2621 XFORM xformWnd2Vport;
2622 FLOAT scaleX, scaleY;
2623 PDC_ATTR pdcattr = dc->pdcattr;
2624 XFORM xformWorld2Vport, xformWorld2Wnd, xformVport2World;
2625
2626 /* Construct a transformation to do the window-to-viewport conversion */
2627 scaleX = (pdcattr->szlWindowExt.cx ? (FLOAT)pdcattr->szlViewportExt.cx / (FLOAT)pdcattr->szlWindowExt.cx : 0.0f);
2628 scaleY = (pdcattr->szlWindowExt.cy ? (FLOAT)pdcattr->szlViewportExt.cy / (FLOAT)pdcattr->szlWindowExt.cy : 0.0f);
2629 xformWnd2Vport.eM11 = scaleX;
2630 xformWnd2Vport.eM12 = 0.0;
2631 xformWnd2Vport.eM21 = 0.0;
2632 xformWnd2Vport.eM22 = scaleY;
2633 xformWnd2Vport.eDx = (FLOAT)pdcattr->ptlViewportOrg.x - scaleX * (FLOAT)pdcattr->ptlWindowOrg.x;
2634 xformWnd2Vport.eDy = (FLOAT)pdcattr->ptlViewportOrg.y - scaleY * (FLOAT)pdcattr->ptlWindowOrg.y;
2635
2636 /* Combine with the world transformation */
2637 MatrixS2XForm(&xformWorld2Vport, &dc->DcLevel.mxWorldToDevice);
2638 MatrixS2XForm(&xformWorld2Wnd, &dc->DcLevel.mxWorldToPage);
2639 IntGdiCombineTransform(&xformWorld2Vport, &xformWorld2Wnd, &xformWnd2Vport);
2640
2641 /* Create inverse of world-to-viewport transformation */
2642 MatrixS2XForm(&xformVport2World, &dc->DcLevel.mxDeviceToWorld);
2643 if (DC_InvertXform(&xformWorld2Vport, &xformVport2World))
2644 {
2645 pdcattr->flXform &= ~DEVICE_TO_WORLD_INVALID;
2646 }
2647 else
2648 {
2649 pdcattr->flXform |= DEVICE_TO_WORLD_INVALID;
2650 }
2651
2652 XForm2MatrixS(&dc->DcLevel.mxWorldToDevice, &xformWorld2Vport);
2653
2654 }
2655
2656 BOOL FASTCALL
2657 DC_InvertXform(const XFORM *xformSrc,
2658 XFORM *xformDest)
2659 {
2660 FLOAT determinant;
2661
2662 determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21;
2663 if (determinant > -1e-12 && determinant < 1e-12)
2664 {
2665 return FALSE;
2666 }
2667
2668 xformDest->eM11 = xformSrc->eM22 / determinant;
2669 xformDest->eM12 = -xformSrc->eM12 / determinant;
2670 xformDest->eM21 = -xformSrc->eM21 / determinant;
2671 xformDest->eM22 = xformSrc->eM11 / determinant;
2672 xformDest->eDx = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21;
2673 xformDest->eDy = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22;
2674
2675 return TRUE;
2676 }
2677
2678 BOOL
2679 FASTCALL
2680 DC_SetOwnership(HDC hDC, PEPROCESS Owner)
2681 {
2682 PDC pDC;
2683
2684 if(!GDIOBJ_SetOwnership(hDC, Owner)) return FALSE;
2685 pDC = DC_LockDc(hDC);
2686 if (pDC)
2687 {
2688 if (pDC->rosdc.hClipRgn)
2689 {
2690 if(!GDIOBJ_SetOwnership(pDC->rosdc.hClipRgn, Owner)) return FALSE;
2691 }
2692 if (pDC->rosdc.hVisRgn)
2693 {
2694 if(!GDIOBJ_SetOwnership(pDC->rosdc.hVisRgn, Owner)) return FALSE;
2695 }
2696 if (pDC->rosdc.hGCClipRgn)
2697 {
2698 if(!GDIOBJ_SetOwnership(pDC->rosdc.hGCClipRgn, Owner)) return FALSE;
2699 }
2700 if (pDC->DcLevel.hPath)
2701 {
2702 if(!GDIOBJ_SetOwnership(pDC->DcLevel.hPath, Owner)) return FALSE;
2703 }
2704 DC_UnlockDc(pDC);
2705 }
2706 return TRUE;
2707 }
2708
2709 //
2710 // Support multi display/device locks.
2711 //
2712 VOID
2713 FASTCALL
2714 DC_LockDisplay(HDC hDC)
2715 {
2716 PERESOURCE Resource;
2717 PDC dc = DC_LockDc(hDC);
2718 if (!dc) return;
2719 Resource = ((PGDIDEVICE)dc->ppdev)->hsemDevLock;
2720 DC_UnlockDc(dc);
2721 if (!Resource) return;
2722 KeEnterCriticalRegion();
2723 ExAcquireResourceExclusiveLite( Resource , TRUE);
2724 }
2725
2726 VOID
2727 FASTCALL
2728 DC_UnlockDisplay(HDC hDC)
2729 {
2730 PERESOURCE Resource;
2731 PDC dc = DC_LockDc(hDC);
2732 if (!dc) return;
2733 Resource = ((PGDIDEVICE)dc->ppdev)->hsemDevLock;
2734 DC_UnlockDc(dc);
2735 if (!Resource) return;
2736 ExReleaseResourceLite( Resource );
2737 KeLeaveCriticalRegion();
2738 }
2739
2740 BOOL FASTCALL
2741 IntIsPrimarySurface(SURFOBJ *SurfObj)
2742 {
2743 if (PrimarySurface.pSurface == NULL)
2744 {
2745 return FALSE;
2746 }
2747 return SurfObj->hsurf == PrimarySurface.pSurface;
2748 }
2749
2750 //
2751 // Enumerate HDev
2752 //
2753 PGDIDEVICE FASTCALL
2754 IntEnumHDev(VOID)
2755 {
2756 // I guess we will soon have more than one primary surface.
2757 // This will do for now.
2758 return &PrimarySurface;
2759 }
2760
2761
2762 VOID FASTCALL
2763 IntGdiReferencePdev(PGDIDEVICE ppdev)
2764 {
2765 if(!hsemDriverMgmt) hsemDriverMgmt = EngCreateSemaphore(); // Hax, should be in dllmain.c
2766 IntGdiAcquireSemaphore(hsemDriverMgmt);
2767 ppdev->cPdevRefs++;
2768 IntGdiReleaseSemaphore(hsemDriverMgmt);
2769 }
2770
2771 VOID FASTCALL
2772 IntGdiUnreferencePdev(PGDIDEVICE ppdev, DWORD CleanUpType)
2773 {
2774 IntGdiAcquireSemaphore(hsemDriverMgmt);
2775 ppdev->cPdevRefs--;
2776 if (!ppdev->cPdevRefs)
2777 {
2778 // Handle the destruction of ppdev or GDIDEVICE or PDEVOBJ or PDEV etc.
2779 }
2780 IntGdiReleaseSemaphore(hsemDriverMgmt);
2781 }
2782
2783
2784 #define SIZEOF_DEVMODEW_300 188
2785 #define SIZEOF_DEVMODEW_400 212
2786 #define SIZEOF_DEVMODEW_500 220
2787
2788 static NTSTATUS FASTCALL
2789 GetDisplayNumberFromDeviceName(
2790 IN PUNICODE_STRING pDeviceName OPTIONAL,
2791 OUT ULONG *DisplayNumber)
2792 {
2793 UNICODE_STRING DisplayString = RTL_CONSTANT_STRING(L"\\\\.\\DISPLAY");
2794 NTSTATUS Status = STATUS_SUCCESS;
2795 ULONG Length;
2796 ULONG Number;
2797 ULONG i;
2798
2799 if (DisplayNumber == NULL)
2800 return STATUS_INVALID_PARAMETER_2;
2801
2802 /* Check if DeviceName is valid */
2803 if (pDeviceName &&
2804 pDeviceName->Length > 0 && pDeviceName->Length <= DisplayString.Length)
2805 return STATUS_OBJECT_NAME_INVALID;
2806
2807 if (pDeviceName == NULL || pDeviceName->Length == 0)
2808 {
2809 PWINDOW_OBJECT DesktopObject;
2810 HDC DesktopHDC;
2811 PDC pDC;
2812
2813 DesktopObject = UserGetDesktopWindow();
2814 DesktopHDC = UserGetWindowDC(DesktopObject);
2815 pDC = DC_LockDc(DesktopHDC);
2816
2817 *DisplayNumber = ((GDIDEVICE *)pDC->ppdev)->DisplayNumber;
2818
2819 DC_UnlockDc(pDC);
2820 UserReleaseDC(DesktopObject, DesktopHDC, FALSE);
2821
2822 return STATUS_SUCCESS;
2823 }
2824
2825 /* Hack to check if the first parts are equal, by faking the device name length */
2826 Length = pDeviceName->Length;
2827 pDeviceName->Length = DisplayString.Length;
2828 if (RtlEqualUnicodeString(&DisplayString, pDeviceName, FALSE) == FALSE)
2829 Status = STATUS_OBJECT_NAME_INVALID;
2830 pDeviceName->Length = Length;
2831
2832 if (NT_SUCCESS(Status))
2833 {
2834 /* Convert the last part of pDeviceName to a number */
2835 Number = 0;
2836 Length = pDeviceName->Length / sizeof(WCHAR);
2837 for (i = DisplayString.Length / sizeof(WCHAR); i < Length; i++)
2838 {
2839 WCHAR Char = pDeviceName->Buffer[i];
2840 if (Char >= L'0' && Char <= L'9')
2841 Number = Number * 10 + Char - L'0';
2842 else if (Char != L'\0')
2843 return STATUS_OBJECT_NAME_INVALID;
2844 }
2845
2846 *DisplayNumber = Number - 1;
2847 }
2848
2849 return Status;
2850 }
2851
2852 /*! \brief Enumerate possible display settings for the given display...
2853 *
2854 * \todo Make thread safe!?
2855 * \todo Don't ignore pDeviceName
2856 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
2857 */
2858 NTSTATUS
2859 FASTCALL
2860 IntEnumDisplaySettings(
2861 IN PUNICODE_STRING pDeviceName OPTIONAL,
2862 IN DWORD iModeNum,
2863 IN OUT LPDEVMODEW pDevMode,
2864 IN DWORD dwFlags)
2865 {
2866 static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL;
2867 static DWORD SizeOfCachedDevModes = 0;
2868 static UNICODE_STRING CachedDeviceName;
2869 PDEVMODEW CachedMode = NULL;
2870 DEVMODEW DevMode;
2871 ULONG DisplayNumber;
2872 NTSTATUS Status;
2873
2874 Status = GetDisplayNumberFromDeviceName(pDeviceName, &DisplayNumber);
2875 if (!NT_SUCCESS(Status))
2876 {
2877 return Status;
2878 }
2879
2880 DPRINT("DevMode->dmSize = %d\n", pDevMode->dmSize);
2881 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode->dmDriverExtra);
2882 if (pDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
2883 pDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
2884 pDevMode->dmSize != SIZEOF_DEVMODEW_500)
2885 {
2886 return STATUS_BUFFER_TOO_SMALL;
2887 }
2888
2889 if (iModeNum == ENUM_CURRENT_SETTINGS)
2890 {
2891 CachedMode = &PrimarySurface.DMW;
2892 ASSERT(CachedMode->dmSize > 0);
2893 }
2894 else if (iModeNum == ENUM_REGISTRY_SETTINGS)
2895 {
2896 RtlZeroMemory(&DevMode, sizeof (DevMode));
2897 DevMode.dmSize = sizeof (DevMode);
2898 DevMode.dmDriverExtra = 0;
2899 if (SetupDevMode(&DevMode, DisplayNumber))
2900 CachedMode = &DevMode;
2901 else
2902 {
2903 return STATUS_UNSUCCESSFUL; // FIXME: what status?
2904 }
2905 /* FIXME: Maybe look for the matching devmode supplied by the
2906 * driver so we can provide driver private/extra data?
2907 */
2908 }
2909 else
2910 {
2911 BOOL IsCachedDevice = (CachedDevModes != NULL);
2912
2913 if (CachedDevModes &&
2914 ((pDeviceName == NULL && CachedDeviceName.Length > 0) ||
2915 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length == 0) ||
2916 (pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length > 0 && RtlEqualUnicodeString(pDeviceName, &CachedDeviceName, TRUE) == FALSE)))
2917 {
2918 IsCachedDevice = FALSE;
2919 }
2920
2921 if (iModeNum == 0 || IsCachedDevice == FALSE) /* query modes from drivers */
2922 {
2923 UNICODE_STRING DriverFileNames;
2924 LPWSTR CurrentName;
2925 DRVENABLEDATA DrvEnableData;
2926
2927 /* Free resources from last driver cache */
2928 if (IsCachedDevice == FALSE && CachedDeviceName.Buffer != NULL)
2929 {
2930 RtlFreeUnicodeString(&CachedDeviceName);
2931 }
2932
2933 /* Retrieve DDI driver names from registry */
2934 RtlInitUnicodeString(&DriverFileNames, NULL);
2935 if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
2936 {
2937 DPRINT1("FindDriverFileNames failed\n");
2938 return STATUS_UNSUCCESSFUL;
2939 }
2940
2941 if (!IntPrepareDriverIfNeeded())
2942 {
2943 DPRINT1("IntPrepareDriverIfNeeded failed\n");
2944 return STATUS_UNSUCCESSFUL;
2945 }
2946
2947 /*
2948 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
2949 * scan all of them until a good one found.
2950 */
2951 CurrentName = DriverFileNames.Buffer;
2952 for (;CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR));
2953 CurrentName += wcslen(CurrentName) + 1)
2954 {
2955 INT i;
2956 PGD_ENABLEDRIVER GDEnableDriver;
2957 PGD_GETMODES GetModes = NULL;
2958 INT SizeNeeded, SizeUsed;
2959
2960 /* Get the DDI driver's entry point */
2961 //GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
2962 GDEnableDriver = DRIVER_FindExistingDDIDriver(L"DISPLAY");
2963 if (NULL == GDEnableDriver)
2964 {
2965 DPRINT("FindDDIDriver failed for %S\n", CurrentName);
2966 continue;
2967 }
2968
2969 /* Call DDI driver's EnableDriver function */
2970 RtlZeroMemory(&DrvEnableData, sizeof(DrvEnableData));
2971
2972 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof (DrvEnableData), &DrvEnableData))
2973 {
2974 DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
2975 continue;
2976 }
2977
2978 CachedDevModesEnd = CachedDevModes;
2979
2980 /* find DrvGetModes function */
2981 for (i = 0; i < DrvEnableData.c; i++)
2982 {
2983 PDRVFN DrvFn = DrvEnableData.pdrvfn + i;
2984
2985 if (DrvFn->iFunc == INDEX_DrvGetModes)
2986 {
2987 GetModes = (PGD_GETMODES)DrvFn->pfn;
2988 break;
2989 }
2990 }
2991
2992 if (GetModes == NULL)
2993 {
2994 DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName);
2995 continue;
2996 }
2997
2998 /* make sure we have enough memory to hold the modes */
2999 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), 0, NULL);
3000 if (SizeNeeded <= 0)
3001 {
3002 DPRINT("DrvGetModes failed for %S\n", CurrentName);
3003 break;
3004 }
3005
3006 SizeUsed = (PCHAR)CachedDevModesEnd - (PCHAR)CachedDevModes;
3007 if (SizeOfCachedDevModes < SizeUsed + SizeNeeded)
3008 {
3009 PVOID NewBuffer;
3010
3011 SizeOfCachedDevModes += SizeNeeded;
3012 NewBuffer = ExAllocatePool(PagedPool, SizeOfCachedDevModes);
3013 if (NewBuffer == NULL)
3014 {
3015 /* clean up */
3016 ExFreePool(CachedDevModes);
3017 CachedDevModes = NULL;
3018 CachedDevModesEnd = NULL;
3019 SizeOfCachedDevModes = 0;
3020
3021 if (CachedDeviceName.Buffer != NULL)
3022 RtlFreeUnicodeString(&CachedDeviceName);
3023
3024 return STATUS_NO_MEMORY;
3025 }
3026 if (CachedDevModes != NULL)
3027 {
3028 RtlCopyMemory(NewBuffer, CachedDevModes, SizeUsed);
3029 ExFreePool(CachedDevModes);
3030 }
3031 CachedDevModes = NewBuffer;
3032 CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed);
3033 }
3034
3035 if (!IsCachedDevice)
3036 {
3037 if (CachedDeviceName.Buffer != NULL)
3038 RtlFreeUnicodeString(&CachedDeviceName);
3039
3040 if (pDeviceName)
3041 IntSafeCopyUnicodeString(&CachedDeviceName, pDeviceName);
3042
3043 IsCachedDevice = TRUE;
3044 }
3045
3046 /* query modes */
3047 SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject),
3048 SizeNeeded,
3049 CachedDevModesEnd);
3050 if (SizeNeeded <= 0)
3051 {
3052 DPRINT("DrvGetModes failed for %S\n", CurrentName);
3053 }
3054 else
3055 {
3056 CachedDevModesEnd = (DEVMODEW *)((PCHAR)CachedDevModesEnd + SizeNeeded);
3057 }
3058 }
3059
3060 ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
3061 }
3062
3063 /* return cached info */
3064 CachedMode = CachedDevModes;
3065 if (CachedMode >= CachedDevModesEnd)
3066 {
3067 return STATUS_NO_MORE_ENTRIES;
3068 }
3069 while (iModeNum-- > 0 && CachedMode < CachedDevModesEnd)
3070 {
3071 assert(CachedMode->dmSize > 0);
3072 CachedMode = (DEVMODEW *)((PCHAR)CachedMode + CachedMode->dmSize + CachedMode->dmDriverExtra);
3073 }
3074 if (CachedMode >= CachedDevModesEnd)
3075 {
3076 return STATUS_NO_MORE_ENTRIES;
3077 }
3078 }
3079
3080 ASSERT(CachedMode != NULL);
3081
3082 RtlCopyMemory(pDevMode, CachedMode, min(pDevMode->dmSize, CachedMode->dmSize));
3083 RtlZeroMemory(pDevMode + pDevMode->dmSize, pDevMode->dmDriverExtra);
3084 RtlCopyMemory(pDevMode + min(pDevMode->dmSize, CachedMode->dmSize), CachedMode + CachedMode->dmSize, min(pDevMode->dmDriverExtra, CachedMode->dmDriverExtra));
3085
3086 return STATUS_SUCCESS;
3087 }
3088
3089 static NTSTATUS FASTCALL
3090 GetVideoDeviceName(
3091 OUT PUNICODE_STRING VideoDeviceName,
3092 IN PCUNICODE_STRING DisplayDevice) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
3093 {
3094 UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\??\\");
3095 UNICODE_STRING ObjectName;
3096 UNICODE_STRING KernelModeName = { 0, };
3097 OBJECT_ATTRIBUTES ObjectAttributes;
3098 USHORT LastSlash;
3099 ULONG Length;
3100 HANDLE LinkHandle = NULL;
3101 NTSTATUS Status;
3102
3103 RtlInitUnicodeString(VideoDeviceName, NULL);
3104
3105 /* Get device name (DisplayDevice is "\.\xxx") */
3106 for (LastSlash = DisplayDevice->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
3107 {
3108 if (DisplayDevice->Buffer[LastSlash - 1] == L'\\')
3109 break;
3110 }
3111
3112 if (LastSlash == 0)
3113 {
3114 DPRINT1("Invalid device name '%wZ'\n", DisplayDevice);
3115 Status = STATUS_OBJECT_NAME_INVALID;
3116 goto cleanup;
3117 }
3118 ObjectName = *DisplayDevice;
3119 ObjectName.Length -= LastSlash * sizeof(WCHAR);
3120 ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
3121 ObjectName.Buffer += LastSlash;
3122
3123 /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
3124 KernelModeName.MaximumLength = Prefix.Length + ObjectName.Length + sizeof(UNICODE_NULL);
3125 KernelModeName.Buffer = ExAllocatePoolWithTag(PagedPool,
3126 KernelModeName.MaximumLength,
3127 TAG_DC);
3128 if (!KernelModeName.Buffer)
3129 {
3130 Status = STATUS_NO_MEMORY;
3131 goto cleanup;
3132 }
3133 RtlCopyUnicodeString(&KernelModeName, &Prefix);
3134 Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName);
3135 if (!NT_SUCCESS(Status))
3136 goto cleanup;
3137
3138 /* Open \??\xxx (ex: "\??\DISPLAY1") */
3139 InitializeObjectAttributes(&ObjectAttributes,
3140 &KernelModeName,
3141 OBJ_KERNEL_HANDLE,
3142 NULL,
3143 NULL);
3144 Status = ZwOpenSymbolicLinkObject(&LinkHandle,
3145 GENERIC_READ,
3146 &ObjectAttributes);
3147 if (!NT_SUCCESS(Status))
3148 {
3149 DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
3150 Status = STATUS_NO_SUCH_DEVICE;
3151 goto cleanup;
3152 }
3153
3154 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, &Length);
3155 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
3156 {
3157 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
3158 Status = STATUS_NO_SUCH_DEVICE;
3159 goto cleanup;
3160 }
3161 VideoDeviceName->MaximumLength = Length;
3162 VideoDeviceName->Buffer = ExAllocatePoolWithTag(PagedPool,
3163 VideoDeviceName->MaximumLength + sizeof(UNICODE_NULL),
3164 TAG_DC);
3165 if (!VideoDeviceName->Buffer)
3166 {
3167 Status = STATUS_NO_MEMORY;
3168 goto cleanup;
3169 }
3170 Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, NULL);
3171 VideoDeviceName->Buffer[VideoDeviceName->MaximumLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
3172 if (!NT_SUCCESS(Status))
3173 {
3174 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
3175 Status = STATUS_NO_SUCH_DEVICE;
3176 goto cleanup;
3177 }
3178 Status = STATUS_SUCCESS;
3179
3180 cleanup:
3181 if (!NT_SUCCESS(Status) && VideoDeviceName->Buffer)
3182 ExFreePoolWithTag(VideoDeviceName->Buffer, TAG_DC);
3183 if (KernelModeName.Buffer)
3184 ExFreePoolWithTag(KernelModeName.Buffer, TAG_DC);
3185 if (LinkHandle)
3186 ZwClose(LinkHandle);
3187 return Status;
3188 }
3189
3190 static NTSTATUS FASTCALL
3191 GetVideoRegistryKey(
3192 OUT PUNICODE_STRING RegistryPath,
3193 IN PCUNICODE_STRING DeviceName) /* ex: "\Device\Video0" */
3194 {
3195 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
3196 NTSTATUS Status;
3197
3198 RtlInitUnicodeString(RegistryPath, NULL);
3199 RtlZeroMemory(QueryTable, sizeof(QueryTable));
3200 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
3201 QueryTable[0].Name = DeviceName->Buffer;
3202 QueryTable[0].EntryContext = RegistryPath;
3203
3204 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
3205 L"VIDEO",
3206 QueryTable,
3207 NULL,
3208 NULL);
3209 if (!NT_SUCCESS(Status))
3210 {
3211 DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName, Status);
3212 return STATUS_NO_SUCH_DEVICE;
3213 }
3214
3215 DPRINT("RegistryPath %wZ\n", RegistryPath);
3216 return STATUS_SUCCESS;
3217 }
3218
3219 LONG
3220 FASTCALL
3221 IntChangeDisplaySettings(
3222 IN PUNICODE_STRING pDeviceName OPTIONAL,
3223 IN LPDEVMODEW DevMode,
3224 IN DWORD dwflags,
3225 IN PVOID lParam OPTIONAL)
3226 {
3227 BOOLEAN Global = FALSE;
3228 BOOLEAN NoReset = FALSE;
3229 BOOLEAN Reset = FALSE;
3230 BOOLEAN SetPrimary = FALSE;
3231 LONG Ret=0;
3232 NTSTATUS Status ;
3233
3234 DPRINT1("display flags : %x\n",dwflags);
3235
3236 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
3237 {
3238 /* Check global, reset and noreset flags */
3239 if ((dwflags & CDS_GLOBAL) == CDS_GLOBAL)
3240 Global = TRUE;
3241 if ((dwflags & CDS_NORESET) == CDS_NORESET)
3242 NoReset = TRUE;
3243 dwflags &= ~(CDS_GLOBAL | CDS_NORESET);
3244 }
3245 if ((dwflags & CDS_RESET) == CDS_RESET)
3246 Reset = TRUE;
3247 if ((dwflags & CDS_SET_PRIMARY) == CDS_SET_PRIMARY)
3248 SetPrimary = TRUE;
3249 dwflags &= ~(CDS_RESET | CDS_SET_PRIMARY);
3250
3251 if (Reset && NoReset)
3252 return DISP_CHANGE_BADFLAGS;
3253
3254 if (dwflags == 0)
3255 {
3256 /* Dynamically change graphics mode */
3257 DPRINT1("flag 0 UNIMPLEMENTED\n");
3258 return DISP_CHANGE_FAILED;
3259 }
3260
3261 if ((dwflags & CDS_TEST) == CDS_TEST)
3262 {
3263 /* Test reslution */
3264 dwflags &= ~CDS_TEST;
3265 DPRINT1("flag CDS_TEST UNIMPLEMENTED\n");
3266 Ret = DISP_CHANGE_FAILED;
3267 }
3268
3269 if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN)
3270 {
3271 DEVMODEW lpDevMode;
3272 /* Full Screen */
3273 dwflags &= ~CDS_FULLSCREEN;
3274 DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
3275 Ret = DISP_CHANGE_FAILED;
3276
3277 RtlZeroMemory(&lpDevMode, sizeof(DEVMODEW));
3278 lpDevMode.dmSize = sizeof(DEVMODEW);
3279
3280 if (!IntEnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &lpDevMode, 0))
3281 return DISP_CHANGE_FAILED;
3282
3283 DPRINT1("Req Mode : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel);
3284 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel);
3285
3286
3287 if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) &&
3288 (lpDevMode.dmPelsWidth == DevMode->dmPelsWidth) &&
3289 (lpDevMode.dmPelsHeight == DevMode->dmPelsHeight))
3290 Ret = DISP_CHANGE_SUCCESSFUL;
3291 }
3292
3293 if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS)
3294 {
3295 dwflags &= ~CDS_VIDEOPARAMETERS;
3296 if (lParam == NULL)
3297 Ret=DISP_CHANGE_BADPARAM;
3298 else
3299 {
3300 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
3301 Ret = DISP_CHANGE_FAILED;
3302 }
3303
3304 }
3305
3306 if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
3307 {
3308
3309 UNICODE_STRING DeviceName;
3310 UNICODE_STRING RegistryKey;
3311 UNICODE_STRING InDeviceName;
3312 OBJECT_ATTRIBUTES ObjectAttributes;
3313 HANDLE DevInstRegKey;
3314 ULONG NewValue;
3315
3316 DPRINT1("set CDS_UPDATEREGISTRY\n");
3317
3318 dwflags &= ~CDS_UPDATEREGISTRY;
3319
3320 /* Check if pDeviceName is NULL, we need to retrieve it */
3321 if (pDeviceName == NULL)
3322 {
3323 WCHAR szBuffer[MAX_DRIVER_NAME];
3324 PDC DC;
3325 PWINDOW_OBJECT Wnd=NULL;
3326 HWND hWnd;
3327 HDC hDC;
3328
3329 hWnd = IntGetDesktopWindow();
3330 if (!(Wnd = UserGetWindowObject(hWnd)))
3331 {
3332 return FALSE;
3333 }
3334
3335 hDC = UserGetWindowDC(Wnd);
3336
3337 DC = DC_LockDc(hDC);
3338 if (NULL == DC)
3339 {
3340 return FALSE;
3341 }
3342 swprintf (szBuffer, L"\\\\.\\DISPLAY%lu", ((GDIDEVICE *)DC->ppdev)->DisplayNumber);
3343 DC_UnlockDc(DC);
3344
3345 RtlInitUnicodeString(&InDeviceName, szBuffer);
3346 pDeviceName = &InDeviceName;
3347 }
3348
3349 Status = GetVideoDeviceName(&DeviceName, pDeviceName);
3350 if (!NT_SUCCESS(Status))
3351 {
3352 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName, Status);
3353 return DISP_CHANGE_FAILED;
3354 }
3355 Status = GetVideoRegistryKey(&RegistryKey, &DeviceName);
3356 if (!NT_SUCCESS(Status))
3357 {
3358 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName, Status);
3359 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
3360 return DISP_CHANGE_FAILED;
3361 }
3362 ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
3363
3364 InitializeObjectAttributes(&ObjectAttributes, &RegistryKey,
3365 OBJ_CASE_INSENSITIVE, NULL, NULL);
3366 Status = ZwOpenKey(&DevInstRegKey, KEY_SET_VALUE, &ObjectAttributes);
3367 if (!NT_SUCCESS(Status))
3368 {
3369 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey, Status);
3370 ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
3371 return DISP_CHANGE_FAILED;
3372 }
3373 ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
3374
3375 /* Update needed fields */
3376 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_BITSPERPEL)
3377 {
3378 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel");
3379 NewValue = DevMode->dmBitsPerPel;
3380 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
3381 }
3382
3383 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH)
3384 {
3385 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution");
3386 NewValue = DevMode->dmPelsWidth;
3387 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
3388 }
3389
3390 if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT)
3391 {
3392 RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution");
3393 NewValue = DevMode->dmPelsHeight;
3394 Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
3395 }
3396
3397 ZwClose(DevInstRegKey);
3398 if (NT_SUCCESS(Status))
3399 Ret = DISP_CHANGE_RESTART;
3400 else
3401 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
3402 Ret = DISP_CHANGE_NOTUPDATED;
3403 }
3404
3405 if (dwflags != 0)
3406 Ret = DISP_CHANGE_BADFLAGS;
3407
3408 return Ret;
3409 }
3410
3411 DWORD
3412 APIENTRY
3413 NtGdiGetBoundsRect(
3414 IN HDC hdc,
3415 OUT LPRECT prc,
3416 IN DWORD f)
3417 {
3418 DPRINT1("stub\n");
3419 return DCB_RESET; /* bounding rectangle always empty */
3420 }
3421
3422 DWORD
3423 APIENTRY
3424 NtGdiSetBoundsRect(
3425 IN HDC hdc,
3426 IN LPRECT prc,
3427 IN DWORD f)
3428 {
3429 DPRINT1("stub\n");
3430 return DCB_DISABLE; /* bounding rectangle always empty */
3431 }
3432
3433 /*
3434 * @implemented
3435 */
3436 DHPDEV
3437 APIENTRY
3438 NtGdiGetDhpdev(
3439 IN HDEV hdev)
3440 {
3441 PGDIDEVICE ppdev, pGdiDevice = (PGDIDEVICE) hdev;
3442 if (!pGdiDevice) return NULL;
3443 if ( pGdiDevice < (PGDIDEVICE)MmSystemRangeStart) return NULL;
3444 ppdev = pPrimarySurface;
3445 IntGdiAcquireSemaphore(hsemDriverMgmt);
3446 do
3447 {
3448 if (pGdiDevice == ppdev) break;
3449 else
3450 ppdev = ppdev->ppdevNext;
3451 } while (ppdev != NULL);
3452 IntGdiReleaseSemaphore(hsemDriverMgmt);
3453 if (!ppdev) return NULL;
3454 return pGdiDevice->hPDev;
3455 }
3456
3457 /*
3458 * @unimplemented
3459 */
3460 BOOL
3461 APIENTRY
3462 NtGdiMakeInfoDC(
3463 IN HDC hdc,
3464 IN BOOL bSet)
3465 {
3466 UNIMPLEMENTED;
3467 return FALSE;
3468 }
3469
3470 /* EOF */