home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / cxpane.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  47.5 KB  |  1,495 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "stdafx.h"
  20. #include "cxpane.h"
  21. #ifdef XP_WIN32
  22. #include "intelli.h"
  23. #endif
  24. #include "navcontv.h"
  25.  
  26. //  What is CPaneCX?
  27. //      A pane is part of a complete window.
  28. //
  29. //      There is no relation from a pane to the chrome of a full window.
  30. //      There is no frame, no document, no view, no toolbar, etc.
  31. //      No assumptions should be made, or the pane becomes non-reusable in a
  32. //          window that is yet to be invented.
  33. //
  34. //      A pane can be put many places:
  35. //          In a dialog.
  36. //          In a navigation tool.
  37. //          In a browser.
  38. //      It is up to the place to provide the chrome.  It is up to the pane to
  39. //          provide the HTML.
  40.  
  41. #ifdef XP_WIN32
  42. #define STR_CPANECX "CPaneCX"
  43. #else
  44. #define STR_CPANECX_HI "CPaneCXHi"
  45. #define STR_CPANECX_LO "CPaneCXLo"
  46. #endif
  47.  
  48. CPaneCX::CPaneCX(HWND hPane, BOOL bDestroyOnWMDestroy)
  49. {
  50.     MWContext *pContext = GetContext();
  51.  
  52.     m_MM = MM_TEXT;
  53.  
  54.     m_bDestroyOnWMDestroy = bDestroyOnWMDestroy;
  55.     m_hPane = NULL;
  56.     m_pPrevProc = NULL;
  57.     m_hOwnDC = NULL;
  58.     m_hClassDC = NULL;
  59.     m_hSubstDC = NULL;
  60.  
  61.     m_cxType = Pane;
  62.     pContext->type = MWContextPane;
  63.  
  64.     m_pDrawable = NULL;
  65.     m_pOffscreenDrawable = NULL;
  66.     m_pOnscreenDrawable = NULL;
  67.  
  68.     m_pResizeReloadTimeout = NULL;
  69.  
  70.     m_bDynamicScrollBars = TRUE;
  71.     m_bAlwaysShowScrollBars = FALSE;
  72.     m_bHScrollBarOn = FALSE;
  73.     m_bVScrollBarOn = FALSE;
  74. #ifdef _WIN32
  75.     m_iWheelDelta = 0;
  76. #endif
  77.  
  78. #ifdef XP_WIN16
  79.     m_hTextElementSegment = NULL;
  80.     m_lpTextElementHeap = NULL;
  81. #endif
  82.  
  83.     //  If a pane was passed in, perform the step manually.
  84.     SetPane(hPane);
  85. }
  86.  
  87. CPaneCX::~CPaneCX()
  88. {
  89.     SetPane(NULL);
  90.  
  91.     // Destroy the compositor associated with the context
  92.     MWContext *pContext = GetContext();
  93.     if (pContext && pContext->compositor) {
  94.         CL_DestroyCompositor(pContext->compositor);
  95.         pContext->compositor = NULL;
  96.     }
  97.     
  98.     if(m_pOnscreenDrawable) {
  99.         delete m_pOnscreenDrawable;
  100.         m_pOnscreenDrawable = NULL;
  101.     }
  102.     if(m_pOffscreenDrawable) {
  103.         delete m_pOffscreenDrawable;
  104.         m_pOffscreenDrawable = NULL;
  105.     }
  106.     m_pDrawable = NULL;
  107.  
  108. #ifdef XP_WIN16
  109.     if(m_hTextElementSegment) {
  110.         ::GlobalFree(m_hTextElementSegment);
  111.         m_hTextElementSegment = NULL;
  112.         m_lpTextElementHeap = NULL;
  113.     }
  114. #endif
  115. }
  116.  
  117. //  Set current pane for context.
  118. //  Can switch panes from one to another (wow).
  119. //  Can pass in NULL, which detaches current pane.
  120. HWND CPaneCX::SetPane(HWND hPane)
  121. {
  122.     HWND hRetval = GetPane();
  123.     
  124.     if(hRetval) {
  125.         //  Need to release all cached information.
  126.         CacheDCInfo(FALSE);
  127.         
  128.         //  Need to unsubclass old window.
  129.         BOOL bSub = SubClass(hRetval, FALSE);
  130.         ASSERT(bSub);
  131.         
  132.         //  Destroy any pending reload.
  133.         if(m_pResizeReloadTimeout) {
  134.             FE_ClearTimeout(m_pResizeReloadTimeout);
  135.             m_pResizeReloadTimeout = NULL;
  136.         }
  137.     }
  138.     
  139.     m_hPane = hPane;
  140.     
  141.     if(m_hPane) {
  142.         //  Need to subclass new window.
  143.         BOOL bSub = SubClass(m_hPane, TRUE);
  144.         ASSERT(bSub);
  145.         
  146.         //  Need to gather all cached information.
  147.         CacheDCInfo(TRUE);
  148.  
  149.         //  Reflect current scroll bar state.
  150.         ::EnableScrollBar(m_hPane, SB_VERT, ESB_ENABLE_BOTH);
  151.         ::EnableScrollBar(m_hPane, SB_HORZ, ESB_ENABLE_BOTH);
  152.         ::SetScrollRange(m_hPane, SB_VERT, 0, SCROLL_UNITS, FALSE);
  153.         ::SetScrollRange(m_hPane, SB_HORZ, 0, SCROLL_UNITS, FALSE);
  154.         ::ShowScrollBar(m_hPane, SB_BOTH, FALSE);
  155.         ShowScrollBars(SB_HORZ, IsHScrollBarOn());
  156.         ShowScrollBars(SB_VERT, IsVScrollBarOn());
  157.     }
  158.     
  159.     //  Shouldn't have a substituted DC at this point.
  160.     ASSERT(m_hSubstDC == NULL);
  161.     
  162.     return(hRetval);
  163. }
  164.  
  165. void CPaneCX::CacheDCInfo(BOOL bCache)
  166. {
  167.     if(bCache) {
  168.         //  Determine window class name.
  169.         char aClassName[128];
  170.         memset(aClassName, 0, sizeof(aClassName));
  171.         int iLen = GetClassName(GetPane(), aClassName, sizeof(aClassName));
  172.         ASSERT(iLen && iLen < sizeof(aClassName));
  173.         
  174.         //  Fill in WNDCLASS.
  175.         //  This needs to be expanded if we ever attempt to take over
  176.         //      windows outside of our instance.
  177.         WNDCLASS PaneClass;
  178.         memset(&PaneClass, 0, sizeof(PaneClass));
  179.         BOOL bClass = GetClassInfo(AfxGetInstanceHandle(), aClassName, &PaneClass);
  180.         ASSERT(bClass);
  181.         
  182.         //  OwnDC
  183.         if(PaneClass.style & CS_OWNDC) {
  184.             SetOwnDC(TRUE);
  185.             m_hOwnDC = ::GetDC(GetPane());
  186.         }
  187.         else if(PaneClass.style & CS_CLASSDC) {
  188.             SetClassDC(TRUE);
  189.             m_hClassDC = ::GetDC(GetPane());
  190.         }
  191.         else {
  192.             SetOwnDC(FALSE);
  193.             SetClassDC(FALSE);
  194.         }
  195.     }
  196.     else {
  197.         //  Any persistent data needs to go.
  198.         ClearFontCache();
  199.         
  200.         //  OwnDC
  201.         SetOwnDC(FALSE);
  202.         m_hOwnDC = NULL;
  203.         SetClassDC(FALSE);
  204.         m_hClassDC = NULL;
  205.     }
  206. }
  207.  
  208. BOOL CPaneCX::IsOwnDC() const
  209. {
  210.     BOOL bRetval = FALSE;
  211.     
  212.     if(m_pDrawable && (m_pDrawable == m_pOffscreenDrawable)) {
  213.         bRetval = FALSE;
  214.     }
  215.     else if(m_hSubstDC) {
  216.         //  We want substituted DCs to act like OwnDCs
  217.         //      until unsubstituted.
  218.         bRetval = TRUE;
  219.     }
  220.     else {
  221.         bRetval = CDCCX::IsOwnDC();
  222.     }
  223.     
  224.     return(bRetval);
  225. }
  226.  
  227. BOOL CPaneCX::IsClassDC() const
  228. {
  229.     BOOL bRetval = FALSE;
  230.     
  231.     if(m_pDrawable && (m_pDrawable == m_pOffscreenDrawable)) {
  232.         bRetval = FALSE;
  233.     }
  234.     else {
  235.         bRetval = CDCCX::IsClassDC();
  236.     }
  237.     
  238.     return(bRetval);
  239. }
  240.  
  241. HDC CPaneCX::SubstituteDC(HDC hDC)
  242. {
  243.     //  Flush cached info for old DC (take away any attributes
  244.     //      we may have assumed as OwnDC).
  245.     //  This could be further optimized if the font code
  246.     //      didn't hold onto the DC for the life of a font.
  247.     if(m_hSubstDC) {
  248.         ClearFontCache();
  249.     }
  250.     
  251.     HDC hRetval = m_hSubstDC;
  252.     m_hSubstDC = hDC;
  253.     
  254.     //  Set new mapping mode for new DC.
  255.     if(m_hSubstDC) {
  256.         SetMappingMode(m_hSubstDC);
  257.     }
  258.     return(hRetval);
  259. }
  260.  
  261. //  Return appropriate HDC
  262. HDC CPaneCX::GetContextDC()
  263. {
  264.     HDC hRetval = NULL;
  265.     if(m_pDrawable && (m_pDrawable == m_pOffscreenDrawable)) {
  266.         hRetval = m_pDrawable->GetDrawableDC();
  267.     }
  268.     else if(m_hSubstDC) {
  269.         hRetval = m_hSubstDC;
  270.     }
  271.     else if(IsClassDC()) {
  272.         hRetval = m_hClassDC;
  273.     }
  274.     else if(CDCCX::IsOwnDC()) {
  275.         hRetval = m_hOwnDC;
  276.     }
  277.     else if(GetPane()) {
  278.         hRetval = ::GetDC(GetPane());
  279.         SetMappingMode(hRetval);
  280.     }
  281.     
  282.     return(hRetval);
  283. }
  284.  
  285. //  Release appropriate HDC
  286. void CPaneCX::ReleaseContextDC(HDC hDC)
  287. {
  288.     if(hDC != m_hSubstDC && IsClassDC() == FALSE && CDCCX::IsOwnDC() == FALSE && (!m_pOffscreenDrawable || hDC != m_pOffscreenDrawable->GetDrawableDC())) {
  289.         ASSERT(GetPane());
  290.         ::ReleaseDC(GetPane(), hDC);
  291.     }
  292. }
  293.  
  294. void CPaneCX::DestroyContext()
  295. {
  296.     if(IsDestroyed() == FALSE) {
  297.         if(m_pResizeReloadTimeout)  {
  298.             FE_ClearTimeout(m_pResizeReloadTimeout);
  299.             m_pResizeReloadTimeout = NULL;
  300.         }
  301.     }
  302.     
  303.     CDCCX::DestroyContext();
  304. }
  305.  
  306. void CPaneCX::Initialize(BOOL bOwnDC, RECT *pRect, BOOL bInitialPalette, BOOL bNewMemDC)
  307. {
  308.     MWContext *pContext = GetContext();
  309.  
  310.     //  Top of the document.
  311.     m_lOrgX = 0;
  312.     m_lOrgY = 0;
  313.     
  314.     //  Call base.
  315.     CDCCX::Initialize(bOwnDC, pRect, bInitialPalette, bNewMemDC);
  316.     
  317.     //  Get the DC.
  318.     HDC hDC = GetContextDC();
  319.     SetMappingMode(hDC);
  320.     
  321.     //  Init compositor.
  322.     CL_Drawable *pOnscreenDrawable = NULL;
  323.     CL_Drawable *pOffscreenDrawable = NULL;
  324.     
  325.     m_pOnscreenDrawable = new COnscreenDrawable(hDC, this);
  326.     pOnscreenDrawable = CL_NewDrawable(
  327.         CASTUINT(m_lWidth),
  328.         CASTUINT(m_lHeight),
  329.         CL_WINDOW,
  330.         &wfe_drawable_vtable,
  331.         (void *)m_pOnscreenDrawable);
  332.         
  333.     m_pOffscreenDrawable = COffscreenDrawable::AllocateOffscreen(hDC, GetPalette(), this);
  334.     
  335.     pOffscreenDrawable = CL_NewDrawable(
  336.         CASTUINT(m_lWidth),
  337.         CASTUINT(m_lHeight),
  338.         CL_BACKING_STORE,
  339.         &wfe_drawable_vtable,
  340.         (void *)m_pOffscreenDrawable);
  341.  
  342.     GetContext()->compositor = CL_NewCompositor(
  343.         pOnscreenDrawable,
  344.         pOffscreenDrawable,
  345.         m_lOrgX,
  346.         m_lOrgY,
  347.         m_lWidth,
  348.         m_lHeight,
  349.         20);
  350.         
  351.     m_pDrawable = (CDrawable *)m_pOnscreenDrawable;
  352.  
  353.     //  If a grid cell, select the palette.
  354.     if(IsGridCell() && GetPalette()) {
  355.         ::SelectPalette(hDC, GetPalette(), FALSE);
  356.         int iError = ::RealizePalette(hDC);
  357.     }
  358.  
  359.     ReleaseContextDC(hDC);
  360.     hDC = NULL;
  361. }
  362.  
  363. void CPaneCX::SetDrawable(MWContext *pContext, CL_Drawable *pDrawable)
  364. {
  365.     if(pDrawable) {
  366.         CDrawable *pFEDrawable = (CDrawable *)CL_GetDrawableClientData(pDrawable);
  367.         m_pDrawable = pFEDrawable;
  368.     }
  369.     else {
  370.         m_pDrawable = m_pOnscreenDrawable;
  371.     }
  372. }
  373.  
  374. FE_Region CPaneCX::GetDrawingClip()
  375. {
  376.     if (m_pDrawable) {
  377.         return m_pDrawable->GetClip();
  378.     }
  379.     else {
  380.         return NULL;
  381.     }
  382. }
  383.  
  384. void CPaneCX::GetDrawingOrigin(int32 *plOrgX, int32 *plOrgY)
  385. {
  386.     if(m_pDrawable)  {
  387.         m_pDrawable->GetOrigin(plOrgX, plOrgY);
  388.     }
  389.     else {
  390.         *plOrgX = *plOrgY = 0;
  391.     }
  392. }
  393.  
  394. void CPaneCX::RefreshArea(int32 lLeft, int32 lTop, uint32 ulWidth, uint32 ulHeight)
  395. {
  396.     MWContext *pContext = GetContext();
  397.  
  398.     //  Simple validation, can pass in 0 for all.
  399.     if(ulWidth == 0)    {
  400.         ulWidth = GetDocumentWidth() - lLeft;
  401.     }
  402.     if(ulHeight == 0)   {
  403.         ulHeight = GetDocumentHeight() - lTop;
  404.     }
  405.  
  406.     XP_Rect rect;
  407.     if(pContext->compositor) {
  408.           rect.left = lLeft - m_lOrgX;
  409.           rect.top = lTop - m_lOrgY;
  410.           rect.right = rect.left + ulWidth;
  411.           rect.bottom = rect.top + ulHeight;
  412.           CL_RefreshWindowRect(pContext->compositor, &rect);
  413.     }
  414.  
  415. #ifdef DDRAW
  416.     LTRB tempRect(rect.left, rect.top, rect.right, rect.bottom);
  417.     tempRect.left += GetWindowsXPos();
  418.     tempRect.right += GetWindowsXPos();
  419.     tempRect.top += GetWindowsYPos();
  420.     tempRect.bottom += GetWindowsYPos();
  421.     BltToScreen(tempRect, NULL);
  422. #endif
  423. }
  424.  
  425. //  Window handle is about to go away; let go of it.
  426. void CPaneCX::AftWMDestroy(PaneMessage *pMessage)
  427. {
  428.     SetPane(NULL);
  429.     
  430.     //  If we are supposed to clean up ourselves, do so now.
  431.     if(m_bDestroyOnWMDestroy) {
  432.         DestroyContext();
  433.     }
  434. }
  435.  
  436. void CPaneCX::PreWMErasebkgnd(PaneMessage *pMessage)
  437. {
  438.     HDC hEraseDC = (HDC)pMessage->wParam;
  439.     HDC hOldSubst = NULL;
  440.     if(hEraseDC != m_hClassDC && hEraseDC != m_hOwnDC) {
  441.         hOldSubst = SubstituteDC(hEraseDC);
  442.     }
  443.     
  444.     //  Layers may want to handle erasing of background.
  445.     MWContext *pContext = GetContext();
  446.     if(pContext->compositor && CL_GetCompositorEnabled(pContext->compositor)) {
  447.         pMessage->bSetRetval = TRUE;
  448.         pMessage->lRetval = (LPARAM)TRUE;
  449.     }
  450.     else {
  451.         RECT rClip;
  452.         ::GetClipBox(hEraseDC, &rClip);
  453.         pMessage->bSetRetval = TRUE;
  454.         pMessage->lRetval = (LPARAM)_EraseBkgnd(hEraseDC, rClip, GetOriginX(), GetOriginY());
  455.     }
  456.     
  457.     if(hEraseDC != m_hClassDC && hEraseDC != m_hOwnDC) {
  458.         HDC hUnSubst = SubstituteDC(hOldSubst);
  459.         //  Someone forget to unsubst their DC?
  460.         ASSERT(hUnSubst == hEraseDC);
  461.     }
  462. }
  463.  
  464. void CPaneCX::PreWMPaint(PaneMessage *pMessage)
  465. {
  466.     pMessage->lRetval = NULL;
  467.     pMessage->bSetRetval = TRUE;
  468.     
  469.     //  Redirecting output in this fashion not supported yet.
  470.     ASSERT((HDC)pMessage->wParam == NULL);
  471.     
  472.     BOOL bBeginPaint = ::GetUpdateRect(GetPane(), NULL, FALSE);
  473.     if(bBeginPaint) {
  474.         PAINTSTRUCT ps;
  475.         HDC hPaintDC = ::BeginPaint(GetPane(), &ps);
  476.         uint32 ulWidth = ps.rcPaint.right - ps.rcPaint.left;
  477.         uint32 ulHeight = ps.rcPaint.bottom - ps.rcPaint.top;
  478.         if(ulWidth && ulHeight) {
  479.             HDC hOldSubst = NULL;
  480.             if(hPaintDC != m_hClassDC && hPaintDC != m_hOwnDC) {
  481.                 hOldSubst = SubstituteDC(hPaintDC);
  482.             }
  483.             RefreshArea(ps.rcPaint.left + GetOriginX(), ps.rcPaint.top + GetOriginY(), ulWidth, ulHeight);
  484.             if(hPaintDC != m_hClassDC && hPaintDC != m_hOwnDC) {
  485.                 HDC hUnSubst = SubstituteDC(hOldSubst);
  486.                 //  Someone forget to unsubst their DC?
  487.                 ASSERT(hUnSubst == hPaintDC);
  488.             }
  489.         }
  490.         ::EndPaint(GetPane(), &ps);
  491.     }
  492.     else {
  493.         //  No update area.
  494.         //  Possible internal draw request (see RedrawWindow).
  495.         //  Not supported until needed.
  496.         ASSERT(0);
  497.     }
  498. }
  499.  
  500. void CPaneCX::AftWMSize(PaneMessage *pMessage)
  501. {
  502.     UINT uSizeType = (UINT)pMessage->wParam;
  503.     int iWidth = LOWORD(pMessage->lParam);
  504.     int iHeight = HIWORD(pMessage->lParam);
  505.     
  506.     //  Only care if resized visibly.
  507.     if(uSizeType == SIZE_MAXIMIZED || uSizeType == SIZE_RESTORED) {
  508.         BOOL bNiceReload = TRUE;
  509.         
  510.         //  Let frame contexts decide on their own if they would like to reload.
  511.         if(IsFrameContext()) {
  512.             bNiceReload = FALSE;
  513.         }
  514.         
  515.         int iNewWidth = iWidth;
  516.         if(IsVScrollBarOn()) {
  517.             iNewWidth += sysInfo.m_iScrollWidth;
  518.         }
  519.         int iNewHeight = iHeight;
  520.         if(IsHScrollBarOn()) {
  521.             iNewHeight += sysInfo.m_iScrollHeight;
  522.         }
  523.         
  524.         /* Resize the compositor's notion of the window area
  525.          * as well as the size of the background layer. This
  526.          * might all be moot, because we might relayout, but
  527.          * that doesn't happen all the time (e.g. HTML dialogs).
  528.          * We want the composited area - without the scrollbars 
  529.          */
  530.         MWContext *pContext = GetContext();
  531.         if (pContext->compositor) {
  532.             CL_Layer *bglayer, *doclayer;
  533.             CL_Compositor *compositor = pContext->compositor;
  534.  
  535.             CL_ResizeCompositorWindow(compositor, iNewWidth, iNewHeight);
  536.             doclayer = CL_GetCompositorRoot(compositor);
  537.             if (doclayer) {
  538.                 bglayer = CL_GetLayerChildByName(doclayer, LO_BACKGROUND_LAYER_NAME);
  539.                 if (bglayer) {
  540.                     XP_Rect bbox;
  541.                     int32 layerWidth, layerHeight;
  542.  
  543.                     /* Make sure that the new dimensions are larger than the  */
  544.                     /* original ones before resizing the layer. We still want */
  545.                     /* the layer size to be the maximum of the window and the */
  546.                     /* document dimensions.                                   */
  547.                     CL_GetLayerBbox(bglayer, &bbox);
  548.                     layerWidth = bbox.right - bbox.left;
  549.                     layerHeight = bbox.bottom - bbox.top;
  550.  
  551.                     if (iNewWidth > layerWidth)
  552.                         layerWidth = iNewWidth;
  553.                     if (iNewHeight > layerHeight)
  554.                         layerHeight = iNewHeight;
  555.  
  556.                     CL_ResizeLayer(bglayer, layerWidth, layerHeight);
  557.                 }
  558.             }
  559.         }
  560.         
  561.         m_lWidth = (int32)iNewWidth;
  562.         m_lHeight = (int32)iNewHeight;
  563.         
  564.         //  If we've resized bigger than the page,
  565.         //      and we are scrolled, reset our position.
  566.         if((m_lDocWidth > 0) && (m_lDocWidth < m_lWidth) && (m_lOrgX != 0)) {
  567.             m_lOrgX = 0;
  568.         }
  569.         if((m_lDocHeight > 0) &&(m_lDocHeight < m_lHeight) && (m_lOrgY != 0))   {
  570.             m_lOrgY = 0;
  571.         }
  572.  
  573.         RealizeScrollBars();
  574.         
  575.         if(bNiceReload) {
  576. #ifdef RELAYOUT_WITHOUT_RELOAD
  577.             LO_RelayoutOnResize(GetDocumentContext(), m_lWidth, m_lHeight, m_lLeftMargin, m_lTopMargin);
  578. #else
  579.             NiceResizeReload();
  580. #endif
  581.         }
  582.     }
  583. }
  584.  
  585. static void resize_reload_timeout(void *closure)
  586. {
  587.     CPaneCX *cw = VOID2CX(closure, CPaneCX);
  588.     cw->m_pResizeReloadTimeout = NULL;
  589.     cw->NiceReload();
  590. }
  591.  
  592. //  Wait to do the reload for just a wee bit.
  593. void CPaneCX::NiceResizeReload()
  594. {
  595.     // If there was already a resize timeout that hasn't fired, cancel it,
  596.     // since that means resize messages are still arriving close together
  597.     if(m_pResizeReloadTimeout) {
  598.         FE_ClearTimeout(m_pResizeReloadTimeout);
  599.         m_pResizeReloadTimeout = NULL;
  600.     }
  601.     
  602.     //  Can't reload anything
  603.     if(!CanCreateUrlFromHist()) {
  604.         return;
  605.     }
  606.     
  607.     m_pResizeReloadTimeout = FE_SetTimeout(resize_reload_timeout, this, 200);
  608. }
  609.  
  610. int CPaneCX::GetUrl(URL_Struct *pUrl, FO_Present_Types iFormatOut, BOOL bReallyLoading, BOOL bForceNew)   
  611. {
  612.     // Stop any reload timers, no need.
  613.     if(m_pResizeReloadTimeout)  {
  614.         FE_ClearTimeout(m_pResizeReloadTimeout);
  615.         m_pResizeReloadTimeout = NULL;
  616.     }
  617.     return(CDCCX::GetUrl(pUrl, iFormatOut, bReallyLoading, bForceNew));
  618. }
  619.  
  620. void CPaneCX::LayoutNewDocument(MWContext *pContext, URL_Struct *pURL, int32 *pWidth, int32 *pHeight, int32 *pmWidth, int32 *pmHeight)
  621. {
  622.     m_lOrgY = 0;
  623.     m_lOrgX = 0;
  624.     
  625.     // Stop any reload timers, no need.
  626.     if(m_pResizeReloadTimeout)  {
  627.         FE_ClearTimeout(m_pResizeReloadTimeout);
  628.         m_pResizeReloadTimeout = NULL;
  629.     }
  630.     
  631.     //  Call the base.
  632.     CDCCX::LayoutNewDocument(pContext, pURL, pWidth, pHeight, pmWidth, pmHeight);
  633.     
  634.     //  Initialize Scrollbars for new document.
  635.     ShowScrollBars(SB_BOTH, FALSE);
  636.     m_nPageY = SCROLL_UNITS;
  637.     m_nPageX = SCROLL_UNITS;
  638.     
  639. #ifdef XP_WIN32
  640.     SCROLLINFO siY;
  641.     siY.cbSize = sizeof(SCROLLINFO);
  642.     siY.fMask = SIF_PAGE;
  643.     siY.nPage = 0;
  644.     if(GetPane() && IsVScrollBarOn() == TRUE)   {
  645.         ::SetScrollInfo(GetPane(), SB_VERT, &siY, FALSE);
  646.     }
  647.     
  648.     SCROLLINFO siX;
  649.     siX.cbSize = sizeof(SCROLLINFO);
  650.     siX.fMask = SIF_PAGE;
  651.     siX.nPage = 0;
  652.     if(GetPane() && IsHScrollBarOn() == TRUE)   {
  653.         ::SetScrollInfo(GetPane(), SB_HORZ, &siX, FALSE);
  654.     }
  655. #endif
  656.     
  657.     if(*pmWidth || *pmHeight) {
  658.         //  Layout wants to set these.
  659.         m_lLeftMargin = *pmWidth;
  660.         m_lTopMargin = *pmHeight;
  661.         m_lRightMargin = -1 * *pmWidth;
  662.         m_lBottomMargin = -1 * *pmHeight;
  663.     }
  664.     else    {
  665.         //  Set these to the old defaults which I'll never understand.
  666.         m_lLeftMargin = LEFT_MARGIN;
  667.         m_lTopMargin = TOP_MARGIN;
  668.         m_lRightMargin = RIGHT_MARGIN;
  669.         m_lBottomMargin = BOTTOM_MARGIN;
  670.     }
  671.     *pmWidth = m_lLeftMargin;
  672.     *pmHeight = m_lTopMargin;
  673.     
  674.     //  When we report the size to layout, we must always take care to subtract
  675.     //      for the size of the scrollbars if we have dynamic or always on
  676.     //      scrollers.
  677.     if(DynamicScrollBars() == FALSE && IsHScrollBarOn() == FALSE && IsVScrollBarOn() == FALSE)  {
  678.         *pWidth = GetWidth();
  679.         *pHeight = GetHeight();
  680.     }
  681.     else    {
  682.         *pWidth = GetWidth() - sysInfo.m_iScrollWidth;
  683.         *pHeight = GetHeight() - sysInfo.m_iScrollHeight;
  684.     }
  685. }
  686.  
  687. void CPaneCX::FinishedLayout(MWContext *pContext)
  688. {
  689.     CDCCX::FinishedLayout(pContext);
  690.  
  691.     //  Have the scroll bars correctly set themselves.
  692.     RealizeScrollBars();
  693. }
  694.  
  695. void CPaneCX::ShowScrollBars(int iBars, BOOL bShow)  {
  696.     //  Don't do this if we don't have a view.
  697.     if(GetPane() != NULL) {
  698.         //  Turning them off or on?
  699.         if(bShow == FALSE)  {
  700.             //  Decide which set of scrollers, if any, that we need to take
  701.             //      action on, and take that action.
  702.             if(iBars == SB_BOTH) {
  703.                 m_bVScrollBarOn = FALSE;
  704.                 m_bHScrollBarOn = FALSE;
  705.                 ::ShowScrollBar(GetPane(), SB_BOTH, FALSE);
  706.             }
  707.             else if((iBars == SB_VERT) && IsVScrollBarOn()) {
  708.                 m_bVScrollBarOn = FALSE;
  709.                 ::ShowScrollBar(GetPane(), SB_VERT, FALSE);
  710.             }
  711.             else if((iBars == SB_HORZ) && IsHScrollBarOn()) {
  712.                 m_bHScrollBarOn = FALSE;
  713.                 ::ShowScrollBar(GetPane(), SB_HORZ, FALSE);
  714.             }
  715.         }
  716.         else    {
  717.             //  Decide which set of scrollers, if any, that we need to take
  718.             //      action on, and take that action.
  719.             if(iBars == SB_BOTH) {
  720.                 m_bVScrollBarOn = TRUE;
  721.                 m_bHScrollBarOn = TRUE;
  722.                 ::ShowScrollBar(GetPane(), SB_BOTH, TRUE);
  723.             }
  724.             else if((iBars == SB_VERT) && !IsVScrollBarOn())    {
  725.                 m_bVScrollBarOn = TRUE;
  726.                 ::ShowScrollBar(GetPane(), SB_VERT, TRUE);
  727.             }
  728.             else if((iBars == SB_HORZ) && !IsHScrollBarOn())    {
  729.                 m_bHScrollBarOn = TRUE;
  730.                 ::ShowScrollBar(GetPane(), SB_HORZ, TRUE);
  731.             }
  732.         }
  733.         //  We have just shown/hidden a scroll bar.
  734.         //  Update the window to avoid flash (reduces overall invalidated
  735.         //      rectangle, except when we show/hide both at the same time).
  736.         ::UpdateWindow(GetPane());
  737.     }
  738. }
  739.  
  740. void CPaneCX::RealizeScrollBars(int32 *pX, int32 *pY)  
  741. {
  742.     if(m_lDocHeight && m_lDocWidth) {
  743.         if(AlwaysShowScrollBars()) {
  744.             ShowScrollBars(SB_BOTH, TRUE);
  745.         }
  746.         
  747.         //  Are we checking for dynamic scroll bars?
  748.         if(DynamicScrollBars() == TRUE) {
  749.             //  If the document fits in our client area, or if we have children, turn them off.
  750.             //  If the document is larger than our client area, turn them on.
  751.             int iSB = -1;
  752.             BOOL bShow = FALSE;
  753.             BOOL vScrollBar = FALSE;
  754.             BOOL hScrollBar = FALSE;
  755.             if (m_lHeight >= m_lDocHeight && m_lWidth >= m_lDocWidth && (IsVScrollBarOn() == TRUE || IsHScrollBarOn() == TRUE)) {
  756.                 ShowScrollBars(SB_BOTH, FALSE);
  757.             }
  758.             else if(m_lHeight < m_lDocHeight && m_lWidth < m_lDocWidth && (IsVScrollBarOn() == FALSE || IsHScrollBarOn() == FALSE)) {
  759.                 ShowScrollBars(SB_BOTH, TRUE);
  760.             }
  761.             else { 
  762.                 if(m_lHeight >= m_lDocHeight && IsVScrollBarOn() == TRUE)   {
  763.                     ShowScrollBars(SB_VERT, FALSE);
  764.                 }
  765.                 else if(m_lHeight < m_lDocHeight && IsVScrollBarOn() == FALSE)  {
  766.                     ShowScrollBars(SB_VERT, TRUE);
  767.                 }
  768.                 if(m_lWidth >= m_lDocWidth && IsHScrollBarOn() == TRUE) {
  769.                     ShowScrollBars(SB_HORZ, FALSE);
  770.                 }
  771.                 else if(m_lWidth < m_lDocWidth && IsHScrollBarOn() == FALSE)    {
  772.                     ShowScrollBars(SB_HORZ, TRUE);
  773.                 }
  774.             }
  775.         }
  776.  
  777.         //  See if we're going to be changing the values.
  778.         BOOL bRefreshHorz = FALSE;
  779.         BOOL bRefreshVert = FALSE;
  780.         if(pX != NULL && m_lOrgX != *pX)   {
  781.             m_lOrgX = *pX;
  782.             bRefreshHorz = TRUE;
  783.         }
  784.         if(pY != NULL && m_lOrgY != *pY)   {
  785.             m_lOrgY = *pY;
  786.             bRefreshVert = TRUE;
  787.         }
  788.  
  789.         //  Make sure that the current origins are within the document iWidth
  790.         //      and iHeight.
  791.         //  In the event that they are exactly the same, make sure to refresh
  792.         //      the scroll bar anyhow (this will happen if you scroll to the
  793.         //      bottom of a page, go to a new page, and then go back; your scroll
  794.         //      bars are wrong).
  795.         int32 lCalcHeight = m_lDocHeight - m_lHeight + (IsHScrollBarOn() ? sysInfo.m_iScrollHeight : 0);
  796.         if(m_lOrgY >= lCalcHeight && lCalcHeight > 0)  {
  797.             m_lOrgY = lCalcHeight;  // always show one screen
  798.             bRefreshVert = TRUE;
  799.         }
  800.         int32 lCalcWidth = m_lDocWidth - m_lWidth + (IsVScrollBarOn() ? sysInfo.m_iScrollWidth : 0);
  801.         if(m_lOrgX >= lCalcWidth && lCalcWidth > 0) {
  802.             m_lOrgX = lCalcWidth;    // always leave some visible
  803.             bRefreshHorz = TRUE;
  804.         }
  805.  
  806.     #ifdef XP_WIN32
  807.         //  Special fun for proportional scrollbars.
  808.         SCROLLINFO siY;
  809.         siY.cbSize = sizeof(SCROLLINFO);
  810.         siY.fMask = SIF_PAGE;
  811.         //  If the document is longer than a single page
  812.         if(m_lDocHeight > m_lHeight && IsVScrollBarOn() == TRUE)   {
  813.             siY.nPage = m_lHeight * SCROLL_UNITS / m_lDocHeight;
  814.             if(GetPane())  {
  815.                 ::SetScrollInfo(GetPane(), SB_VERT, &siY, FALSE);
  816.                 if((UINT)m_nPageY != SCROLL_UNITS - siY.nPage)    {
  817.                     m_nPageY = SCROLL_UNITS - siY.nPage;
  818.                     bRefreshVert = TRUE;
  819.                 }
  820.             } else
  821.                 bRefreshVert = TRUE;
  822.         }
  823.         else if(IsVScrollBarOn() == TRUE)    {
  824.             siY.nPage = SCROLL_UNITS;
  825.             if(GetPane())  {
  826.                 ::SetScrollInfo(GetPane(), SB_VERT, &siY, FALSE);
  827.                 m_nPageY = SCROLL_UNITS;
  828.             }
  829.         }
  830.  
  831.         SCROLLINFO siX;
  832.         siX.cbSize = sizeof(SCROLLINFO);
  833.         siX.fMask = SIF_PAGE;
  834.         //  If the document is wider than a single screen
  835.         if((m_lDocWidth != 0) && (m_lDocWidth > m_lWidth) && IsHScrollBarOn() == TRUE) {
  836.             siX.nPage = m_lWidth * SCROLL_UNITS / m_lDocWidth;
  837.             if(GetPane())  {
  838.                 ::SetScrollInfo(GetPane(), SB_HORZ, &siX, FALSE);
  839.                 if((UINT)m_nPageX != SCROLL_UNITS - siX.nPage)    {
  840.                     m_nPageX = SCROLL_UNITS - siX.nPage;
  841.                     bRefreshHorz = TRUE;
  842.                 }
  843.             } else
  844.                 bRefreshHorz = TRUE;
  845.         }
  846.         else if(IsHScrollBarOn() == TRUE)    {
  847.             siX.nPage = SCROLL_UNITS;
  848.             if(GetPane())  {
  849.                 ::SetScrollInfo(GetPane(), SB_HORZ, &siX, FALSE);
  850.                 m_nPageX = SCROLL_UNITS;
  851.             }
  852.         }
  853.     #endif
  854.  
  855.         //  Figure the thumb position.
  856.         float fYPos = 0.0f;
  857.         float fXPos = 0.0f;
  858.         if(m_lDocHeight != 0)    {
  859.             long lScrollHeight = m_lDocHeight - m_lHeight;
  860.             if(lScrollHeight != 0)
  861.                 fYPos = (float)m_lOrgY / (float) lScrollHeight;
  862.             else
  863.                 fYPos = 1.0f;
  864.         }
  865.         if(m_lDocWidth != 0) {
  866.             long lScrollWidth = m_lDocWidth - m_lWidth;
  867.             if(lScrollWidth != 0)
  868.                 fXPos = (float)m_lOrgX / (float) lScrollWidth;
  869.             else
  870.                 fXPos = 1.0f;
  871.         }
  872.  
  873.         //  See if we should turn off the scroll bars.
  874.  
  875.         if(m_lDocWidth <= m_lWidth && IsHScrollBarOn() == TRUE && GetPane()) {
  876.             ::EnableScrollBar(GetPane(), SB_HORZ, ESB_DISABLE_BOTH);
  877.         }
  878.         else if(IsHScrollBarOn() == TRUE && GetPane())    {
  879.             ::EnableScrollBar(GetPane(), SB_HORZ, ESB_ENABLE_BOTH);
  880.  
  881.             // only reset if different to avoid flashing on NT and Win16
  882.             int iNewPosX = (int) (fXPos * m_nPageX);
  883.             if(iNewPosX != ::GetScrollPos(GetPane(), SB_HORZ) || bRefreshHorz == TRUE)  {
  884.                 ::SetScrollPos(GetPane(), SB_HORZ, iNewPosX, TRUE);    
  885.             }
  886.         }
  887.  
  888.  
  889.         if(m_lDocHeight <= m_lHeight && IsVScrollBarOn() == TRUE && GetPane())   {
  890.             ::EnableScrollBar(GetPane(), SB_VERT, ESB_DISABLE_BOTH);
  891.         }
  892.         else if(IsVScrollBarOn() == TRUE && GetPane())    {
  893.             ::EnableScrollBar(GetPane(), SB_VERT, ESB_ENABLE_BOTH);
  894.  
  895.             // only reset if different to avoid flashing on NT and Win16
  896.             int iNewPosY = (int) (fYPos * m_nPageY);
  897.             if(iNewPosY != ::GetScrollPos(GetPane(), SB_VERT) || bRefreshVert == TRUE)  {
  898.                 ::SetScrollPos(GetPane(), SB_VERT, iNewPosY, TRUE);
  899.             }
  900.         }
  901.  
  902.         MWContext *pContext = GetContext();
  903.         if(pContext->compositor) {
  904.             CL_ScrollCompositorWindow(pContext->compositor, m_lOrgX, m_lOrgY);
  905.         }
  906.     }
  907. }
  908.  
  909. void CPaneCX::SetDocDimension(MWContext *pContext, int iLocation, int32 lWidth, int32 lLength)   {
  910.     //  Call the base.
  911.     CDCCX::SetDocDimension(pContext, iLocation, lWidth, lLength);
  912.     RealizeScrollBars();
  913. }
  914.  
  915. void CPaneCX::PreWMVScroll(PaneMessage *pMsg)
  916. {
  917. #ifdef XP_WIN16
  918.     UINT uSBCode = (UINT)pMsg->wParam;
  919.     UINT uPos = LOWORD(pMsg->lParam);
  920.     HWND hwndCtrl = (HWND)HIWORD(pMsg->lParam);
  921. #else
  922.     UINT uSBCode = LOWORD(pMsg->wParam);
  923.     UINT uPos = HIWORD(pMsg->wParam);
  924.     HWND hwndCtrl = (HWND)pMsg->lParam;
  925. #endif
  926.     
  927.     Scroll(SB_VERT, uSBCode, uPos, hwndCtrl);
  928.     
  929.     pMsg->lRetval = NULL;
  930.     pMsg->bSetRetval = TRUE;
  931. }
  932.  
  933. void CPaneCX::PreWMHScroll(PaneMessage *pMsg)
  934. {
  935. #ifdef XP_WIN16
  936.     UINT uSBCode = (UINT)pMsg->wParam;
  937.     UINT uPos = LOWORD(pMsg->lParam);
  938.     HWND hwndCtrl = (HWND)HIWORD(pMsg->lParam);
  939. #else
  940.     UINT uSBCode = LOWORD(pMsg->wParam);
  941.     UINT uPos = HIWORD(pMsg->wParam);
  942.     HWND hwndCtrl = (HWND)pMsg->lParam;
  943. #endif
  944.     
  945.     Scroll(SB_HORZ, uSBCode, uPos, hwndCtrl);
  946.     
  947.     pMsg->lRetval = NULL;
  948.     pMsg->bSetRetval = TRUE;
  949. }
  950.  
  951. void CPaneCX::AftWMMouseActivate(PaneMessage *pMsg)
  952. {
  953.     BOOL bSetFocus = FALSE;
  954.     if(pMsg->bSetRetval) {
  955.         //  Check to see if we need to activate.
  956.         if(pMsg->lRetval == MA_ACTIVATE || pMsg->lRetval == MA_ACTIVATEANDEAT) {
  957.             bSetFocus = TRUE;
  958.         }
  959.     }
  960.     else {
  961.         //  Real class didn't handle, take some action.
  962.         pMsg->bSetRetval = TRUE;
  963.         pMsg->lRetval = MA_ACTIVATE;
  964.         bSetFocus = TRUE;
  965.     }
  966.     
  967.     if(bSetFocus) {
  968.         if(::GetFocus() != GetPane()) {
  969.             ::SetFocus(GetPane());
  970.         }
  971.     }
  972. }
  973.  
  974. #if defined(XP_WIN32) && _MSC_VER >= 1100
  975. void CPaneCX::PreWMMouseWheel(PaneMessage *pMsg)
  976. {
  977.     //  Increase the delta.
  978.     m_iWheelDelta += MOUSEWHEEL_DELTA(pMsg->wParam, pMsg->lParam);
  979.  
  980.     //  Number of lines to scroll.
  981.     UINT uScroll = intelli.ScrollLines();
  982.  
  983.     //  Direction.
  984.     BOOL bForward = TRUE;
  985.     if(m_iWheelDelta < 0)   {
  986.         bForward = FALSE;
  987.     }
  988.  
  989.     //  Scroll bar code to use.
  990.     UINT uSBCode = SB_LINEUP;
  991.  
  992.     if(m_iWheelDelta / WHEEL_DELTA)  {
  993.         if(uScroll == WHEEL_PAGESCROLL)   {
  994.             if(bForward)    {
  995.                 uSBCode = SB_PAGEUP;
  996.             }
  997.             else    {
  998.                 uSBCode = SB_PAGEDOWN;
  999.             }
  1000.             uScroll = 1;
  1001.         }
  1002.         else    {
  1003.             if(bForward)    {
  1004.                 uSBCode = SB_LINEUP;
  1005.             }
  1006.             else    {
  1007.                 uSBCode = SB_LINEDOWN;
  1008.             }
  1009.         }
  1010.  
  1011.         //  Take off scroll increment.
  1012.         UINT uLoops = 0;
  1013.         while(m_iWheelDelta / WHEEL_DELTA)  {
  1014.             if(bForward)   {
  1015.                 m_iWheelDelta -= WHEEL_DELTA;
  1016.             }
  1017.             else    {
  1018.                 m_iWheelDelta += WHEEL_DELTA;
  1019.             }
  1020.             uLoops++;
  1021.         }
  1022.  
  1023.         //  Do it.
  1024.         if(uLoops) {
  1025.             Scroll(SB_VERT, uSBCode, 0, NULL, uScroll * uLoops);
  1026.         }
  1027.     }
  1028.  
  1029.     pMsg->lRetval = (LPARAM)1;
  1030.     pMsg->bSetRetval = TRUE;
  1031. }
  1032.  
  1033. void CPaneCX::PreWMHackedMouseWheel(PaneMessage *pMsg)
  1034. {
  1035.     //  Shunt.
  1036.     WPARAM wSubst = pMsg->wParam;
  1037.     pMsg->wParam = wSubst << 16;
  1038.     PreWMMouseWheel(pMsg);
  1039.     pMsg->wParam = wSubst;
  1040. }
  1041. #endif
  1042.  
  1043. void CPaneCX::Scroll(int iBars, UINT uSBCode, UINT uPos, HWND hCtrl, UINT uTimes)
  1044. {
  1045.     //  Provide a way to keep flow of control but not return early.
  1046.     BOOL bContinue = TRUE;
  1047.  
  1048.     if((iBars == SB_VERT || iBars == SB_BOTH) && IsVScrollBarOn() && GetHeight() < GetDocumentHeight()) {
  1049.         //  Calc an area leaving at least one page.
  1050.         //  Align the pixel and twips boundary, and check again to see if we're really
  1051.         //      doing anything.
  1052.         //  Account for Horiz scroll bar getting in the way.
  1053.         int32 lScrollable = GetDocumentHeight() - GetHeight();
  1054.         if(IsHScrollBarOn()) {
  1055.             lScrollable += sysInfo.m_iScrollHeight;
  1056.         }
  1057.         if(lScrollable > 0)    {
  1058.             int32 lOldOrgY = GetOriginY();
  1059.             int32 lScrollTwips = 0;
  1060.             double fYPos = 0.0f;
  1061.             int32 lTrack = 0;
  1062.  
  1063.             //  Figure out what we're doing.
  1064.             switch(uSBCode) {
  1065.             case SB_PAGEUP:
  1066.                 lScrollTwips = (-1 * GetHeight()) + VSCROLL_LINE;
  1067.                 break;
  1068.             case SB_PAGEDOWN:
  1069.                 lScrollTwips = GetHeight() - VSCROLL_LINE;
  1070.                 break;
  1071.             case SB_LINEUP:
  1072.                 lScrollTwips = -1 * VSCROLL_LINE;
  1073.                 break;
  1074.             case SB_LINEDOWN:
  1075.                 lScrollTwips = VSCROLL_LINE;
  1076.                 break;
  1077.             case SB_THUMBPOSITION:
  1078.             case SB_THUMBTRACK:
  1079.                 //  User is dragging the thumb tack.
  1080.                 //  Only move if we've moved more than a single pixel, or the display
  1081.                 //  gets messed up
  1082.                 fYPos = (double)uPos / (double)GetPageY();
  1083.                 lTrack = (int32)((fYPos * lScrollable)+0.5);
  1084.                 break;
  1085.             case SB_TOP:
  1086.                 lScrollTwips = -1 * GetOriginY();
  1087.                 break;
  1088.             case SB_BOTTOM:
  1089.                 lScrollTwips = lScrollable - GetOriginY();
  1090.                 break;
  1091.             default:
  1092.                 bContinue = FALSE;
  1093.                 break;
  1094.             }
  1095.             
  1096.             if(bContinue) {
  1097.                 //  Check to see if we need to do further math....
  1098.                 if(uSBCode != SB_THUMBPOSITION && uSBCode != SB_THUMBTRACK) {
  1099.                     lTrack = GetOriginY();
  1100.                     lTrack += lScrollTwips * (int32)uTimes;
  1101.                     
  1102.                     if (lTrack < 0)
  1103.                         lTrack = 0;
  1104.                     else if(lTrack > lScrollable)
  1105.                         lTrack = lScrollable;
  1106.                 }
  1107.                 
  1108.                 //  Position the scroll bar on an even pixel boundary
  1109.                 RealizeScrollBars(NULL, &lTrack);
  1110.                 
  1111.                 //  Figure the distance we actually scrolled.
  1112.                 int32 lPixAct = lOldOrgY - GetOriginY();
  1113.                 if(lPixAct)    {
  1114.                     ::ScrollWindowEx(GetPane(), 0, (int) lPixAct, NULL, NULL, NULL, NULL, SW_INVALIDATE |
  1115.                         SW_ERASE | SW_SCROLLCHILDREN);
  1116.                     ::UpdateWindow(GetPane());
  1117.                 }
  1118.             }
  1119.         }
  1120.     }
  1121.     
  1122.     //  Reset for horizontal test.
  1123.     bContinue = TRUE;
  1124.     
  1125.     if((iBars == SB_HORZ || iBars == SB_BOTH) && IsHScrollBarOn() && GetWidth() < GetDocumentWidth()) {
  1126.         //  Calc an area leaving at least one page.
  1127.         //  Align the pixel and twips boundary, and check again to see if we're really
  1128.         //      doing anything.
  1129.         //  Account for vertical scroller getting in the way.
  1130.         int32 lScrollable = GetDocumentWidth() - GetWidth();
  1131.         if(IsVScrollBarOn()) {
  1132.             lScrollable += sysInfo.m_iScrollWidth;
  1133.         }
  1134.         if(lScrollable > 0)    {
  1135.             int32 lOldOrgX = GetOriginX();
  1136.             int32 lScrollTwips = 0;
  1137.             double fXPos = 0.0f;
  1138.             int32 lTrack = 0;
  1139.             
  1140.             //  Figure out what we're doing.
  1141.             switch(uSBCode) {
  1142.             case SB_PAGELEFT:
  1143.                 lScrollTwips = -1 * GetWidth();
  1144.                 break;
  1145.             case SB_PAGERIGHT:
  1146.                 lScrollTwips = GetWidth();
  1147.                 break;
  1148.             case SB_LINELEFT:
  1149.             case SB_LINERIGHT:
  1150.                 lScrollTwips = HSCROLL_LINE;
  1151.                 if(uSBCode == SB_LINELEFT)  {
  1152.                     lScrollTwips *= -1;
  1153.                 }
  1154.                 break;
  1155.             case SB_THUMBPOSITION:
  1156.             case SB_THUMBTRACK:
  1157.                 //  User is dragging the thumb tack.
  1158.                 //  Only move if we've moved more than a single pixel, or the display
  1159.                 //  gets messed up.
  1160.                 fXPos = (double)uPos / (double)GetPageX();
  1161.                 lTrack = (int32)((fXPos * lScrollable)+0.5);
  1162.                 break;
  1163.             default:
  1164.                 bContinue = FALSE;
  1165.                 break;
  1166.             }
  1167.             
  1168.             if(bContinue) {
  1169.                 //  Check to see if we need to do further math....
  1170.                 if(uSBCode != SB_THUMBPOSITION && uSBCode != SB_THUMBTRACK) {
  1171.                     lTrack = GetOriginX();
  1172.                     lTrack += lScrollTwips * (int32)uTimes;
  1173.                     
  1174.                     if(lTrack > lScrollable)
  1175.                         lTrack = lScrollable;
  1176.                     if(lTrack < 0)
  1177.                         lTrack = 0;
  1178.                 }
  1179.                 
  1180.                 //  Position the scroll bar.
  1181.                 RealizeScrollBars(&lTrack);
  1182.                 
  1183.                 //  Figure the distance we actually scrolled.
  1184.                 int32 lPixAct = lOldOrgX - GetOriginX();
  1185.                 if(lPixAct)    {
  1186.                     ::ScrollWindowEx(GetPane(), (int) lPixAct, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE |
  1187.                     SW_ERASE | SW_SCROLLCHILDREN);
  1188.                     ::UpdateWindow(GetPane());
  1189.                 }
  1190.             }
  1191.         }
  1192.     }
  1193. }
  1194.  
  1195. void CPaneCX::GetWindowOffset(int32 *pX, int32 *pY)
  1196. {
  1197.     RECT rWindow;
  1198.     ::GetWindowRect(GetPane(), &rWindow);
  1199.     
  1200.     *pX = rWindow.left;
  1201.     *pY = rWindow.top;
  1202.     return;
  1203. }
  1204.  
  1205. void CPaneCX::MakeElementVisible(int32 lX, int32 lY)
  1206. {
  1207.     //  Figure out if any element is there.
  1208.     XY Point;
  1209.     Point.x = lX;
  1210.     Point.y = lY;
  1211.  
  1212.     LO_Element *pElement = GetLayoutElement(Point, NULL);
  1213.     if(pElement == NULL)    {
  1214.         SetDocPosition(GetContext(), FE_VIEW, lX, lY);
  1215.         return;
  1216.     }
  1217.  
  1218.     //  Figure up the coords of the element.
  1219.     LTRB Rect;
  1220.     LO_Any *pAny = &(pElement->lo_any);
  1221.     Rect.left = pAny->x + pAny->x_offset;
  1222.     Rect.top = pAny->y + pAny->y_offset;
  1223.     Rect.right = Rect.left + pAny->width;
  1224.     Rect.bottom = Rect.top + pAny->height;
  1225.  
  1226.     //  Is it currently Fully On Screen?
  1227.     //  Disregard the Y values (we'll want to scroll exactly on the Y, but perhaps not on the X).
  1228.     //  To the right?
  1229.     if(Rect.left >= GetOriginX())   {
  1230.         //  To the left?
  1231.         if(Rect.right <= GetOriginX() + GetWidth()) {
  1232.             //  It's on the X view.
  1233.             //  Use the current X origin.
  1234.             lX = GetOriginX();
  1235.             SetDocPosition(GetContext(), FE_VIEW, lX, lY);
  1236.             return;
  1237.         }
  1238.     }
  1239.  
  1240.     //  X wasn't on screen fully, so we're going to use very exact values when scrolling
  1241.     //      for whatever effect this gives....
  1242.     SetDocPosition(GetContext(), FE_VIEW, lX, lY);
  1243. }
  1244.  
  1245. void CPaneCX::PreNavCenterQueryPosition(PaneMessage *pMessage)
  1246. {
  1247.     //  Only handle if we're a NavCenter HTML Pane.
  1248.     if(IsNavCenterHTMLPane()) {
  1249.         NAVCENTPOS *pPos = (NAVCENTPOS *)pMessage->lParam;
  1250.         
  1251.         //  We like being at the bottom.
  1252.         pPos->m_iYDisposition = INT_MAX;
  1253.         
  1254.         //  We like being this many units in size.
  1255.         pPos->m_iYVector = 100;
  1256.         
  1257.         //  Handled.
  1258.         pMessage->lRetval = NULL;
  1259.         pMessage->bSetRetval = TRUE;
  1260.     }
  1261. }
  1262.  
  1263. void CPaneCX::PreIdleUpdateCmdUI(PaneMessage *pMsg)
  1264. {
  1265.     //  Don't want to update CMD UI unless we have a frame parent.
  1266.     //  This effectively stops CMD UI in the NavCenter HTML pane
  1267.     //      from messing with the UI state when docked.
  1268.     if(IsNavCenterHTMLPane()) {
  1269.         //  Handled.
  1270.         pMsg->lRetval = NULL;
  1271.         pMsg->bSetRetval = TRUE;
  1272.     }
  1273. }
  1274.  
  1275. #ifdef XP_WIN16
  1276. HINSTANCE CPaneCX::GetSegment()
  1277. {
  1278.     //  Form elements on a per context basis receive their own segment.
  1279.     HINSTANCE hRetval = NULL;
  1280.     
  1281.     if(NULL == m_hTextElementSegment) {
  1282.         m_hTextElementSegment = ::GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, (UINT) 8 * 1024); 
  1283.     }
  1284.     if(m_hTextElementSegment && NULL == m_lpTextElementHeap) {
  1285.         //  Initialize the segment.
  1286.         m_lpTextElementHeap = ::GlobalLock(m_hTextElementSegment);
  1287.         if(m_lpTextElementHeap) {
  1288.             ::LocalInit(HIWORD((LONG)m_lpTextElementHeap), 0, (WORD)(::GlobalSize(m_hTextElementSegment) - 16));
  1289.             ::UnlockSegment(HIWORD((LONG)m_lpTextElementHeap));
  1290.         }
  1291.     }
  1292.     
  1293.     if(m_lpTextElementHeap) {
  1294.         hRetval = (HINSTANCE)HIWORD((LONG)m_lpTextElementHeap);
  1295.     }
  1296.     
  1297.     return(hRetval);
  1298. }
  1299. #endif
  1300.  
  1301.  
  1302.  
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308. LRESULT
  1309. CALLBACK
  1310. #ifndef _WIN32
  1311. _export
  1312. #endif
  1313. PaneProc(HWND hPane, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1314. {
  1315. #ifdef XP_WIN32
  1316.     const char *pPropName = STR_CPANECX;  //  Not a UI string.
  1317. #else
  1318.     const char *pPropNameHi = STR_CPANECX_HI;
  1319.     const char *pPropNameLo = STR_CPANECX_LO;
  1320. #endif
  1321.     PaneMessage message(wParam, lParam);
  1322.     
  1323.     //  Get the property (which is a this pointer).
  1324.     void *pvThis = NULL;
  1325. #ifdef XP_WIN32
  1326.     pvThis = (void *)GetProp(hPane, pPropName);
  1327. #else
  1328.     pvThis = (void *)MAKELONG(GetProp(hPane, pPropNameLo), GetProp(hPane, pPropNameHi));
  1329. #endif
  1330.     if(pvThis) {
  1331.         CPaneCX *pThis = VOID2CX(pvThis, CPaneCX);
  1332.         
  1333.         //  Messages handled BEFORE calling other window procedure.
  1334.         //  Make calls here when you don't care about the LRESULT
  1335.         //      of the normal message handler or don't want the normal
  1336.         //      message handler being called at all (by marking that
  1337.         //      the return value has been set).
  1338.         switch(uMsg) {
  1339.             case WM_PAINT:
  1340.                 pThis->PreWMPaint(&message);
  1341.                 break;
  1342.             case WM_ERASEBKGND:
  1343.                 pThis->PreWMErasebkgnd(&message);
  1344.                 break;
  1345.             case WM_VSCROLL:
  1346.                 pThis->PreWMVScroll(&message);
  1347.                 break;
  1348.             case WM_HSCROLL:
  1349.                 pThis->PreWMHScroll(&message);
  1350.                 break;
  1351.             case WM_NAVCENTER_QUERYPOSITION:
  1352.                 pThis->PreNavCenterQueryPosition(&message);
  1353.                 break;
  1354.             case WM_IDLEUPDATECMDUI:
  1355.                 pThis->PreIdleUpdateCmdUI(&message);
  1356.                 break;
  1357. #if defined(XP_WIN32) && _MSC_VER >= 1100
  1358.             case WM_MOUSEWHEEL:
  1359.                 pThis->PreWMMouseWheel(&message);
  1360.                 break;
  1361. #endif
  1362.             default:
  1363.                 //  Handle non constant messages here.
  1364. #if defined(XP_WIN32) && _MSC_VER >= 1100
  1365.                 if(uMsg == msg_MouseWheel)   {
  1366.                     pThis->PreWMHackedMouseWheel(&message);
  1367.                 }
  1368. #endif
  1369.                 break;
  1370.         }
  1371.         
  1372.         //  Call previous window proc.
  1373.         if(!message.bSetRetval) {
  1374.             WNDPROC pPrevProc = pThis->GetSubclassedProc();
  1375.             if(pPrevProc) {
  1376.                 message.lRetval = CallWindowProc(pPrevProc, hPane, uMsg, wParam, lParam);
  1377.                 message.bSetRetval = TRUE;
  1378.             }
  1379.         }
  1380.         
  1381.         //  Notifications handled AFTER calling other window procedure.
  1382.         //  Make calls here when you care about the LRESULT
  1383.         //      of any above message handler, or want to handle a
  1384.         //      message if no one else did before the default window
  1385.         //      procedure is invoked..
  1386.         switch(uMsg) {
  1387.             case WM_SIZE:
  1388.                 pThis->AftWMSize(&message);
  1389.                 break;
  1390.             case WM_DESTROY:
  1391.                 pThis->AftWMDestroy(&message);
  1392.                 break;
  1393.             case WM_MOUSEACTIVATE:
  1394.                 pThis->AftWMMouseActivate(&message);
  1395.                 break;
  1396.             default:
  1397.                 break;
  1398.         }
  1399.         
  1400.         //  Default handler if nothing happened.
  1401.         if(!message.bSetRetval) {
  1402.             message.lRetval = DefWindowProc(hPane, uMsg, wParam, lParam);
  1403.             message.bSetRetval = TRUE;
  1404.         }
  1405.     }
  1406.     else {
  1407.         //  Either someone subclassed and we need to unsubclass in
  1408.         //      their stack, or this is getting called before we
  1409.         //      set the property on the window.
  1410.         //  Don't crash or do anything stupid, but we currently don't
  1411.         //      attempt to handle.
  1412.         message.lRetval = DefWindowProc(hPane, uMsg, wParam, lParam);
  1413.         message.bSetRetval = TRUE;
  1414.     }
  1415.     
  1416.     ASSERT(message.bSetRetval);
  1417.     return(message.lRetval);
  1418. }
  1419.  
  1420. //  Subclass or unsubclass a window.
  1421. BOOL CPaneCX::SubClass(HWND hWnd, BOOL bSubClass)
  1422. {
  1423.     BOOL bRetval = FALSE;
  1424. #ifdef XP_WIN32
  1425.     const char *pPropName = STR_CPANECX;  //  Not a UI string.
  1426. #else
  1427.     const char *pPropNameHi = STR_CPANECX_HI;  //  Not a UI string.
  1428.     const char *pPropNameLo = STR_CPANECX_LO;  //  Not a UI string.
  1429. #endif
  1430.     
  1431.     if(hWnd) {
  1432.         if(bSubClass) {
  1433.             ASSERT(!m_pPrevProc);
  1434.             
  1435.             //  Make sure no one else is already doing this window.
  1436.             //  We could add the support by making each property
  1437.             //      name unique by pid() then ptr, but no need right now.
  1438.             if(!
  1439. #ifdef XP_WIN32
  1440.                 (::GetProp(hWnd, pPropName))
  1441. #else
  1442.                 (::GetProp(hWnd, pPropNameLo) || ::GetProp(hWnd, pPropNameHi))
  1443. #endif
  1444.                 ) {
  1445.                 m_pPrevProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)PaneProc);
  1446.                 if(m_pPrevProc) {
  1447.                     BOOL bAddProp;
  1448. #ifdef XP_WIN32
  1449.                     bAddProp = ::SetProp(hWnd, pPropName, (HANDLE)this);
  1450. #else
  1451.                     bAddProp = ::SetProp(hWnd, pPropNameHi, (HANDLE)HIWORD(this));
  1452.                     if(bAddProp)    {
  1453.                         bAddProp = ::SetProp(hWnd, pPropNameLo, (HANDLE)LOWORD(this));
  1454.                     }
  1455. #endif
  1456.                     if(bAddProp) {
  1457.                         bRetval = TRUE;
  1458.                     }
  1459.                     else {
  1460.                         LONG lCheck = ::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)m_pPrevProc);
  1461.                         m_pPrevProc = NULL;
  1462.                         ASSERT(lCheck == (LONG)PaneProc);
  1463.                     }
  1464.                 }
  1465.             }
  1466.         }
  1467.         else {
  1468.             ASSERT(m_pPrevProc);
  1469.             
  1470.             void *pThis = NULL;
  1471. #ifdef XP_WIN32
  1472.             pThis = (void *)::RemoveProp(hWnd, pPropName);
  1473. #else
  1474.             pThis = (void *)MAKELONG(::RemoveProp(hWnd, pPropNameLo), ::RemoveProp(hWnd, pPropNameHi));
  1475. #endif
  1476.             ASSERT(pThis && pThis == (void *)this);
  1477.             if(pThis && pThis == (void *)this) {
  1478.                 LONG lOurProc = ::GetWindowLong(hWnd, GWL_WNDPROC);
  1479.                 ASSERT(lOurProc && lOurProc == (LONG)PaneProc);
  1480.                 if(lOurProc && lOurProc == (LONG)PaneProc) {
  1481.                     LONG lCheck = ::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)m_pPrevProc);
  1482.                     ASSERT(lCheck && lCheck == (LONG)PaneProc);
  1483.                     if(lCheck && lCheck == (LONG)PaneProc) {
  1484.                         bRetval = TRUE;
  1485.                     }
  1486.                 }
  1487.                 m_pPrevProc = NULL;
  1488.             }
  1489.         }
  1490.     }
  1491.     
  1492.     return(bRetval);
  1493. }
  1494.  
  1495.