Click here to Skip to main content
15,886,518 members
Articles / Mobile Apps

Window Tabs (WndTabs) Add-In for DevStudio

Rate me:
Please Sign up or sign in to vote.
5.00/5 (37 votes)
11 Jul 2002 365K   7.3K   94  
Window and File Management add-in for Visual C++
/***************************************************************************/
/* NOTE:                                                                   */
/* This document is copyright (c) by Oz Solomonovich, and is bound by the  */
/* MIT open source license (www.opensource.org/licenses/mit-license.html). */
/* See License.txt for more information.                                   */
/***************************************************************************/


// BCGSupp.cpp - BCG support classes

#include "stdafx.h"
#include "BCGSupp.h"
#include "Config.h"
#include "MainFrame.h"
#include "DevStudioWnd.h"
#include "WndTabs.h"


#define GETINSTANCE(hWnd)   (HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE) 

static HHOOK s_hook      = NULL;
static HHOOK s_hookKB    = NULL;
static HHOOK s_hookMouse = NULL;

static DWORD s_msgThreadID = (DWORD)-1;


inline bool IsTooltipMessage(int message)
{
    return ((message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE ||
             message == WM_LBUTTONUP || message == WM_RBUTTONUP ||
             message == WM_MBUTTONUP) &&
            (GetKeyState(VK_LBUTTON) >= 0 && GetKeyState(VK_RBUTTON) >= 0 &&
             GetKeyState(VK_MBUTTON) >= 0));
}

static LONG cRefCount = -1;

LRESULT CALLBACK GetMsgProc(
  int iCode,       // hook code
  WPARAM wParam,  // removal flag
  LPARAM lParam   // address of structure with message
)  
{
    MSG * const pMsg = (MSG *)lParam;

    if (wParam != PM_REMOVE         ||
        pMsg->message == WM_TIMER   ||
        !g_pMainFrame)
    {
        // quick exit
        return CallNextHookEx(s_hook, iCode, wParam, lParam);
    }

    WT_ASSERT(g_pMainFrame == pTheApp->m_pMainWnd);
    
    if (InterlockedIncrement(&cRefCount) == 0)
    {
#ifdef _DEBUG
        if (s_msgThreadID != GetCurrentThreadId())
        {
            WT_ASSERT(FALSE);
            goto chain_hook;
        }
#endif

        CFrameWnd *& pRoutingFrame = AfxGetThreadState()->m_pRoutingFrame;
        if (pRoutingFrame  &&  pRoutingFrame->m_hWnd == g_pMainFrame->m_hWnd)
        {
            pRoutingFrame = (CFrameWnd *)g_pDevStudioWnd;
        }
    
        if (pTheApp->m_pMainWnd)
        {
            WT_L4_TRACE("GetMsgProc, wp=%d msg=%d", wParam, ((MSG *)lParam)->message);
            if (iCode == HC_ACTION)
            {
                WT_L4_TRACE(".. routing");
//                CWnd* pWnd = CWnd::FromHandle/*Permanent*/(pMsg->hwnd);
                HWND  hWnd;
//                if (pWnd->GetSafeHwnd())
                if (1)
                {
                    hWnd = pMsg->hwnd;
                    HWND  hWndParent = pTheApp->m_pMainWnd->m_hWnd;
                    while (hWnd  &&  hWnd != hWndParent)
                        hWnd = ::GetParent(hWnd);
                }
                else
                {
                    hWnd = NULL;
                }
                BOOL bRes = false;
                if (hWnd)
                {
//                    if ((pWnd->GetStyle() & WS_CHILD) != 0)
                    {
                        WT_MANAGE_STATE();
                        bRes = g_pMainFrame->PreTranslateMessage(pMsg);
                        if (bRes)
                        {
                            pMsg->message = WM_NULL;
                        }
                    }
                }
                else           
                {
                    if (!IsTooltipMessage(pMsg->message))
                    {
                        if (pMsg->message != WM_SYSKEYUP)
                        {
                            WT_MANAGE_STATE();
                            bRes = g_pMainFrame->PreTranslateMessage(pMsg);
                        }
                        if (bRes)
                        {
                            if (pMsg->message == WM_KEYDOWN  ||
                                pMsg->message == WM_SYSKEYDOWN)
                            {
                                // cloak keystrokes processed by the 
                                // WndTabs accelerators
                                pMsg->message = WM_NULL;
                            }
                            WT_L3_TRACE(" (*)");
                        }
                    }
                }
                if (bRes)
                {
                    WT_L4_TRACE(" - processed\n");
                    goto chain_hook;
                }
            }
            WT_L4_TRACE("\n");
        }
    }
    else
    {
//        MessageBeep(MB_OK);
    }

chain_hook:    
    LRESULT lResult = CallNextHookEx(s_hook, iCode, wParam, lParam);

    InterlockedDecrement(&cRefCount);

    return lResult;
}
 

