917 lines
29 KiB
C++
917 lines
29 KiB
C++
/*++
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
supertip.cpp
|
|
|
|
Abstract:
|
|
This module contains the code to invoke SuperTIP.
|
|
|
|
Author:
|
|
Michael Tsang (MikeTs) 11-Jul-2000
|
|
|
|
Environment:
|
|
User mode
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include <cpl.h>
|
|
#include <shellapi.h>
|
|
|
|
static const TCHAR tstrClassName[] = TEXT("SuperTIPWndClass");
|
|
UINT guimsgTaskbarCreated = 0;
|
|
UINT guimsgTrayCallback = 0;
|
|
HICON ghSuperTIPIcon = NULL;
|
|
HMENU ghmenuTray = NULL;
|
|
HMENU ghmenuTrayPopup = NULL;
|
|
TCHAR gtszSuperTIPTitle[64] = {0};
|
|
TCHAR gtszBalloonTip[256] = {0};
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func unsigned | SuperTIPThread | SuperTIP thread.
|
|
|
|
@parm IN PVOID | param | Points to the thread structure.
|
|
|
|
@rvalue Always returns 0.
|
|
--*/
|
|
|
|
unsigned __stdcall
|
|
SuperTIPThread(
|
|
IN PVOID param
|
|
)
|
|
{
|
|
TRACEPROC("SuperTIPThread", 2)
|
|
WNDCLASSEX wc;
|
|
BOOL fSuccess = TRUE;
|
|
HRESULT hr;
|
|
|
|
TRACEENTER(("(pThread=%p)\n", param));
|
|
TRACEASSERT(ghwndSuperTIP == NULL);
|
|
|
|
guimsgTaskbarCreated = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
|
guimsgTrayCallback = RegisterWindowMessage(
|
|
TEXT("{D0061156-D460-4230-AF87-9E7658AB987D}"));
|
|
TRACEINFO(1, ("TaskbarCreateMsg=%x, TrayCallbackMsg=%x\n",
|
|
guimsgTaskbarCreated, guimsgTrayCallback));
|
|
|
|
LoadString(ghMod,
|
|
IDS_SUPERTIP_TITLE,
|
|
gtszSuperTIPTitle,
|
|
ARRAYSIZE(gtszSuperTIPTitle));
|
|
LoadString(ghMod,
|
|
IDS_BALLOON_TEXT,
|
|
gtszBalloonTip,
|
|
ARRAYSIZE(gtszBalloonTip));
|
|
ghSuperTIPIcon = (HICON)LoadImage(ghMod,
|
|
MAKEINTRESOURCE(IDI_SUPERTIP),
|
|
IMAGE_ICON,
|
|
16,
|
|
16,
|
|
0);
|
|
TRACEASSERT(ghSuperTIPIcon != NULL);
|
|
|
|
memset(&wc, 0, sizeof(wc));
|
|
wc.cbSize = sizeof(wc);
|
|
wc.lpfnWndProc = SuperTIPWndProc;
|
|
wc.hInstance = ghMod;
|
|
wc.lpszClassName = tstrClassName;
|
|
RegisterClassEx(&wc);
|
|
|
|
//
|
|
// Protect the majority of this thread in a try/except block to catch any
|
|
// faults in the SuperTip object. If there is a fault, this thread will
|
|
// be destroyed and then recreated.
|
|
//
|
|
|
|
__try
|
|
{
|
|
while (fSuccess && !(gdwfTabSrv & TSF_TERMINATE))
|
|
{
|
|
if (SwitchThreadToInputDesktop((PTSTHREAD)param))
|
|
{
|
|
BOOL fImpersonate;
|
|
|
|
fImpersonate = ImpersonateCurrentUser();
|
|
CoInitialize(NULL);
|
|
hr = CoCreateInstance(CLSID_SuperTip,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ISuperTip,
|
|
(LPVOID *)&gpISuperTip);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_TellMe,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_TellMe,
|
|
(LPVOID *)&gpITellMe);
|
|
if (FAILED(hr))
|
|
{
|
|
TABSRVERR(("CoCreateInstance on ITellMe failed (hr=%x)\n", hr));
|
|
}
|
|
|
|
ghwndSuperTIP = CreateWindow(tstrClassName,
|
|
tstrClassName,
|
|
WS_POPUP,
|
|
CW_USEDEFAULT,
|
|
0,
|
|
CW_USEDEFAULT,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
ghMod,
|
|
0);
|
|
|
|
if (ghwndSuperTIP != NULL)
|
|
{
|
|
BOOL rc;
|
|
MSG msg;
|
|
|
|
PostMessage(ghwndSuperTIP, WM_SUPERTIP_INIT, 0, 0);
|
|
|
|
//
|
|
// Pump messages for our window until it is destroyed.
|
|
//
|
|
((PTSTHREAD)param)->pvSDTParam = ghwndSuperTIP;
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
((PTSTHREAD)param)->pvSDTParam = ghwndSuperTIP = NULL;
|
|
gdwfTabSrv &= ~TSF_TRAYICON_CREATED;
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to create SuperTIP window.\n"));
|
|
fSuccess = FALSE;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
gpITellMe->Release();
|
|
gpITellMe = NULL;
|
|
}
|
|
gpISuperTip->Release();
|
|
gpISuperTip = NULL;
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to create SuperTIP COM instance (hr=%x).\n",
|
|
hr));
|
|
fSuccess = FALSE;
|
|
}
|
|
|
|
CoUninitialize();
|
|
if (fImpersonate)
|
|
{
|
|
RevertToSelf();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to set current desktop.\n"));
|
|
fSuccess = FALSE;
|
|
}
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
TABSRVERR(("Exception in SuperTIP thread (%X).\n", _exception_code()));
|
|
}
|
|
|
|
DestroyIcon(ghSuperTIPIcon);
|
|
ghSuperTIPIcon = NULL;
|
|
|
|
TRACEEXIT(("=0\n"));
|
|
return 0;
|
|
} //SuperTIPThread
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func LRESULT | SuperTIPWndProc | SuperTIP window proc.
|
|
|
|
@parm IN HWND | hwnd | Window handle.
|
|
@parm IN UINT | uiMsg | Window message.
|
|
@parm IN WPARAM | wParam | Param 1.
|
|
@parm IN LPARAM | lParam | Param 2.
|
|
|
|
@rvalue Return code is message specific.
|
|
--*/
|
|
|
|
LRESULT CALLBACK
|
|
SuperTIPWndProc(
|
|
IN HWND hwnd,
|
|
IN UINT uiMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
TRACEPROC("SuperTIPWndProc", 5)
|
|
LRESULT rc = 0;
|
|
|
|
TRACEENTER(("(hwnd=%x,Msg=%s,wParam=%x,lParam=%x)\n",
|
|
hwnd, LookupName(uiMsg, WMMsgNames), wParam, lParam));
|
|
|
|
if ((guimsgTaskbarCreated != 0) && (uiMsg == guimsgTaskbarCreated))
|
|
{
|
|
TRACEINFO(1, ("Taskbar created...\n"));
|
|
|
|
//
|
|
// If whistler fixes the shell bug, we can restore this code.
|
|
//
|
|
gdwfTabSrv |= TSF_TASKBAR_CREATED;
|
|
if (!CreateTrayIcon(hwnd,
|
|
guimsgTrayCallback,
|
|
ghSuperTIPIcon,
|
|
gtszSuperTIPTitle))
|
|
{
|
|
TABSRVERR(("OnTaskbarCreated: failed to create tray icon.\n"));
|
|
}
|
|
}
|
|
else if ((guimsgTrayCallback != 0) && (uiMsg == guimsgTrayCallback))
|
|
{
|
|
switch (lParam)
|
|
{
|
|
case WM_LBUTTONUP:
|
|
{
|
|
int iDefaultCmd = GetMenuDefaultItem(ghmenuTrayPopup,
|
|
FALSE,
|
|
0);
|
|
|
|
//
|
|
// Perform default action.
|
|
//
|
|
if (iDefaultCmd != -1)
|
|
{
|
|
PostMessage(hwnd, WM_COMMAND, iDefaultCmd, 0);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_RBUTTONUP:
|
|
{
|
|
TCHAR tszMenuText[128];
|
|
POINT pt;
|
|
|
|
//
|
|
// Do popup menu.
|
|
//
|
|
TRACEASSERT(ghmenuTrayPopup != NULL);
|
|
LoadString(ghMod,
|
|
gdwfTabSrv & TSF_SUPERTIP_OPENED?
|
|
IDS_HIDE_SUPERTIP: IDS_SHOW_SUPERTIP,
|
|
tszMenuText,
|
|
ARRAYSIZE(tszMenuText));
|
|
ModifyMenu(ghmenuTrayPopup,
|
|
IDM_OPEN,
|
|
MF_BYCOMMAND | MF_STRING,
|
|
IDM_OPEN,
|
|
tszMenuText);
|
|
|
|
LoadString(ghMod,
|
|
gdwfTabSrv & TSF_PORTRAIT_MODE?
|
|
IDS_SCREEN_LANDSCAPE: IDS_SCREEN_PORTRAIT,
|
|
tszMenuText,
|
|
ARRAYSIZE(tszMenuText));
|
|
ModifyMenu(ghmenuTrayPopup,
|
|
IDM_TOGGLE_ROTATION,
|
|
MF_BYCOMMAND | MF_STRING,
|
|
IDM_TOGGLE_ROTATION,
|
|
tszMenuText);
|
|
|
|
GetCursorPos(&pt);
|
|
//
|
|
// It is necessary to set focus on this window in order to
|
|
// popup the menu.
|
|
//
|
|
SetForegroundWindow(hwnd);
|
|
TrackPopupMenu(ghmenuTrayPopup,
|
|
TPM_NONOTIFY | TPM_RIGHTBUTTON,
|
|
pt.x,
|
|
pt.y,
|
|
0,
|
|
hwnd,
|
|
NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HRESULT hr;
|
|
|
|
switch (uiMsg)
|
|
{
|
|
case WM_SUPERTIP_INIT:
|
|
hr = gpISuperTip->Activate();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = gpISuperTip->SetNotifyHWND(hwnd,
|
|
WM_SUPERTIP_NOTIFY,
|
|
0);
|
|
if (FAILED(hr))
|
|
{
|
|
TABSRVERR(("Failed to set notify hwnd (hr=%x)\n", hr));
|
|
}
|
|
|
|
//
|
|
// If we are not on the Winlogon desktop, wait for the
|
|
// shell's tray notification window to be created so
|
|
// our tray icon can be added. Keep checking the
|
|
// Winlogon desktop flag in case the user switches
|
|
// desktops while this loop is still waiting for the
|
|
// tray window.
|
|
//
|
|
int i;
|
|
PTSTHREAD SuperTIPThread = FindThread(TSF_SUPERTIPTHREAD);
|
|
|
|
for (i = 0;
|
|
(i < 30) &&
|
|
!(SuperTIPThread->dwfThread & THREADF_DESKTOP_WINLOGON);
|
|
i++)
|
|
{
|
|
if (FindWindow(TEXT("Shell_TrayWnd"), NULL))
|
|
{
|
|
break;
|
|
}
|
|
Sleep(500);
|
|
}
|
|
//
|
|
// At this point we're either on the Winlogon desktop or
|
|
// we're ready to create our tray icon.
|
|
//
|
|
|
|
if (SuperTIPThread->dwfThread & THREADF_DESKTOP_WINLOGON)
|
|
{
|
|
POINT pt;
|
|
|
|
pt.x = gcxPrimary;
|
|
pt.y = gcyPrimary;
|
|
gpISuperTip->Show(TIP_SHOW_KBDONLY, pt);
|
|
gdwfTabSrv |= TSF_SUPERTIP_OPENED;
|
|
}
|
|
else
|
|
{
|
|
if (i > 1)
|
|
{
|
|
TRACEINFO(1, ("Shell_TrayWnd loop count: %d\n", i));
|
|
}
|
|
|
|
ghmenuTray = LoadMenu(ghMod,
|
|
MAKEINTRESOURCE(IDR_TRAYMENU));
|
|
TRACEASSERT(ghmenuTray != NULL);
|
|
ghmenuTrayPopup = GetSubMenu(ghmenuTray, 0);
|
|
TRACEASSERT(ghmenuTrayPopup != NULL);
|
|
SetMenuDefaultItem(ghmenuTrayPopup, IDM_OPEN, FALSE);
|
|
|
|
if (!CreateTrayIcon(hwnd,
|
|
guimsgTrayCallback,
|
|
ghSuperTIPIcon,
|
|
gtszSuperTIPTitle))
|
|
{
|
|
TABSRVERR(("OnCreate: failed to create tray icon.\n"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to activate SuperTIP (hr=%d)\n", hr));
|
|
rc = -1;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
ghwndSuperTIPInk = NULL;
|
|
guimsgSuperTIPInk = 0;
|
|
gdwfTabSrv &= ~(TSF_SUPERTIP_OPENED | TSF_SUPERTIP_SENDINK);
|
|
if (gdwfTabSrv & TSF_TRAYICON_CREATED)
|
|
{
|
|
if (!DestroyTrayIcon(hwnd,
|
|
guimsgTrayCallback,
|
|
ghSuperTIPIcon))
|
|
{
|
|
TABSRVERR(("failed to destroy tray icon.\n"));
|
|
}
|
|
}
|
|
|
|
if (ghmenuTray != NULL)
|
|
{
|
|
DestroyMenu(ghmenuTray);
|
|
ghmenuTray = ghmenuTrayPopup = NULL;
|
|
}
|
|
gpISuperTip->Deactivate();
|
|
DestroyWindow(hwnd);
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
UpdateRotation();
|
|
break;
|
|
|
|
case WM_SETTINGCHANGE:
|
|
if ((wParam == SPI_SETKEYBOARDDELAY) ||
|
|
(wParam == SPI_SETKEYBOARDSPEED))
|
|
{
|
|
UpdateButtonRepeatRate();
|
|
}
|
|
break;
|
|
|
|
case WM_SUPERTIP_NOTIFY:
|
|
if (wParam == 0)
|
|
{
|
|
gdwfTabSrv &= ~TSF_SUPERTIP_OPENED;
|
|
if (!(gdwfTabSrv & TSF_SUPERTIP_MINIMIZED_BEFORE))
|
|
{
|
|
gdwfTabSrv |= TSF_SUPERTIP_MINIMIZED_BEFORE;
|
|
if (gdwfTabSrv & TSF_TRAYICON_CREATED)
|
|
{
|
|
if (!SetBalloonToolTip(hwnd,
|
|
guimsgTrayCallback,
|
|
gtszSuperTIPTitle,
|
|
gtszBalloonTip,
|
|
TIMEOUT_BALLOON_TIP,
|
|
NIIF_INFO))
|
|
{
|
|
TABSRVERR(("failed to popup balloon tip.\n"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (wParam >= WM_USER)
|
|
{
|
|
ghwndSuperTIPInk = (HWND)lParam;
|
|
guimsgSuperTIPInk = (UINT)wParam;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDM_OPEN:
|
|
{
|
|
if (gpITellMe != NULL)
|
|
{
|
|
HWND hwndTarget;
|
|
|
|
__try
|
|
{
|
|
if (SUCCEEDED(
|
|
gpITellMe->GetLastValidFocusHWnd(&hwndTarget)))
|
|
{
|
|
SetForegroundWindow(hwndTarget);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
TABSRVERR(("Exception in TellMe::GetLastValidFocusHWnd (%X).\n",
|
|
_exception_code()));
|
|
}
|
|
}
|
|
|
|
POINT pt = {0, 0};
|
|
HRESULT hr = gpISuperTip->Show(TIP_SHOW_TOGGLE, pt);
|
|
gdwfTabSrv ^= TSF_SUPERTIP_OPENED;
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
case IDM_PROPERTIES:
|
|
{
|
|
HMODULE hmod;
|
|
APPLET_PROC pfnCplApplet;
|
|
LRESULT lrc;
|
|
|
|
hmod = LoadLibrary(TEXT("tabletpc.cpl"));
|
|
if (hmod != NULL)
|
|
{
|
|
pfnCplApplet = (APPLET_PROC)GetProcAddress(
|
|
hmod,
|
|
TEXT("CPlApplet"));
|
|
if (pfnCplApplet != NULL)
|
|
{
|
|
pfnCplApplet(hwnd, CPL_DBLCLK, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to get entry point of control panel (err=%d)\n",
|
|
GetLastError()));
|
|
}
|
|
FreeLibrary(hmod);
|
|
hmod = NULL;
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to load control panel (err=%d)\n",
|
|
GetLastError()));
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
case IDM_TOGGLE_ROTATION:
|
|
{
|
|
#if 0
|
|
DEVMODE DevMode;
|
|
LONG rcDisplay;
|
|
|
|
//
|
|
// To circumvent the dynamic mode tablet problem,
|
|
// we need to enumerate the display modes table to
|
|
// force the SMI driver to load a mode table that
|
|
// supports portrait modes.
|
|
//
|
|
EnumDisplayModes();
|
|
|
|
memset(&DevMode, 0, sizeof(DevMode));
|
|
DevMode.dmSize = sizeof(DevMode);
|
|
DevMode.dmPelsWidth = gcyPrimary;
|
|
DevMode.dmPelsHeight = gcxPrimary;
|
|
DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
|
|
if (DevMode.dmPelsWidth < DevMode.dmPelsHeight)
|
|
{
|
|
//
|
|
// We are switching to Portrait mode,
|
|
// make sure our color depth is 16-bit.
|
|
//
|
|
DevMode.dmBitsPerPel = 16;
|
|
DevMode.dmFields |= DM_BITSPERPEL;
|
|
}
|
|
rcDisplay = ChangeDisplaySettings(&DevMode,
|
|
CDS_UPDATEREGISTRY);
|
|
if (rcDisplay < 0)
|
|
{
|
|
TABSRVERR(("Failed to toggle rotation (rc=%d)\n",
|
|
rcDisplay));
|
|
//BUGBUG: make this LoadString
|
|
MessageBox(NULL,
|
|
TEXT("Failed to toggle rotation"),
|
|
TEXT(MODNAME),
|
|
MB_OK);
|
|
}
|
|
#endif
|
|
//#if 0
|
|
typedef BOOL (__stdcall *PFNSETROTATION)(DWORD);
|
|
HMODULE hmod = LoadLibrary(TEXT("tabletpc.cpl"));
|
|
PFNSETROTATION pfnSetRotation;
|
|
LRESULT lrc;
|
|
|
|
if (hmod != NULL)
|
|
{
|
|
pfnSetRotation = (PFNSETROTATION)GetProcAddress(
|
|
hmod,
|
|
TEXT("SetRotation"));
|
|
if (pfnSetRotation != NULL)
|
|
{
|
|
if (pfnSetRotation(
|
|
(gdwfTabSrv & TSF_PORTRAIT_MODE)?
|
|
0: RT_CLOCKWISE))
|
|
{
|
|
//
|
|
// Sometimes the system miss sending
|
|
// WM_DISPLAYCHANGE, so we will do it
|
|
// here just in case.
|
|
//
|
|
UpdateRotation();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to get entry point of SetRotation (err=%d)\n",
|
|
GetLastError()));
|
|
}
|
|
FreeLibrary(hmod);
|
|
}
|
|
else
|
|
{
|
|
TABSRVERR(("Failed to load control panel (err=%d)\n",
|
|
GetLastError()));
|
|
}
|
|
//#endif
|
|
break;
|
|
}
|
|
|
|
default:
|
|
rc = DefWindowProc(hwnd, uiMsg, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
case WM_GESTURE:
|
|
{
|
|
POINT pt;
|
|
|
|
//
|
|
// Unpack x and y. Sign extend if necessary.
|
|
//
|
|
pt.x = (LONG)((SHORT)(lParam & 0xffff));
|
|
pt.y = (LONG)((SHORT)(lParam >> 16));
|
|
|
|
switch (wParam)
|
|
{
|
|
case PopupSuperTIP:
|
|
TRACEINFO(1, ("Popup SuperTIP\n"));
|
|
gpISuperTip->Show(TIP_SHOW_GESTURE, pt);
|
|
gdwfTabSrv |= TSF_SUPERTIP_OPENED;
|
|
break;
|
|
|
|
case PopupMIP:
|
|
TRACEINFO(1, ("Popup MIP\n"));
|
|
gpISuperTip->ShowMIP(TIP_SHOW_GESTURE, pt);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
rc = DefWindowProc(hwnd, uiMsg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
TRACEEXIT(("=%x\n", rc));
|
|
return rc;
|
|
} //SuperTIPWndProc
|
|
|
|
#if 0
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func VOID | EnumDisplayModes | Enumerate display modes to force
|
|
SMI driver to dynamically load a mode table that supports
|
|
Portrait modes.
|
|
|
|
@parm None.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID
|
|
EnumDisplayModes(
|
|
VOID
|
|
)
|
|
{
|
|
TRACEPROC("EnumDisplayModes", 3)
|
|
DWORD i;
|
|
DEVMODE DevMode;
|
|
|
|
TRACEENTER(("()\n"));
|
|
|
|
for (i = 0; EnumDisplaySettings(NULL, i, &DevMode); ++i)
|
|
{
|
|
//
|
|
// Don't have to do anything.
|
|
//
|
|
}
|
|
|
|
TRACEEXIT(("!\n"));
|
|
return;
|
|
} //EnumDisplayModes
|
|
#endif
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func VOID | UpdateRotation | Update the rotation info.
|
|
|
|
@parm None.
|
|
|
|
@rvalue None.
|
|
--*/
|
|
|
|
VOID
|
|
UpdateRotation(
|
|
VOID
|
|
)
|
|
{
|
|
TRACEPROC("UpdateRotation", 3)
|
|
|
|
TRACEENTER(("()\n"));
|
|
|
|
//
|
|
// Display mode has changed, better recompute everything related
|
|
// to screen.
|
|
//
|
|
glVirtualDesktopLeft =
|
|
glVirtualDesktopRight =
|
|
glVirtualDesktopTop =
|
|
glVirtualDesktopBottom = 0;
|
|
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
|
|
gcxPrimary = GetSystemMetrics(SM_CXSCREEN);
|
|
gcyPrimary = GetSystemMetrics(SM_CYSCREEN);
|
|
gcxScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
|
gcyScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
|
if (gcxPrimary > gcyPrimary)
|
|
{
|
|
gdwfTabSrv &= ~TSF_PORTRAIT_MODE;
|
|
}
|
|
else
|
|
{
|
|
gdwfTabSrv |= TSF_PORTRAIT_MODE;
|
|
}
|
|
glLongOffset = ((NUM_PIXELS_LONG -
|
|
max(gcxPrimary, gcyPrimary))*(MAX_NORMALIZED_X + 1))/
|
|
(2*NUM_PIXELS_LONG);
|
|
glShortOffset = ((NUM_PIXELS_SHORT -
|
|
min(gcxPrimary, gcyPrimary))*(MAX_NORMALIZED_Y + 1))/
|
|
(2*NUM_PIXELS_SHORT);
|
|
|
|
TRACEEXIT(("!\n"));
|
|
return;
|
|
} //UpdateRotation
|
|
|
|
/*++
|
|
@doc EXTERNAL
|
|
|
|
@func BOOL | MonitorEnumProc | The callback function for
|
|
EnumDisplayMonitors.
|
|
|
|
@parm IN HMONITOR | hMon | Handle to display monitor.
|
|
@parm IN HDC | hdcMon | Handle to monitor DC.
|
|
@parm IN LPRECT | lprcMon | Monitor intersection rectangle.
|
|
@parm IN LPARAM | dwData | Unused.
|
|
|
|
@rvalue Always return TRUE to continue enumeration.
|
|
--*/
|
|
|
|
BOOL CALLBACK
|
|
MonitorEnumProc(
|
|
IN HMONITOR hMon,
|
|
IN HDC hdcMon,
|
|
IN LPRECT lprcMon,
|
|
IN LPARAM dwData
|
|
)
|
|
{
|
|
TRACEPROC("MonitorEnumProc", 3)
|
|
|
|
TRACEENTER(("(hMon=%x,hdcMon=%x,MonLeft=%d,MonRight=%d,MonTop=%d,MonBottom=%d,dwData=%x)\n",
|
|
hMon, hdcMon, lprcMon->left, lprcMon->right, lprcMon->top,
|
|
lprcMon->bottom, dwData));
|
|
|
|
if (lprcMon->left < glVirtualDesktopLeft)
|
|
{
|
|
glVirtualDesktopLeft = lprcMon->left;
|
|
}
|
|
|
|
if (lprcMon->right - 1 > glVirtualDesktopRight)
|
|
{
|
|
glVirtualDesktopRight = lprcMon->right - 1;
|
|
}
|
|
|
|
if (lprcMon->top < glVirtualDesktopTop)
|
|
{
|
|
glVirtualDesktopTop = lprcMon->top;
|
|
}
|
|
|
|
if (lprcMon->bottom - 1> glVirtualDesktopBottom)
|
|
{
|
|
glVirtualDesktopBottom = lprcMon->bottom - 1;
|
|
}
|
|
|
|
TRACEEXIT(("=1\n"));
|
|
return TRUE;
|
|
} //MonitorEnumProc
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func BOOL | CreateTrayIcon | Create the tray icon.
|
|
|
|
@parm IN HWND | hwnd | Window handle that the tray can send message to.
|
|
@parm IN UINT | umsgTray | Message ID that the tray used to send messages.
|
|
@parm IN HICON | hIcon | Icon handle.
|
|
@parm IN LPCTSTR | ptszTip | Points to the Tip string.
|
|
|
|
@rvalue SUCCESS | Returns TRUE.
|
|
@rvalue FAILURE | Returns FALSE.
|
|
--*/
|
|
|
|
BOOL
|
|
CreateTrayIcon(
|
|
IN HWND hwnd,
|
|
IN UINT umsgTray,
|
|
IN HICON hIcon,
|
|
IN LPCTSTR ptszTip
|
|
)
|
|
{
|
|
TRACEPROC("CreateTrayIcon", 2)
|
|
BOOL rc;
|
|
NOTIFYICONDATA nid;
|
|
|
|
TRACEENTER(("(hwnd=%x,msgTray=%x,hIcon=%x,Tip=%s)\n",
|
|
hwnd, umsgTray, hIcon, ptszTip));
|
|
TRACEASSERT(hIcon != NULL);
|
|
TRACEASSERT(ptszTip != NULL);
|
|
|
|
memset(&nid, 0, sizeof(nid));
|
|
nid.cbSize = sizeof(nid);
|
|
nid.hWnd = hwnd;
|
|
nid.uCallbackMessage = umsgTray;
|
|
nid.hIcon = hIcon;
|
|
lstrcpyn(nid.szTip, ptszTip, ARRAYSIZE(nid.szTip));
|
|
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
|
rc = Shell_NotifyIcon(NIM_ADD, &nid);
|
|
if (rc == TRUE)
|
|
{
|
|
gdwfTabSrv |= TSF_TRAYICON_CREATED;
|
|
}
|
|
|
|
TRACEEXIT(("=%x\n", rc));
|
|
return rc;
|
|
} //CreateTrayIcon
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func BOOL | DestroyTrayIcon | Destroy the tray icon.
|
|
|
|
@parm IN HWND | hwnd | Window handle that the tray can send message to.
|
|
@parm IN UINT | umsgTray | Message ID that the tray used to send messages.
|
|
@parm IN HICON | hIcon | Icon handle.
|
|
@parm IN LPCTSTR | ptszTip | Points to the Tip string.
|
|
|
|
@rvalue SUCCESS | Returns TRUE.
|
|
@rvalue FAILURE | Returns FALSE.
|
|
--*/
|
|
|
|
BOOL
|
|
DestroyTrayIcon(
|
|
IN HWND hwnd,
|
|
IN UINT umsgTray,
|
|
IN HICON hIcon
|
|
)
|
|
{
|
|
TRACEPROC("DestroyTrayIcon", 2)
|
|
BOOL rc;
|
|
NOTIFYICONDATA nid;
|
|
|
|
TRACEENTER(("(hwnd=%x,msgTray=%x,hIcon=%x)\n", hwnd, umsgTray, hIcon));
|
|
TRACEASSERT(hIcon != NULL);
|
|
TRACEASSERT(gdwfTabSrv & TSF_TRAYICON_CREATED);
|
|
|
|
memset(&nid, 0, sizeof(nid));
|
|
nid.cbSize = sizeof(nid);
|
|
nid.hWnd = hwnd;
|
|
nid.uCallbackMessage = umsgTray;
|
|
nid.hIcon = hIcon;
|
|
nid.uFlags = NIF_ICON | NIF_MESSAGE;
|
|
rc = Shell_NotifyIcon(NIM_DELETE, &nid);
|
|
if (rc == TRUE)
|
|
{
|
|
gdwfTabSrv &= ~TSF_TRAYICON_CREATED;
|
|
}
|
|
|
|
TRACEEXIT(("=%x\n", rc));
|
|
return rc;
|
|
} //DestroyTrayIcon
|
|
|
|
/*++
|
|
@doc INTERNAL
|
|
|
|
@func BOOL | SetBalloonToolTip | Set Balloon Tool Tip on tray icon
|
|
|
|
@parm IN HWND | hwnd | Window handle that the tray can send message to.
|
|
@parm IN UINT | umsgTray | Message ID that the tray used to send messages.
|
|
@parm IN LPCTSTR | ptszTitle | Points to the Tip title string.
|
|
@parm IN LPCTSTR | ptszTip | Points to the Tip text string.
|
|
@parm IN UINT | uTimeout | Specify how long the balloon tip stays up.
|
|
|
|
@rvalue SUCCESS | Returns TRUE.
|
|
@rvalue FAILURE | Returns FALSE.
|
|
--*/
|
|
|
|
BOOL SetBalloonToolTip(
|
|
IN HWND hwnd,
|
|
IN UINT umsgTray,
|
|
IN LPCTSTR ptszTitle,
|
|
IN LPCTSTR ptszTip,
|
|
IN UINT uTimeout,
|
|
IN DWORD dwInfoFlags
|
|
)
|
|
{
|
|
TRACEPROC("SetBalloonToolTip", 2)
|
|
BOOL rc;
|
|
NOTIFYICONDATA nid;
|
|
|
|
TRACEENTER(("(hwnd=%x,TrayMsg=%x,Title=%s,Tip=%s,Timeout=%d,InfoFlags=%x)\n",
|
|
hwnd, umsgTray, ptszTitle, ptszTip, uTimeout, dwInfoFlags));
|
|
TRACEASSERT(gdwfTabSrv & TSF_TRAYICON_CREATED);
|
|
|
|
memset(&nid, 0, sizeof(nid));
|
|
nid.cbSize = sizeof(nid);
|
|
nid.hWnd = hwnd;
|
|
nid.uFlags = NIF_INFO;
|
|
nid.uCallbackMessage = umsgTray;
|
|
nid.uTimeout = uTimeout;
|
|
lstrcpyn(nid.szInfo, ptszTip, ARRAYSIZE(nid.szInfo));
|
|
lstrcpyn(nid.szInfoTitle, ptszTitle, ARRAYSIZE(nid.szInfoTitle));
|
|
nid.dwInfoFlags = dwInfoFlags;
|
|
rc = Shell_NotifyIcon(NIM_MODIFY, &nid);
|
|
|
|
TRACEEXIT(("=%x\n", rc));
|
|
return rc;
|
|
} //SetBalloonToolTip
|