[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[TSVN] balloon help problems with multiple monitors

From: Bodo <bodo42_at_gmx.de>
Date: 2004-12-16 19:31:40 CET

Dear TSVN team,

I could not find anything relating to this in the mailing list, so here is
my bug report (and fix).
Best regards,
 Bodo Maass

P.S.: Please reply to me directly, as I'm not subscribed to the mailing
list.

This problem occurs with TSVN 1.1.1 Build 1857 (and lower).

Problem:
On a computer with two monitors, place the secondary monitor to the left of
the primary monitor in the display settings. Open the TSVN settings dialog
and point at a control that has a Balloonhelp tooltip. The tooltip will be
displayed on the primary monitor.
The same thing happens if the secondary monitor is above the primary
monitor.

Explanation:
The code for the balloon help is somewhat aware of multiple monitors by
calling GetSystemMetrics(SM_CXVIRTUALSCREEN) and related functions. However,
the code is not aware of the fact that display coordinates can be negative
if the secondary monitor is to the left or above the primary monitor. Hence
clipping the windowrect of the Balloonhelp window to positive coordinates
can cause it to appear on the wrong monitor.

Solution:
This requires changes to the methods CalculateInfoBoxRect,
TestHorizDirection, and TestVertDirection. I also added a new helper method
called GetMonitorWorkArea which retrieves the work area of the monitor that
contains a given point.
As a side effect, using the work area instead of the monitor rect causes the
Balloon window not be be behind the taskbar.
According to MSDN, this will not work on Windows 95 or NT. If those systems
ought to be supported, some other code needs to be in place.

Here are the modified methods as they appear in Balloon.cpp:

void CBalloon::GetMonitorWorkArea(const CPoint& sourcePoint, CRect&
monitorRect)
{
  // identify the monitor that contains the sourcePoint
  // and return the work area (the portion of the screen
  // not obscured by the system taskbar or by application
  // desktop toolbars) of that monitor
    HMONITOR hMonitor;
    MONITORINFO mi;
    hMonitor = MonitorFromPoint(sourcePoint, MONITOR_DEFAULTTONEAREST);

    //
    // get the work area
    //
    mi.cbSize = sizeof(mi);
    GetMonitorInfo(hMonitor, &mi);

    monitorRect = mi.rcWork;
}

void CBalloon::CalculateInfoBoxRect(CPoint * pt, CRect * rect)
{
  CRect monitorRect;
  GetMonitorWorkArea(*pt, monitorRect);

        CPoint ptEnd;
        m_nLastDirection = m_pToolInfo.nDirection;
        if (!TestHorizDirection(pt->x, rect->Width(), monitorRect,
m_nLastDirection, rect))
        {
                m_nLastDirection = GetNextHorizDirection(m_nLastDirection);
                TestHorizDirection(pt->x, rect->Width(), monitorRect,
m_nLastDirection, rect);
        }
        if (!TestVertDirection(pt->y, rect->Height(), monitorRect,
m_nLastDirection, rect))
        {
                m_nLastDirection = GetNextVertDirection(m_nLastDirection);
                TestVertDirection(pt->y, rect->Height(), monitorRect,
m_nLastDirection, rect);
        }

        if ((m_pToolInfo.nStyles & BALLOON_SHADOW) &&
                ((m_nLastDirection == BALLOON_LEFT_TOP) || (m_nLastDirection
== BALLOON_LEFT_BOTTOM)))
                rect->OffsetRect(m_nSizes[XBLSZ_SHADOW_CX],
m_nSizes[XBLSZ_SHADOW_CY]);
}

BOOL CBalloon::TestHorizDirection(int x, int cx, const CRect& monitorRect,
int nDirection, LPRECT rect)
{
        int left = 0;
        int right = 0;
        int anchorMarginSize = (int)m_nSizes[XBLSZ_MARGIN_ANCHOR];
        
        switch (nDirection)
        {
        case BALLOON_LEFT_TOP:
        case BALLOON_LEFT_BOTTOM:
                right = ((x + anchorMarginSize) > monitorRect.right) ?
monitorRect.right : (x + anchorMarginSize);
                left = right - cx;
                break;
        case BALLOON_RIGHT_TOP:
        case BALLOON_RIGHT_BOTTOM:
                left = (x - anchorMarginSize)<monitorRect.left ?
monitorRect.left : (x - anchorMarginSize);
                right = left + cx;
                break;
        }

        BOOL bTestOk = ((left >= monitorRect.left) && (right <=
monitorRect.right)) ? TRUE : FALSE;
        if (bTestOk)
        {
                rect->left = left;
                rect->right = right;
        }

        return bTestOk;
}

BOOL CBalloon::TestVertDirection(int y, int cy, const CRect& monitorRect,
int nDirection, LPRECT rect)
{
        int top = 0;
        int bottom = 0;

        switch (nDirection)
        {
        case BALLOON_LEFT_TOP:
        case BALLOON_RIGHT_TOP:
                bottom = y;
                top = bottom - cy;
                break;
        case BALLOON_LEFT_BOTTOM:
        case BALLOON_RIGHT_BOTTOM:
                top = y;
                bottom = top + cy;
                break;
        }

        BOOL bTestOk = ((top >= monitorRect.top) && (bottom <=
monitorRect.bottom)) ? TRUE : FALSE;
        if (bTestOk)
        {
                rect->top = top;
                rect->bottom = bottom;
        }

        return bTestOk;
}

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tortoisesvn.tigris.org
For additional commands, e-mail: dev-help@tortoisesvn.tigris.org
Received on Thu Dec 16 19:47:59 2004

This is an archived mail posted to the TortoiseSVN Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.