LRESULT CALLBACK KeyboardProc(
  int iCode,       // hook code
  WPARAM wParam,  // virtual-key code
  LPARAM lParam   // keystroke-message information
)  
{
    WT_L4_TRACE("KeyboardProc, kb=%d ", wParam);
    if (iCode == HC_ACTION)
    {
        // If this is a repeat or the key is being released, ignore it.
        if (!(lParam & 0x80000000 || lParam & 0x40000000))
        {
            WT_L4_TRACE(".. routing");
            MSG msg;
            msg.hwnd = g_pDevStudioWnd->m_hWnd;
            msg.lParam = lParam;
            msg.wParam = wParam;
            msg.message = WM_KEYDOWN;
            WT_MANAGE_STATE();
            if (((CMainFrame *)pTheApp->m_pMainWnd)->PreTranslateMessage(&msg))
            {
                WT_L4_TRACE(" - processed\n");
                CallNextHookEx(s_hookKB, iCode, wParam, lParam);
                return 1;
            }
        }
    }
    WT_L4_TRACE("\n");
    
    return CallNextHookEx(s_hookKB, iCode, wParam, lParam);
}
 
LRESULT CALLBACK MouseProc(
  int iCode,       // hook code
  WPARAM wParam,  
  LPARAM lParam   
)  
{
    WT_L4_TRACE("MouseProc, msg=%d ", wParam);
    MOUSEHOOKSTRUCT& mhs = *(MOUSEHOOKSTRUCT *)lParam;
    
    if (iCode >= 0)
    {
        WT_L4_TRACE(".. routing");
        MSG msg;
        msg.hwnd = pTheApp->m_pMainWnd->m_hWnd;// g_pDevStudioWnd->m_hWnd;
        msg.wParam = mhs.dwExtraInfo;
        pTheApp->m_pMainWnd->ScreenToClient(&mhs.pt);
        msg.lParam = MAKELONG(mhs.pt.x, mhs.pt.y);
        msg.message = wParam;
        WT_MANAGE_STATE();
        if (((CMainFrame *)pTheApp->m_pMainWnd)->PreTranslateMessage(&msg))
        {
            WT_L4_TRACE(" - processed\n");
            CallNextHookEx(s_hookMouse, iCode, wParam, lParam);
            return 1;
        }
    }
    WT_L4_TRACE("\n");
    
    return CallNextHookEx(s_hookMouse, iCode, wParam, lParam);
}
 
void StopBCGHooks()
{
    if (s_hook)      UnhookWindowsHookEx(s_hook);
    if (s_hookKB)    UnhookWindowsHookEx(s_hookKB);
    if (s_hookMouse) UnhookWindowsHookEx(s_hookMouse);
    s_hook      = NULL;
    s_hookKB    = NULL;
    s_hookMouse = NULL;
    s_msgThreadID = (DWORD)-1;
}

void ResetBCGHooks()
{
    WT_L2_TRACE("Resetting hooks\n");
    WT_ASSERT(s_msgThreadID == -1  ||  s_msgThreadID == GetCurrentThreadId());
    StopBCGHooks();
    s_msgThreadID = GetCurrentThreadId();
    HINSTANCE hInst = (HINSTANCE)GETINSTANCE(g_pDevStudioWnd->m_hWnd);
    s_hook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, 
        NULL, GetCurrentThreadId());
    s_hookKB = s_hookMouse = 0;
//    s_hookKB = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, hInst, 0);
//    s_hookMouse = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseProc, hInst, 0);
}



/////////////////////////////////////////////////////////////////////////////
// CWTMenuBar

IMPLEMENT_SERIAL(CWTMenuBar, CBCGMenuBar, VERSIONABLE_SCHEMA | 1)

BEGIN_MESSAGE_MAP(CWTMenuBar, CBCGMenuBar)
    //{{AFX_MSG_MAP(CWTMenuBar)
    ON_WM_WINDOWPOSCHANGING()
	ON_WM_LBUTTONUP()
	ON_WM_MBUTTONDOWN()
	ON_WM_MBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_CREATE()
	ON_WM_LBUTTONDBLCLK()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


int CWTMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    WT_FN_TRACE("CWTMenuBar::OnCreate");

    m_pLastHit = NULL;
    m_nLastHit = -1;
    m_ToolTipCtrl.Create(this, WS_VISIBLE | TTS_ALWAYSTIP);
    m_ToolTipCtrl.AddTool(this, "test");

    return CBCGMenuBar::OnCreate(lpCreateStruct);
}

BOOL CWTMenuBar::PreCreateWindow(CREATESTRUCT& cs)
{
	return CBCGMenuBar::PreCreateWindow(cs);
}

void CWTMenuBar::DoTooltipRelay(CPoint& point)
{
    MSG msg = AfxGetThreadState()->m_lastSentMsg;
    msg.time = 0;

    TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));
    ti.cbSize = sizeof(ti);
    ti.uFlags = TTF_IDISHWND;
    ti.hwnd = m_hWnd;
    ti.uId = (UINT)m_hWnd;
    if (!m_ToolTipCtrl.SendMessage(TTM_GETTOOLINFO, 0, (LPARAM)&ti))
    {
        ASSERT(ti.uFlags == TTF_IDISHWND);
        ASSERT(ti.hwnd == m_hWnd);
        ASSERT(ti.uId == (UINT)m_hWnd);
        VERIFY(m_ToolTipCtrl.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti));
    }

    // determine which tool was hit
    TOOLINFO tiHit; memset(&tiHit, 0, sizeof(TOOLINFO));
    tiHit.cbSize = sizeof(tiHit); //sizeof(AFX_OLDTOOLINFO);
    int nHit = OnToolHitTest(point, &tiHit);

    m_ToolTipCtrl.Activate(TRUE);
    // build new toolinfo and if different than current, register it
    CWnd* pHitWnd = nHit == -1 ? NULL : this;
    if (m_nLastHit != nHit || m_pLastHit != pHitWnd)
    {
        if (nHit != -1)
        {
            // add new tool and activate the tip
            ti = tiHit;
            ti.uFlags &= ~(TTF_NOTBUTTON|TTF_ALWAYSTIP);
            if (m_nFlags & WF_TRACKINGTOOLTIPS)
                ti.uFlags |= TTF_TRACK;
            VERIFY(m_ToolTipCtrl.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti));
        }
        else
        {
            m_ToolTipCtrl.DelTool(this);
        }
        m_pLastHit = pHitWnd;
        m_nLastHit = nHit;
    }
    else
    {
        m_ToolTipCtrl.RelayEvent(&msg);
    }

    if ((tiHit.lpszText != LPSTR_TEXTCALLBACK) && (tiHit.hinst == 0))
        free(tiHit.lpszText);
}

void CWTMenuBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
    DWORD dwStyle = GetBarStyle();
    if (IS_HORIZONTAL(cfg_iOrientation))
    {
        dwStyle |= CBRS_BORDER_BOTTOM;
        if (!IsFloating())
        {
            dwStyle &= ~CBRS_BORDER_RIGHT;
        }
        else
        {
            dwStyle |= CBRS_BORDER_RIGHT;
        }
    }
    else
    {
        dwStyle &= ~CBRS_BORDER_RIGHT;
        if (!IsFloating())
        {
            dwStyle &= ~(CBRS_BORDER_BOTTOM | CBRS_BORDER_3D);
        }
        else
        {
            dwStyle |= CBRS_BORDER_BOTTOM;
        }
    }
    SetBarStyle(dwStyle);
    EnableToolTips(FALSE);
    CBCGMenuBar::OnWindowPosChanging(lpwndpos);
}

CSize CWTMenuBar::CalcLayout(DWORD dwMode, int nLength)
{
    CSize sz = CBCGMenuBar::CalcLayout(dwMode, nLength);

    if ((dwMode & (LM_HORZDOCK | LM_VERTDOCK)) &&
        pTheApp->m_pMainWnd->GetSafeHwnd())
    {
        CRect r;
        pTheApp->m_pMainWnd->GetWindowRect(r);
        if (dwMode & LM_HORZDOCK)
            sz.cy = r.Height() + 1;
        else
            sz.cx = r.Width() + 3;

        BOOL bVert = (dwMode & LM_VERTDOCK) || ((dwMode & LM_HORZ) == 0);

        if (!bVert)
        {
            CRect rect;
            GetClientRect(rect);
            WrapToolBar (rect.Width(), rect.Height());
        }

    }
    return sz;
}

