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

📄 traywnd.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
        rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
    }

    /* Calculate the nearest screen border */
    if (pt.x < rcScreen.right / 2)
    {
        DeltaPt.cx = pt.x;
        PosH = ABE_LEFT;
    }
    else
    {
        DeltaPt.cx = rcScreen.right - pt.x;
        PosH = ABE_RIGHT;
    }

    if (pt.y < rcScreen.bottom / 2)
    {
        DeltaPt.cy = pt.y;
        PosV = ABE_TOP;
    }
    else
    {
        DeltaPt.cy = rcScreen.bottom - pt.y;
        PosV = ABE_BOTTOM;
    }

    Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;

    /* Fix the screen origin to be relative to the primary monitor again */
    OffsetRect(&rcScreen,
               ScreenOffset.cx,
               ScreenOffset.cy);

    hMonNew = ITrayWindowImpl_GetMonitorFromRect(This,
                                                 &This->rcTrayWnd[Pos]);
    if (hMon != hMonNew)
    {
        SIZE szTray;

        /* Recalculate the rectangle, we're dragging to another monitor.
           We don't need to recalculate the rect on single monitor systems. */
        szTray.cx = This->rcTrayWnd[Pos].right - This->rcTrayWnd[Pos].left;
        szTray.cy = This->rcTrayWnd[Pos].bottom - This->rcTrayWnd[Pos].top;

        ITrayWindowImpl_GetTrayRectFromScreenRect(This,
                                                  Pos,
                                                  &rcScreen,
                                                  &szTray,
                                                  pRect);

        hMon = hMonNew;
    }
    else
    {
        /* The user is dragging the tray window on the same monitor. We don't need
           to recalculate the rectangle */
        *pRect = This->rcTrayWnd[Pos];
    }

    *phMonitor = hMon;

    return Pos;
}

static DWORD
ITrayWindowImpl_GetDraggingRectFromRect(IN OUT ITrayWindowImpl *This,
                                        IN OUT RECT *pRect,
                                        OUT HMONITOR *phMonitor)
{
    POINT pt;

    /* Calculate the center of the rectangle. We call
       ITrayWindowImpl_GetDraggingRectFromPt to calculate a valid
       dragging rectangle */
    pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
    pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);

    return ITrayWindowImpl_GetDraggingRectFromPt(This,
                                                 pt,
                                                 pRect,
                                                 phMonitor);
}

static VOID
ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This,
                               IN OUT LPWINDOWPOS pwp)
{
    RECT rcTray;

    if (This->IsDragging)
    {
        rcTray.left = pwp->x;
        rcTray.top = pwp->y;
        rcTray.right = rcTray.left + pwp->cx;
        rcTray.bottom = rcTray.top + pwp->cy;

        if (!EqualRect(&rcTray,
                       &This->rcTrayWnd[This->DraggingPosition]))
        {
            /* Recalculate the rectangle, the user dragged the tray
               window to another monitor or the window was somehow else
               moved or resized */
            This->DraggingPosition = ITrayWindowImpl_GetDraggingRectFromRect(This,
                                                                             &rcTray,
                                                                             &This->DraggingMonitor);
            //This->rcTrayWnd[This->DraggingPosition] = rcTray;
        }

        //This->Monitor = ITrayWindowImpl_CalculateValidSize(This,
        //                                                   This->DraggingPosition,
        //                                                   &rcTray);

        This->Monitor = This->DraggingMonitor;
        This->Position = This->DraggingPosition;
        This->IsDragging = FALSE;

        This->rcTrayWnd[This->Position] = rcTray;
        goto ChangePos;
    }
    else if (GetWindowRect(This->hWnd,
                           &rcTray))
    {
        if (This->InSizeMove)
        {
            if (!(pwp->flags & SWP_NOMOVE))
            {
                rcTray.left = pwp->x;
                rcTray.top = pwp->y;
            }

            if (!(pwp->flags & SWP_NOSIZE))
            {
                rcTray.right = rcTray.left + pwp->cx;
                rcTray.bottom = rcTray.top + pwp->cy;
            }

            This->Position = ITrayWindowImpl_GetDraggingRectFromRect(This,
                                                                     &rcTray,
                                                                     &This->Monitor);

            if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
            {
                SIZE szWnd;

                szWnd.cx = pwp->cx;
                szWnd.cy = pwp->cy;

                ITrayWindowImpl_MakeTrayRectWithSize(This->Position,
                                                     &szWnd,
                                                     &rcTray);
            }

            This->rcTrayWnd[This->Position] = rcTray;
        }
        else
        {
            /* If the user isn't resizing the tray window we need to make sure the
               new size or position is valid. This is to prevent changes to the window
               without user interaction. */
            rcTray = This->rcTrayWnd[This->Position];
        }

ChangePos:
        This->TraySize.cx = rcTray.right - rcTray.left;
        This->TraySize.cy = rcTray.bottom - rcTray.top;

        pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
        pwp->x = rcTray.left;
        pwp->y = rcTray.top;
        pwp->cx = This->TraySize.cx;
        pwp->cy = This->TraySize.cy;
    }
}

