⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 traywnd.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * ReactOS Explorer
 *
 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <precomp.h>

static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;

#define WM_APP_TRAYDESTROY  (WM_APP + 0x100)

static LONG TrayWndCount = 0;

static const TCHAR szTrayWndClass[] = TEXT("Shell_TrayWnd");

static const ITrayWindowVtbl ITrayWindowImpl_Vtbl;
static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl;

/*
 * ITrayWindow
 */

const GUID IID_IShellDesktopTray = {0x213e2df9, 0x9a14, 0x4328, {0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9}};

typedef struct
{
    const ITrayWindowVtbl *lpVtbl;
    const IShellDesktopTrayVtbl *lpVtblShellDesktopTray;
    LONG Ref;

    HWND hWnd;
    HWND hWndDesktop;

    HWND hwndStart;
    HIMAGELIST himlStartBtn;
    SIZE StartBtnSize;
    HFONT hStartBtnFont;
    HFONT hCaptionFont;

    ITrayBandSite *TrayBandSite;
    HWND hwndRebar;
    HWND hwndTaskSwitch;
    HWND hwndTrayNotify;

    DWORD Position;
    HMONITOR Monitor;
    DWORD DraggingPosition;
    HMONITOR DraggingMonitor;

    RECT rcTrayWnd[4];
    RECT rcNewPosSize;
    SIZE TraySize;
    union
    {
        DWORD Flags;
        struct
        {
            DWORD AutoHide : 1;
            DWORD AlwaysOnTop : 1;
            DWORD SmSmallIcons : 1;
            DWORD HideClock : 1;
            DWORD Locked : 1;

            /* UI Status */
            DWORD InSizeMove : 1;
            DWORD IsDragging : 1;
            DWORD NewPosSize : 1;
        };
    };

    NONCLIENTMETRICS ncm;
    HFONT hFont;

    IMenuBand *StartMenuBand;
    IMenuPopup *StartMenuPopup;
    HBITMAP hbmStartMenu;

    HWND hWndTrayProperties;
} ITrayWindowImpl;

static IUnknown *
IUnknown_from_impl(ITrayWindowImpl *This)
{
    return (IUnknown *)&This->lpVtbl;
}

static ITrayWindow *
ITrayWindow_from_impl(ITrayWindowImpl *This)
{
    return (ITrayWindow *)&This->lpVtbl;
}

static IShellDesktopTray *
IShellDesktopTray_from_impl(ITrayWindowImpl *This)
{
    return (IShellDesktopTray *)&This->lpVtblShellDesktopTray;
}

static ITrayWindowImpl *
impl_from_ITrayWindow(ITrayWindow *iface)
{
    return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl,
                                                               lpVtbl));
}

static ITrayWindowImpl *
impl_from_IShellDesktopTray(IShellDesktopTray *iface)
{
    return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl,
                                                               lpVtblShellDesktopTray));
}

/*
 * ITrayWindow
 */

static BOOL
ITrayWindowImpl_UpdateNonClientMetrics(IN OUT ITrayWindowImpl *This)
{
    This->ncm.cbSize = sizeof(This->ncm);
    if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
                             sizeof(This->ncm),
                             &This->ncm,
                             0))
    {
        if (This->hFont != NULL)
            DeleteObject(This->hFont);

        This->hFont = CreateFontIndirect(&This->ncm.lfMessageFont);
        return TRUE;
    }

    return FALSE;
}

static VOID
ITrayWindowImpl_SetWindowsFont(IN OUT ITrayWindowImpl *This)
{
    if (This->hwndTrayNotify != NULL)
    {
        SendMessage(This->hwndTrayNotify,
                    WM_SETFONT,
                    (WPARAM)This->hFont,
                    TRUE);
    }
}

static HMONITOR
ITrayWindowImpl_GetScreenRectFromRect(IN OUT ITrayWindowImpl *This,
                                      IN OUT RECT *pRect,
                                      IN DWORD dwFlags)
{
    MONITORINFO mi;
    HMONITOR hMon;

    mi.cbSize = sizeof(mi);
    hMon = MonitorFromRect(pRect,
                           dwFlags);
    if (hMon != NULL &&
        GetMonitorInfo(hMon,
                       &mi))
    {
        *pRect = mi.rcMonitor;
    }
    else
    {
        pRect->left = 0;
        pRect->top = 0;
        pRect->right = GetSystemMetrics(SM_CXSCREEN);
        pRect->bottom = GetSystemMetrics(SM_CYSCREEN);

        hMon = NULL;
    }

    return hMon;
}

static HMONITOR
ITrayWindowImpl_GetMonitorFromRect(IN OUT ITrayWindowImpl *This,
                                   IN const RECT *pRect)
{
    HMONITOR hMon;

    /* In case the monitor sizes or saved sizes differ a bit (probably
       not a lot, only so the tray window overlaps into another monitor
       now), minimize the risk that we determine a wrong monitor by
       using the center point of the tray window if we can't determine
       it using the rectangle. */
    hMon = MonitorFromRect(pRect,
                           MONITOR_DEFAULTTONULL);
    if (hMon == NULL)
    {
        POINT pt;

        pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
        pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);

        /* be less error-prone, find the nearest monitor */
        hMon = MonitorFromPoint(pt,
                                MONITOR_DEFAULTTONEAREST);
    }

    return hMon;
}

