2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
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.
19 * $Id: desktop.c,v 1.10 2004/04/09 20:03:19 navaraf Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/desktop.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
33 #include <ddk/ntddmou.h>
34 #include <win32k/win32k.h>
35 #include <csrss/csrss.h>
36 #include <include/winsta.h>
37 #include <include/desktop.h>
38 #include <include/object.h>
39 #include <include/window.h>
40 #include <include/error.h>
41 #include <include/cursoricon.h>
42 #include <include/hotkey.h>
43 #include <include/color.h>
44 #include <include/mouse.h>
45 #include <include/callback.h>
46 #include <include/guicheck.h>
47 #include <include/intgdi.h>
52 /* GLOBALS *******************************************************************/
54 /* Currently active desktop */
55 PDESKTOP_OBJECT InputDesktop
= NULL
;
56 HDESK InputDesktopHandle
= NULL
;
57 HDC ScreenDeviceContext
= NULL
;
59 /* INITALIZATION FUNCTIONS ****************************************************/
64 return STATUS_SUCCESS
;
68 CleanupDesktopImpl(VOID
)
70 return STATUS_SUCCESS
;
73 /* PRIVATE FUNCTIONS **********************************************************/
76 * IntValidateDesktopHandle
78 * Validates the desktop handle.
81 * If the function succeeds, the handle remains referenced. If the
82 * fucntion fails, last error is set.
86 IntValidateDesktopHandle(
88 KPROCESSOR_MODE AccessMode
,
89 ACCESS_MASK DesiredAccess
,
90 PDESKTOP_OBJECT
*Object
)
94 Status
= ObReferenceObjectByHandle(
102 if (!NT_SUCCESS(Status
))
103 SetLastNtError(Status
);
109 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop
)
113 Ret
= &Desktop
->WorkArea
;
114 if((Ret
->right
== -1) && ScreenDeviceContext
)
118 dc
= DC_LockDc(ScreenDeviceContext
);
119 SurfObj
= (SURFOBJ
*)AccessUserObject((ULONG
) dc
->Surface
);
122 Ret
->right
= SurfObj
->sizlBitmap
.cx
;
123 Ret
->bottom
= SurfObj
->sizlBitmap
.cy
;
125 DC_UnlockDc(ScreenDeviceContext
);
131 PDESKTOP_OBJECT FASTCALL
132 IntGetActiveDesktop(VOID
)
137 PUSER_MESSAGE_QUEUE FASTCALL
138 IntGetFocusMessageQueue(VOID
)
140 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
143 DPRINT("No active desktop\n");
146 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
150 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
152 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
155 DPRINT("No active desktop\n");
158 pdo
->ActiveMessageQueue
= NewQueue
;
161 HWND FASTCALL
IntGetDesktopWindow(VOID
)
163 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
166 DPRINT("No active desktop\n");
169 return pdo
->DesktopWindow
;
172 /* PUBLIC FUNCTIONS ***********************************************************/
175 static NTSTATUS FASTCALL
176 NotifyCsrss(PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
179 UNICODE_STRING PortName
;
180 ULONG ConnectInfoLength
;
181 static HANDLE WindowsApiPort
= NULL
;
183 RtlInitUnicodeString(&PortName
, L
"\\Windows\\ApiPort");
184 ConnectInfoLength
= 0;
185 Status
= ZwConnectPort(&WindowsApiPort
,
193 if (! NT_SUCCESS(Status
))
198 Request
->Header
.DataSize
= sizeof(CSRSS_API_REQUEST
) - LPC_MESSAGE_BASE_SIZE
;
199 Request
->Header
.MessageSize
= sizeof(CSRSS_API_REQUEST
);
201 Status
= ZwRequestWaitReplyPort(WindowsApiPort
,
204 if (! NT_SUCCESS(Status
) || ! NT_SUCCESS(Status
= Reply
->Status
))
206 ZwClose(WindowsApiPort
);
210 // ZwClose(WindowsApiPort);
212 return STATUS_SUCCESS
;
216 IntShowDesktop(PDESKTOP_OBJECT Desktop
, ULONG Width
, ULONG Height
)
218 CSRSS_API_REQUEST Request
;
219 CSRSS_API_REPLY Reply
;
221 Request
.Type
= CSRSS_SHOW_DESKTOP
;
222 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
223 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
224 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
226 return NotifyCsrss(&Request
, &Reply
);
230 IntHideDesktop(PDESKTOP_OBJECT Desktop
)
233 CSRSS_API_REQUEST Request
;
234 CSRSS_API_REPLY Reply
;
236 Request
.Type
= CSRSS_HIDE_DESKTOP
;
237 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
239 return NotifyCsrss(&Request
, &Reply
);
241 PWINDOW_OBJECT DesktopWindow
;
243 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
246 return ERROR_INVALID_WINDOW_HANDLE
;
248 DesktopWindow
->Style
&= ~WS_VISIBLE
;
250 return STATUS_SUCCESS
;
255 * NtUserCreateDesktop
257 * Creates a new desktop.
261 * Name of the new desktop.
267 * Requested type of access.
270 * Security descriptor.
273 * Handle to window station on which to create the desktop.
276 * If the function succeeds, the return value is a handle to the newly
277 * created desktop. If the specified desktop already exists, the function
278 * succeeds and returns a handle to the existing desktop. When you are
279 * finished using the handle, call the CloseDesktop function to close it.
280 * If the function fails, the return value is NULL.
288 PUNICODE_STRING lpszDesktopName
,
290 ACCESS_MASK dwDesiredAccess
,
291 LPSECURITY_ATTRIBUTES lpSecurity
,
292 HWINSTA hWindowStation
)
294 OBJECT_ATTRIBUTES ObjectAttributes
;
295 PWINSTATION_OBJECT WinStaObject
;
296 PDESKTOP_OBJECT DesktopObject
;
297 UNICODE_STRING DesktopName
;
300 CSRSS_API_REQUEST Request
;
301 CSRSS_API_REPLY Reply
;
303 Status
= IntValidateWindowStationHandle(
309 if (! NT_SUCCESS(Status
))
311 DPRINT1("Failed validation of window station handle (0x%X)\n",
313 SetLastNtError(Status
);
317 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
320 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
321 ObDereferenceObject(WinStaObject
);
325 ObDereferenceObject(WinStaObject
);
328 * Try to open already existing desktop
331 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
333 /* Initialize ObjectAttributes for the desktop object */
334 InitializeObjectAttributes(
341 Status
= ObOpenObjectByName(
350 if (NT_SUCCESS(Status
))
352 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
353 ExFreePool(DesktopName
.Buffer
);
358 * No existing desktop found, try to create new one
361 Status
= ObCreateObject(
367 sizeof(DESKTOP_OBJECT
),
370 (PVOID
*)&DesktopObject
);
372 if (! NT_SUCCESS(Status
))
374 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName
);
375 ExFreePool(DesktopName
.Buffer
);
376 SetLastNtError(STATUS_UNSUCCESSFUL
);
381 DesktopObject
->WorkArea
.left
= 0;
382 DesktopObject
->WorkArea
.top
= 0;
383 DesktopObject
->WorkArea
.right
= -1;
384 DesktopObject
->WorkArea
.bottom
= -1;
385 IntGetDesktopWorkArea(DesktopObject
);
387 /* Initialize some local (to win32k) desktop state. */
388 DesktopObject
->ActiveMessageQueue
= NULL
;
390 Status
= ObInsertObject(
391 (PVOID
)DesktopObject
,
393 STANDARD_RIGHTS_REQUIRED
,
398 DesktopObject
->Self
= (HANDLE
)Desktop
;
400 ObDereferenceObject(DesktopObject
);
401 ExFreePool(DesktopName
.Buffer
);
403 if (! NT_SUCCESS(Status
))
405 DPRINT1("Failed to create desktop handle\n");
406 SetLastNtError(Status
);
410 Request
.Type
= CSRSS_CREATE_DESKTOP
;
411 memcpy(Request
.Data
.CreateDesktopRequest
.DesktopName
, lpszDesktopName
->Buffer
,
412 lpszDesktopName
->Length
);
413 Request
.Data
.CreateDesktopRequest
.DesktopName
[lpszDesktopName
->Length
/ sizeof(WCHAR
)] = L
'\0';
415 Status
= NotifyCsrss(&Request
, &Reply
);
416 if (! NT_SUCCESS(Status
))
418 DPRINT1("Failed to notify CSRSS about new desktop\n");
420 SetLastNtError(Status
);
430 * Opens an existing desktop.
434 * Name of the existing desktop.
440 * Requested type of access.
443 * Handle to the desktop or zero on failure.
451 PUNICODE_STRING lpszDesktopName
,
453 ACCESS_MASK dwDesiredAccess
)
455 OBJECT_ATTRIBUTES ObjectAttributes
;
456 PWINSTATION_OBJECT WinStaObject
;
457 UNICODE_STRING DesktopName
;
462 * Validate the window station handle and compose the fully
463 * qualified desktop name
466 Status
= IntValidateWindowStationHandle(
467 PROCESS_WINDOW_STATION(),
472 if (!NT_SUCCESS(Status
))
474 DPRINT("Failed validation of window station handle (0x%X)\n",
475 PROCESS_WINDOW_STATION());
476 SetLastNtError(Status
);
480 if (!IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
483 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
484 ObDereferenceObject(WinStaObject
);
488 ObDereferenceObject(WinStaObject
);
490 DPRINT("Trying to open desktop station (%wZ)\n", &DesktopName
);
492 /* Initialize ObjectAttributes for the desktop object */
493 InitializeObjectAttributes(
500 Status
= ObOpenObjectByName(
509 if (!NT_SUCCESS(Status
))
511 SetLastNtError(Status
);
512 ExFreePool(DesktopName
.Buffer
);
516 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
517 ExFreePool(DesktopName
.Buffer
);
523 * NtUserOpenInputDesktop
525 * Opens the input (interactive) desktop.
532 * Inheritance option.
535 * Requested type of access.
538 * Handle to the input desktop or zero on failure.
545 NtUserOpenInputDesktop(
548 ACCESS_MASK dwDesiredAccess
)
550 PDESKTOP_OBJECT Object
;
554 DPRINT("About to open input desktop\n");
556 /* Get a pointer to the desktop object */
558 Status
= IntValidateDesktopHandle(
564 if (!NT_SUCCESS(Status
))
566 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
570 /* Create a new handle to the object */
572 Status
= ObOpenObjectByPointer(
581 ObDereferenceObject(Object
);
583 if (NT_SUCCESS(Status
))
585 DPRINT("Successfully opened input desktop\n");
586 return (HDESK
)Desktop
;
589 SetLastNtError(Status
);
596 * Closes a desktop handle.
600 * Handle to the desktop.
606 * The desktop handle can be created with NtUserCreateDesktop or
607 * NtUserOpenDesktop. This function will fail if any thread in the calling
608 * process is using the specified desktop handle or if the handle refers
609 * to the initial desktop of the calling process.
616 NtUserCloseDesktop(HDESK hDesktop
)
618 PDESKTOP_OBJECT Object
;
621 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
623 Status
= IntValidateDesktopHandle(
629 if (!NT_SUCCESS(Status
))
631 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
635 ObDereferenceObject(Object
);
637 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
639 Status
= ZwClose(hDesktop
);
640 if (!NT_SUCCESS(Status
))
642 SetLastNtError(Status
);
652 * The NtUserPaintDesktop function fills the clipping region in the
653 * specified device context with the desktop pattern or wallpaper. The
654 * function is provided primarily for shell desktops.
658 * Handle to the device context.
665 NtUserPaintDesktop(HDC hDC
)
668 HBRUSH DesktopBrush
, PreviousBrush
;
671 IntGdiGetClipBox(hDC
, &Rect
);
673 hWndDesktop
= IntGetDesktopWindow();
674 DesktopBrush
= (HBRUSH
)NtUserGetClassLong(hWndDesktop
, GCL_HBRBACKGROUND
, FALSE
);
677 * Paint desktop background
680 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
681 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
682 NtGdiSelectObject(hDC
, PreviousBrush
);
688 * NtUserSwitchDesktop
690 * Sets the current input (interactive) desktop.
704 NtUserSwitchDesktop(HDESK hDesktop
)
706 PDESKTOP_OBJECT DesktopObject
;
709 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
711 Status
= IntValidateDesktopHandle(
717 if (!NT_SUCCESS(Status
))
719 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
723 /* FIXME: Fail if the desktop belong to an invisible window station */
724 /* FIXME: Fail if the process is associated with a secured
725 desktop such as Winlogon or Screen-Saver */
726 /* FIXME: Connect to input device */
728 /* Set the active desktop in the desktop's window station. */
729 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
731 /* Set the global state. */
732 InputDesktop
= DesktopObject
;
733 InputDesktopHandle
= hDesktop
;
734 InputWindowStation
= DesktopObject
->WindowStation
;
736 ObDereferenceObject(DesktopObject
);
742 * NtUserResolveDesktopForWOW
749 NtUserResolveDesktopForWOW(DWORD Unknown0
)
756 * NtUserGetThreadDesktop
763 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
765 PDESKTOP_OBJECT Desktop
;
772 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
776 Status
= PsLookupThreadByThreadId((PVOID
)dwThreadId
, &Thread
);
777 if(!NT_SUCCESS(Status
))
779 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
783 Desktop
= Thread
->Win32Thread
->Desktop
;
787 Status
= ObReferenceObjectByPointer(Desktop
,
791 if(!NT_SUCCESS(Status
))
793 SetLastNtError(Status
);
797 Ret
= (HDESK
)Desktop
->Self
;
799 ObDereferenceObject(Desktop
);
807 * NtUserSetThreadDesktop
814 NtUserSetThreadDesktop(HDESK hDesktop
)
816 PDESKTOP_OBJECT DesktopObject
;
819 /* Validate the new desktop. */
820 Status
= IntValidateDesktopHandle(
826 if (!NT_SUCCESS(Status
))
828 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
832 /* Check for setting the same desktop as before. */
833 if (DesktopObject
== PsGetWin32Thread()->Desktop
)
835 ObDereferenceObject(DesktopObject
);
839 /* FIXME: Should check here to see if the thread has any windows. */
841 if (PsGetWin32Thread()->Desktop
!= NULL
)
843 ObDereferenceObject(PsGetWin32Thread()->Desktop
);
846 PsGetWin32Thread()->Desktop
= DesktopObject
;