static VOID
ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl *This,
                              IN BOOL Clip)
{
    RECT rcClip, rcWindow;
    HRGN hClipRgn;

    if (GetWindowRect(This->hWnd,
                      &rcWindow))
    {
        /* Disable clipping on systems with only one monitor */
        if (GetSystemMetrics(SM_CMONITORS) <= 1)
            Clip = FALSE;

        if (Clip)
        {
            rcClip = rcWindow;

            ITrayWindowImpl_GetScreenRect(This,
                                          This->Monitor,
                                          &rcClip);

            if (!IntersectRect(&rcClip,
                               &rcClip,
                               &rcWindow))
            {
                rcClip = rcWindow;
            }

            OffsetRect(&rcClip,
                       -rcWindow.left,
                       -rcWindow.top);

            hClipRgn = CreateRectRgnIndirect(&rcClip);
        }
        else
            hClipRgn = NULL;

        /* Set the clipping region or make sure the window isn't clipped
           by disabling it explicitly. */
        SetWindowRgn(This->hWnd,
                     hClipRgn,
                     TRUE);
    }
}

static VOID
ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl *This)
{
    RECT rcTray;

    rcTray = This->rcTrayWnd[This->Position];
//    DbgPrint("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);

    /* Move the tray window */
    SetWindowPos(This->hWnd,
                 NULL,
                 rcTray.left,
                 rcTray.top,
                 rcTray.right - rcTray.left,
                 rcTray.bottom - rcTray.top,
                 SWP_NOZORDER);

    ITrayWindowImpl_ApplyClipping(This,
                                  TRUE);
}

typedef struct _TW_STUCKRECTS2
{
    DWORD cbSize;
    LONG Unknown;
    DWORD dwFlags;
    DWORD Position;
    SIZE Size;
    RECT Rect;
} TW_STRUCKRECTS2, *PTW_STUCKRECTS2;