void CWTMenuBar::CalculateCustomizeButton()
{
    static CString sBlank = "";

    if (IsFloating() == FALSE)
    {
        SetRedraw(FALSE);
        CSize sz;
        CRect r;
        BOOL bHorz = IS_HORIZONTAL(cfg_iOrientation);
        GetClientRect(r);
        if (m_pCustomizeBtn != NULL)
        {
            EnableCustomizeButton(FALSE, -1, sBlank);
            AdjustLayout();
        }
        sz = CalcSize(!bHorz);
        if (( bHorz  &&  sz.cx > (r.Width()  - 1))  ||
            (!bHorz  &&  sz.cy > (r.Height() - 1)))
        {
            EnableCustomizeButton(TRUE, -1, sBlank);
        }
        AdjustLayout();
        SetRedraw(TRUE);
        RedrawWindow();
    }
}

int CWTMenuBar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    ASSERT_VALID(this);
    // use toolbar handler
    return CBCGToolBar::OnToolHitTest(point, pTI);
}


// there is a problem on multiple monitor systems: dragging the toolbar 
// causes a crash.
// this function returns true is there is a danger of that happening.
bool CWTMenuBar::WillCrashOnMultipleMonitors(CPoint pt)
{
	ClientToScreen(&pt);
    if (pt.x < 0  ||  pt.y < 0)
    {
        return true;
    }
    return false;
}


void CWTMenuBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
	DoTooltipRelay(point);

    // this should fix the problem with multiple monitor configurations
	if (m_pDockBar != NULL  &&  OnToolHitTest(point, NULL) == -1)
	{
        // if reached here, then this will be a drag operation
        if (WillCrashOnMultipleMonitors(point))
        {
            return;
        }
    }
	
	CBCGMenuBar::OnLButtonDown(nFlags, point);
}


void CWTMenuBar::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
    if (WillCrashOnMultipleMonitors(point))
    {
        AfxMessageBox(IDS_CANT_UNDOCK, MB_OK | MB_ICONINFORMATION);
        return;
    }
	
	CBCGMenuBar::OnLButtonDblClk(nFlags, point);
}

void CWTMenuBar::OnLButtonUp(UINT nFlags, CPoint point) 
{
	DoTooltipRelay(point);
	
	CBCGMenuBar::OnLButtonUp(nFlags, point);
}

void CWTMenuBar::OnMButtonDown(UINT nFlags, CPoint point) 
{
	DoTooltipRelay(point);
	
	CBCGMenuBar::OnMButtonDown(nFlags, point);
}

void CWTMenuBar::OnMButtonUp(UINT nFlags, CPoint point) 
{
	DoTooltipRelay(point);
	
	CBCGMenuBar::OnMButtonUp(nFlags, point);
}

void CWTMenuBar::OnMouseMove(UINT nFlags, CPoint point) 
{
	DoTooltipRelay(point);
	
	CBCGMenuBar::OnMouseMove(nFlags, point);
}

void CWTMenuBar::OnRButtonDown(UINT nFlags, CPoint point) 
{
	DoTooltipRelay(point);
	
	CBCGMenuBar::OnRButtonDown(nFlags, point);
}

void CWTMenuBar::OnRButtonUp(UINT nFlags, CPoint point) 
{
    DoTooltipRelay(point);
	
	CBCGMenuBar::OnRButtonUp(nFlags, point);
}


/////////////////////////////////////////////////////////////////////////////
// CMainFrameHolder


BEGIN_MESSAGE_MAP(CMainFrameHolder, CWnd)
    //{{AFX_MSG_MAP(CMainFrameHolder)
    ON_WM_CREATE()
    ON_WM_WINDOWPOSCHANGED()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CMainFrameHolder::SetMF(CFrameWnd *pWndMF)
{
    m_pWndMF = pWndMF;
    m_pWndMF->SetParent(this);
}
int CMainFrameHolder::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    int iRetVal = CWnd::OnCreate(lpCreateStruct);
    return iRetVal;
}

void CMainFrameHolder::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
{
    if (m_pWndMF)
    {
        const BOOL bHorz = IS_HORIZONTAL(cfg_iOrientation);
        CRect r;
        GetWindowRect(r);
        ScreenToClient(r);
        CSize sz;
        if (bHorz)
        {
            r.top -= 2;
            r.bottom += 1;
        }
        else
        {
            r.top -= 2;
            r.bottom += 2;
        }

        CMainFrame *pFrame = (CMainFrame *)m_pWndMF;
        if (pFrame)
        {
            m_pWndMF->MoveWindow(r);
            pFrame->m_wndMenuBar.CalculateCustomizeButton();
            m_pWndMF->RecalcLayout(FALSE);
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Experion
Canada Canada
You may know Oz from his WndTabs days. Oz has long since left client side development to work on web technologies and to consult in the R&D management field.

Comments and Discussions