--- /dev/null
+
+include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
+add_definitions(-D__WINESRC__)
+set_rc_compiler()
+
+spec2def(uxtheme.dll uxtheme.spec)
+
+list(APPEND SOURCE
+ buffer.c
+ draw.c
+ main.c
+ metric.c
+ msstyles.c
++ ncscrollbar.c
++ nonclient.c
+ property.c
+ stylemap.c
+ system.c
++ themehooks.c
+ uxini.c
+ version.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/uxtheme_stubs.c
+ ${CMAKE_CURRENT_BINARY_DIR}/uxtheme.def)
+
+add_library(uxtheme SHARED ${SOURCE})
+set_module_type(uxtheme win32dll)
+target_link_libraries(uxtheme wine)
+add_delay_importlibs(uxtheme msimg32)
+add_importlibs(uxtheme user32 advapi32 gdi32 msvcrt kernel32 ntdll)
+add_cd_file(TARGET uxtheme DESTINATION reactos/system32 FOR all)
+add_importlib_target(uxtheme.spec)
return S_OK;
}
+
+ static HBITMAP UXTHEME_DrawThemePartToDib(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect)
+ {
+ HDC hdcMem;
+ BITMAPINFO bmi = {0};
+ HBITMAP hbmp, hbmpOld;
+ HBRUSH hbrBack;
+
+ hdcMem = CreateCompatibleDC(0);
+
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = pRect->right;
+ bmi.bmiHeader.biHeight = -pRect->bottom;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ hbmp = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS , NULL, 0, 0);
+
+ hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);
+
+ /* FIXME: use an internal function that doesn't do transparent blt */
+ hbrBack = CreateSolidBrush(RGB(255,0,255));
+
+ FillRect(hdcMem, pRect, hbrBack);
+
+ DrawThemeBackground(hTheme, hdcMem, iPartId, iStateId, pRect, NULL);
+
+ DeleteObject(hbrBack);
+ SelectObject(hdcMem, hbmpOld);
+ DeleteObject(hdcMem);
+
+ return hbmp;
+ }
+
+ #define PT_IN_RECT(lprc,x,y) ( x >= lprc->left && x < lprc->right && \
+ y >= lprc->top && y < lprc->bottom)
+
+ static HRGN UXTHEME_RegionFromDibBits(RGBQUAD* pBuffer, RGBQUAD* pclrTransparent, LPCRECT pRect)
+ {
+ int x, y, xstart;
+ int cMaxRgnRects, cRgnDataSize, cRgnRects;
+ #ifdef EXTCREATEREGION_WORKS
+ RECT* prcCurrent;
+ PRGNDATA prgnData;
+ #else
+ HRGN hrgnTemp;
+ #endif
+ ULONG clrTransparent, *pclrCurrent;
+ HRGN hrgnRet;
+
+ pclrCurrent = (PULONG)pBuffer;
+ clrTransparent = *(PULONG)pclrTransparent;
+
+ /* Create a region and pre-allocate memory enough for 3 spaces in one row*/
+ cRgnRects = 0;
+ cMaxRgnRects = 4* (pRect->bottom-pRect->top);
+ cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
+
+ #ifdef EXTCREATEREGION_WORKS
+ /* Allocate the region data */
+ prgnData = (PRGNDATA)HeapAlloc(GetProcessHeap(), 0, cRgnDataSize);
+
+ prcCurrent = (PRECT)prgnData->Buffer;
+ #else
+ hrgnRet = CreateRectRgn(0,0,0,0);
+ #endif
+
+ /* Calculate the region rects */
+ y=0;
+ /* Scan each line of the bitmap */
+ while(y<pRect->bottom)
+ {
+ x=0;
+ /* Scan each pixel */
+ while (x<pRect->right)
+ {
+ /* Check if the pixel is not transparent and it is in the requested rect */
+ if(*pclrCurrent != clrTransparent && PT_IN_RECT(pRect,x,y))
+ {
+ xstart = x;
+ /* Find the end of the opaque row of pixels */
+ while (x<pRect->right)
+ {
+ if(*pclrCurrent == clrTransparent || !PT_IN_RECT(pRect,x,y))
+ break;
+ x++;
+ pclrCurrent++;
+ }
+
+ #ifdef EXTCREATEREGION_WORKS
+ /* Add the scaned line to the region */
+ SetRect(prcCurrent, xstart, y,x,y+1);
+ prcCurrent++;
+ cRgnRects++;
+
+ /* Increase the size of the buffer if it is full */
+ if(cRgnRects == cMaxRgnRects)
+ {
+ cMaxRgnRects *=2;
+ cRgnDataSize = sizeof(RGNDATA) + cMaxRgnRects * sizeof(RECT);
+ prgnData = (PRGNDATA)HeapReAlloc(GetProcessHeap(),
+ 0,
+ prgnData,
+ cRgnDataSize);
+ prcCurrent = (RECT*)prgnData->Buffer + cRgnRects;
+ }
+ #else
+ hrgnTemp = CreateRectRgn(xstart, y,x,y+1);
+ CombineRgn(hrgnRet, hrgnRet, hrgnTemp, RGN_OR );
+ DeleteObject(hrgnTemp);
+ #endif
+ }
+ else
+ {
+ x++;
+ pclrCurrent++;
+ }
+ }
+ y++;
+ }
+
+ #ifdef EXTCREATEREGION_WORKS
+ /* Fill the region data header */
+ prgnData->rdh.dwSize = sizeof(prgnData->rdh);
+ prgnData->rdh.iType = RDH_RECTANGLES;
+ prgnData->rdh.nCount = cRgnRects;
+ prgnData->rdh.nRgnSize = cRgnDataSize;
+ prgnData->rdh.rcBound = *pRect;
+
+ /* Create the region*/
+ hrgnRet = ExtCreateRegion (NULL, cRgnDataSize, prgnData);
+
+ /* Free the region data*/
+ HeapFree(GetProcessHeap(),0,prgnData);
+ #endif
+
+ /* return the region*/
+ return hrgnRet;
+ }
+
+ HRESULT UXTHEME_GetImageBackBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, HRGN *pRegion)
+ {
+ HBITMAP hbmp;
+ DIBSECTION dib;
+ RGBQUAD clrTransparent = {0xFF,0x0, 0xFF,0x0};
+
+ /* Draw the theme part to a dib */
+ hbmp = UXTHEME_DrawThemePartToDib(hTheme, hdc, iPartId, iStateId, pRect);
+
+ /* Retrieve the info of the dib section */
+ GetObject(hbmp, sizeof (DIBSECTION), &dib);
+
+ /* Convert the bits of the dib section to a region */
+ *pRegion = UXTHEME_RegionFromDibBits((RGBQUAD*)dib.dsBm.bmBits, &clrTransparent, pRect);
+
+ /* Free the temp bitmap */
+ DeleteObject(hbmp);
+
+ return S_OK;
+ }
+
/***********************************************************************
* GetThemeBackgroundRegion (UXTHEME.@)
*
GetThemeEnumValue(hTheme, iPartId, iStateId, TMT_BGTYPE, &bgtype);
if(bgtype == BT_IMAGEFILE) {
- FIXME("Images not handled yet\n");
- hr = ERROR_CALL_NOT_IMPLEMENTED;
+ hr = UXTHEME_GetImageBackBackgroundRegion(hTheme, hdc, iPartId, iStateId, pRect, pRegion);
}
else if(bgtype == BT_BORDERFILL) {
*pRegion = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
*lpValEnd = lpCur;
return E_PROP_ID_UNSUPPORTED;
}
+ if(pointSize > 0)
+ {
+ HDC hdc = GetDC(0);
+ pointSize = -MulDiv(pointSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(0, hdc);
+ }
+
pFont->lfHeight = pointSize;
pFont->lfWeight = FW_REGULAR;
pFont->lfCharSet = DEFAULT_CHARSET;
ZeroMemory(pFont, sizeof(LOGFONTW));
hr = MSSTYLES_GetFont (lpCur, lpEnd, &lpCur, pFont);
- if (SUCCEEDED (hr))
- pFont->lfHeight = -MulDiv(pFont->lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
return hr;
}
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS uxtheme.dll
+ * FILE: dll/win32/uxtheme/ncscrollbar.c
+ * PURPOSE: uxtheme scrollbar support
+ * PROGRAMMER: Giannis Adamopoulos
+ * This file is heavily based on code from the wine project:
+ * Copyright 1993 Martin Ayotte
+ * Copyright 1994, 1996 Alexandre Julliard
+ */
+
+ #include <windows.h>
+ #include "undocuser.h"
+ #include "vfwmsgs.h"
+ #include "uxtheme.h"
+ #include <tmschema.h>
+ #include <Windowsx.h>
+ #include "ncthm.h"
+ #include <assert.h>
+ #include "wine/debug.h"
+
+ WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
+
+ static BOOL SCROLL_trackVertical;
+ static enum SCROLL_HITTEST SCROLL_trackHitTest;
+ /* Is the moving thumb being displayed? */
+ static BOOL SCROLL_MovingThumb = FALSE;
+ static HWND SCROLL_TrackingWin = 0;
+ static INT SCROLL_TrackingBar = 0;
+ static INT SCROLL_TrackingPos = 0;
+ static INT SCROLL_TrackingVal = 0;
+
+ void static ScreenToWindow( HWND hWnd, POINT* pt)
+ {
+ RECT rcWnd;
+ GetWindowRect(hWnd, &rcWnd);
+ pt->x -= rcWnd.left;
+ pt->y -= rcWnd.top;
+ }
+
+ static BOOL SCROLL_IsVertical(HWND hwnd, INT nBar)
+ {
+ switch(nBar)
+ {
+ case SB_HORZ:
+ return FALSE;
+ case SB_VERT:
+ return TRUE;
+ default:
+ assert(FALSE);
+ return FALSE;
+ }
+ }
+
+ static LONG SCROLL_getObjectId(INT nBar)
+ {
+ switch(nBar)
+ {
+ case SB_HORZ:
+ return OBJID_HSCROLL;
+ case SB_VERT:
+ return OBJID_VSCROLL;
+ default:
+ assert(FALSE);
+ return 0;
+ }
+ }
+
+ /***********************************************************************
+ * SCROLL_PtInRectEx
+ */
+ static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
+ {
+ RECT rect = *lpRect;
+ int scrollbarWidth;
+
+ /* Pad hit rect to allow mouse to be dragged outside of scrollbar and
+ * still be considered in the scrollbar. */
+ if (vertical)
+ {
+ scrollbarWidth = lpRect->right - lpRect->left;
+ rect.left -= scrollbarWidth*8;
+ rect.right += scrollbarWidth*8;
+ rect.top -= scrollbarWidth*2;
+ rect.bottom += scrollbarWidth*2;
+ }
+ else
+ {
+ scrollbarWidth = lpRect->bottom - lpRect->top;
+ rect.left -= scrollbarWidth*2;
+ rect.right += scrollbarWidth*2;
+ rect.top -= scrollbarWidth*8;
+ rect.bottom += scrollbarWidth*8;
+ }
+ return PtInRect( &rect, pt );
+ }
+
+
+ /***********************************************************************
+ * SCROLL_HitTest
+ *
+ * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
+ */
+ static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, SCROLLBARINFO* psbi, BOOL vertical,
+ POINT pt, BOOL bDragging )
+ {
+ if ( (bDragging && !SCROLL_PtInRectEx( &psbi->rcScrollBar, pt, vertical )) ||
+ (!PtInRect( &psbi->rcScrollBar, pt )) )
+ {
+ return SCROLL_NOWHERE;
+ }
+
+ if (vertical)
+ {
+ if (pt.y < psbi->rcScrollBar.top + psbi->dxyLineButton)
+ return SCROLL_TOP_ARROW;
+ if (pt.y >= psbi->rcScrollBar.bottom - psbi->dxyLineButton)
+ return SCROLL_BOTTOM_ARROW;
+ if (!psbi->xyThumbTop)
+ return SCROLL_TOP_RECT;
+ pt.y -= psbi->rcScrollBar.top;
+ if (pt.y < psbi->xyThumbTop)
+ return SCROLL_TOP_RECT;
+ if (pt.y >= psbi->xyThumbTop + psbi->dxyLineButton)
+ return SCROLL_BOTTOM_RECT;
+ }
+ else /* horizontal */
+ {
+ if (pt.x < psbi->rcScrollBar.left + psbi->dxyLineButton)
+ return SCROLL_TOP_ARROW;
+ if (pt.x >= psbi->rcScrollBar.right - psbi->dxyLineButton)
+ return SCROLL_BOTTOM_ARROW;
+ if (!psbi->xyThumbTop)
+ return SCROLL_TOP_RECT;
+ pt.x -= psbi->rcScrollBar.left;
+ if (pt.x < psbi->xyThumbTop)
+ return SCROLL_TOP_RECT;
+ if (pt.x >= psbi->xyThumbTop + psbi->dxyLineButton)
+ return SCROLL_BOTTOM_RECT;
+ }
+ return SCROLL_THUMB;
+ }
+
+ static void SCROLL_ThemeDrawPart(PDRAW_CONTEXT pcontext, int iPartId,int iStateId, SCROLLBARINFO* psbi, int htCurrent, int htDown, int htHot, RECT* r)
+ {
+ if(psbi->rgstate[htCurrent] & STATE_SYSTEM_UNAVAILABLE)
+ iStateId += BUTTON_DISABLED - BUTTON_NORMAL;
+ else if (htHot == htCurrent)
+ iStateId += BUTTON_HOT - BUTTON_NORMAL;
+ else if (htDown == htCurrent)
+ iStateId += BUTTON_PRESSED - BUTTON_NORMAL;
+
+ DrawThemeBackground(pcontext->scrolltheme, pcontext->hDC, iPartId, iStateId, r, NULL);
+ }
+
+ /***********************************************************************
+ * SCROLL_DrawArrows
+ *
+ * Draw the scroll bar arrows.
+ */
+ static void SCROLL_DrawArrows( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi,
+ BOOL vertical, int htDown, int htHot )
+ {
+ RECT r;
+ int iStateId;
+
+ r = psbi->rcScrollBar;
+ if( vertical )
+ {
+ r.bottom = r.top + psbi->dxyLineButton;
+ iStateId = ABS_UPNORMAL;
+ }
+ else
+ {
+ r.right = r.left + psbi->dxyLineButton;
+ iStateId = ABS_LEFTNORMAL;
+ }
+
+ SCROLL_ThemeDrawPart(pcontext, SBP_ARROWBTN, iStateId, psbi, SCROLL_TOP_ARROW, htDown, htHot, &r);
+
+ r = psbi->rcScrollBar;
+ if( vertical )
+ {
+ r.top = r.bottom - psbi->dxyLineButton;
+ iStateId = ABS_DOWNNORMAL;
+ }
+ else
+ {
+ iStateId = ABS_RIGHTNORMAL;
+ r.left = r.right - psbi->dxyLineButton;
+ }
+
+ SCROLL_ThemeDrawPart(pcontext, SBP_ARROWBTN, iStateId, psbi, SCROLL_BOTTOM_ARROW, htDown, htHot, &r);
+ }
+
+ static void SCROLL_DrawInterior( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi,
+ INT thumbPos, BOOL vertical,
+ int htDown, int htHot )
+ {
+ RECT r, rcPart;
+
+ r = psbi->rcScrollBar;
+ if (vertical)
+ {
+ r.top += psbi->dxyLineButton;
+ r.bottom -= (psbi->dxyLineButton);
+ }
+ else
+ {
+ r.left += psbi->dxyLineButton;
+ r.right -= psbi->dxyLineButton;
+ }
+
+ /* Draw the scroll rectangles and thumb */
+
+ if (!thumbPos) /* No thumb to draw */
+ {
+ rcPart = r;
+ SCROLL_ThemeDrawPart(pcontext, vertical ? SBP_UPPERTRACKVERT: SBP_UPPERTRACKHORZ , BUTTON_NORMAL, psbi, SCROLL_THUMB, 0, 0, &rcPart);
+ return;
+ }
+
+ if (vertical)
+ {
+ rcPart = r;
+ rcPart.bottom = rcPart.top + thumbPos - psbi->dxyLineButton;
+ SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKVERT, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart);
+ r.top = rcPart.bottom;
+
+ rcPart = r;
+ rcPart.top += psbi->dxyLineButton;
+ SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKVERT, BUTTON_NORMAL, psbi, SCROLL_BOTTOM_RECT, htDown, htHot, &rcPart);
+ r.bottom = rcPart.top;
+
+ SCROLL_ThemeDrawPart(pcontext, SBP_THUMBBTNVERT, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
+ SCROLL_ThemeDrawPart(pcontext, SBP_GRIPPERVERT, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
+ }
+ else /* horizontal */
+ {
+ rcPart = r;
+ rcPart.right = rcPart.left + thumbPos - psbi->dxyLineButton;
+ SCROLL_ThemeDrawPart(pcontext, SBP_UPPERTRACKHORZ, BUTTON_NORMAL, psbi, SCROLL_TOP_RECT, htDown, htHot, &rcPart);
+ r.left = rcPart.right;
+
+ rcPart = r;
+ rcPart.left += psbi->dxyLineButton;
+ SCROLL_ThemeDrawPart(pcontext, SBP_LOWERTRACKHORZ, BUTTON_NORMAL, psbi, SCROLL_BOTTOM_RECT, htDown, htHot, &rcPart);
+ r.right = rcPart.left;
+
+ SCROLL_ThemeDrawPart(pcontext, SBP_THUMBBTNHORZ, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
+ SCROLL_ThemeDrawPart(pcontext, SBP_GRIPPERHORZ, BUTTON_NORMAL, psbi, SCROLL_THUMB, htDown, htHot, &r);
+ }
+ }
+
+ static void SCROLL_DrawMovingThumb( PDRAW_CONTEXT pcontext, SCROLLBARINFO* psbi, BOOL vertical)
+ {
+ INT pos = SCROLL_TrackingPos;
+ INT max_size;
+
+ if( vertical )
+ max_size = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
+ else
+ max_size = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
+
+ max_size -= (psbi->dxyLineButton -SCROLL_ARROW_THUMB_OVERLAP) + psbi->dxyLineButton;
+
+ if( pos < (psbi->dxyLineButton-SCROLL_ARROW_THUMB_OVERLAP) )
+ pos = (psbi->dxyLineButton-SCROLL_ARROW_THUMB_OVERLAP);
+ else if( pos > max_size )
+ pos = max_size;
+
+ SCROLL_DrawInterior(pcontext, psbi, pos, vertical, SCROLL_THUMB, 0);
+
+ SCROLL_MovingThumb = !SCROLL_MovingThumb;
+ }
+
+
+ void
+ ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT nBar, POINT* pt)
+ {
+ SCROLLINFO si;
+ SCROLLBARINFO sbi;
+ BOOL vertical;
+ enum SCROLL_HITTEST htHot = SCROLL_NOWHERE;
+
+ /* Retrieve scrollbar info */
+ sbi.cbSize = sizeof(sbi);
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL ;
+ GetScrollInfo(pcontext->hWnd, nBar, &si);
+ GetScrollBarInfo(pcontext->hWnd, SCROLL_getObjectId(nBar), &sbi);
+ vertical = SCROLL_IsVertical(pcontext->hWnd, nBar);
+ if(sbi.rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE &&
+ sbi.rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE )
+ {
+ sbi.xyThumbTop = 0;
+ }
+
+ #ifndef ROS_SUCKS
+ /* The scrollbar rect is in screen coordinates */
+ // OffsetRect(&sbi.rcScrollBar, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top);
+ #endif
+
+ if(pt)
+ {
+ ScreenToWindow(pcontext->hWnd, pt);
+ htHot = SCROLL_HitTest(pcontext->hWnd, &sbi, vertical, *pt, FALSE);
+ }
+
+ if (((nBar == SB_VERT) && !(pcontext->wi.dwStyle & WS_VSCROLL)) ||
+ ((nBar == SB_HORZ) && !(pcontext->wi.dwStyle & WS_HSCROLL))) return;
+
+ /* do not draw if the scrollbar rectangle is empty */
+ if(IsRectEmpty(&sbi.rcScrollBar)) return;
+
+ /* Draw the scrollbar */
+ SCROLL_DrawArrows( pcontext, &sbi, vertical, 0, htHot );
+ SCROLL_DrawInterior( pcontext, &sbi, sbi.xyThumbTop, vertical, 0, htHot );
+ }
+
+
+
+ /***********************************************************************
+ * SCROLL_ClipPos
+ */
+ static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt )
+ {
+ if( pt.x < lpRect->left )
+ pt.x = lpRect->left;
+ else
+ if( pt.x > lpRect->right )
+ pt.x = lpRect->right;
+
+ if( pt.y < lpRect->top )
+ pt.y = lpRect->top;
+ else
+ if( pt.y > lpRect->bottom )
+ pt.y = lpRect->bottom;
+
+ return pt;
+ }
+
+
+
+ /***********************************************************************
+ * SCROLL_GetThumbVal
+ *
+ * Compute the current scroll position based on the thumb position in pixels
+ * from the top of the scroll-bar.
+ */
+ static UINT SCROLL_GetThumbVal( SCROLLINFO *psi, RECT *rect,
+ BOOL vertical, INT pos )
+ {
+ INT thumbSize;
+ INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
+ INT range;
+
+ if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
+ return psi->nMin;
+
+ if (psi->nPage)
+ {
+ thumbSize = MulDiv(pixels,psi->nPage,(psi->nMax-psi->nMin+1));
+ if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
+ }
+ else thumbSize = GetSystemMetrics(SM_CXVSCROLL);
+
+ if ((pixels -= thumbSize) <= 0) return psi->nMin;
+
+ pos = max( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) );
+ if (pos > pixels) pos = pixels;
+
+ if (!psi->nPage)
+ range = psi->nMax - psi->nMin;
+ else
+ range = psi->nMax - psi->nMin - psi->nPage + 1;
+
+ return psi->nMin + MulDiv(pos, range, pixels);
+ }
+
+ static void
+ SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
+ {
+ /* Previous mouse position for timer events */
+ static POINT prevPt;
+ /* Thumb position when tracking started. */
+ static UINT trackThumbPos;
+ /* Position in the scroll-bar of the last button-down event. */
+ static INT lastClickPos;
+ /* Position in the scroll-bar of the last mouse event. */
+ static INT lastMousePos;
+
+ enum SCROLL_HITTEST hittest;
+ HWND hwndOwner, hwndCtl;
+ BOOL vertical;
+ SCROLLINFO si;
+ SCROLLBARINFO sbi;
+ DRAW_CONTEXT context;
+
+ si.cbSize = sizeof(si);
+ sbi.cbSize = sizeof(sbi);
+ si.fMask = SIF_ALL;
+ GetScrollInfo(hwnd, nBar, &si);
+ GetScrollBarInfo(hwnd, SCROLL_getObjectId(nBar), &sbi);
+ vertical = SCROLL_IsVertical(hwnd, nBar);
+ if(sbi.rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE &&
+ sbi.rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE )
+ {
+ return;
+ }
+ ThemeInitDrawContext(&context, hwnd, 0);
+
+ #ifndef ROS_SUCKS
+ /* The scrollbar rect is in screen coordinates */
+ // OffsetRect(&sbi.rcScrollBar, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
+ #endif
+
+ if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN))
+ return;
+
+ hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
+ hwndCtl = (nBar == SB_CTL) ? hwnd : 0;
+
+ switch(msg)
+ {
+ case WM_LBUTTONDOWN: /* Initialise mouse tracking */
+ HideCaret(hwnd); /* hide caret while holding down LBUTTON */
+ SCROLL_trackVertical = vertical;
+ SCROLL_trackHitTest = hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE );
+ lastClickPos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left);
+ lastMousePos = lastClickPos;
+ trackThumbPos = sbi.xyThumbTop;
+ prevPt = pt;
+ SetCapture( hwnd );
+ break;
+
+ case WM_MOUSEMOVE:
+ hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, TRUE );
+ prevPt = pt;
+ break;
+
+ case WM_LBUTTONUP:
+ hittest = SCROLL_NOWHERE;
+ ReleaseCapture();
+ /* if scrollbar has focus, show back caret */
+ if (hwnd==GetFocus())
+ ShowCaret(hwnd);
+ break;
+
+ case WM_SYSTIMER:
+ pt = prevPt;
+ hittest = SCROLL_HitTest( hwnd, &sbi, vertical, pt, FALSE );
+ break;
+
+ default:
+ return; /* Should never happen */
+ }
+
+ //TRACE("Event: hwnd=%p bar=%d msg=%s pt=%d,%d hit=%d\n",
+ // hwnd, nBar, SPY_GetMsgName(msg,hwnd), pt.x, pt.y, hittest );
+
+ switch(SCROLL_trackHitTest)
+ {
+ case SCROLL_NOWHERE: /* No tracking in progress */
+ break;
+
+ case SCROLL_TOP_ARROW:
+ if (hittest == SCROLL_trackHitTest)
+ {
+ SCROLL_DrawArrows( &context, &sbi, vertical, SCROLL_trackHitTest, 0 );
+ if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
+ {
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ SB_LINEUP, (LPARAM)hwndCtl );
+ }
+
+ SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+ SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
+ }
+ else
+ {
+ SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 );
+ KillSystemTimer( hwnd, SCROLL_TIMER );
+ }
+
+ break;
+
+ case SCROLL_TOP_RECT:
+ SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, SCROLL_trackHitTest, 0);
+ if (hittest == SCROLL_trackHitTest)
+ {
+ if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
+ {
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ SB_PAGEUP, (LPARAM)hwndCtl );
+ }
+ SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+ SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
+ }
+ else KillSystemTimer( hwnd, SCROLL_TIMER );
+ break;
+
+ case SCROLL_THUMB:
+ if (msg == WM_LBUTTONDOWN)
+ {
+ SCROLL_TrackingWin = hwnd;
+ SCROLL_TrackingBar = nBar;
+ SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
+ SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar,
+ vertical, SCROLL_TrackingPos );
+ if (!SCROLL_MovingThumb)
+ SCROLL_DrawMovingThumb(&context, &sbi, vertical);
+ }
+ else if (msg == WM_LBUTTONUP)
+ {
+ if (SCROLL_MovingThumb)
+ SCROLL_DrawMovingThumb(&context, &sbi, vertical);
+
+ SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, SCROLL_trackHitTest );
+ }
+ else /* WM_MOUSEMOVE */
+ {
+ INT pos;
+
+ if (!SCROLL_PtInRectEx( &sbi.rcScrollBar, pt, vertical ))
+ pos = lastClickPos;
+ else
+ {
+ pt = SCROLL_ClipPos( &sbi.rcScrollBar, pt );
+ pos = vertical ? (pt.y - sbi.rcScrollBar.top) : (pt.x - sbi.rcScrollBar.left);
+ }
+ if ( (pos != lastMousePos) || (!SCROLL_MovingThumb) )
+ {
+ if (SCROLL_MovingThumb)
+ SCROLL_DrawMovingThumb( &context, &sbi, vertical);
+ lastMousePos = pos;
+ SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
+ SCROLL_TrackingVal = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar,
+ vertical,
+ SCROLL_TrackingPos );
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal),
+ (LPARAM)hwndCtl );
+ if (!SCROLL_MovingThumb)
+ SCROLL_DrawMovingThumb( &context, &sbi, vertical);
+ }
+ }
+ break;
+
+ case SCROLL_BOTTOM_RECT:
+ if (hittest == SCROLL_trackHitTest)
+ {
+ SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, SCROLL_trackHitTest, 0 );
+ if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
+ {
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ SB_PAGEDOWN, (LPARAM)hwndCtl );
+ }
+ SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+ SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
+ }
+ else
+ {
+ SCROLL_DrawInterior( &context, &sbi, sbi.xyThumbTop, vertical, 0, 0 );
+ KillSystemTimer( hwnd, SCROLL_TIMER );
+ }
+ break;
+
+ case SCROLL_BOTTOM_ARROW:
+ if (hittest == SCROLL_trackHitTest)
+ {
+ SCROLL_DrawArrows( &context, &sbi, vertical, SCROLL_trackHitTest, 0 );
+ if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
+ {
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ SB_LINEDOWN, (LPARAM)hwndCtl );
+ }
+
+ SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
+ SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, NULL );
+ }
+ else
+ {
+ SCROLL_DrawArrows( &context, &sbi, vertical, 0, 0 );
+ KillSystemTimer( hwnd, SCROLL_TIMER );
+ }
+ break;
+ }
+
+ if (msg == WM_LBUTTONDOWN)
+ {
+
+ if (hittest == SCROLL_THUMB)
+ {
+ UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical,
+ trackThumbPos + lastMousePos - lastClickPos );
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ MAKEWPARAM( SB_THUMBTRACK, val ), (LPARAM)hwndCtl );
+ }
+ }
+
+ if (msg == WM_LBUTTONUP)
+ {
+ hittest = SCROLL_trackHitTest;
+ SCROLL_trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
+
+ if (hittest == SCROLL_THUMB)
+ {
+ UINT val = SCROLL_GetThumbVal( &si, &sbi.rcScrollBar, vertical,
+ trackThumbPos + lastMousePos - lastClickPos );
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl );
+ }
+ /* SB_ENDSCROLL doesn't report thumb position */
+ SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
+ SB_ENDSCROLL, (LPARAM)hwndCtl );
+
+ /* Terminate tracking */
+ SCROLL_TrackingWin = 0;
+ }
+
+ ThemeCleanupDrawContext(&context);
+ }
+
+ static void
+ SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt )
+ {
+ MSG msg;
+
+ ScreenToWindow(hwnd, &pt);
+
+ SCROLL_HandleScrollEvent( hwnd, scrollbar, WM_LBUTTONDOWN, pt );
+
+ do
+ {
+ if (!GetMessageW( &msg, 0, 0, 0 )) break;
+ if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue;
+ if (msg.message == WM_LBUTTONUP ||
+ msg.message == WM_MOUSEMOVE ||
+ (msg.message == WM_SYSTIMER && msg.wParam == SCROLL_TIMER))
+ {
+ pt.x = GET_X_LPARAM(msg.lParam);
+ pt.y = GET_Y_LPARAM(msg.lParam);
+ ClientToScreen(hwnd, &pt);
+ ScreenToWindow(hwnd, &pt);
+ SCROLL_HandleScrollEvent( hwnd, scrollbar, msg.message, pt );
+ }
+ else
+ {
+ TranslateMessage( &msg );
+ DispatchMessageW( &msg );
+ }
+ if (!IsWindow( hwnd ))
+ {
+ ReleaseCapture();
+ break;
+ }
+ } while (msg.message != WM_LBUTTONUP && GetCapture() == hwnd);
+ }
+
+ void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
+ {
+ INT scrollbar;
+
+ if ((wParam & 0xfff0) == SC_HSCROLL)
+ {
+ if ((wParam & 0x0f) != HTHSCROLL) return;
+ scrollbar = SB_HORZ;
+ }
+ else /* SC_VSCROLL */
+ {
+ if ((wParam & 0x0f) != HTVSCROLL) return;
+ scrollbar = SB_VERT;
+ }
+ SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
+ }
--- /dev/null
+
+ typedef struct _WND_CONTEXT
+ {
+ BOOL HasAppDefinedRgn;
+ BOOL HasThemeRgn;
+ BOOL UpdatingRgn;
+ } WND_CONTEXT, *PWND_CONTEXT;
+
+ typedef struct _DRAW_CONTEXT
+ {
+ HWND hWnd;
+ HDC hDC;
+ HTHEME theme;
+ HTHEME scrolltheme;
+ HTHEME hPrevTheme;
+ WINDOWINFO wi;
+ BOOL Active; /* wi.dwWindowStatus isn't correct for mdi child windows */
+ HRGN hRgn;
+ int CaptionHeight;
+
+ /* for double buffering */
+ HDC hDCScreen;
+ HBITMAP hbmpOld;
+ } DRAW_CONTEXT, *PDRAW_CONTEXT;
+
+ typedef enum
+ {
+ CLOSEBUTTON,
+ MAXBUTTON,
+ MINBUTTON,
+ HELPBUTTON
+ } CAPTIONBUTTON;
+
+ /*
+ The following values specify all possible vutton states
+ Note that not all of them are documented but it is easy to
+ find them by opening a theme file
+ */
+ typedef enum {
+ BUTTON_NORMAL = 1 ,
+ BUTTON_HOT ,
+ BUTTON_PRESSED ,
+ BUTTON_DISABLED ,
+ BUTTON_INACTIVE
+ } THEME_BUTTON_STATES;
+
+ /* Scroll-bar hit testing */
+ enum SCROLL_HITTEST
+ {
+ SCROLL_NOWHERE, /* Outside the scroll bar */
+ SCROLL_TOP_ARROW, /* Top or left arrow */
+ SCROLL_TOP_RECT, /* Rectangle between the top arrow and the thumb */
+ SCROLL_THUMB, /* Thumb rectangle */
+ SCROLL_BOTTOM_RECT, /* Rectangle between the thumb and the bottom arrow */
+ SCROLL_BOTTOM_ARROW /* Bottom or right arrow */
+ };
+
+ #define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
+ ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE)) || \
+ ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
+ (WindowRect.right - WindowRect.left == ParentClientRect.right) && \
+ (WindowRect.bottom - WindowRect.top == ParentClientRect.bottom)))
+
+ #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
+
+ #define BUTTON_GAP_SIZE 2
+
+ #define MENU_BAR_ITEMS_SPACE (12)
+
+ #define SCROLL_TIMER 0 /* Scroll timer id */
+
+ /* Overlap between arrows and thumb */
+ #define SCROLL_ARROW_THUMB_OVERLAP 0
+
+ /* Delay (in ms) before first repetition when holding the button down */
+ #define SCROLL_FIRST_DELAY 200
+
+ /* Delay (in ms) between scroll repetitions */
+ #define SCROLL_REPEAT_DELAY 50
+
+ /* Minimum size of the thumb in pixels */
+ #define SCROLL_MIN_THUMB 6
+
+ /* Minimum size of the rectangle between the arrows */
+ #define SCROLL_MIN_RECT 4
+
+ void
+ ThemeDrawScrollBar(PDRAW_CONTEXT pcontext, INT Bar, POINT* pt);
+
+ VOID
+ NC_TrackScrollBar(HWND Wnd, WPARAM wParam, POINT Pt);
+
+ void
+ ThemeInitDrawContext(PDRAW_CONTEXT pcontext,
+ HWND hWnd,
+ HRGN hRgn);
+
+ void
+ ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext);
+
+ PWND_CONTEXT
+ ThemeGetWndContext(HWND hWnd);
+
+ extern ATOM atWindowTheme;
+ extern ATOM atWndContrext;
+
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS uxtheme.dll
+ * FILE: dll/win32/uxtheme/nonclient.c
+ * PURPOSE: uxtheme non client area management
+ * PROGRAMMER: Giannis Adamopoulos
+ */
+
+ #include <windows.h>
+ #include <windowsx.h>
+ #include "undocuser.h"
+ #include "vfwmsgs.h"
+ #include "uxtheme.h"
+ #include <tmschema.h>
+ #include "ncthm.h"
+
+ #include "wine/debug.h"
+
+ WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
+
+ HFONT hMenuFont = NULL;
+ HFONT hMenuFontBold = NULL;
+
+ void InitMenuFont(VOID)
+ {
+ NONCLIENTMETRICS ncm;
+
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);
+
+ if(!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+ {
+ return ;
+ }
+
+ hMenuFont = CreateFontIndirect(&ncm.lfMenuFont);
+
+ ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
+ hMenuFontBold = CreateFontIndirect(&ncm.lfMenuFont);
+
+ }
+
+ static BOOL
+ IsWindowActive(HWND hWnd, DWORD ExStyle)
+ {
+ BOOL ret;
+
+ if (ExStyle & WS_EX_MDICHILD)
+ {
+ ret = IsChild(GetForegroundWindow(), hWnd);
+ if (ret)
+ ret = (hWnd == (HWND)SendMessageW(GetParent(hWnd), WM_MDIGETACTIVE, 0, 0));
+ }
+ else
+ {
+ ret = (GetForegroundWindow() == hWnd);
+ }
+
+ return ret;
+ }
+
+ static BOOL
+ UserHasWindowEdge(DWORD Style, DWORD ExStyle)
+ {
+ if (Style & WS_MINIMIZE)
+ return TRUE;
+ if (ExStyle & WS_EX_DLGMODALFRAME)
+ return TRUE;
+ if (ExStyle & WS_EX_STATICEDGE)
+ return FALSE;
+ if (Style & WS_THICKFRAME)
+ return TRUE;
+ if (Style == WS_DLGFRAME || Style == WS_CAPTION)
+ return TRUE;
+ return FALSE;
+ }
+
+ HICON
+ UserGetWindowIcon(HWND hwnd)
+ {
+ HICON hIcon = 0;
+
+ SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+ if (!hIcon)
+ SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+ if (!hIcon)
+ SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+ if (!hIcon)
+ hIcon = (HICON)GetClassLong(hwnd, GCL_HICONSM);
+
+ if (!hIcon)
+ hIcon = (HICON)GetClassLong(hwnd, GCL_HICON);
+
+ if(!hIcon)
+ hIcon = LoadIcon(NULL, IDI_WINLOGO);
+
+ return hIcon;
+ }
+
+ WCHAR *UserGetWindowCaption(HWND hwnd)
+ {
+ INT len = 512;
+ WCHAR *text;
+ text = (WCHAR*)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (text) InternalGetWindowText(hwnd, text, len);
+ return text;
+ }
+
+ static void
+ ThemeDrawTitle(PDRAW_CONTEXT context, RECT* prcCurrent)
+ {
+
+ }
+
+ HRESULT WINAPI ThemeDrawCaptionText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
+ LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
+ DWORD dwTextFlags2, const RECT *pRect, BOOL Active)
+ {
+ HRESULT hr;
+ HFONT hFont = NULL;
+ HGDIOBJ oldFont = NULL;
+ LOGFONTW logfont;
+ COLORREF textColor;
+ COLORREF oldTextColor;
+ int oldBkMode;
+ RECT rt;
+
+ hr = GetThemeSysFont(0,TMT_CAPTIONFONT,&logfont);
+
+ if(SUCCEEDED(hr)) {
+ hFont = CreateFontIndirectW(&logfont);
+ }
+ CopyRect(&rt, pRect);
+ if(hFont)
+ oldFont = SelectObject(hdc, hFont);
+
+ if(dwTextFlags2 & DTT_GRAYED)
+ textColor = GetSysColor(COLOR_GRAYTEXT);
+ else if (!Active)
+ textColor = GetSysColor(COLOR_INACTIVECAPTIONTEXT);
+ else
+ textColor = GetSysColor(COLOR_CAPTIONTEXT);
+
+ oldTextColor = SetTextColor(hdc, textColor);
+ oldBkMode = SetBkMode(hdc, TRANSPARENT);
+ DrawTextW(hdc, pszText, iCharCount, &rt, dwTextFlags);
+ SetBkMode(hdc, oldBkMode);
+ SetTextColor(hdc, oldTextColor);
+
+ if(hFont) {
+ SelectObject(hdc, oldFont);
+ DeleteObject(hFont);
+ }
+ return S_OK;
+ }
+
+ void
+ ThemeInitDrawContext(PDRAW_CONTEXT pcontext,
+ HWND hWnd,
+ HRGN hRgn)
+ {
+ pcontext->wi.cbSize = sizeof(pcontext->wi);
+ GetWindowInfo(hWnd, &pcontext->wi);
+ pcontext->hWnd = hWnd;
+ pcontext->Active = IsWindowActive(hWnd, pcontext->wi.dwExStyle);
+ pcontext->hPrevTheme = GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWindowTheme));
+ pcontext->theme = OpenThemeData(pcontext->hWnd, L"WINDOW");
+ pcontext->scrolltheme = OpenThemeData(pcontext->hWnd, L"SCROLLBAR");
+
+ pcontext->CaptionHeight = pcontext->wi.cyWindowBorders;
+ pcontext->CaptionHeight += GetSystemMetrics(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
+
+ if(hRgn <= (HRGN)1)
+ {
+ hRgn = CreateRectRgnIndirect(&pcontext->wi.rcWindow);
+ }
+ pcontext->hRgn = hRgn;
+
+ pcontext->hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
+ }
+
+ void
+ ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext)
+ {
+ ReleaseDC(pcontext->hWnd ,pcontext->hDC);
+
+ CloseThemeData (pcontext->theme);
+ CloseThemeData (pcontext->scrolltheme);
+
+ SetPropW(pcontext->hWnd, (LPCWSTR)MAKEINTATOM(atWindowTheme), pcontext->hPrevTheme);
+
+ if(pcontext->hRgn != NULL)
+ {
+ DeleteObject(pcontext->hRgn);
+ }
+ }
+
+ static void
+ ThemeStartBufferedPaint(PDRAW_CONTEXT pcontext, int cx, int cy)
+ {
+ HBITMAP hbmp;
+
+ pcontext->hDCScreen = pcontext->hDC;
+ pcontext->hDC = CreateCompatibleDC(pcontext->hDCScreen);
+ hbmp = CreateCompatibleBitmap(pcontext->hDCScreen, cx, cy);
+ pcontext->hbmpOld = (HBITMAP)SelectObject(pcontext->hDC, hbmp);
+ }
+
+ static void
+ ThemeEndBufferedPaint(PDRAW_CONTEXT pcontext, int x, int y, int cx, int cy)
+ {
+ HBITMAP hbmp;
+ BitBlt(pcontext->hDCScreen, 0, 0, cx, cy, pcontext->hDC, x, y, SRCCOPY);
+ hbmp = (HBITMAP) SelectObject(pcontext->hDC, pcontext->hbmpOld);
+ DeleteObject(pcontext->hDC);
+ DeleteObject(hbmp);
+
+ pcontext->hDC = pcontext->hDCScreen;
+ }
+
+ static void
+ ThemeDrawCaptionButton(PDRAW_CONTEXT pcontext,
+ RECT* prcCurrent,
+ CAPTIONBUTTON buttonId,
+ INT iStateId)
+ {
+ RECT rcPart;
+ INT ButtonWidth, ButtonHeight, iPartId;
+
+ ButtonHeight = GetSystemMetrics( pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMSIZE : SM_CYSIZE);
+ ButtonWidth = GetSystemMetrics( pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CXSMSIZE : SM_CXSIZE);
+
+ switch(buttonId)
+ {
+ case CLOSEBUTTON:
+ iPartId = pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
+ break;
+
+ case MAXBUTTON:
+ if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
+ {
+ if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
+ return;
+ else
+ iStateId = BUTTON_DISABLED;
+ }
+
+ iPartId = pcontext->wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON;
+ break;
+
+ case MINBUTTON:
+ if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
+ {
+ if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
+ return;
+ else
+ iStateId = BUTTON_DISABLED;
+ }
+
+ iPartId = WP_MINBUTTON;
+ break;
+
+ default:
+ //FIXME: Implement Help Button
+ return;
+ }
+
+ ButtonHeight -= 4;
+ ButtonWidth -= 4;
+
+ /* Calculate the position */
+ rcPart.top = prcCurrent->top;
+ rcPart.right = prcCurrent->right;
+ rcPart.bottom = rcPart.top + ButtonHeight ;
+ rcPart.left = rcPart.right - ButtonWidth ;
+ prcCurrent->right -= ButtonWidth + BUTTON_GAP_SIZE;
+
+ DrawThemeBackground(pcontext->theme, pcontext->hDC, iPartId, iStateId, &rcPart, NULL);
+ }
+
+ static DWORD
+ ThemeGetButtonState(DWORD htCurrect, DWORD htHot, DWORD htDown, BOOL Active)
+ {
+ if (htHot == htCurrect)
+ return BUTTON_HOT;
+ if (!Active)
+ return BUTTON_INACTIVE;
+ if (htDown == htCurrect)
+ return BUTTON_PRESSED;
+
+ return BUTTON_NORMAL;
+ }
+
+ /* Used only from mouse event handlers */
+ static void
+ ThemeDrawCaptionButtons(PDRAW_CONTEXT pcontext, DWORD htHot, DWORD htDown)
+ {
+ RECT rcCurrent;
+
+ /* Check if the window has caption buttons */
+ if (!((pcontext->wi.dwStyle & WS_CAPTION) && (pcontext->wi.dwStyle & WS_SYSMENU)))
+ return ;
+
+ rcCurrent.top = rcCurrent.left = 0;
+ rcCurrent.right = pcontext->wi.rcWindow.right - pcontext->wi.rcWindow.left;
+ rcCurrent.bottom = pcontext->CaptionHeight;
+
+ /* Add a padding around the objects of the caption */
+ InflateRect(&rcCurrent, -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE,
+ -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE);
+
+ /* Draw the buttons */
+ ThemeDrawCaptionButton(pcontext, &rcCurrent, CLOSEBUTTON,
+ ThemeGetButtonState(HTCLOSE, htHot, htDown, pcontext->Active));
+ ThemeDrawCaptionButton(pcontext, &rcCurrent, MAXBUTTON,
+ ThemeGetButtonState(HTMAXBUTTON, htHot, htDown, pcontext->Active));
+ ThemeDrawCaptionButton(pcontext, &rcCurrent, MINBUTTON,
+ ThemeGetButtonState(HTMINBUTTON, htHot, htDown, pcontext->Active));
+ ThemeDrawCaptionButton(pcontext, &rcCurrent, HELPBUTTON,
+ ThemeGetButtonState(HTHELP, htHot, htDown, pcontext->Active));
+ }
+
+ /* Used from WM_NCPAINT and WM_NCACTIVATE handlers*/
+ static void
+ ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
+ {
+ RECT rcPart;
+ int iPart, iState;
+ HICON hIcon;
+ WCHAR *CaptionText;
+
+ hIcon = UserGetWindowIcon(pcontext->hWnd);
+ CaptionText = UserGetWindowCaption(pcontext->hWnd);
+
+ /* Get the caption part and state id */
+ if (pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW)
+ iPart = WP_SMALLCAPTION;
+ else if (pcontext->wi.dwStyle & WS_MAXIMIZE)
+ iPart = WP_MAXCAPTION;
+ else
+ iPart = WP_CAPTION;
+
+ iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
+
+ /* Draw the caption background*/
+ rcPart = *prcCurrent;
+ rcPart.bottom = pcontext->CaptionHeight;
+ prcCurrent->top = rcPart.bottom;
+ DrawThemeBackground(pcontext->theme, pcontext->hDC,iPart,iState,&rcPart,NULL);
+
+ /* Add a padding around the objects of the caption */
+ InflateRect(&rcPart, -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE,
+ -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE);
+
+ /* Draw the caption buttons */
+ if (pcontext->wi.dwStyle & WS_SYSMENU)
+ {
+ iState = pcontext->Active ? BUTTON_NORMAL : BUTTON_INACTIVE;
+
+ ThemeDrawCaptionButton(pcontext, &rcPart, CLOSEBUTTON, iState);
+ ThemeDrawCaptionButton(pcontext, &rcPart, MAXBUTTON, iState);
+ ThemeDrawCaptionButton(pcontext, &rcPart, MINBUTTON, iState);
+ ThemeDrawCaptionButton(pcontext, &rcPart, HELPBUTTON, iState);
+ }
+
+ rcPart.top += 3 ;
+
+ /* Draw the icon */
+ if(hIcon && !(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW))
+ {
+ int IconHeight = GetSystemMetrics(SM_CYSMICON);
+ int IconWidth = GetSystemMetrics(SM_CXSMICON);
+ DrawIconEx(pcontext->hDC, rcPart.left, rcPart.top , hIcon, IconWidth, IconHeight, 0, NULL, DI_NORMAL);
+ rcPart.left += IconWidth + 4;
+ }
+
+ rcPart.right -= 4;
+
+ /* Draw the caption */
+ if(CaptionText)
+ {
+ /*FIXME: Use DrawThemeTextEx*/
+ ThemeDrawCaptionText(pcontext->theme,
+ pcontext->hDC,
+ iPart,
+ iState,
+ CaptionText,
+ lstrlenW(CaptionText),
+ DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS,
+ 0,
+ &rcPart ,
+ pcontext->Active);
+ HeapFree(GetProcessHeap(), 0, CaptionText);
+ }
+ }
+
+ static void
+ ThemeDrawBorders(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
+ {
+ RECT rcPart;
+ int iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
+
+ /* Draw the bottom border */
+ rcPart = *prcCurrent;
+ rcPart.top = rcPart.bottom - pcontext->wi.cyWindowBorders;
+ prcCurrent->bottom = rcPart.top;
+ DrawThemeBackground(pcontext->theme, pcontext->hDC, WP_FRAMEBOTTOM, iState, &rcPart, NULL);
+
+ /* Draw the left border */
+ rcPart = *prcCurrent;
+ rcPart.right = pcontext->wi.cxWindowBorders ;
+ prcCurrent->left = rcPart.right;
+ DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMELEFT, iState, &rcPart, NULL);
+
+ /* Draw the right border */
+ rcPart = *prcCurrent;
+ rcPart.left = rcPart.right - pcontext->wi.cxWindowBorders;
+ prcCurrent->right = rcPart.left;
+ DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMERIGHT, iState, &rcPart, NULL);
+ }
+
+ static void
+ DrawClassicFrame(PDRAW_CONTEXT context, RECT* prcCurrent)
+ {
+ /* Draw outer edge */
+ if (UserHasWindowEdge(context->wi.dwStyle, context->wi.dwExStyle))
+ {
+ DrawEdge(context->hDC, prcCurrent, EDGE_RAISED, BF_RECT | BF_ADJUST);
+ }
+ else if (context->wi.dwExStyle & WS_EX_STATICEDGE)
+ {
+ DrawEdge(context->hDC, prcCurrent, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
+ }
+
+ /* Firstly the "thick" frame */
+ if ((context->wi.dwStyle & WS_THICKFRAME) && !(context->wi.dwStyle & WS_MINIMIZE))
+ {
+ INT Width =
+ (GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
+ GetSystemMetrics(SM_CXBORDER);
+ INT Height =
+ (GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
+ GetSystemMetrics(SM_CYBORDER);
+
+ SelectObject(context->hDC, GetSysColorBrush(
+ context->Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
+
+ /* Draw frame */
+ PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
+ prcCurrent->right - prcCurrent->left, Height, PATCOPY);
+ PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
+ Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
+ PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom,
+ prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
+ PatBlt(context->hDC, prcCurrent->right, prcCurrent->top,
+ -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
+
+ InflateRect(prcCurrent, -Width, -Height);
+ }
+
+ /* Now the other bit of the frame */
+ if (context->wi.dwStyle & (WS_DLGFRAME | WS_BORDER) || context->wi.dwExStyle & WS_EX_DLGMODALFRAME)
+ {
+ INT Width = GetSystemMetrics(SM_CXBORDER);
+ INT Height = GetSystemMetrics(SM_CYBORDER);
+
+ SelectObject(context->hDC, GetSysColorBrush(
+ (context->wi.dwExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
+ (context->wi.dwExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
+ (context->wi.dwStyle & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
+ COLOR_WINDOWFRAME));
+
+ /* Draw frame */
+ PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
+ prcCurrent->right - prcCurrent->left, Height, PATCOPY);
+ PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
+ Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
+ PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom,
+ prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
+ PatBlt(context->hDC, prcCurrent->right, prcCurrent->top,
+ -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
+
+ InflateRect(prcCurrent, -Width, -Height);
+ }
+
+ if (context->wi.dwExStyle & WS_EX_CLIENTEDGE)
+ {
+ DrawEdge(context->hDC, prcCurrent, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+ }
+ }
+
+ static void
+ ThemeDrawMenuItem(PDRAW_CONTEXT pcontext, HMENU Menu, int imenu)
+ {
+ PWCHAR Text;
+ BOOL flat_menu = FALSE;
+ MENUITEMINFOW Item;
+ RECT Rect,rcCalc;
+ WCHAR wstrItemText[20];
+ register int i = 0;
+ HFONT FontOld = NULL;
+ UINT uFormat = DT_CENTER | DT_VCENTER | DT_SINGLELINE;
+
+ Item.cbSize = sizeof(MENUITEMINFOW);
+ Item.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING;
+ Item.dwTypeData = wstrItemText;
+ Item.cch = 20;
+ if (!GetMenuItemInfoW(Menu, imenu, TRUE, &Item))
+ return;
+
+ if(Item.fType & MF_SEPARATOR)
+ return;
+
+ if(Item.cch >= 20)
+ {
+ Item.cch++;
+ Item.dwTypeData = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, Item.cch * sizeof(WCHAR));
+ Item.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING;
+ GetMenuItemInfoW(Menu, imenu, TRUE, &Item);
+ }
+
+ if(Item.cch == 0)
+ return;
+
+ flat_menu = GetThemeSysBool(pcontext->theme, TMT_FLATMENUS);
+
+ GetMenuItemRect(pcontext->hWnd, Menu, imenu, &Rect);
+
+ #ifdef __REACTOS__
+ OffsetRect(&Rect, -pcontext->wi.rcClient.left, -pcontext->wi.rcClient.top);
+ #else
+ OffsetRect(&Rect, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top);
+ #endif
+
+ SetBkColor(pcontext->hDC, GetSysColor(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
+ SetTextColor(pcontext->hDC, GetSysColor(Item.fState & MF_GRAYED ? COLOR_GRAYTEXT : COLOR_MENUTEXT));
+
+ if (0 != (Item.fState & MFS_DEFAULT))
+ {
+ FontOld = (HFONT)SelectObject(pcontext->hDC, hMenuFontBold);
+ }
+
+ Rect.left += MENU_BAR_ITEMS_SPACE / 2;
+ Rect.right -= MENU_BAR_ITEMS_SPACE / 2;
+
+ Text = (PWCHAR) Item.dwTypeData;
+ if(Text)
+ {
+ for (i = 0; L'\0' != Text[i]; i++)
+ {
+ if (L'\t' == Text[i] || L'\b' == Text[i])
+ {
+ break;
+ }
+ }
+ }
+
+ SetBkMode(pcontext->hDC, OPAQUE);
+
+ if (0 != (Item.fState & MF_GRAYED))
+ {
+ if (0 == (Item.fState & MF_HILITE))
+ {
+ ++Rect.left; ++Rect.top; ++Rect.right; ++Rect.bottom;
+ SetTextColor(pcontext->hDC, RGB(0xff, 0xff, 0xff));
+ DrawTextW(pcontext->hDC, Text, i, &Rect, uFormat);
+ --Rect.left; --Rect.top; --Rect.right; --Rect.bottom;
+ }
+ SetTextColor(pcontext->hDC, RGB(0x80, 0x80, 0x80));
+ SetBkMode(pcontext->hDC, TRANSPARENT);
+ }
+
+ DrawTextW(pcontext->hDC, Text, i, &Rect, uFormat);
+
+ /* Exclude from the clip region the area drawn by DrawText */
+ SetRect(&rcCalc, 0,0,0,0);
+ DrawTextW(pcontext->hDC, Text, i, &rcCalc, uFormat | DT_CALCRECT);
+ InflateRect( &Rect, 0, -(rcCalc.bottom+1)/2);
+ ExcludeClipRect(pcontext->hDC, Rect.left, Rect.top, Rect.right, Rect.bottom);
+
+ if (NULL != FontOld)
+ {
+ SelectObject(pcontext->hDC, FontOld);
+ }
+ }
+
+ void WINAPI
+ ThemeDrawMenuBar(PDRAW_CONTEXT pcontext, PRECT prcCurrent)
+ {
+ HMENU Menu;
+ MENUBARINFO MenuBarInfo;
+ int i;
+ HFONT FontOld = NULL;
+ BOOL flat_menu;
+ RECT Rect;
+ HPEN oldPen ;
+
+ if (!hMenuFont)
+ InitMenuFont();
+
+ flat_menu = GetThemeSysBool(pcontext->theme, TMT_FLATMENUS);
+
+ MenuBarInfo.cbSize = sizeof(MENUBARINFO);
+ if (! GetMenuBarInfo(pcontext->hWnd, OBJID_MENU, 0, &MenuBarInfo))
+ return;
+
+ Menu = GetMenu(pcontext->hWnd);
+ if (GetMenuItemCount(Menu) == 0)
+ return;
+
+ Rect = MenuBarInfo.rcBar;
+ OffsetRect(&Rect, -pcontext->wi.rcWindow.left, -pcontext->wi.rcWindow.top);
+
+ /* Draw a line under the menu*/
+ oldPen = (HPEN)SelectObject(pcontext->hDC, GetStockObject(DC_PEN));
+ SetDCPenColor(pcontext->hDC, GetSysColor(COLOR_3DFACE));
+ MoveToEx(pcontext->hDC, Rect.left, Rect.bottom, NULL);
+ LineTo(pcontext->hDC, Rect.right, Rect.bottom);
+ SelectObject(pcontext->hDC, oldPen);
+
+ /* Draw menu items */
+ FontOld = (HFONT)SelectObject(pcontext->hDC, hMenuFont);
+
+ for (i = 0; i < GetMenuItemCount(Menu); i++)
+ {
+ ThemeDrawMenuItem(pcontext, Menu, i);
+ }
+
+ SelectObject(pcontext->hDC, FontOld);
+
+ /* Fill the menu background area that isn't painted yet*/
+ FillRect(pcontext->hDC, &Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
+ }
+
+ static void
+ ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
+ {
+ if(!(pcontext->wi.dwStyle & WS_VISIBLE))
+ return;
+
+ if(pcontext->wi.dwStyle & WS_MINIMIZE)
+ {
+ ThemeDrawTitle(pcontext, prcCurrent);
+ return;
+ }
+
+ if((pcontext->wi.dwStyle & WS_CAPTION)==WS_CAPTION)
+ {
+ ThemeStartBufferedPaint(pcontext, prcCurrent->right, pcontext->CaptionHeight);
+ ThemeDrawCaption(pcontext, prcCurrent);
+ ThemeEndBufferedPaint(pcontext, 0, 0, prcCurrent->right, pcontext->CaptionHeight);
+ ThemeDrawBorders(pcontext, prcCurrent);
+ }
+ else
+ {
+ DrawClassicFrame(pcontext, prcCurrent);
+ }
+
+ if(HAS_MENU(pcontext->hWnd, pcontext->wi.dwStyle))
+ ThemeDrawMenuBar(pcontext, prcCurrent);
+
+ if(pcontext->wi.dwStyle & WS_HSCROLL)
+ ThemeDrawScrollBar(pcontext, SB_HORZ , NULL);
+
+ if(pcontext->wi.dwStyle & WS_VSCROLL)
+ ThemeDrawScrollBar(pcontext, SB_VERT, NULL);
+ }
+
+ /*
+ Message handlers
+ */
+
+ static LRESULT
+ ThemeHandleNCPaint(HWND hWnd, HRGN hRgn)
+ {
+ DRAW_CONTEXT context;
+ RECT rcCurrent;
+
+ ThemeInitDrawContext(&context, hWnd, hRgn);
+
+ rcCurrent = context.wi.rcWindow;
+ OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
+
+ ThemePaintWindow(&context, &rcCurrent);
+ ThemeCleanupDrawContext(&context);
+
+ return 0;
+ }
+
+ static LRESULT
+ ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
+ {
+ DRAW_CONTEXT context;
+ TRACKMOUSEEVENT tme;
+
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_QUERY;
+ tme.hwndTrack = hWnd;
+ TrackMouseEvent(&tme);
+ if (tme.dwFlags != (TME_LEAVE | TME_NONCLIENT))
+ {
+ tme.hwndTrack = hWnd;
+ tme.dwFlags = TME_LEAVE | TME_NONCLIENT;
+ TrackMouseEvent(&tme);
+ }
+
+ ThemeInitDrawContext(&context, hWnd, 0);
+ ThemeDrawCaptionButtons(&context, ht, 0);
+
+ if(context.wi.dwStyle & WS_HSCROLL)
+ ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL);
+
+ if(context.wi.dwStyle & WS_VSCROLL)
+ ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL);
+
+ ThemeCleanupDrawContext(&context);
+
+ return 0;
+ }
+
+ static LRESULT
+ ThemeHandleNcMouseLeave(HWND hWnd)
+ {
+ DRAW_CONTEXT context;
+
+ ThemeInitDrawContext(&context, hWnd, 0);
+ ThemeDrawCaptionButtons(&context, 0, 0);
+
+ if(context.wi.dwStyle & WS_HSCROLL)
+ ThemeDrawScrollBar(&context, SB_HORZ, NULL);
+
+ if(context.wi.dwStyle & WS_VSCROLL)
+ ThemeDrawScrollBar(&context, SB_VERT, NULL);
+
+ ThemeCleanupDrawContext(&context);
+
+ return 0;
+ }
+
+ static VOID
+ ThemeHandleButton(HWND hWnd, WPARAM wParam)
+ {
+ MSG Msg;
+ BOOL Pressed = TRUE, OldState;
+ WPARAM SCMsg, ht;
+ ULONG Style;
+ DRAW_CONTEXT context;
+
+ Style = GetWindowLongW(hWnd, GWL_STYLE);
+ switch (wParam)
+ {
+ case HTCLOSE:
+ if (!(Style & WS_SYSMENU))
+ return;
+ SCMsg = SC_CLOSE;
+ break;
+ case HTMINBUTTON:
+ if (!(Style & WS_MINIMIZEBOX))
+ return;
+ SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
+ break;
+ case HTMAXBUTTON:
+ if (!(Style & WS_MAXIMIZEBOX))
+ return;
+ SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
+ break;
+ default :
+ return;
+ }
+
+ ThemeInitDrawContext(&context, hWnd, 0);
+ ThemeDrawCaptionButtons(&context, 0, wParam);
+
+ SetCapture(hWnd);
+
+ for (;;)
+ {
+ if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
+ break;
+
+ if (Msg.message == WM_LBUTTONUP)
+ break;
+
+ if (Msg.message != WM_MOUSEMOVE)
+ continue;
+
+ OldState = Pressed;
+ ht = SendMessage(hWnd, WM_NCHITTEST, 0, MAKELPARAM(Msg.pt.x, Msg.pt.y));
+ Pressed = (ht == wParam);
+
+ ThemeDrawCaptionButtons(&context, 0, Pressed ? wParam: 0);
+ }
+
+ ThemeDrawCaptionButtons(&context, 0, 0);
+ ThemeCleanupDrawContext(&context);
+
+ ReleaseCapture();
+
+ if (Pressed)
+ SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, 0);
+ }
+
+
+ static LRESULT
+ DefWndNCHitTest(HWND hWnd, POINT Point)
+ {
+ RECT WindowRect;
+ POINT ClientPoint;
+ WINDOWINFO wi;
+
+ GetWindowInfo(hWnd, &wi);
+
+ if (!PtInRect(&wi.rcWindow, Point))
+ {
+ return HTNOWHERE;
+ }
+ WindowRect = wi.rcWindow;
+
+ if (UserHasWindowEdge(wi.dwStyle, wi.dwExStyle))
+ {
+ LONG XSize, YSize;
+
+ InflateRect(&WindowRect, -(int)wi.cxWindowBorders, -(int)wi.cyWindowBorders);
+ XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
+ YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
+ if (!PtInRect(&WindowRect, Point))
+ {
+ BOOL ThickFrame;
+
+ ThickFrame = (wi.dwStyle & WS_THICKFRAME);
+ if (Point.y < WindowRect.top)
+ {
+ if(wi.dwStyle & WS_MINIMIZE)
+ return HTCAPTION;
+ if(!ThickFrame)
+ return HTBORDER;
+ if (Point.x < (WindowRect.left + XSize))
+ return HTTOPLEFT;
+ if (Point.x >= (WindowRect.right - XSize))
+ return HTTOPRIGHT;
+ return HTTOP;
+ }
+ if (Point.y >= WindowRect.bottom)
+ {
+ if(wi.dwStyle & WS_MINIMIZE)
+ return HTCAPTION;
+ if(!ThickFrame)
+ return HTBORDER;
+ if (Point.x < (WindowRect.left + XSize))
+ return HTBOTTOMLEFT;
+ if (Point.x >= (WindowRect.right - XSize))
+ return HTBOTTOMRIGHT;
+ return HTBOTTOM;
+ }
+ if (Point.x < WindowRect.left)
+ {
+ if(wi.dwStyle & WS_MINIMIZE)
+ return HTCAPTION;
+ if(!ThickFrame)
+ return HTBORDER;
+ if (Point.y < (WindowRect.top + YSize))
+ return HTTOPLEFT;
+ if (Point.y >= (WindowRect.bottom - YSize))
+ return HTBOTTOMLEFT;
+ return HTLEFT;
+ }
+ if (Point.x >= WindowRect.right)
+ {
+ if(wi.dwStyle & WS_MINIMIZE)
+ return HTCAPTION;
+ if(!ThickFrame)
+ return HTBORDER;
+ if (Point.y < (WindowRect.top + YSize))
+ return HTTOPRIGHT;
+ if (Point.y >= (WindowRect.bottom - YSize))
+ return HTBOTTOMRIGHT;
+ return HTRIGHT;
+ }
+ }
+ }
+ else
+ {
+ if (wi.dwExStyle & WS_EX_STATICEDGE)
+ InflateRect(&WindowRect, -GetSystemMetrics(SM_CXBORDER),
+ -GetSystemMetrics(SM_CYBORDER));
+ if (!PtInRect(&WindowRect, Point))
+ return HTBORDER;
+ }
+
+ if ((wi.dwStyle & WS_CAPTION) == WS_CAPTION)
+ {
+ if (wi.dwExStyle & WS_EX_TOOLWINDOW)
+ WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
+ else
+ WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
+
+ if (!PtInRect(&WindowRect, Point))
+ {
+
+ INT ButtonWidth;
+
+ if (wi.dwExStyle & WS_EX_TOOLWINDOW)
+ ButtonWidth = GetSystemMetrics(SM_CXSMSIZE);
+ else
+ ButtonWidth = GetSystemMetrics(SM_CXSIZE);
+
+ ButtonWidth -= 4;
+ ButtonWidth+= BUTTON_GAP_SIZE;
+
+ if (wi.dwStyle & WS_SYSMENU)
+ {
+ if (wi.dwExStyle & WS_EX_TOOLWINDOW)
+ {
+ WindowRect.right -= ButtonWidth;
+ }
+ else
+ {
+ if(!(wi.dwExStyle & WS_EX_DLGMODALFRAME))
+ WindowRect.left += ButtonWidth;
+ WindowRect.right -= ButtonWidth;
+ }
+ }
+ if (Point.x < WindowRect.left)
+ return HTSYSMENU;
+ if (WindowRect.right <= Point.x)
+ return HTCLOSE;
+ if (wi.dwStyle & WS_MAXIMIZEBOX || wi.dwStyle & WS_MINIMIZEBOX)
+ WindowRect.right -= ButtonWidth;
+ if (Point.x >= WindowRect.right)
+ return HTMAXBUTTON;
+ if (wi.dwStyle & WS_MINIMIZEBOX)
+ WindowRect.right -= ButtonWidth;
+ if (Point.x >= WindowRect.right)
+ return HTMINBUTTON;
+ return HTCAPTION;
+ }
+ }
+
+ if(!(wi.dwStyle & WS_MINIMIZE))
+ {
+ HMENU menu;
+
+ ClientPoint = Point;
+ ScreenToClient(hWnd, &ClientPoint);
+ GetClientRect(hWnd, &wi.rcClient);
+
+ if (PtInRect(&wi.rcClient, ClientPoint))
+ {
+ return HTCLIENT;
+ }
+
+ if ((menu = GetMenu(hWnd)) && !(wi.dwStyle & WS_CHILD))
+ {
+ if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
+ return HTMENU;
+ }
+
+ if (wi.dwExStyle & WS_EX_CLIENTEDGE)
+ {
+ InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
+ -2 * GetSystemMetrics(SM_CYBORDER));
+ }
+
+ if ((wi.dwStyle & WS_VSCROLL) && (wi.dwStyle & WS_HSCROLL) &&
+ (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
+ {
+ RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
+ HWND Parent = GetParent(hWnd);
+
+ TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
+ if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+ TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
+ else
+ TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
+ if (PtInRect(&TempRect, Point))
+ return HTVSCROLL;
+
+ TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
+ if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+ TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
+ else
+ TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
+ if (PtInRect(&TempRect2, Point))
+ return HTHSCROLL;
+
+ TempRect.top = TempRect2.top;
+ TempRect.bottom = TempRect2.bottom;
+ if(Parent)
+ GetClientRect(Parent, &ParentRect);
+ if (PtInRect(&TempRect, Point) && HASSIZEGRIP(wi.dwStyle, wi.dwExStyle,
+ GetWindowLongW(Parent, GWL_STYLE), wi.rcWindow, ParentRect))
+ {
+ if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+ return HTBOTTOMLEFT;
+ else
+ return HTBOTTOMRIGHT;
+ }
+ }
+ else
+ {
+ if (wi.dwStyle & WS_VSCROLL)
+ {
+ RECT TempRect = WindowRect;
+
+ if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
+ TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
+ else
+ TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
+ if (PtInRect(&TempRect, Point))
+ return HTVSCROLL;
+ }
+ else if (wi.dwStyle & WS_HSCROLL)
+ {
+ RECT TempRect = WindowRect;
+ TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
+ if (PtInRect(&TempRect, Point))
+ return HTHSCROLL;
+ }
+ }
+ }
+
+ return HTNOWHERE;
+ }
+
+ LRESULT CALLBACK
+ ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndProc)
+ {
+ switch(Msg)
+ {
+ case WM_NCPAINT:
+ return ThemeHandleNCPaint(hWnd, (HRGN)wParam);
+ case WM_NCACTIVATE:
+ ThemeHandleNCPaint(hWnd, (HRGN)1);
+ return TRUE;
+ case WM_NCMOUSEMOVE:
+ {
+ POINT Point;
+ Point.x = GET_X_LPARAM(lParam);
+ Point.y = GET_Y_LPARAM(lParam);
+ return ThemeHandleNcMouseMove(hWnd, wParam, &Point);
+ }
+ case WM_NCMOUSELEAVE:
+ return ThemeHandleNcMouseLeave(hWnd);
+ case WM_NCLBUTTONDOWN:
+ switch (wParam)
+ {
+ case HTMINBUTTON:
+ case HTMAXBUTTON:
+ case HTCLOSE:
+ {
+ ThemeHandleButton(hWnd, wParam);
+ return 0;
+ }
+ default:
+ return DefWndProc(hWnd, Msg, wParam, lParam);
+ }
+ case WM_NCHITTEST:
+ {
+ POINT Point;
+ Point.x = GET_X_LPARAM(lParam);
+ Point.y = GET_Y_LPARAM(lParam);
+ return DefWndNCHitTest(hWnd, Point);
+ }
+ case WM_SYSCOMMAND:
+ {
+ if((wParam & 0xfff0) == SC_VSCROLL ||
+ (wParam & 0xfff0) == SC_HSCROLL)
+ {
+ POINT Pt;
+ Pt.x = (short)LOWORD(lParam);
+ Pt.y = (short)HIWORD(lParam);
+ NC_TrackScrollBar(hWnd, wParam, Pt);
+ }
+ else
+ {
+ return DefWndProc(hWnd, Msg, wParam, lParam);
+ }
+ }
+ case WM_NCUAHDRAWCAPTION:
+ case WM_NCUAHDRAWFRAME:
+ /* FIXME: how should these be handled? */
+ return 0;
+ default:
+ return DefWndProc(hWnd, Msg, wParam, lParam);
+ }
+ }
#include "vfwmsgs.h"
#include "uxtheme.h"
#include "tmschema.h"
+ #include "uxundoc.h"
#include "uxthemedll.h"
#include "msstyles.h"
+ #include "ncthm.h"
#include "wine/debug.h"
ATOM atDialogThemeEnabled;
static DWORD dwThemeAppProperties = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS;
- static ATOM atWindowTheme;
+ ATOM atWindowTheme;
static ATOM atSubAppName;
static ATOM atSubIdList;
+ ATOM atWndContrext;
static BOOL bThemeActive = FALSE;
static WCHAR szCurrentTheme[MAX_PATH];
}
/* Broadcast a message to *all* windows, including children */
- static BOOL CALLBACK UXTHEME_broadcast_msg (HWND hWnd, LPARAM msg)
+ BOOL CALLBACK UXTHEME_broadcast_msg (HWND hWnd, LPARAM msg)
{
if (hWnd == NULL)
{
}
}
- RegCloseKey(hKey);
return dwRet;
}
*
* Set the current active theme from the registry
*/
- static void UXTHEME_LoadTheme(void)
+ void UXTHEME_LoadTheme(BOOL bLoad)
{
HKEY hKey;
DWORD buffsize;
WCHAR tmp[10];
PTHEME_FILE pt;
- /* Get current theme configuration */
- if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
- TRACE("Loading theme config\n");
- buffsize = sizeof(tmp)/sizeof(tmp[0]);
- if(!RegQueryValueExW(hKey, szThemeActive, NULL, NULL, (LPBYTE)tmp, &buffsize)) {
- bThemeActive = (tmp[0] != '0');
- }
- else {
- bThemeActive = FALSE;
- TRACE("Failed to get ThemeActive: %d\n", GetLastError());
+ if(bLoad == TRUE)
+ {
+ /* Get current theme configuration */
+ if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
+ TRACE("Loading theme config\n");
+ buffsize = sizeof(tmp)/sizeof(tmp[0]);
+ if(!RegQueryValueExW(hKey, szThemeActive, NULL, NULL, (LPBYTE)tmp, &buffsize)) {
+ bThemeActive = (tmp[0] != '0');
+ }
+ else {
+ bThemeActive = FALSE;
+ TRACE("Failed to get ThemeActive: %d\n", GetLastError());
+ }
+ buffsize = sizeof(szCurrentColor)/sizeof(szCurrentColor[0]);
+ if(RegQueryValueExW(hKey, szColorName, NULL, NULL, (LPBYTE)szCurrentColor, &buffsize))
+ szCurrentColor[0] = '\0';
+ buffsize = sizeof(szCurrentSize)/sizeof(szCurrentSize[0]);
+ if(RegQueryValueExW(hKey, szSizeName, NULL, NULL, (LPBYTE)szCurrentSize, &buffsize))
+ szCurrentSize[0] = '\0';
+ if (query_reg_path (hKey, szDllName, szCurrentTheme))
+ szCurrentTheme[0] = '\0';
+ RegCloseKey(hKey);
}
- buffsize = sizeof(szCurrentColor)/sizeof(szCurrentColor[0]);
- if(RegQueryValueExW(hKey, szColorName, NULL, NULL, (LPBYTE)szCurrentColor, &buffsize))
- szCurrentColor[0] = '\0';
- buffsize = sizeof(szCurrentSize)/sizeof(szCurrentSize[0]);
- if(RegQueryValueExW(hKey, szSizeName, NULL, NULL, (LPBYTE)szCurrentSize, &buffsize))
- szCurrentSize[0] = '\0';
- if (query_reg_path (hKey, szDllName, szCurrentTheme))
- szCurrentTheme[0] = '\0';
- RegCloseKey(hKey);
+ else
+ TRACE("Failed to open theme registry key\n");
}
else
- TRACE("Failed to open theme registry key\n");
+ {
+ bThemeActive = FALSE;
+ }
if(bThemeActive) {
/* Make sure the theme requested is actually valid */
atSubAppName = GlobalAddAtomW(szSubAppName);
atSubIdList = GlobalAddAtomW(szSubIdList);
atDialogThemeEnabled = GlobalAddAtomW(szDialogThemeEnabled);
-
- UXTHEME_LoadTheme();
+ atWndContrext = GlobalAddAtomW(L"ux_WndContext");
}
/***********************************************************************
* Success: S_OK
* Failure: HRESULT error-code
*/
- HRESULT WINAPI EnumThemes(LPCWSTR pszThemePath, EnumThemeProc callback,
+ HRESULT WINAPI EnumThemes(LPCWSTR pszThemePath, ENUMTHEMEPROC callback,
LPVOID lpData)
{
WCHAR szDir[MAX_PATH];
* any other purpose
*/
HRESULT WINAPI ParseThemeIniFile(LPCWSTR pszIniFileName, LPWSTR pszUnknown,
- ParseThemeIniFileProc callback, LPVOID lpData)
+ PARSETHEMEINIFILEPROC callback, LPVOID lpData)
{
FIXME("%s %s: stub\n", debugstr_w(pszIniFileName), debugstr_w(pszUnknown));
return ERROR_CALL_NOT_IMPLEMENTED;
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS uxtheme.dll
+ * FILE: dll/win32/uxtheme/themehooks.c
+ * PURPOSE: uxtheme user api hook functions
+ * PROGRAMMER: Giannis Adamopoulos
+ */
+
+ #include <windows.h>
+ #include <undocuser.h>
+
+ #include "vfwmsgs.h"
+ #include "uxtheme.h"
+ #include "uxthemedll.h"
+ #include "ncthm.h"
+ #include "tmschema.h"
+
+ #include "wine/debug.h"
+
+ WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
+
+
+
+ extern HINSTANCE hDllInst;
+
+ LRESULT CALLBACK ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndProc);
+
+ USERAPIHOOK user32ApiHook;
+ BYTE gabDWPmessages[UAHOWP_MAX_SIZE];
+ BYTE gabMSGPmessages[UAHOWP_MAX_SIZE];
+
+
+ PWND_CONTEXT ThemeGetWndContext(HWND hWnd)
+ {
+ PWND_CONTEXT pcontext;
+
+ pcontext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext));
+ if(pcontext == NULL)
+ {
+ pcontext = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(WND_CONTEXT));
+ if(pcontext == NULL)
+ {
+ return NULL;
+ }
+
+ SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext), pcontext);
+ }
+
+ return pcontext;
+ }
+
+ void ThemeDetroyWndContext(HWND hWnd)
+ {
+ PWND_CONTEXT pContext;
+ DWORD ProcessId;
+
+ /*Do not destroy WND_CONTEXT of a window that belong to another process */
+ GetWindowThreadProcessId(hWnd, &ProcessId);
+ if(ProcessId != GetCurrentProcessId())
+ {
+ return;
+ }
+
+ pContext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext));
+ if(pContext == NULL)
+ {
+ return;
+ }
+
+ if(pContext->HasThemeRgn)
+ {
+ user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
+ }
+
+ HeapFree(GetProcessHeap(), 0, pContext);
+
+ SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext), NULL);
+ }
+
+ static BOOL CALLBACK ThemeCleanupChildWndContext (HWND hWnd, LPARAM msg)
+ {
+ ThemeDetroyWndContext(hWnd);
+ return TRUE;
+ }
+
+ static BOOL CALLBACK ThemeCleanupWndContext(HWND hWnd, LPARAM msg)
+ {
+ if (hWnd == NULL)
+ {
+ EnumWindows (ThemeCleanupWndContext, 0);
+ }
+ else
+ {
+ ThemeDetroyWndContext(hWnd);
+ EnumChildWindows (hWnd, ThemeCleanupChildWndContext, 0);
+ }
+
+ return TRUE;
+ }
+
+ void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
+ {
+ HTHEME hTheme;
+ RECT rcWindow;
+ HRGN hrgn, hrgn1;
+ int CaptionHeight, iPart;
+ WINDOWINFO wi;
+
+ if(!IsAppThemed())
+ {
+ if(pcontext->HasThemeRgn)
+ {
+ pcontext->HasThemeRgn = FALSE;
+ user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
+ }
+ return;
+ }
+
+ wi.cbSize = sizeof(wi);
+
+ GetWindowInfo(hWnd, &wi);
+
+ if((wi.dwStyle & WS_CAPTION)!=WS_CAPTION)
+ {
+ return;
+ }
+
+ /* Get the caption part id */
+ if (wi.dwExStyle & WS_EX_TOOLWINDOW)
+ iPart = WP_SMALLCAPTION;
+ else if (wi.dwStyle & WS_MAXIMIZE)
+ iPart = WP_MAXCAPTION;
+ else
+ iPart = WP_CAPTION;
+
+ pcontext->HasThemeRgn = TRUE;
+
+ CaptionHeight = wi.cyWindowBorders;
+ CaptionHeight += GetSystemMetrics(wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
+
+ GetWindowRect(hWnd, &rcWindow);
+ rcWindow.right -= rcWindow.left;
+ rcWindow.bottom = CaptionHeight;
+ rcWindow.top = 0;
+ rcWindow.left = 0;
+
+ hTheme = OpenThemeData (hWnd, L"WINDOW");
+
+ GetThemeBackgroundRegion(hTheme, 0, iPart, FS_ACTIVE, &rcWindow, &hrgn);
+
+ CloseThemeData(hTheme);
+
+ GetWindowRect(hWnd, &rcWindow);
+ rcWindow.right -= rcWindow.left;
+ rcWindow.bottom -= rcWindow.top;
+ rcWindow.top = CaptionHeight;
+ rcWindow.left = 0;
+ hrgn1 = CreateRectRgnIndirect(&rcWindow);
+
+ CombineRgn(hrgn, hrgn, hrgn1, RGN_OR );
+
+ DeleteObject(hrgn1);
+
+ user32ApiHook.SetWindowRgn(hWnd, hrgn, TRUE);
+ }
+
+ int OnPostWinPosChanged(HWND hWnd)
+ {
+ PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
+
+ if(pcontext &&
+ pcontext->HasAppDefinedRgn == FALSE &&
+ pcontext->UpdatingRgn == FALSE)
+ {
+ pcontext->UpdatingRgn = TRUE;
+ SetThemeRegion(hWnd, pcontext);
+ pcontext = ThemeGetWndContext(hWnd);
+ pcontext->UpdatingRgn = FALSE;
+ }
+ return 0;
+ }
+
+ /**********************************************************************
+ * Hook Functions
+ */
+
+ static LRESULT CALLBACK
+ ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+ {
+ if(!IsThemeActive())
+ {
+ return user32ApiHook.DefWindowProcW(hWnd,
+ Msg,
+ wParam,
+ lParam);
+ }
+
+ return ThemeWndProc(hWnd,
+ Msg,
+ wParam,
+ lParam,
+ user32ApiHook.DefWindowProcW);
+ }
+
+ static LRESULT CALLBACK
+ ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+ {
+ if(!IsThemeActive())
+ {
+ return user32ApiHook.DefWindowProcA(hWnd,
+ Msg,
+ wParam,
+ lParam);
+ }
+
+ return ThemeWndProc(hWnd,
+ Msg,
+ wParam,
+ lParam,
+ user32ApiHook.DefWindowProcA);
+ }
+
+ static LRESULT CALLBACK
+ ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
+ {
+ switch(Msg)
+ {
+ case WM_THEMECHANGED:
+ UXTHEME_LoadTheme(TRUE);
+ return 0;
+ }
+
+ return 0;
+ }
+
+
+ static LRESULT CALLBACK
+ ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
+ {
+ switch(Msg)
+ {
+ case WM_WINDOWPOSCHANGED:
+ {
+ return OnPostWinPosChanged(hWnd);
+ }
+ case WM_DESTROY:
+ {
+ ThemeDetroyWndContext(hWnd);
+ return 0;
+ }
+ }
+
+ return 0;
+ }
+
+ int WINAPI ThemeSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
+ {
+ PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
+ if(pcontext)
+ {
+ pcontext->HasAppDefinedRgn = TRUE;
+ pcontext->HasThemeRgn = FALSE;
+ }
+
+ return user32ApiHook.SetWindowRgn(hWnd, hRgn, bRedraw);
+ }
+
+ /**********************************************************************
+ * Exports
+ */
+
+ BOOL CALLBACK
+ ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
+ {
+ /* Sanity checks for the caller */
+ if (!puah || State != uahLoadInit)
+ {
+ UXTHEME_LoadTheme(FALSE);
+ ThemeCleanupWndContext(NULL, 0);
+ return TRUE;
+ }
+
+ /* Store the original functions from user32 */
+ user32ApiHook = *puah;
+
+ puah->DefWindowProcA = ThemeDefWindowProcA;
+ puah->DefWindowProcW = ThemeDefWindowProcW;
+ puah->PreWndProc = ThemePreWindowProc;
+ puah->PostWndProc = ThemePostWindowProc;
+ puah->PreDefDlgProc = ThemePreWindowProc;
+ puah->PostDefDlgProc = ThemePostWindowProc;
+ puah->DefWndProcArray.MsgBitArray = gabDWPmessages;
+ puah->DefWndProcArray.Size = UAHOWP_MAX_SIZE;
+ puah->WndProcArray.MsgBitArray = gabMSGPmessages;
+ puah->WndProcArray.Size = UAHOWP_MAX_SIZE;
+ puah->DlgProcArray.MsgBitArray = gabMSGPmessages;
+ puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
+
+ puah->SetWindowRgn = ThemeSetWindowRgn;
+
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCPAINT);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCACTIVATE);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSEMOVE);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSELEAVE);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCHITTEST);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCLBUTTONDOWN);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWCAPTION);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWFRAME);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETTEXT);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_WINDOWPOSCHANGED);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CONTEXTMENU);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_STYLECHANGED);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETICON);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCDESTROY);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SYSCOMMAND);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORMSGBOX);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORBTN);
+ UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORSTATIC);
+
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_CREATE);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_SETTINGCHANGE);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_DRAWITEM);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MEASUREITEM);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGING);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGED);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGING);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGED);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCCREATE);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCDESTROY);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCPAINT);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MENUCHAR);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MDISETMENU);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED);
+ UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT);
+
+ UXTHEME_LoadTheme(TRUE);
+
+ return TRUE;
+ }
+
+ typedef BOOL (WINAPI * PREGISTER_UAH_WINXP)(HINSTANCE hInstance, USERAPIHOOKPROC CallbackFunc);
+ typedef BOOL (WINAPI * PREGISTER_UUAH_WIN2003)(PUSERAPIHOOKINFO puah);
+
+ BOOL WINAPI
+ ThemeHooksInstall()
+ {
+ PVOID lpFunc;
+ OSVERSIONINFO osvi;
+ BOOL ret;
+
+ lpFunc = GetProcAddress(GetModuleHandle("user32.dll"), "RegisterUserApiHook");
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+
+ if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
+ {
+ PREGISTER_UAH_WINXP lpfuncxp = (PREGISTER_UAH_WINXP)lpFunc;
+ ret = lpfuncxp(hDllInst, ThemeInitApiHook);
+ }
+ else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
+ {
+ PREGISTER_UUAH_WIN2003 lpfunc2003 = (PREGISTER_UUAH_WIN2003)lpFunc;
+ USERAPIHOOKINFO uah;
+
+ uah.m_size = sizeof(uah);
+ uah.m_dllname1 = L"uxtheme.dll";
+ uah.m_funname1 = L"ThemeInitApiHook";
+ uah.m_dllname2 = NULL;
+ uah.m_funname2 = NULL;
+
+ ret = lpfunc2003(&uah);
+ }
+ else
+ {
+ UNIMPLEMENTED;
+ ret = FALSE;
+ }
+
+ UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
+
+ return ret;
+ }
+
+ BOOL WINAPI
+ ThemeHooksRemove()
+ {
+ BOOL ret;
+
+ ret = UnregisterUserApiHook();
+
+ UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
+
+ return ret;
+ }
<file>main.c</file>
<file>metric.c</file>
<file>msstyles.c</file>
+ <file>ncscrollbar.c</file>
+ <file>nonclient.c</file>
<file>property.c</file>
<file>stylemap.c</file>
<file>system.c</file>
+ <file>themehooks.c</file>
<file>uxini.c</file>
<file>version.rc</file>
<library>wine</library>
31 stub -noname InitUserTheme
32 stub -noname InitUserRegistry
33 stub -noname ReestablishServerConnection
- 34 stub -noname ThemeHooksInstall
- 35 stub -noname ThemeHooksRemove
+ 34 stdcall -noname ThemeHooksInstall()
+ 35 stdcall -noname ThemeHooksRemove()
36 stub -noname RefreshThemeForTS
43 stub -noname ClassicGetSystemMetrics
44 stub -noname ClassicSystemParametersInfoA
@ stdcall OpenThemeData(ptr wstr)
@ stdcall SetThemeAppProperties(long)
@ stdcall SetWindowTheme(ptr wstr wstr)
+ @ stdcall ThemeInitApiHook(long ptr)
#ifndef __WINE_UXTHEMEDLL_H
#define __WINE_UXTHEMEDLL_H
- typedef HANDLE HTHEMEFILE;
-
- /**********************************************************************
- * EnumThemeProc
- *
- * Callback function for EnumThemes.
- *
- * RETURNS
- * TRUE to continue enumeration, FALSE to stop
- *
- * PARAMS
- * lpReserved Always 0
- * pszThemeFileName Full path to theme msstyles file
- * pszThemeName Display name for theme
- * pszToolTip Tooltip name for theme
- * lpReserved2 Always 0
- * lpData Value passed through lpData from EnumThemes
- */
- typedef BOOL (CALLBACK *EnumThemeProc)(LPVOID lpReserved, LPCWSTR pszThemeFileName,
- LPCWSTR pszThemeName, LPCWSTR pszToolTip, LPVOID lpReserved2,
- LPVOID lpData);
-
- /**********************************************************************
- * ParseThemeIniFileProc
- *
- * Callback function for ParseThemeIniFile.
- *
- * RETURNS
- * TRUE to continue enumeration, FALSE to stop
- *
- * PARAMS
- * dwType Entry type
- * pszParam1 Use defined by entry type
- * pszParam2 Use defined by entry type
- * pszParam3 Use defined by entry type
- * dwParam Use defined by entry type
- * lpData Value passed through lpData from ParseThemeIniFile
- *
- * NOTES
- * I don't know what the valid entry types are
- */
- typedef BOOL (CALLBACK*ParseThemeIniFileProc)(DWORD dwType, LPWSTR pszParam1,
- LPWSTR pszParam2, LPWSTR pszParam3,
- DWORD dwParam, LPVOID lpData);
-
- /* Structure filled in by EnumThemeColors() and EnumeThemeSizes() with the
- * various strings for a theme color or size. */
- typedef struct tagTHEMENAMES
- {
- WCHAR szName[MAX_PATH+1];
- WCHAR szDisplayName[MAX_PATH+1];
- WCHAR szTooltip[MAX_PATH+1];
- } THEMENAMES, *PTHEMENAMES;
-
- /* Declarations for undocumented functions for use internally */
- DWORD WINAPI QueryThemeServices(void);
- HRESULT WINAPI OpenThemeFile(LPCWSTR pszThemeFileName, LPCWSTR pszColorName,
- LPCWSTR pszSizeName, HTHEMEFILE *hThemeFile,
- DWORD unknown);
- HRESULT WINAPI CloseThemeFile(HTHEMEFILE hThemeFile);
- HRESULT WINAPI ApplyTheme(HTHEMEFILE hThemeFile, char *unknown, HWND hWnd);
- HRESULT WINAPI GetThemeDefaults(LPCWSTR pszThemeFileName, LPWSTR pszColorName,
- DWORD dwColorNameLen, LPWSTR pszSizeName,
- DWORD dwSizeNameLen);
- HRESULT WINAPI EnumThemes(LPCWSTR pszThemePath, EnumThemeProc callback,
- LPVOID lpData);
- HRESULT WINAPI EnumThemeColors(LPWSTR pszThemeFileName, LPWSTR pszSizeName,
- DWORD dwColorNum, PTHEMENAMES pszColorNames);
- HRESULT WINAPI EnumThemeSizes(LPWSTR pszThemeFileName, LPWSTR pszColorName,
- DWORD dwSizeNum, PTHEMENAMES pszColorNames);
- HRESULT WINAPI ParseThemeIniFile(LPCWSTR pszIniFileName, LPWSTR pszUnknown,
- ParseThemeIniFileProc callback, LPVOID lpData);
-
extern void UXTHEME_InitSystem(HINSTANCE hInst);
+ extern void UXTHEME_LoadTheme(BOOL bLoad);
+ extern BOOL CALLBACK UXTHEME_broadcast_msg (HWND hWnd, LPARAM msg);
/* No alpha blending */
#define ALPHABLEND_NONE 0