diff --git a/reactos/dll/win32/uxtheme/CMakeLists.txt b/reactos/dll/win32/uxtheme/CMakeLists.txt index 8d7631fdbdb..ff0b7108459 100644 --- a/reactos/dll/win32/uxtheme/CMakeLists.txt +++ b/reactos/dll/win32/uxtheme/CMakeLists.txt @@ -11,9 +11,12 @@ list(APPEND SOURCE 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 diff --git a/reactos/dll/win32/uxtheme/draw.c b/reactos/dll/win32/uxtheme/draw.c index 17900f8352b..0949cf64617 100644 --- a/reactos/dll/win32/uxtheme/draw.c +++ b/reactos/dll/win32/uxtheme/draw.c @@ -1731,6 +1731,166 @@ HRESULT WINAPI GetThemeBackgroundExtent(HTHEME hTheme, HDC hdc, int iPartId, 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(ybottom) + { + x=0; + /* Scan each pixel */ + while (xright) + { + /* 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 (xright) + { + 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.@) * @@ -1752,8 +1912,7 @@ HRESULT WINAPI GetThemeBackgroundRegion(HTHEME hTheme, HDC hdc, int iPartId, 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); diff --git a/reactos/dll/win32/uxtheme/msstyles.c b/reactos/dll/win32/uxtheme/msstyles.c index 0adb70d529a..d21700ac2da 100644 --- a/reactos/dll/win32/uxtheme/msstyles.c +++ b/reactos/dll/win32/uxtheme/msstyles.c @@ -1257,6 +1257,13 @@ static HRESULT MSSTYLES_GetFont (LPCWSTR lpCur, LPCWSTR lpEnd, *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; @@ -1278,8 +1285,6 @@ HRESULT MSSTYLES_GetPropertyFont(PTHEME_PROPERTY tp, HDC hdc, LOGFONTW *pFont) 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; } diff --git a/reactos/dll/win32/uxtheme/ncscrollbar.c b/reactos/dll/win32/uxtheme/ncscrollbar.c new file mode 100644 index 00000000000..f8f729fd73c --- /dev/null +++ b/reactos/dll/win32/uxtheme/ncscrollbar.c @@ -0,0 +1,676 @@ +/* + * 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 +#include "undocuser.h" +#include "vfwmsgs.h" +#include "uxtheme.h" +#include +#include +#include "ncthm.h" +#include +#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 ); +} diff --git a/reactos/dll/win32/uxtheme/ncthm.h b/reactos/dll/win32/uxtheme/ncthm.h new file mode 100644 index 00000000000..4b9e76bf5a9 --- /dev/null +++ b/reactos/dll/win32/uxtheme/ncthm.h @@ -0,0 +1,106 @@ + +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; + diff --git a/reactos/dll/win32/uxtheme/nonclient.c b/reactos/dll/win32/uxtheme/nonclient.c new file mode 100644 index 00000000000..ffcbb36d61d --- /dev/null +++ b/reactos/dll/win32/uxtheme/nonclient.c @@ -0,0 +1,1088 @@ +/* + * 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 +#include +#include "undocuser.h" +#include "vfwmsgs.h" +#include "uxtheme.h" +#include +#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); + } +} diff --git a/reactos/dll/win32/uxtheme/system.c b/reactos/dll/win32/uxtheme/system.c index b84e978dba8..6cb934f6795 100644 --- a/reactos/dll/win32/uxtheme/system.c +++ b/reactos/dll/win32/uxtheme/system.c @@ -31,9 +31,11 @@ #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" @@ -61,9 +63,10 @@ HINSTANCE hDllInst; 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]; @@ -79,7 +82,7 @@ static BOOL CALLBACK UXTHEME_broadcast_msg_enumchild (HWND hWnd, LPARAM msg) } /* 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) { @@ -140,7 +143,6 @@ static DWORD query_reg_path (HKEY hKey, LPCWSTR lpszValue, } } - RegCloseKey(hKey); return dwRet; } @@ -149,7 +151,7 @@ static DWORD query_reg_path (HKEY hKey, LPCWSTR lpszValue, * * Set the current active theme from the registry */ -static void UXTHEME_LoadTheme(void) +void UXTHEME_LoadTheme(BOOL bLoad) { HKEY hKey; DWORD buffsize; @@ -157,29 +159,36 @@ static void UXTHEME_LoadTheme(void) 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'); + 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); } - 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); + 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 */ @@ -543,8 +552,7 @@ void UXTHEME_InitSystem(HINSTANCE hInst) atSubAppName = GlobalAddAtomW(szSubAppName); atSubIdList = GlobalAddAtomW(szSubIdList); atDialogThemeEnabled = GlobalAddAtomW(szDialogThemeEnabled); - - UXTHEME_LoadTheme(); + atWndContrext = GlobalAddAtomW(L"ux_WndContext"); } /*********************************************************************** @@ -973,7 +981,7 @@ HRESULT WINAPI GetThemeDefaults(LPCWSTR pszThemeFileName, LPWSTR pszColorName, * 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]; @@ -1171,7 +1179,7 @@ HRESULT WINAPI EnumThemeSizes(LPWSTR pszThemeFileName, LPWSTR pszColorName, * 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; diff --git a/reactos/dll/win32/uxtheme/themehooks.c b/reactos/dll/win32/uxtheme/themehooks.c new file mode 100644 index 00000000000..94df23a4418 --- /dev/null +++ b/reactos/dll/win32/uxtheme/themehooks.c @@ -0,0 +1,398 @@ +/* + * 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 +#include + +#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; +} \ No newline at end of file diff --git a/reactos/dll/win32/uxtheme/uxtheme.rbuild b/reactos/dll/win32/uxtheme/uxtheme.rbuild index 7e4c4dcfce5..723f14b618b 100644 --- a/reactos/dll/win32/uxtheme/uxtheme.rbuild +++ b/reactos/dll/win32/uxtheme/uxtheme.rbuild @@ -11,9 +11,12 @@ main.c metric.c msstyles.c + ncscrollbar.c + nonclient.c property.c stylemap.c system.c + themehooks.c uxini.c version.rc wine diff --git a/reactos/dll/win32/uxtheme/uxtheme.spec b/reactos/dll/win32/uxtheme/uxtheme.spec index 2646a150869..01f3608417b 100644 --- a/reactos/dll/win32/uxtheme/uxtheme.spec +++ b/reactos/dll/win32/uxtheme/uxtheme.spec @@ -29,8 +29,8 @@ 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 @@ -95,3 +95,4 @@ @ stdcall OpenThemeData(ptr wstr) @ stdcall SetThemeAppProperties(long) @ stdcall SetWindowTheme(ptr wstr wstr) +@ stdcall ThemeInitApiHook(long ptr) diff --git a/reactos/dll/win32/uxtheme/uxthemedll.h b/reactos/dll/win32/uxtheme/uxthemedll.h index ed37e725ff6..e55d98fb401 100644 --- a/reactos/dll/win32/uxtheme/uxthemedll.h +++ b/reactos/dll/win32/uxtheme/uxthemedll.h @@ -21,80 +21,9 @@ #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