From 4abbb3fed6fb5ae71ca92f64522fffd2bc1220d5 Mon Sep 17 00:00:00 2001 From: dmex Date: Mon, 8 Apr 2013 18:16:56 +0000 Subject: [PATCH] Toolstatus: fixed searchbox subclass git-svn-id: svn://svn.code.sf.net/p/processhacker/code@5290 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- 2.x/trunk/plugins/ToolStatus/searchbox.c | 339 +++++++++++++++-------- 1 file changed, 220 insertions(+), 119 deletions(-) diff --git a/2.x/trunk/plugins/ToolStatus/searchbox.c b/2.x/trunk/plugins/ToolStatus/searchbox.c index 0d5a87637..1960143ea 100644 --- a/2.x/trunk/plugins/ToolStatus/searchbox.c +++ b/2.x/trunk/plugins/ToolStatus/searchbox.c @@ -1,24 +1,24 @@ /* - * Process Hacker - - * Subclassed Edit control - * - * Copyright (C) 2012-2013 dmex - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ +* Process Hacker - +* Subclassed Edit control +* +* Copyright (C) 2012-2013 dmex +* +* This file is part of Process Hacker. +* +* Process Hacker is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* Process Hacker is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Process Hacker. If not, see . +*/ // dmex: The non-client area subclassing code has been modified based on the following guide: // http://www.catch22.net/tuts/insert-buttons-edit-control @@ -28,8 +28,11 @@ #include #include +#include #pragma comment(lib, "uxtheme.lib") +#define HRGN_FULL ((HRGN)1) // passed by WM_NCPAINT even though it's completely undocumented + typedef struct _NC_CONTROL { UINT CommandID; // sent in a WM_COMMAND message @@ -46,15 +49,14 @@ typedef struct _NC_CONTROL RECT rect; RECT oldrect; RECT* prect; - + HBRUSH BorderBrush; HBRUSH DcBrush; HTHEME WndHTheme; HIMAGELIST ImageList; HWND ParentWindow; - WNDPROC NCAreaWndProc; } NC_CONTROL; - + static VOID GetButtonRect( __inout NC_CONTROL* nc, __in RECT* rect @@ -92,7 +94,7 @@ static VOID DrawInsertedButton( 0, 0, CLR_NONE, CLR_NONE, - ILD_NORMAL | ILD_TRANSPARENT | ILD_SCALE + ILD_NORMAL | ILD_SCALE ); } else @@ -106,21 +108,118 @@ static VOID DrawInsertedButton( 0, 0, CLR_NONE, CLR_NONE, - ILD_NORMAL | ILD_TRANSPARENT | ILD_SCALE + ILD_NORMAL | ILD_SCALE ); } } +VOID PhTnpDrawThemedBorder( + __in HWND hwnd, + __in NC_CONTROL* Context, + __in HDC hdc + ) +{ + RECT windowRect; + RECT clientRect; + LONG sizingBorderWidth; + LONG borderX; + LONG borderY; + + GetWindowRect(hwnd, &windowRect); + windowRect.right -= windowRect.left; + windowRect.bottom -= windowRect.top; + windowRect.left = 0; + windowRect.top = 0; + + clientRect.left = windowRect.left + GetSystemMetrics(SM_CXEDGE); + clientRect.top = windowRect.top + GetSystemMetrics(SM_CYEDGE); + clientRect.right = windowRect.right - GetSystemMetrics(SM_CXEDGE); + clientRect.bottom = windowRect.bottom - GetSystemMetrics(SM_CYEDGE); + + // Make sure we don't paint in the client area. + //ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + + // Draw the themed border. + DrawThemeBackground(Context->WndHTheme, hdc, 0, 0, &windowRect, NULL); + + // Calculate the size of the border we just drew, and fill in the rest of the space if we didn't fully paint the region. + if (SUCCEEDED(GetThemeInt(Context->WndHTheme, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth))) + { + borderX = sizingBorderWidth; + borderY = sizingBorderWidth; + } + else + { + borderX = GetSystemMetrics(SM_CXBORDER); + borderY = GetSystemMetrics(SM_CYBORDER); + } + + if (borderX < GetSystemMetrics(SM_CXEDGE) || borderY < GetSystemMetrics(SM_CYEDGE)) + { + windowRect.left += GetSystemMetrics(SM_CXEDGE) - borderX; + windowRect.top += GetSystemMetrics(SM_CYEDGE) - borderY; + windowRect.right -= GetSystemMetrics(SM_CXEDGE) - borderX; + windowRect.bottom -= GetSystemMetrics(SM_CYEDGE) - borderY; + + FillRect(hdc, &windowRect, GetSysColorBrush(COLOR_WINDOW)); + } + + //IntersectClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + + { + // get the screen coordinates of the window + GetWindowRect(hwnd, &Context->rect); + // adjust the coordinates - start from 0,0 + OffsetRect(&Context->rect, -Context->rect.left, -Context->rect.top); + + // work out where to draw the button + GetButtonRect(Context, &Context->rect); + DrawInsertedButton(hwnd, Context, hdc, &Context->rect); + } +} + +BOOLEAN PhTnpOnNcPaint( + __in HWND hwnd, + __in NC_CONTROL* Context, + __in_opt HRGN UpdateRegion + ) +{ + // Themed border + //if ((Context->ExtendedStyle & WS_EX_CLIENTEDGE) && Context->ThemeData) + HDC hdc; + ULONG flags; + + if (UpdateRegion == HRGN_FULL) + UpdateRegion = NULL; + + // Note the use of undocumented flags below. GetDCEx doesn't work without these. + flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000; + + if (UpdateRegion) + flags |= DCX_INTERSECTRGN | 0x40000; + + if (hdc = GetDCEx(hwnd, UpdateRegion, flags)) + { + PhTnpDrawThemedBorder(hwnd, Context, hdc); + ReleaseDC(hwnd, hdc); + return TRUE; + } + + return FALSE; +} + LRESULT CALLBACK NcAreaWndSubclassProc( __in HWND hwndDlg, __in UINT uMsg, __in WPARAM wParam, - __in LPARAM lParam + __in LPARAM lParam, + __in UINT_PTR uIdSubclass, + __in DWORD_PTR dwRefData ) { NC_CONTROL* context = (NC_CONTROL*)GetProp(hwndDlg, L"Context"); - if (!context || !context->NCAreaWndProc) + if (!context) return FALSE; if (uMsg == WM_DESTROY) @@ -133,13 +232,11 @@ LRESULT CALLBACK NcAreaWndSubclassProc( RemoveProp(hwndDlg, L"Context"); PhFree(context); - return FALSE; } - + switch (uMsg) { - case WM_NCACTIVATE: case WM_ERASEBKGND: return TRUE; case WM_NCCALCSIZE: @@ -156,7 +253,8 @@ LRESULT CALLBACK NcAreaWndSubclassProc( nccsp->rgrc[0].bottom -= 1; // let the old wndproc allocate space for the borders, or any other non-client space. - CallWindowProc(context->NCAreaWndProc, hwndDlg, uMsg, wParam, lParam); + //CallWindowProc(context->NCAreaWndProc, hwndDlg, uMsg, wParam, lParam); + DefSubclassProc(hwndDlg, uMsg, wParam, lParam); // calculate what the size of each window border is, // we need to know where the button is going to live. @@ -170,46 +268,51 @@ LRESULT CALLBACK NcAreaWndSubclassProc( // and will be the same width as a scrollbar button context->prect->right -= context->nButSize; } - return FALSE; + return FALSE; case WM_NCPAINT: - { - HDC hdc; - - if (hdc = GetWindowDC(hwndDlg)) - { - // get the screen coordinates of the window - GetWindowRect(hwndDlg, &context->rect); - // adjust the coordinates - start from 0,0 - OffsetRect(&context->rect, -context->rect.left, -context->rect.top); - - if (context->WndHTheme) - { - DrawThemeBackground( - context->WndHTheme, - hdc, - EP_BACKGROUNDWITHBORDER, - EBWBS_NORMAL, - &context->rect, - 0 - ); - } - else - { - // Clear the draw region - FillRect(hdc, &context->rect, context->DcBrush); - // Set border color - FrameRect(hdc, &context->rect, context->BorderBrush); - } - - // work out where to draw the button - GetButtonRect(context, &context->rect); - DrawInsertedButton(hwndDlg, context, hdc, &context->rect); - - // cleanup - ReleaseDC(hwndDlg, hdc); - } + { + if (!PhTnpOnNcPaint(hwndDlg, context, (HRGN)wParam)) + return 0; } - return FALSE; + break; + //case WM_NCPAINT: + // { + // HDC hdc; + // if (hdc = GetWindowDC(hwndDlg)) + // { + // // get the screen coordinates of the window + // GetWindowRect(hwndDlg, &context->rect); + // // adjust the coordinates - start from 0,0 + // OffsetRect(&context->rect, -context->rect.left, -context->rect.top); + + // if (context->WndHTheme) + // { + // DrawThemeBackground( + // context->WndHTheme, + // hdc, + // EP_BACKGROUNDWITHBORDER, + // EBWBS_NORMAL, + // &context->rect, + // 0 + // ); + // } + // else + // { + // // Clear the draw region + // FillRect(hdc, &context->rect, context->DcBrush); + // // Set border color + // FrameRect(hdc, &context->rect, context->BorderBrush); + // } + + // // work out where to draw the button + // GetButtonRect(context, &context->rect); + // DrawInsertedButton(hwndDlg, context, hdc, &context->rect); + + // // cleanup + // ReleaseDC(hwndDlg, hdc); + // } + // } + // return FALSE; case WM_NCHITTEST: { // get the screen coordinates of the mouse @@ -234,7 +337,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( // get the position of the inserted button GetWindowRect(hwndDlg, &context->rect); - + context->pt.x -= context->rect.left; context->pt.y -= context->rect.top; @@ -247,7 +350,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc( if (PtInRect(&context->rect, context->pt)) { SetCapture(hwndDlg); - + // Send the click notification to the parent window PostMessage( context->ParentWindow, @@ -257,42 +360,42 @@ LRESULT CALLBACK NcAreaWndSubclassProc( ); // invalidate the nonclient area - //RedrawWindow( - // hwndDlg, - // NULL, NULL, - // RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN - // ); + SetWindowPos( + hwndDlg, + 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER + ); } } return FALSE; - //case WM_NCMOUSEMOVE: - //case WM_NCMOUSELEAVE: - // { - // // get the screen coordinates of the mouse - // context->pt.x = GET_X_LPARAM(lParam); - // context->pt.y = GET_Y_LPARAM(lParam); - // // get the position of the inserted button - // GetWindowRect(hwndDlg, &context->rect); - // context->pt.x -= context->rect.left; - // context->pt.y -= context->rect.top; - // // adjust the coordinates so they start from 0,0 - // OffsetRect(&context->rect, -context->rect.left, -context->rect.top); - // GetButtonRect(context, &context->rect); - // context->oldstate = context->IsMouseActive; - // //check that the mouse is within the inserted button - // if (PtInRect(&context->rect, context->pt)) - // { - // context->IsMouseActive = TRUE; - // } - // else - // { - // context->IsMouseActive = FALSE; - // } - // // to prevent flicker, we only redraw the button if its state has changed - // if (context->oldstate != context->IsMouseActive) - // DrawInsertedButton(hwndDlg, context, NULL, &context->rect); - // } - // break; + //case WM_NCMOUSEMOVE: + //case WM_NCMOUSELEAVE: + // { + // // get the screen coordinates of the mouse + // context->pt.x = GET_X_LPARAM(lParam); + // context->pt.y = GET_Y_LPARAM(lParam); + // // get the position of the inserted button + // GetWindowRect(hwndDlg, &context->rect); + // context->pt.x -= context->rect.left; + // context->pt.y -= context->rect.top; + // // adjust the coordinates so they start from 0,0 + // OffsetRect(&context->rect, -context->rect.left, -context->rect.top); + // GetButtonRect(context, &context->rect); + // context->oldstate = context->IsMouseActive; + // //check that the mouse is within the inserted button + // if (PtInRect(&context->rect, context->pt)) + // { + // context->IsMouseActive = TRUE; + // } + // else + // { + // context->IsMouseActive = FALSE; + // } + // // to prevent flicker, we only redraw the button if its state has changed + // if (context->oldstate != context->IsMouseActive) + // DrawInsertedButton(hwndDlg, context, NULL, &context->rect); + // } + // break; case WM_LBUTTONUP: { // get the SCREEN coordinates of the mouse @@ -317,11 +420,11 @@ LRESULT CALLBACK NcAreaWndSubclassProc( { context->TextLength = Edit_GetTextLength(hwndDlg) > 0; - //RedrawWindow( - // hwndDlg, - // NULL, NULL, - // RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN - // ); + SetWindowPos( + hwndDlg, + 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER + ); } } return FALSE; @@ -330,16 +433,16 @@ LRESULT CALLBACK NcAreaWndSubclassProc( context->TextLength = Edit_GetTextLength(hwndDlg) > 0; // invalidate the nonclient area - RedrawWindow( - hwndDlg, - NULL, NULL, - RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN + SetWindowPos( + hwndDlg, + 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER ); } break; } - return CallWindowProc(context->NCAreaWndProc, hwndDlg, uMsg, wParam, lParam); + return DefSubclassProc(hwndDlg, uMsg, wParam, lParam); } BOOLEAN InsertButton( @@ -347,12 +450,10 @@ BOOLEAN InsertButton( __in UINT CommandID ) { - NC_CONTROL* context = (NC_CONTROL*)PhAllocate( - sizeof(NC_CONTROL) - ); + NC_CONTROL* context = (NC_CONTROL*)PhAllocate(sizeof(NC_CONTROL)); memset(context, 0, sizeof(NC_CONTROL)); - + context->CommandID = CommandID; context->ParentWindow = GetParent(hwndDlg); context->BorderBrush = (HBRUSH)CreateSolidBrush(RGB(0x8f, 0x8f, 0x8f)); @@ -381,7 +482,7 @@ BOOLEAN InsertButton( SetProp(hwndDlg, L"Context", (HANDLE)context); // replace the old window procedure with our new one - context->NCAreaWndProc = SubclassWindow(hwndDlg, NcAreaWndSubclassProc); + SetWindowSubclass(hwndDlg, NcAreaWndSubclassProc, 0, 0); if (!context->WndHTheme) {