/*
* PROJECT: ReactOS user32.dll
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE: Ghost window handling
+ * PURPOSE: Window ghosting feature
* COPYRIGHT: Copyright 2018 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include <win32k.h>
+#include "ghostwnd.h"
-BOOL FASTCALL IntGoGhost(PWND Window, BOOL bGo)
+#define NDEBUG
+#include <debug.h>
+
+static UNICODE_STRING GhostClass = RTL_CONSTANT_STRING(GHOSTCLASSNAME);
+static UNICODE_STRING GhostProp = RTL_CONSTANT_STRING(GHOST_PROP);
+
+BOOL FASTCALL IntIsGhostWindow(PWND Window)
+{
+ BOOLEAN Ret = FALSE;
+ UNICODE_STRING ClassName;
+ INT iCls, Len;
+ RTL_ATOM Atom = 0;
+
+ if (!Window)
+ return FALSE;
+
+ if (Window->fnid && !(Window->fnid & FNID_DESTROY))
+ {
+ if (LookupFnIdToiCls(Window->fnid, &iCls))
+ {
+ Atom = gpsi->atomSysClass[iCls];
+ }
+ }
+
+ // check class name
+ RtlInitUnicodeString(&ClassName, NULL);
+ Len = UserGetClassName(Window->pcls, &ClassName, Atom, FALSE);
+ if (Len > 0)
+ {
+ Ret = RtlEqualUnicodeString(&ClassName, &GhostClass, TRUE);
+ }
+ else
+ {
+ DPRINT1("Unable to get class name\n");
+ }
+ RtlFreeUnicodeString(&ClassName);
+
+ return Ret;
+}
+
+HWND FASTCALL IntGhostWindowFromHungWindow(PWND pHungWnd)
+{
+ RTL_ATOM Atom;
+ HWND hwndGhost;
+
+ if (!IntGetAtomFromStringOrAtom(&GhostProp, &Atom))
+ ASSERT(FALSE);
+
+ hwndGhost = UserGetProp(pHungWnd, Atom, TRUE);
+ if (hwndGhost)
+ {
+ if (ValidateHwndNoErr(hwndGhost))
+ return hwndGhost;
+
+ DPRINT("Not a window\n");
+ }
+
+ return NULL;
+}
+
+HWND FASTCALL UserGhostWindowFromHungWindow(HWND hwndHung)
{
+ PWND pHungWnd = ValidateHwndNoErr(hwndHung);
+ if (!pHungWnd)
+ {
+ DPRINT("Not a window\n");
+ return NULL;
+ }
+ return IntGhostWindowFromHungWindow(pHungWnd);
+}
+
+HWND FASTCALL IntHungWindowFromGhostWindow(PWND pGhostWnd)
+{
+ const GHOST_DATA *UserData;
+ HWND hwndTarget;
+
+ if (!IntIsGhostWindow(pGhostWnd))
+ {
+ DPRINT("Not a ghost window\n");
+ return NULL;
+ }
+
+ UserData = (const GHOST_DATA *)pGhostWnd->dwUserData;
+ if (UserData)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(UserData, sizeof(GHOST_DATA), 1);
+ hwndTarget = UserData->hwndTarget;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DPRINT1("Exception!\n");
+ hwndTarget = NULL;
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ DPRINT("No user data\n");
+ hwndTarget = NULL;
+ }
+
+ if (hwndTarget)
+ {
+ if (ValidateHwndNoErr(hwndTarget))
+ return hwndTarget;
+
+ DPRINT1("Not a window\n");
+ }
+
+ return NULL;
+}
+
+HWND FASTCALL UserHungWindowFromGhostWindow(HWND hwndGhost)
+{
+ PWND pGhostWnd = ValidateHwndNoErr(hwndGhost);
+ return IntHungWindowFromGhostWindow(pGhostWnd);
+}
+
+BOOL FASTCALL IntMakeHungWindowGhosted(HWND hwndHung)
+{
+ PWND pHungWnd = ValidateHwndNoErr(hwndHung);
+ if (!pHungWnd)
+ {
+ DPRINT1("Not a window\n");
+ return FALSE; // not a window
+ }
+
+ if (!MsqIsHung(pHungWnd->head.pti))
+ {
+ DPRINT1("Not hung window\n");
+ return FALSE; // not hung window
+ }
+
+ if (!(pHungWnd->style & WS_VISIBLE))
+ return FALSE; // invisible
+
+ if (pHungWnd->style & WS_CHILD)
+ return FALSE; // child
+
+ if (IntIsGhostWindow(pHungWnd))
+ {
+ DPRINT1("IntIsGhostWindow\n");
+ return FALSE; // ghost window cannot be ghosted
+ }
+
+ if (IntGhostWindowFromHungWindow(pHungWnd))
+ {
+ DPRINT("Already ghosting\n");
+ return FALSE; // already ghosting
+ }
+
// TODO:
// 1. Create a thread.
// 2. Create a ghost window in the thread.
// 3. Do message loop in the thread
- static int bWarnedOnce = 0;
- if (!bWarnedOnce)
{
- bWarnedOnce++;
- STUB;
+ static int bWarnedOnce = 0;
+ if (!bWarnedOnce)
+ {
+ bWarnedOnce++;
+ STUB;
+ }
}
+
return FALSE;
}
#include <user32.h>
#include <strsafe.h>
+#include "ghostwnd.h"
WINE_DEFAULT_DEBUG_CHANNEL(ghost);
#define GHOST_TIMER_ID 0xFACEDEAD
#define GHOST_INTERVAL 1000 // one second
-#define GHOST_PROP L"GhostProp"
const struct builtin_class_descr GHOST_builtin_class =
{
/****************************************************************************/
-typedef struct GHOST_DATA
-{
- HWND hwndTarget;
- HBITMAP hbm32bpp;
- BOOL bDestroyTarget;
-} GHOST_DATA;
-
static GHOST_DATA *
Ghost_GetData(HWND hwnd)
{
// get the target
hwndTarget = (HWND)lpcs->lpCreateParams;
- if (!IsWindowVisible(hwndTarget) || // invisible?
- GetParent(hwndTarget) || // child?
- !IsHungAppWindow(hwndTarget)) // not hung?
+ if (!IsWindowVisible(hwndTarget) || // invisible?
+ (GetWindowLongPtrW(hwndTarget, GWL_STYLE) & WS_CHILD) || // child?
+ !IsHungAppWindow(hwndTarget)) // not hung?
{
return FALSE;
}