static HMONITOR
ITrayWindowImpl_GetScreenRect(IN OUT ITrayWindowImpl *This,
                              IN HMONITOR hMonitor,
                              IN OUT RECT *pRect)
{
    HMONITOR hMon = NULL;

    if (hMonitor != NULL)
    {
        MONITORINFO mi;

        mi.cbSize = sizeof(mi);
        if (!GetMonitorInfo(This->Monitor,
                            &mi))
        {
            /* Hm, the monitor is gone? Try to find a monitor where it
               could be located now */
            hMon = ITrayWindowImpl_GetMonitorFromRect(This,
                                                      pRect);
            if (hMon == NULL ||
                !GetMonitorInfo(hMon,
                                &mi))
            {
                hMon = NULL;
                goto GetPrimaryRect;
            }
        }

        *pRect = mi.rcMonitor;
    }
    else
    {
GetPrimaryRect:
        pRect->left = 0;
        pRect->top = 0;
        pRect->right = GetSystemMetrics(SM_CXSCREEN);
        pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
    }

    return hMon;
}

static VOID
ITrayWindowImpl_MakeTrayRectWithSize(IN DWORD Position,
                                     IN const SIZE *pTraySize,
                                     IN OUT RECT *pRect)
{
    switch (Position)
    {
        case ABE_LEFT:
            pRect->right = pRect->left + pTraySize->cx;
            break;

        case ABE_TOP:
            pRect->bottom = pRect->top + pTraySize->cy;
            break;

        case ABE_RIGHT:
            pRect->left = pRect->right - pTraySize->cx;
            break;

        case ABE_BOTTOM:
        default:
            pRect->top = pRect->bottom - pTraySize->cy;
            break;
    }
}

static VOID
ITrayWindowImpl_GetTrayRectFromScreenRect(IN OUT ITrayWindowImpl *This,
                                          IN DWORD Position,
                                          IN const RECT *pScreen,
                                          IN const SIZE *pTraySize  OPTIONAL,
                                          OUT RECT *pRect)
{
    if (pTraySize == NULL)
        pTraySize = &This->TraySize;

    *pRect = *pScreen;

    /* Move the border outside of the screen */
    InflateRect(pRect,
                GetSystemMetrics(SM_CXEDGE),
                GetSystemMetrics(SM_CYEDGE));

    ITrayWindowImpl_MakeTrayRectWithSize(Position,
                                         pTraySize,
                                         pRect);
}

BOOL
ITrayWindowImpl_IsPosHorizontal(IN OUT ITrayWindowImpl *This)
{
    return This->Position == ABE_TOP || This->Position == ABE_BOTTOM;
}

static HMONITOR
ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl *This,
                                   IN DWORD Position,
                                   IN OUT RECT *pRect)
{
    RECT rcScreen;
    BOOL Horizontal;
    HMONITOR hMon;
    SIZE szMax, szWnd;

    Horizontal = ITrayWindowImpl_IsPosHorizontal(This);

    szWnd.cx = pRect->right - pRect->left;
    szWnd.cy = pRect->bottom - pRect->top;

    rcScreen = *pRect;
    hMon = ITrayWindowImpl_GetScreenRectFromRect(This,
                                                 &rcScreen,
                                                 MONITOR_DEFAULTTONEAREST);

    /* Calculate the maximum size of the tray window and limit the window
       size to half of the screen's size. */
    szMax.cx = (rcScreen.right - rcScreen.left) / 2;
    szMax.cy = (rcScreen.bottom - rcScreen.top) / 2;
    if (szWnd.cx > szMax.cx)
        szWnd.cx = szMax.cx;
    if (szWnd.cy > szMax.cy)
        szWnd.cy = szMax.cy;

    /* FIXME - calculate */

    ITrayWindowImpl_GetTrayRectFromScreenRect(This,
                                              Position,
                                              &rcScreen,
                                              &szWnd,
                                              pRect);

    return hMon;
}

#if 0
static VOID
ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl *This,
                                     OUT RECT *pRect)
{
    RECT rcMin = {0};

    AdjustWindowRectEx(&rcMin,
                       GetWindowLong(This->hWnd,
                                     GWL_STYLE),
                       FALSE,
                       GetWindowLong(This->hWnd,
                                     GWL_EXSTYLE));

    *pRect = rcMin;
}
#endif


static DWORD
ITrayWindowImpl_GetDraggingRectFromPt(IN OUT ITrayWindowImpl *This,
                                      IN POINT pt,
                                      OUT RECT *pRect,
                                      OUT HMONITOR *phMonitor)
{
    HMONITOR hMon, hMonNew;
    DWORD PosH, PosV, Pos;
    SIZE DeltaPt, ScreenOffset;
    RECT rcScreen;

    rcScreen.left = 0;
    rcScreen.top = 0;

    /* Determine the screen rectangle */
    hMon = MonitorFromPoint(pt,
                            MONITOR_DEFAULTTONULL);

    if (hMon != NULL)
    {
        MONITORINFO mi;

        mi.cbSize = sizeof(mi);
        if (!GetMonitorInfo(hMon,
                            &mi))
        {
            hMon = NULL;
            goto GetPrimaryScreenRect;
        }

        /* make left top corner of the screen zero based to
           make calculations easier */
        pt.x -= mi.rcMonitor.left;
        pt.y -= mi.rcMonitor.top;

        ScreenOffset.cx = mi.rcMonitor.left;
        ScreenOffset.cy = mi.rcMonitor.top;
        rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left;
        rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top;
    }
    else
    {
GetPrimaryScreenRect:
        ScreenOffset.cx = 0;
        ScreenOffset.cy = 0;
        rcScreen.right = GetSystemMetrics(SM_CXSCREEN);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -