2025-11-28 00:35:46 +09:00

339 lines
9.5 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#include <windows.h>
#include <shobjidl.h>
#include <dwmapi.h>
#include <strsafe.h>
#include "TabWnd.h"
#include "TabApp.h"
WCHAR const c_szWindowClass[] = L"TabApp_TdiWnd";
ATOM CTabWnd::RegisterClass()
{
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(wcex);
wcex.lpfnWndProc = CTabWnd::_WndProc;
wcex.hInstance = g_hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = c_szWindowClass;
return ::RegisterClassEx(&wcex);
}
CTabWnd *CTabWnd::Create(int iTab, CMainDlg *pMainDlg)
{
CTabWnd *pWnd = new CTabWnd(iTab, pMainDlg);
if (pWnd)
{
WCHAR szTab[100];
StringCchPrintf(szTab, ARRAYSIZE(szTab), L"Tab %d", iTab);
// Create the CTabWnd window offscreen.
HWND hwnd = ::CreateWindowEx(
WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE,
c_szWindowClass,
szTab,
WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION,
-32000,
-32000,
10,
10,
NULL,
NULL,
g_hInstance,
(LPVOID)pWnd);
if (hwnd == NULL)
{
delete pWnd;
pWnd = NULL;
}
}
return pWnd;
}
VOID CTabWnd::Destroy()
{
if (_hwnd != NULL)
{
_pMainDlg->UnregisterTab(this);
SetWindowLongPtr(_hwnd, GWLP_USERDATA, 0);
HWND hwnd = _hwnd;
_hwnd = NULL;
DestroyWindow(hwnd);
}
}
LRESULT CALLBACK CTabWnd::_WndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
LRESULT lResult = 0;
CTabWnd *pWnd = (CTabWnd*)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pWnd == NULL && message == WM_NCCREATE)
{
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
pWnd = (CTabWnd*)lpcs->lpCreateParams;
pWnd->_hwnd = hWnd;
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWnd);
lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
}
else if (pWnd != NULL)
{
lResult = pWnd->WndProc(message, wParam, lParam);
}
else
{
lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
}
return lResult;
}
//
// Processes messages for the CTabWnd window
//
LRESULT CTabWnd::WndProc(
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
LRESULT lResult = 0;
switch (message)
{
case WM_CREATE:
{
// Set DWM window attributes to indicate we'll provide the iconic bitmap, and
// to always render the thumbnail using the iconic bitmap.
BOOL fForceIconic = TRUE;
BOOL fHasIconicBitmap = TRUE;
DwmSetWindowAttribute(
_hwnd,
DWMWA_FORCE_ICONIC_REPRESENTATION,
&fForceIconic,
sizeof(fForceIconic));
DwmSetWindowAttribute(
_hwnd,
DWMWA_HAS_ICONIC_BITMAP,
&fHasIconicBitmap,
sizeof(fHasIconicBitmap));
// Tell the taskbar about this tab window
_pMainDlg->RegisterTab(this);
break;
}
case WM_ACTIVATE:
// The taskbar will activate this window, so pass along the activation
// to the tab window outer frame.
if (LOWORD(wParam) == WA_ACTIVE)
{
_pMainDlg->ActivateTab(this);
}
break;
case WM_SYSCOMMAND:
// All syscommands except for close will be passed along to the tab window
// outer frame. This allows functions such as move/size to occur properly.
if (wParam != SC_CLOSE)
{
lResult = SendMessage(_pMainDlg->GetHwnd(), WM_SYSCOMMAND, wParam, lParam);
}
else
{
lResult = ::DefWindowProc(_hwnd, message, wParam, lParam);
}
break;
case WM_CLOSE:
// The taskbar (or system menu) is asking this tab window to close. Ask the
// tab window outer frame to destroy this tab.
_pMainDlg->DestroyTab(this);
break;
case WM_DWMSENDICONICTHUMBNAIL:
// This tab window is being asked to provide its iconic bitmap. This indicates
// a thumbnail is being drawn.
_SendIconicRepresentation(HIWORD(lParam), LOWORD(lParam));
break;
case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
// This tab window is being asked to provide a bitmap to show in live preview.
// This indicates the tab's thumbnail in the taskbar is being previewed.
_SendLivePreviewBitmap();
break;
default:
lResult = ::DefWindowProc(_hwnd, message, wParam, lParam);
break;
}
return lResult;
}
HRESULT CTabWnd::_SendIconicRepresentation(int nWidth, int nHeight)
{
HRESULT hr = E_FAIL;
HBITMAP hbm = _CreateDIB(nWidth, nHeight);
if (hbm)
{
hr = DwmSetIconicThumbnail(_hwnd, hbm, 0);
DeleteObject(hbm);
}
return hr;
}
HRESULT CTabWnd::_SendLivePreviewBitmap()
{
HRESULT hr = S_OK;
HWND hwndTabFrame = _pMainDlg->GetHwnd();
DWORD dwStyle = GetWindowLong(hwndTabFrame, GWL_STYLE);
DWORD dwStyleEx = GetWindowLong(hwndTabFrame, GWL_EXSTYLE);
// Compute the actual size the thumbnail will occupy on-screen in order to
// render the live preview bitmap. We use the tab window outer frame window
// to compute this. In case that window is minimized, we use GetWindowPlacement
// to give the correct information.
RECT rcClient = {};
RECT rcNCA = {};
WINDOWPLACEMENT wp;
if (AdjustWindowRectEx(&rcNCA, dwStyle, FALSE, dwStyleEx) != 0 &&
GetWindowPlacement(hwndTabFrame, &wp) != 0)
{
if (wp.flags & WPF_RESTORETOMAXIMIZED)
{
HMONITOR hmon = MonitorFromRect(&wp.rcNormalPosition, MONITOR_DEFAULTTONULL);
if (hmon)
{
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(hmon, &monitorInfo))
{
rcClient = monitorInfo.rcWork;
}
}
}
else
{
CopyRect(&rcClient, &wp.rcNormalPosition);
}
rcClient.right -= (-rcNCA.left + rcNCA.right);
rcClient.bottom -= (-rcNCA.top + rcNCA.bottom);
}
if ((rcClient.right - rcClient.left) > 0 && (rcClient.bottom - rcClient.top) > 0)
{
POINT ptOffset;
ptOffset.x = ptOffset.y = 10;
HBITMAP hbm = _CreateDIB(rcClient.right - rcClient.left - 2*ptOffset.x, rcClient.bottom - rcClient.top - 2*ptOffset.y);
if (hbm)
{
hr = DwmSetIconicLivePreviewBitmap(_hwnd, hbm, &ptOffset, 0);
DeleteObject(hbm);
}
}
return hr;
}
// This is a helper method to render the tab window contents at a specified
// width and height.
HBITMAP CTabWnd::_CreateDIB(int nWidth, int nHeight)
{
HBITMAP hbm = NULL;
HDC hdcMem = CreateCompatibleDC(NULL);
if (hdcMem != NULL)
{
BITMAPINFO bmi;
ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = nWidth;
bmi.bmiHeader.biHeight = -nHeight; // Use a top-down DIB
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
PBYTE pbDS = NULL;
hbm = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS, (VOID**)&pbDS, NULL, NULL);
if (hbm != NULL)
{
int nRed = 0, nBlue = 0, nGreen = 0;
// Compute tab color: red, orange, yellow, green, blue, indigo, violet
switch (_iTab % 7)
{
case 1:
nRed = 255;
break;
case 2:
nRed = 255;
nGreen = 155;
break;
case 3:
nRed = 255;
nGreen = 255;
break;
case 4:
nGreen = 255;
break;
case 5:
nBlue = 255;
break;
case 6:
nRed = 155;
nBlue = 255;
break;
case 0:
nRed = 255;
nBlue = 255;
break;
}
// Fill in the pixels of the bitmap
for (int y = 0; y < nHeight; y++)
{
for (int x = 0; x < nWidth; x++)
{
int edgeDistance = min(min(y, nHeight - y), min(x, nWidth - x));
int ring = min((edgeDistance / RINGWIDTH) + 1, MAXRING);
int nAlpha = ring * (255 / MAXRING);
pbDS[0] = (BYTE)(nBlue * nAlpha / 255);
pbDS[1] = (BYTE)(nGreen * nAlpha / 255);
pbDS[2] = (BYTE)(nRed * nAlpha / 255);
pbDS[3] = (BYTE)(nAlpha);
pbDS += 4;
}
}
}
DeleteDC(hdcMem);
}
return hbm;
}