Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / win32ss / gdi / eng / engwindow.c
diff --git a/win32ss/gdi/eng/engwindow.c b/win32ss/gdi/eng/engwindow.c
new file mode 100644 (file)
index 0000000..d23e974
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * COPYRIGHT:         See COPYING in the top level directory
+ * PROJECT:           ReactOS kernel
+ * PURPOSE:           GDI WNDOBJ Functions
+ * FILE:              win32ss/gdi/eng/engwindow.c
+ * PROGRAMER:         Gregor Anich
+ */
+
+#include <win32k.h>
+#include <debug.h>
+DBG_DEFAULT_CHANNEL(EngWnd);
+
+INT gcountPWO = 0;
+
+/*
+ * Calls the WNDOBJCHANGEPROC of the given WNDOBJ
+ */
+VOID
+FASTCALL
+IntEngWndCallChangeProc(
+    _In_ EWNDOBJ *Clip,
+    _In_ FLONG   flChanged)
+{
+    if (Clip->ChangeProc == NULL)
+    {
+        return;
+    }
+
+    /* check flags of the WNDOBJ */
+    flChanged &= Clip->Flags;
+    if (flChanged == 0)
+    {
+        return;
+    }
+
+    TRACE("Calling WNDOBJCHANGEPROC (0x%p), Changed = 0x%x\n",
+           Clip->ChangeProc, flChanged);
+
+    /* Call the WNDOBJCHANGEPROC */
+    if (flChanged == WOC_CHANGED)
+        Clip->ChangeProc(NULL, flChanged);
+    else
+        Clip->ChangeProc((WNDOBJ *)Clip, flChanged);
+}
+
+/*
+ * Fills the CLIPOBJ and client rect of the WNDOBJ with the data from the given WND
+ */
+BOOLEAN
+FASTCALL
+IntEngWndUpdateClipObj(
+    EWNDOBJ* Clip,
+    PWND Window)
+{
+    PREGION visRgn;
+
+    TRACE("IntEngWndUpdateClipObj\n");
+
+    visRgn = VIS_ComputeVisibleRegion(Window, TRUE, TRUE, TRUE);
+    if (visRgn != NULL)
+    {
+        if (visRgn->rdh.nCount > 0)
+        {
+            IntEngUpdateClipRegion((XCLIPOBJ*)Clip, visRgn->rdh.nCount, visRgn->Buffer, &visRgn->rdh.rcBound);
+            TRACE("Created visible region with %lu rects\n", visRgn->rdh.nCount);
+            TRACE("  BoundingRect: %d, %d  %d, %d\n",
+                   visRgn->rdh.rcBound.left, visRgn->rdh.rcBound.top,
+                   visRgn->rdh.rcBound.right, visRgn->rdh.rcBound.bottom);
+            {
+                ULONG i;
+                for (i = 0; i < visRgn->rdh.nCount; i++)
+                {
+                    TRACE("  Rect #%lu: %ld,%ld  %ld,%ld\n", i+1,
+                           visRgn->Buffer[i].left, visRgn->Buffer[i].top,
+                           visRgn->Buffer[i].right, visRgn->Buffer[i].bottom);
+                }
+            }
+        }
+        REGION_Delete(visRgn);
+    }
+    else
+    {
+        /* Fall back to client rect */
+        IntEngUpdateClipRegion((XCLIPOBJ*)Clip, 1, &Window->rcClient, &Window->rcClient);
+    }
+
+    /* Update the WNDOBJ */
+    Clip->rclClient = Window->rcClient;
+    Clip->iUniq++;
+
+    return TRUE;
+}
+
+/*
+ * Updates all WNDOBJs of the given WND and calls the change-procs.
+ */
+VOID
+FASTCALL
+IntEngWindowChanged(
+    _In_    PWND  Window,
+    _In_    FLONG flChanged)
+{
+    EWNDOBJ *Clip;
+
+    ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
+
+    Clip = UserGetProp(Window, AtomWndObj, TRUE);
+    if (!Clip)
+    {
+        return;
+    }
+
+    ASSERT(Clip->Hwnd == Window->head.h);
+    // if (Clip->pvConsumer != NULL)
+    {
+        /* Update the WNDOBJ */
+        switch (flChanged)
+        {
+        case WOC_RGN_CLIENT:
+            /* Update the clipobj and client rect of the WNDOBJ */
+            IntEngWndUpdateClipObj(Clip, Window);
+            break;
+
+        case WOC_DELETE:
+            /* FIXME: Should the WNDOBJs be deleted by win32k or by the driver? */
+            break;
+        }
+
+        /* Call the change proc */
+        IntEngWndCallChangeProc(Clip, flChanged);
+
+        /* HACK: Send WOC_CHANGED after WOC_RGN_CLIENT */
+        if (flChanged == WOC_RGN_CLIENT)
+        {
+            IntEngWndCallChangeProc(Clip, WOC_CHANGED);
+        }
+    }
+}
+
+/*
+ * @implemented
+ */
+WNDOBJ*
+APIENTRY
+EngCreateWnd(
+    SURFOBJ          *pso,
+    HWND              hWnd,
+    WNDOBJCHANGEPROC  pfn,
+    FLONG             fl,
+    int               iPixelFormat)
+{
+    EWNDOBJ *Clip = NULL;
+    WNDOBJ *WndObjUser = NULL;
+    PWND Window;
+    BOOL calledFromUser;
+    DECLARE_RETURN(WNDOBJ*);
+
+    TRACE("EngCreateWnd: pso = 0x%p, hwnd = 0x%p, pfn = 0x%p, fl = 0x%lx, pixfmt = %d\n",
+            pso, hWnd, pfn, fl, iPixelFormat);
+
+    if (fl & (WO_RGN_WINDOW | WO_RGN_DESKTOP_COORD | WO_RGN_UPDATE_ALL))
+    {
+        FIXME("Unsupported flags: 0x%lx\n", fl & ~(WO_RGN_CLIENT_DELTA | WO_RGN_CLIENT | WO_RGN_SURFACE_DELTA | WO_RGN_SURFACE));
+    }
+
+    calledFromUser = UserIsEntered();
+    if (!calledFromUser) {
+        UserEnterShared();
+    }
+
+    /* Get window object */
+    Window = UserGetWindowObject(hWnd);
+    if (Window == NULL)
+    {
+        RETURN( NULL);
+    }
+
+    /* Create WNDOBJ */
+    Clip = EngAllocMem(FL_ZERO_MEMORY, sizeof (EWNDOBJ), GDITAG_WNDOBJ);
+    if (Clip == NULL)
+    {
+        ERR("Failed to allocate memory for a WND structure!\n");
+        RETURN( NULL);
+    }
+    IntEngInitClipObj((XCLIPOBJ*)Clip);
+
+    /* Fill the clipobj */
+    if (!IntEngWndUpdateClipObj(Clip, Window))
+    {
+        EngFreeMem(Clip);
+        RETURN( NULL);
+    }
+
+    /* Fill user object */
+    WndObjUser = (WNDOBJ *)Clip;
+    WndObjUser->psoOwner = pso;
+    WndObjUser->pvConsumer = NULL;
+
+    /* Fill internal object */
+    Clip->Hwnd = hWnd;
+    Clip->ChangeProc = pfn;
+    /* Keep track of relevant flags */
+    Clip->Flags = fl & (WO_RGN_CLIENT_DELTA | WO_RGN_CLIENT | WO_RGN_SURFACE_DELTA | WO_RGN_SURFACE | WO_DRAW_NOTIFY);
+    if (fl & WO_SPRITE_NOTIFY)
+        Clip->Flags |= WOC_SPRITE_OVERLAP | WOC_SPRITE_NO_OVERLAP;
+    /* Those should always be sent */
+    Clip->Flags |= WOC_CHANGED | WOC_DELETE;
+    Clip->PixelFormat = iPixelFormat;
+
+    /* associate object with window */
+    UserSetProp(Window, AtomWndObj, Clip, TRUE);
+    ++gcountPWO;
+
+    TRACE("EngCreateWnd: SUCCESS: %p!\n", WndObjUser);
+
+    RETURN( WndObjUser);
+
+CLEANUP:
+
+    if (!calledFromUser) {
+        UserLeave();
+    }
+
+    END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+VOID
+APIENTRY
+EngDeleteWnd(
+    IN WNDOBJ *pwo)
+{
+    EWNDOBJ* Clip = (EWNDOBJ *)pwo;//CONTAINING_RECORD(pwo, XCLIPOBJ, WndObj);
+    PWND Window;
+    BOOL calledFromUser;
+
+    TRACE("EngDeleteWnd: pwo = 0x%p\n", pwo);
+
+    calledFromUser = UserIsEntered();
+    if (!calledFromUser) {
+        UserEnterExclusive();
+    }
+
+    /* Get window object */
+    Window = UserGetWindowObject(Clip->Hwnd);
+    if (Window == NULL)
+    {
+        ERR("Couldnt get window object for WndObjInt->Hwnd!!!\n");
+    }
+    else
+    {
+        /* Remove object from window */
+        UserRemoveProp(Window, AtomWndObj, TRUE);
+    }
+    --gcountPWO;
+
+    if (!calledFromUser) {
+        UserLeave();
+    }
+
+    /* Free resources */
+    IntEngFreeClipResources((XCLIPOBJ*)Clip);
+    EngFreeMem(Clip);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+WNDOBJ_bEnum(
+    IN WNDOBJ  *pwo,
+    IN ULONG  cj,
+    OUT ULONG  *pul)
+{
+    /* Relay */
+    return CLIPOBJ_bEnum(&pwo->coClient, cj, pul);
+}
+
+
+/*
+ * @implemented
+ */
+ULONG
+APIENTRY
+WNDOBJ_cEnumStart(
+    IN WNDOBJ  *pwo,
+    IN ULONG  iType,
+    IN ULONG  iDirection,
+    IN ULONG  cLimit)
+{
+    /* Relay */
+    // FIXME: Should we enumerate all rectangles or not?
+    return CLIPOBJ_cEnumStart(&pwo->coClient, FALSE, iType, iDirection, cLimit);
+}
+
+
+/*
+ * @implemented
+ */
+VOID
+APIENTRY
+WNDOBJ_vSetConsumer(
+    IN WNDOBJ  *pwo,
+    IN PVOID  pvConsumer)
+{
+    EWNDOBJ* Clip = (EWNDOBJ *)pwo;//CONTAINING_RECORD(pwo, XCLIPOBJ, WndObj);
+    BOOL Hack;
+
+    TRACE("WNDOBJ_vSetConsumer: pwo = 0x%p, pvConsumer = 0x%p\n", pwo, pvConsumer);
+
+    Hack = (pwo->pvConsumer == NULL);
+    pwo->pvConsumer = pvConsumer;
+
+    /* HACKHACKHACK
+     *
+     * MSDN says that the WNDOBJCHANGEPROC will be called with the most recent state
+     * when a WNDOBJ is created - we do it here because most drivers will need pvConsumer
+     * in the callback to identify the WNDOBJ I think.
+     *
+     *  - blight
+     */
+    if (Hack)
+    {
+        FIXME("Is this hack really needed?\n");
+        IntEngWndCallChangeProc(Clip, WOC_RGN_CLIENT);
+        IntEngWndCallChangeProc(Clip, WOC_CHANGED);
+        IntEngWndCallChangeProc(Clip, WOC_DRAWN);
+    }
+}
+
+/* EOF */
+