2 * PROJECT: ReactOS user32.dll
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Window ghosting feature
5 * COPYRIGHT: Copyright 2018 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
14 DBG_DEFAULT_CHANNEL(UserInput
);
16 static UNICODE_STRING GhostClass
= RTL_CONSTANT_STRING(GHOSTCLASSNAME
);
17 static UNICODE_STRING GhostProp
= RTL_CONSTANT_STRING(GHOST_PROP
);
19 PTHREADINFO gptiGhostThread
= NULL
;
24 * Creates ghost windows and exits when no non-responsive window remains.
27 UserGhostThreadEntry(VOID
)
29 TRACE("Ghost thread started\n");
33 gptiGhostThread
= PsGetCurrentThreadWin32Thread();
35 //TODO: Implement. This thread should handle all ghost windows and exit when no ghost window is needed.
37 gptiGhostThread
= NULL
;
42 BOOL FASTCALL
IntIsGhostWindow(PWND Window
)
45 UNICODE_STRING ClassName
;
52 if (Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
54 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
56 Atom
= gpsi
->atomSysClass
[iCls
];
61 RtlInitUnicodeString(&ClassName
, NULL
);
62 Len
= UserGetClassName(Window
->pcls
, &ClassName
, Atom
, FALSE
);
65 Ret
= RtlEqualUnicodeString(&ClassName
, &GhostClass
, TRUE
);
69 DPRINT1("Unable to get class name\n");
71 RtlFreeUnicodeString(&ClassName
);
76 HWND FASTCALL
IntGhostWindowFromHungWindow(PWND pHungWnd
)
81 if (!IntGetAtomFromStringOrAtom(&GhostProp
, &Atom
))
84 hwndGhost
= UserGetProp(pHungWnd
, Atom
, TRUE
);
87 if (ValidateHwndNoErr(hwndGhost
))
90 DPRINT("Not a window\n");
96 HWND FASTCALL
UserGhostWindowFromHungWindow(HWND hwndHung
)
98 PWND pHungWnd
= ValidateHwndNoErr(hwndHung
);
101 DPRINT("Not a window\n");
104 return IntGhostWindowFromHungWindow(pHungWnd
);
107 HWND FASTCALL
IntHungWindowFromGhostWindow(PWND pGhostWnd
)
109 const GHOST_DATA
*UserData
;
112 if (!IntIsGhostWindow(pGhostWnd
))
114 DPRINT("Not a ghost window\n");
118 UserData
= (const GHOST_DATA
*)pGhostWnd
->dwUserData
;
123 ProbeForRead(UserData
, sizeof(GHOST_DATA
), 1);
124 hwndTarget
= UserData
->hwndTarget
;
126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
128 DPRINT1("Exception!\n");
135 DPRINT("No user data\n");
141 if (ValidateHwndNoErr(hwndTarget
))
144 DPRINT1("Not a window\n");
150 HWND FASTCALL
UserHungWindowFromGhostWindow(HWND hwndGhost
)
152 PWND pGhostWnd
= ValidateHwndNoErr(hwndGhost
);
153 return IntHungWindowFromGhostWindow(pGhostWnd
);
156 BOOL FASTCALL
IntMakeHungWindowGhosted(HWND hwndHung
)
158 PWND pHungWnd
= ValidateHwndNoErr(hwndHung
);
161 DPRINT1("Not a window\n");
162 return FALSE
; // not a window
165 if (!MsqIsHung(pHungWnd
->head
.pti
, MSQ_HUNG
))
167 DPRINT1("Not hung window\n");
168 return FALSE
; // not hung window
171 if (!(pHungWnd
->style
& WS_VISIBLE
))
172 return FALSE
; // invisible
174 if (pHungWnd
->style
& WS_CHILD
)
175 return FALSE
; // child
177 if (IntIsGhostWindow(pHungWnd
))
179 DPRINT1("IntIsGhostWindow\n");
180 return FALSE
; // ghost window cannot be ghosted
183 if (IntGhostWindowFromHungWindow(pHungWnd
))
185 DPRINT("Already ghosting\n");
186 return FALSE
; // already ghosting
189 // TODO: Find a way to pass the hwnd of pHungWnd to the ghost thread as we can't pass parameters directly
191 if (!gptiGhostThread
)
192 UserCreateSystemThread(ST_GHOST_THREAD
);