static VOID
ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
{
    DWORD Pos;
    TW_STRUCKRECTS2 sr;
    RECT rcScreen;
    SIZE WndSize, EdgeSize, DlgFrameSize;
    DWORD cbSize = sizeof(sr);

    EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
    EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
    DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
    DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);

    if (SHGetValue(hkExplorer,
                   TEXT("StuckRects2"),
                   TEXT("Settings"),
                   NULL,
                   &sr,
                   &cbSize) == ERROR_SUCCESS &&
        sr.cbSize == sizeof(sr))
    {
        This->AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0;
        This->AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0;
        This->SmSmallIcons = (sr.dwFlags & 0x4) != 0;
        This->HideClock = (sr.dwFlags & 0x8) != 0;

        /* FIXME: Are there more flags? */

        if (sr.Position > ABE_BOTTOM)
            This->Position = ABE_BOTTOM;
        else
            This->Position = sr.Position;

        /* Try to find out which monitor the tray window was located on last.
           Here we're only interested in the monitor screen that we think
           is the last one used. We're going to determine on which monitor
           we really are after calculating the docked position. */
        rcScreen = sr.Rect;
        ITrayWindowImpl_GetScreenRectFromRect(This,
                                              &rcScreen,
                                              MONITOR_DEFAULTTONEAREST);
    }
    else
    {
        This->Position = ABE_BOTTOM;

        /* Use the minimum size of the taskbar, we'll use the start
           button as a minimum for now. Make sure we calculate the
           entire window size, not just the client size. However, we
           use a thinner border than a standard thick border, so that
           the start button and bands are not stuck to the screen border. */
        sr.Size.cx = This->StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
        sr.Size.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));

        /* Use the primary screen by default */
        rcScreen.left = 0;
        rcScreen.top = 0;
        rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
        rcScreen.right = GetSystemMetrics(SM_CYSCREEN);
        ITrayWindowImpl_GetScreenRectFromRect(This,
                                              &rcScreen,
                                              MONITOR_DEFAULTTOPRIMARY);
    }

    /* Determine a minimum tray window rectangle. The "client" height is
       zero here since we cannot determine an optimal minimum width when
       loaded as a vertical tray window. We just need to make sure the values
       loaded from the registry are at least. The windows explorer behaves
       the same way, it allows the user to save a zero width vertical tray
       window, but not a zero height horizontal tray window. */
    WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
    WndSize.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));

    if (WndSize.cx < sr.Size.cx)
        WndSize.cx = sr.Size.cx;
    if (WndSize.cy < sr.Size.cy)
        WndSize.cy = sr.Size.cy;

    /* Save the calculated size */
    This->TraySize = WndSize;

    /* Calculate all docking rectangles. We need to do this here so they're
       initialized and dragging the tray window to another position gives
       usable results */
    for (Pos = ABE_LEFT;
         Pos <= ABE_BOTTOM;
         Pos++)
    {
        ITrayWindowImpl_GetTrayRectFromScreenRect(This,
                                                  Pos,
                                                  &rcScreen,
                                                  &This->TraySize,
                                                  &This->rcTrayWnd[Pos]);
//        DbgPrint("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom);
    }

    /* Determine which monitor we are on. It shouldn't matter which docked
       position rectangle we use */
    This->Monitor = ITrayWindowImpl_GetMonitorFromRect(This,
                                                       &This->rcTrayWnd[ABE_LEFT]);
}

static UINT
ITrayWindowImpl_TrackMenu(IN OUT ITrayWindowImpl *This,
                          IN HMENU hMenu,
                          IN POINT *ppt  OPTIONAL,
                          IN HWND hwndExclude  OPTIONAL,
                          IN BOOL TrackUp,
                          IN BOOL IsContextMenu)
{
    TPMPARAMS tmp, *ptmp = NULL;
    POINT pt;
    UINT cmdId;
    UINT fuFlags;

    if (hwndExclude != NULL)
    {
        /* Get the client rectangle and map it to screen coordinates */
        if (GetClientRect(hwndExclude,
                          &tmp.rcExclude) &&
            MapWindowPoints(hwndExclude,
                            NULL,
                            (LPPOINT)&tmp.rcExclude,
                            2) != 0)
        {
            ptmp = &tmp;
        }
    }

    if (ppt == NULL)
    {
        if (ptmp == NULL &&
            GetClientRect(This->hWnd,
                          &tmp.rcExclude) &&
            MapWindowPoints(This->hWnd,
                            NULL,
                            (LPPOINT)&tmp.rcExclude,
                            2) != 0)
        {
            ptmp = &tmp;
        }

        if (ptmp != NULL)
        {
            /* NOTE: TrackPopupMenuEx will eventually align the track position
                     for us, no need to take care of it here as long as the
                     coordinates are somewhere within the exclusion rectangle */
            pt.x = ptmp->rcExclude.left;
            pt.y = ptmp->rcExclude.top;
        }
        else
            pt.x = pt.y = 0;
    }
    else
        pt = *ppt;

    tmp.cbSize = sizeof(tmp);

    fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
    fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
    if (IsContextMenu)
        fuFlags |= TPM_RIGHTBUTTON;
    else
        fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);

    cmdId = TrackPopupMenuEx(hMenu,
                             fuFlags,
                             pt.x,
                             pt.y,

⌨️ 快捷键说明

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