+ // scroll lines per page: if 0, no scrolling is needed
+ // check if we need scrollbar in this direction at all
+ if ( pixelsPerUnit == 0 || clientSize >= virtSize )
+ {
+ // scrolling is disabled or unnecessary
+ scrollUnits =
+ scrollPosition = 0;
+ scrollLinesPerPage = 0;
+ }
+ else // might need scrolling
+ {
+ // Round up integer division to catch any "leftover" client space.
+ scrollUnits = (virtSize + pixelsPerUnit - 1) / pixelsPerUnit;
+
+ // Calculate the number of fully scroll units
+ scrollLinesPerPage = clientSize / pixelsPerUnit;
+
+ if ( scrollLinesPerPage >= scrollUnits )
+ {
+ // we're big enough to not need scrolling
+ scrollUnits =
+ scrollPosition = 0;
+ scrollLinesPerPage = 0;
+ }
+ else // we do need a scrollbar
+ {
+ if ( scrollLinesPerPage < 1 )
+ scrollLinesPerPage = 1;
+
+ // Correct position if greater than extent of canvas minus
+ // the visible portion of it or if below zero
+ const int posMax = scrollUnits - scrollLinesPerPage;
+ if ( scrollPosition > posMax )
+ scrollPosition = posMax;
+ else if ( scrollPosition < 0 )
+ scrollPosition = 0;
+ }
+ }
+
+ // in wxSHOW_SB_NEVER case don't show the scrollbar even if it's needed, in
+ // wxSHOW_SB_ALWAYS case show the scrollbar even if it's not needed by
+ // passing a special range value to SetScrollbar()
+ int range;
+ switch ( visibility )
+ {
+ case wxSHOW_SB_NEVER:
+ range = 0;
+ break;
+
+ case wxSHOW_SB_ALWAYS:
+ range = scrollUnits ? scrollUnits : -1;
+ break;
+
+ default:
+ wxFAIL_MSG( wxS("unknown scrollbar visibility") );
+ // fall through
+
+ case wxSHOW_SB_DEFAULT:
+ range = scrollUnits;
+ break;
+
+ }
+
+ m_win->SetScrollbar(orient, scrollPosition, scrollLinesPerPage, range);
+}
+
+void wxScrollHelper::AdjustScrollbars()
+{
+ static wxRecursionGuardFlag s_flagReentrancy;
+ wxRecursionGuard guard(s_flagReentrancy);
+ if ( guard.IsInside() )
+ {
+ // don't reenter AdjustScrollbars() while another call to
+ // AdjustScrollbars() is in progress because this may lead to calling
+ // ScrollWindow() twice and this can really happen under MSW if
+ // SetScrollbar() call below adds or removes the scrollbar which
+ // changes the window size and hence results in another
+ // AdjustScrollbars() call
+ return;
+ }
+
+ int oldXScroll = m_xScrollPosition;
+ int oldYScroll = m_yScrollPosition;
+
+ // we may need to readjust the scrollbars several times as enabling one of
+ // them reduces the area available for the window contents and so can make
+ // the other scrollbar necessary now although it wasn't necessary before
+ //
+ // VZ: normally this loop should be over in at most 2 iterations, I don't
+ // know why do we need 5 of them
+ for ( int iterationCount = 0; iterationCount < 5; iterationCount++ )
+ {
+ wxSize clientSize = GetTargetSize();
+ const wxSize virtSize = m_targetWindow->GetVirtualSize();
+
+ // this block of code tries to work around the following problem: the
+ // window could have been just resized to have enough space to show its
+ // full contents without the scrollbars, but its client size could be
+ // not big enough because it does have the scrollbars right now and so
+ // the scrollbars would remain even though we don't need them any more
+ //
+ // to prevent this from happening, check if we have enough space for
+ // everything without the scrollbars and explicitly disable them then
+ const wxSize availSize = GetSizeAvailableForScrollTarget(
+ m_win->GetSize() - m_win->GetWindowBorderSize());
+ if ( availSize != clientSize )
+ {
+ if ( availSize.x >= virtSize.x && availSize.y >= virtSize.y )
+ {
+ // this will be enough to make the scrollbars disappear below
+ // and then the client size will indeed become equal to the
+ // full available size
+ clientSize = availSize;
+ }
+ }
+
+
+ DoAdjustScrollbar(wxHORIZONTAL,
+ clientSize.x,
+ virtSize.x,
+ m_xScrollPixelsPerLine,
+ m_xScrollLines,
+ m_xScrollPosition,
+ m_xScrollLinesPerPage,
+ m_xVisibility);
+
+ DoAdjustScrollbar(wxVERTICAL,
+ clientSize.y,
+ virtSize.y,
+ m_yScrollPixelsPerLine,
+ m_yScrollLines,
+ m_yScrollPosition,
+ m_yScrollLinesPerPage,
+ m_yVisibility);
+
+
+ // If a scrollbar (dis)appeared as a result of this, we need to adjust
+ // them again but if the client size didn't change, then we're done
+ if ( GetTargetSize() == clientSize )
+ break;
+ }
+
+#ifdef __WXMOTIF__
+ // Sorry, some Motif-specific code to implement a backing pixmap
+ // for the wxRETAINED style. Implementing a backing store can't
+ // be entirely generic because it relies on the wxWindowDC implementation
+ // to duplicate X drawing calls for the backing pixmap.
+
+ if ( m_targetWindow->GetWindowStyle() & wxRETAINED )
+ {
+ Display* dpy = XtDisplay((Widget)m_targetWindow->GetMainWidget());
+
+ int totalPixelWidth = m_xScrollLines * m_xScrollPixelsPerLine;
+ int totalPixelHeight = m_yScrollLines * m_yScrollPixelsPerLine;
+ if (m_targetWindow->GetBackingPixmap() &&
+ !((m_targetWindow->GetPixmapWidth() == totalPixelWidth) &&
+ (m_targetWindow->GetPixmapHeight() == totalPixelHeight)))
+ {
+ XFreePixmap (dpy, (Pixmap) m_targetWindow->GetBackingPixmap());
+ m_targetWindow->SetBackingPixmap((WXPixmap) 0);
+ }
+
+ if (!m_targetWindow->GetBackingPixmap() &&
+ (m_xScrollLines != 0) && (m_yScrollLines != 0))
+ {
+ int depth = wxDisplayDepth();
+ m_targetWindow->SetPixmapWidth(totalPixelWidth);
+ m_targetWindow->SetPixmapHeight(totalPixelHeight);
+ m_targetWindow->SetBackingPixmap((WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
+ m_targetWindow->GetPixmapWidth(), m_targetWindow->GetPixmapHeight(), depth));
+ }