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

  1. /* -*- Mode: C++; tab-width: 8; 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.    scroll.c --- managing the scrolled area
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 23-Jul-94.
  21.  */
  22.  
  23.  
  24. #include "mozilla.h"
  25. #include "xfe.h"
  26. #include "scroller.h"
  27. #include "scrollerP.h"
  28. #include "new_manage.h"
  29. #include "new_manageP.h"
  30.  
  31. /* for XP_GetString() */
  32. #include <xpgetstr.h>
  33.  
  34. extern int XFE_SCROLL_WINDOW_GRAVITY_WARNING;
  35.  
  36. /* C entry point to XFE_HTMLDrag class in  xfe/src/HTMLDrag.cpp */
  37. extern void XFE_HTMLDragCreate(Widget,MWContext*);
  38.  
  39. #ifdef EDITOR
  40. #include "xeditor.h"
  41. extern void fe_EditorReload(MWContext* context, Boolean super_reload);
  42. #endif /*EDITOR*/
  43.  
  44. /* Layering support - LO_RefreshArea is called through compositor */
  45. #include "layers.h"
  46.  
  47. void fe_find_scrollbar_sizes(MWContext *context); /* in xfe.h */
  48.  
  49. static void fe_expose_eh (Widget, XtPointer, XEvent *);
  50. /* static void fe_expose_cb (Widget, XtPointer, XtPointer); */
  51. static void fe_scroll_cb (Widget, XtPointer, XtPointer);
  52.  
  53. #ifdef RESIZE_CALLBACK_WORKS
  54. static void fe_resize_cb (Widget, XtPointer, XtPointer);
  55. #else
  56. static void fe_scroller_resize (Widget, XtPointer);
  57. #endif
  58.  
  59. static void guffaw (MWContext *context);
  60. static void unguffaw (MWContext *context);
  61.  
  62. void
  63. fe_InitScrolling (MWContext *context)
  64. {
  65.   if (CONTEXT_DATA (context)->drawing_area == NULL) return;
  66.   /*
  67.    * Guffaws has 3 states now.  If 0 it is just off.  If 1 it uses
  68.    * static gravity, if 2 it uses a combination of N, S, E, W gravities.
  69.    * Any method that uses gravity needs the configure handler.  Only
  70.    * static uses the guffaw function.
  71.    */
  72.   if (fe_globalData.fe_guffaw_scroll > 0)
  73.     {
  74.       XtAddEventHandler (CONTEXT_DATA (context)->drawing_area,
  75.             StructureNotifyMask, FALSE,
  76.              (XtEventHandler)fe_config_eh, context);
  77.     }
  78.   if (fe_globalData.fe_guffaw_scroll == 1)
  79.     {
  80.       guffaw (context);
  81.     }
  82.   fe_NukeBackingStore (CONTEXT_DATA (context)->drawing_area);
  83. }
  84.  
  85.  
  86. /*
  87.  * Reverse the actions of fe_InitScrolling().  For when a normal
  88.  * document context is turned into a FRAME parent context.
  89.  */
  90. void
  91. fe_DisableScrolling (MWContext *context)
  92. {
  93.   if (CONTEXT_DATA (context)->drawing_area == NULL) return;
  94.   /*
  95.    * Turn off guffaws for a context's drawing area.
  96.    */
  97.   if (fe_globalData.fe_guffaw_scroll > 0)
  98.     {
  99.       XtRemoveEventHandler (CONTEXT_DATA (context)->drawing_area,
  100.             StructureNotifyMask, FALSE,
  101.              (XtEventHandler)fe_config_eh, context);
  102.     }
  103.   if (fe_globalData.fe_guffaw_scroll == 1)
  104.     {
  105.       unguffaw (context);
  106.     }
  107. }
  108.  
  109.  
  110. Widget
  111. fe_MakeScrolledWindow (MWContext *context, Widget parent, const char *name)
  112. {
  113.   Widget scroller, drawing_area, hscroll, vscroll;
  114.   Arg av [20];
  115.   int ac = 0;
  116.  
  117.   ac = 0;
  118.   XtSetArg (av[ac], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ac++;
  119.   /* The background of this widget is the color that shows up in the square
  120.      at the bottom right where the horizontal and vertical scrollbars come
  121.      together, and of the "pad" border between the scrollbars and the document
  122.      area (which we'd like to be of size 0, see below.)  This should be in the
  123.      background color of the widgets, not the background color of the document.
  124.    */
  125.   XtSetArg (av[ac], XmNbackground, parent->core.background_pixel); ac++;
  126. /*  scroller = XmCreateScrolledWindow (parent, name, av, ac);*/
  127.   scroller = XtCreateWidget((char *) name, scrollerClass, parent, av, ac);
  128. #ifndef RESIZE_CALLBACK_WORKS
  129.   ((Scroller) scroller)->scroller.resize_arg = (void *) context;
  130.   ((Scroller) scroller)->scroller.resize_hook = fe_scroller_resize;
  131. #endif
  132.  
  133.   /* This is a kludge - there ought to be a resource to control this, but
  134.      I can't find it.  This controls the extra space between the scrollbars
  135.      and the area being scrolled.  If this isn't 0, then there's a 4-pixel
  136.      border between the document background and the scrollbar, which ends
  137.      up in the user's background instead, which looks stupid.
  138.    */
  139.   ((Scroller) scroller)->swindow.pad = 0;
  140.  
  141.   ac = 0;
  142.   XtSetArg (av[ac], XmNminimum, 0); ac++;
  143.   XtSetArg (av[ac], XmNmaximum, 1); ac++;
  144.   XtSetArg (av[ac], XmNorientation, XmHORIZONTAL); ac++;
  145.   hscroll = XmCreateScrollBar (scroller, "hscroll", av, ac);
  146.   ac = 0;
  147.   XtSetArg (av[ac], XmNminimum, 0); ac++;
  148.   XtSetArg (av[ac], XmNmaximum, 1); ac++;
  149.   XtSetArg (av[ac], XmNorientation, XmVERTICAL); ac++;
  150.   vscroll = XmCreateScrollBar (scroller, "vscroll", av, ac);
  151.   ac = 0;
  152.  
  153.   /* The drawing area we're about to create is the actual document window,
  154.      so its background should be the document background pixel. */
  155.   XtSetArg (av[ac], XmNbackground,
  156.         CONTEXT_DATA (context)->default_bg_pixel); ac++;
  157. /*
  158.   XtSetArg (av[ac], XmNautoUnmanage, FALSE); ac++;
  159.   XtSetArg (av[ac], XmNdefaultPosition, FALSE); ac++;
  160.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_WORK_AREA); ac++;
  161.   XtSetArg (av[ac], XmNmarginHeight, 0); ac++;
  162.   XtSetArg (av[ac], XmNmarginWidth, 0); ac++;
  163. */
  164. #ifdef EDITOR
  165.         if (EDT_IS_EDITOR(context)) {
  166.             /* Let's try using the managed widget */
  167.             drawing_area = XtCreateWidget("editorDrawingArea", newManageClass,
  168.                                           scroller, av, ac);
  169.         }
  170.   else
  171. #endif /* EDITOR */
  172.     drawing_area = XtCreateWidget("drawingArea", newManageClass, scroller, av, ac);
  173.  
  174. /*
  175.   drawing_area = XtCreateWidget("drawingArea", xmManagerWidgetClass, scroller, av, ac);
  176.   drawing_area = XtCreateWidget("drawingArea", xmBulletinBoardWidgetClass, scroller, av, ac);
  177. */
  178. /*  XtAddCallback (drawing_area, XmNexposeCallback, fe_expose_cb, context); */
  179.   XtAddEventHandler(drawing_area, ExposureMask, FALSE,
  180.     (XtEventHandler)fe_expose_eh, context);
  181. /* This is now added later in xfe.c, because we don't know fe_guffaw_scroll
  182.  * yet.
  183.   if (fe_globalData.fe_guffaw_scroll)
  184.   {
  185.     XtAddEventHandler(drawing_area, StructureNotifyMask, FALSE,
  186.     (XtEventHandler)fe_config_eh, context);
  187.   }
  188. */
  189. #ifdef RESIZE_CALLBACK_WORKS
  190.   XtAddCallback (drawing_area, XmNresizeCallback, fe_resize_cb, context);
  191. #endif
  192.  
  193.   XtManageChild (drawing_area);
  194.   SCROLLER_SET_AREAS (scroller, hscroll, vscroll, drawing_area);
  195.  
  196.   XtAddCallback (hscroll, XmNvalueChangedCallback, fe_scroll_cb, context);
  197.   XtAddCallback (vscroll, XmNvalueChangedCallback, fe_scroll_cb, context);
  198.   XtAddCallback (hscroll, XmNdragCallback, fe_scroll_cb, context);
  199.   XtAddCallback (vscroll, XmNdragCallback, fe_scroll_cb, context);
  200.  
  201.   CONTEXT_DATA (context)->scrolled = scroller;
  202.   CONTEXT_DATA (context)->drawing_area = drawing_area;
  203.   CONTEXT_DATA (context)->hscroll = hscroll;
  204.   CONTEXT_DATA (context)->vscroll = vscroll;
  205.  
  206.   XtManageChild (hscroll);
  207.   XtManageChild (vscroll);
  208.  
  209.   /* add drag source via C API */
  210.   XFE_HTMLDragCreate(drawing_area,context);
  211.   
  212.   return scroller;
  213. }
  214.  
  215. static void
  216. guffaw (MWContext *context)
  217. {
  218.   Widget widget = CONTEXT_DATA (context)->drawing_area;
  219.   XSetWindowAttributes attr;
  220.   unsigned long valuemask;
  221.   valuemask = CWBitGravity | CWWinGravity;
  222.   attr.win_gravity = StaticGravity;
  223.   attr.bit_gravity = StaticGravity;
  224.   if (! XtWindow (widget)) abort ();
  225.   XChangeWindowAttributes (XtDisplay (widget), XtWindow (widget),
  226.                valuemask, &attr);
  227. }
  228.  
  229. static void
  230. unguffaw (MWContext *context)
  231. {
  232.   Widget widget = CONTEXT_DATA (context)->drawing_area;
  233.   XSetWindowAttributes attr;
  234.   unsigned long valuemask;
  235.   valuemask = CWBitGravity | CWWinGravity;
  236.   attr.win_gravity = NorthWestGravity;
  237.   attr.bit_gravity = NorthWestGravity;
  238.   if (! XtWindow (widget)) abort ();
  239.   XChangeWindowAttributes (XtDisplay (widget), XtWindow (widget),
  240.                valuemask, &attr);
  241. }
  242.  
  243. /*
  244.  * Toggle on and off the bit and window gravity effects
  245.  * of guffaws scrolling.
  246.  */
  247. void
  248. fe_SetGuffaw(MWContext *context, Boolean on)
  249. {
  250.   if (fe_globalData.fe_guffaw_scroll == 1)
  251.     {
  252.       if (on)
  253.         guffaw (context);
  254.       else
  255.         unguffaw (context);
  256.     }
  257. }
  258.  
  259. static void 
  260. fe_scroll_cb (Widget widget, XtPointer closure, XtPointer call_data)
  261. {
  262.   MWContext *context = (MWContext *) closure;
  263.   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *) call_data;
  264.   Widget da = CONTEXT_DATA (context)->drawing_area;
  265.   int scroll_slop_hack =
  266.     ((Scroller) CONTEXT_DATA (context)->scrolled)->swindow.pad;
  267.   unsigned long lh = CONTEXT_DATA (context)->line_height;
  268.   unsigned long old_x = CONTEXT_DATA (context)->document_x;
  269.   unsigned long old_y = CONTEXT_DATA (context)->document_y;
  270.   unsigned long new_x = old_x;
  271.   unsigned long new_y = old_y;
  272.   Dimension w = 0, h = 0;
  273.   Boolean horiz_p;
  274.   XGCValues gcv;
  275.   GC gc;
  276.  
  277.   fe_UserActivity (context);
  278.   if (widget == CONTEXT_DATA (context)->hscroll)
  279.     new_x = cb->value;
  280.   else if (widget == CONTEXT_DATA (context)->vscroll)
  281.     new_y = cb->value;
  282.   else
  283.     abort ();
  284.   horiz_p = (new_x != old_x);
  285.  
  286.   fe_SetDocPosition (context, new_x, new_y);
  287.  
  288. /*  XtVaGetValues (da, XmNwidth, &w, XmNheight, &h, 0); */
  289.   w = da->core.width;
  290.   h = da->core.height;
  291.  
  292.   memset (&gcv, ~0, sizeof (gcv));
  293.   gcv.function = GXcopy;
  294.   gc = fe_GetGC (da, GCFunction, &gcv);
  295.  
  296.   if (horiz_p)
  297.     {
  298.       if (new_x >= old_x)
  299.     {
  300.       int shift = (new_x - old_x);
  301.       int sb_w = CONTEXT_DATA (context)->sb_w;
  302.       if (fe_globalData.fe_guffaw_scroll == 1)
  303.         {
  304.           int x, y;
  305.           unsigned int w, h, d1, d2;
  306.           Window dummy;
  307.  
  308.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  309.                &x, &y, &w, &h, &d1, &d2);
  310.           XResizeWindow(XtDisplay(da), XtWindow(da),
  311.                 (w + shift + scroll_slop_hack), h);
  312.           XMoveWindow(XtDisplay(da), XtWindow(da), (x - shift), y);
  313.           XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
  314.           fe_GravityCorrectForms (context, -shift, 0);
  315.         }
  316.       else if (fe_globalData.fe_guffaw_scroll == 2)
  317.         {
  318.           int x, y;
  319.           unsigned int w, h, d1, d2;
  320.           Window dummy;
  321.  
  322.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  323.                &x, &y, &w, &h, &d1, &d2);
  324.           fe_SetFormsGravity(context, WestGravity);
  325.           XResizeWindow(XtDisplay(da), XtWindow(da),
  326.                 (w + shift), h);
  327.           XMoveWindow(XtDisplay(da), XtWindow(da), (x - shift), y);
  328.           fe_SetFormsGravity(context, EastGravity);
  329.           XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
  330.           fe_SetFormsGravity(context, NorthWestGravity);
  331.           fe_GravityCorrectForms (context, -shift, 0);
  332.         }
  333.       else
  334.         {
  335.           XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
  336.              shift, 0,
  337.              w - shift, h,
  338.              0, 0);
  339.           fe_ScrollForms (context, old_x - new_x, old_y - new_y);
  340.           fe_RefreshArea (context,
  341.                               new_x + w - (shift+lh+lh),
  342.                               new_y, shift+lh, h);
  343.         }
  344.       if (shift > w)
  345.         {
  346.           shift = w;
  347.         }
  348.  
  349. #ifdef DONT_rhess
  350.       /*
  351.        *  NOTE:  we always need to refresh the delta of the scrolled area...
  352.        *         [ bug:  improper redisplay during scrolling ]
  353.        */
  354.  
  355.       if (fe_globalData.fe_guffaw_scroll == 0)
  356. #endif
  357.         fe_RefreshArea (context,
  358.                             new_x + w - sb_w - shift,
  359.                             new_y, shift + sb_w, h);
  360.     }
  361.       else
  362.     {
  363.       int shift = (old_x - new_x);
  364.       if (fe_globalData.fe_guffaw_scroll == 1)
  365.         {
  366.           int x, y;
  367.           unsigned int w, h, d1, d2;
  368.           Window dummy;
  369.  
  370.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  371.                &x, &y, &w, &h, &d1, &d2);
  372.           XMoveResizeWindow(XtDisplay(da), XtWindow(da),
  373.                 (x - shift), y, (w + shift), h);
  374.           XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
  375.           XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
  376.           fe_GravityCorrectForms (context, shift, 0);
  377.         }
  378.       else if (fe_globalData.fe_guffaw_scroll == 2)
  379.         {
  380.           int x, y;
  381.           unsigned int w, h, d1, d2;
  382.           Window dummy;
  383.  
  384.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  385.                &x, &y, &w, &h, &d1, &d2);
  386.           fe_SetFormsGravity(context, EastGravity);
  387.           XMoveResizeWindow(XtDisplay(da), XtWindow(da),
  388.                 (x - shift), y, (w + shift), h);
  389.           fe_SetFormsGravity(context, WestGravity);
  390.           XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
  391.           XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
  392.           fe_SetFormsGravity(context, NorthWestGravity);
  393.           fe_GravityCorrectForms (context, shift, 0);
  394.         }
  395.       else
  396.         {
  397.           XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
  398.              0, 0,
  399.              w - (old_x - new_x), h,
  400.              (old_x - new_x), 0);
  401.           fe_ScrollForms (context, old_x - new_x, old_y - new_y);
  402.         }
  403.       if (shift > w)
  404.         {
  405.           shift = w;
  406.         }
  407.  
  408. #ifdef DONT_rhess
  409.       if (fe_globalData.fe_guffaw_scroll == 0)
  410. #endif
  411.         fe_RefreshArea (context, new_x, new_y, shift, h);
  412.     }
  413.     }
  414.   else
  415.     {
  416.       if (new_y >= old_y)
  417.     {
  418.       int shift = (new_y - old_y);
  419.       int sb_h = CONTEXT_DATA (context)->sb_h;
  420.       if (fe_globalData.fe_guffaw_scroll == 1)
  421.         {
  422.           int x, y;
  423.           unsigned int w, h, d1, d2;
  424.           Window dummy;
  425.  
  426.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  427.                &x, &y, &w, &h, &d1, &d2);
  428.           XResizeWindow(XtDisplay(da), XtWindow(da), w,
  429.                 (h + shift + scroll_slop_hack));
  430.           XMoveWindow(XtDisplay(da), XtWindow(da), x, (y - shift));
  431.           XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
  432.           fe_GravityCorrectForms (context, 0, -shift);
  433.         }
  434.       else if (fe_globalData.fe_guffaw_scroll == 2)
  435.         {
  436.           int x, y;
  437.           unsigned int w, h, d1, d2;
  438.           Window dummy;
  439.  
  440.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  441.                &x, &y, &w, &h, &d1, &d2);
  442.           fe_SetFormsGravity(context, NorthGravity);
  443.           XResizeWindow(XtDisplay(da), XtWindow(da), w,
  444.                 (h + shift));
  445.           XMoveWindow(XtDisplay(da), XtWindow(da), x, (y - shift));
  446.           fe_SetFormsGravity(context, SouthGravity);
  447.           XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
  448.           fe_SetFormsGravity(context, NorthWestGravity);
  449.           fe_GravityCorrectForms (context, 0, -shift);
  450.         }
  451.       else
  452.         {
  453.           XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
  454.              0, shift,
  455.              w, h - shift,
  456.              0, 0);
  457.           fe_ScrollForms (context, old_x - new_x, old_y - new_y);
  458.         }
  459.       if (shift > h)
  460.         {
  461.           shift = h;
  462.         }
  463.  
  464. #ifdef DONT_rhess
  465.       if (fe_globalData.fe_guffaw_scroll == 0)
  466. #endif
  467.         fe_RefreshArea (context, new_x, new_y + h - sb_h - shift,
  468.                             w, shift + sb_h);
  469.     }
  470.       else
  471.     {
  472.       int shift = (old_y - new_y);
  473.       if (fe_globalData.fe_guffaw_scroll == 1)
  474.         {
  475.           int x, y;
  476.           unsigned int w, h, d1, d2;
  477.           Window dummy;
  478.  
  479.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  480.                &x, &y, &w, &h, &d1, &d2);
  481.           XMoveResizeWindow(XtDisplay(da), XtWindow(da),
  482.                 x, (y - shift), w, (h + shift));
  483.           XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
  484.           XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
  485.           fe_GravityCorrectForms (context, 0, shift);
  486.         }
  487.       else if (fe_globalData.fe_guffaw_scroll == 2)
  488.         {
  489.           int x, y;
  490.           unsigned int w, h, d1, d2;
  491.           Window dummy;
  492.  
  493.           XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
  494.                &x, &y, &w, &h, &d1, &d2);
  495.           fe_SetFormsGravity(context, SouthGravity);
  496.           XMoveResizeWindow(XtDisplay(da), XtWindow(da),
  497.                 x, (y - shift), w, (h + shift));
  498.           fe_SetFormsGravity(context, NorthGravity);
  499.           XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
  500.           XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
  501.           fe_SetFormsGravity(context, NorthWestGravity);
  502.           fe_GravityCorrectForms (context, 0, shift);
  503.         }
  504.       else
  505.         {
  506.           XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
  507.              0, 0,
  508.              w, h - (old_y - new_y),
  509.              0, (old_y - new_y));
  510.           fe_ScrollForms (context, old_x - new_x, old_y - new_y);
  511.         }
  512.       if (shift > h)
  513.         {
  514.           shift = h;
  515.         }
  516.  
  517. #ifdef DONT_rhess
  518.       if (fe_globalData.fe_guffaw_scroll == 0)
  519. #endif
  520.         fe_RefreshArea (context, new_x, new_y, w, shift);
  521.     }
  522.     }
  523.  
  524. #ifdef PERFECT_SCROLL
  525.   /*
  526.    * In any X scrolling, there is the possibility of getting multiple
  527.    * scrolling events before any of the exposure events they
  528.    * generate appear.  The results in improperly placed
  529.    * exposures because the values fo document_x and document_y in the
  530.    * context are different at the time the exposure is processed than 
  531.    * they were at the time the exposure was created.
  532.    * The followind code elminates this.  It first flushes all exposures
  533.    * generated by this scroll event, and then removes all motion events
  534.    * That might potentially cause another scroll to get processed before
  535.    * these exposures.  Throwing out these extra motions in theory makes
  536.    * scrolling a little more jerky.  In practice I notice no difference.
  537.    */
  538.   XSync(XtDisplay(widget), FALSE);
  539.   if (cb->event)
  540.     {
  541.       XEvent new_event;
  542.       while (XCheckTypedWindowEvent(XtDisplay(widget), XtWindow(widget),
  543.                     MotionNotify, &new_event) == TRUE);
  544.     }
  545. #endif /* PERFECT_SCROLL */
  546. }
  547.  
  548. void
  549. fe_ScrollTo (MWContext *context, unsigned long x, unsigned long y)
  550. {
  551.   if (x != CONTEXT_DATA (context)->document_x)
  552.     {
  553.       XmScrollBarCallbackStruct cb;
  554.       {
  555.     int nx = x;
  556.     int max = 0;
  557.     int size = 0;
  558.     XtVaGetValues (CONTEXT_DATA (context)->hscroll,
  559.                XmNmaximum, &max, XmNsliderSize, &size, 0);
  560.     if (nx > max - size) nx = max - size;
  561.     if (nx < 0) nx = 0;
  562.     XtVaSetValues (CONTEXT_DATA (context)->hscroll, XmNvalue, nx, 0);
  563.     x = nx;
  564.       }
  565.       memset (&cb, 0, sizeof (cb));
  566.       cb.value = x;
  567.       fe_scroll_cb (CONTEXT_DATA (context)->hscroll, 
  568.                     (XtPointer)context, (XtPointer)&cb);
  569.     }
  570.   if (y != CONTEXT_DATA (context)->document_y)
  571.     {
  572.       XmScrollBarCallbackStruct cb;
  573.       {
  574.     int ny = y;
  575.     int max = 0;
  576.     int size = 0;
  577.     XtVaGetValues (CONTEXT_DATA (context)->vscroll,
  578.                XmNmaximum, &max, XmNsliderSize, &size, 0);
  579.     if (ny > max - size) ny = max - size;
  580.     if (ny < 0) ny = 0;
  581.     XtVaSetValues (CONTEXT_DATA (context)->vscroll, XmNvalue, ny, 0);
  582.     y = ny;
  583.       }
  584.       memset (&cb, 0, sizeof (cb));
  585.       cb.value = y;
  586.       fe_scroll_cb (CONTEXT_DATA (context)->vscroll,
  587.                     (XtPointer)context, (XtPointer)&cb);
  588.     }
  589. }
  590.  
  591.  
  592. /*
  593.  * When scrolling by moving the window, some expose events are generated
  594.  * when the window is NOT at 0,0 which need to be translated to 0,0
  595.  * when those exposes are processed.  We can locate these exposes because the
  596.  * will have the same serial number as the configure that created them.
  597.  * Thus we need to save that serial number and offset here.
  598.  */
  599. void
  600. fe_config_eh (Widget widget, XtPointer closure, XEvent *event)
  601. {
  602.   MWContext *context = (MWContext *) closure;
  603.   XConfigureEvent *ce = (XConfigureEvent *) event;
  604.  
  605.   if (ce->type != ConfigureNotify)
  606.   {
  607.     return;
  608.   }
  609.  
  610.   CONTEXT_DATA (context)->expose_x_offset = ce->x;
  611.   CONTEXT_DATA (context)->expose_y_offset = ce->y;
  612.   CONTEXT_DATA (context)->expose_serial = ce->serial;
  613. }
  614.  
  615.  
  616. static void
  617. fe_expose_eh (Widget widget, XtPointer closure, XEvent *event)
  618. {
  619.   MWContext *context = (MWContext *) closure;
  620.   XExposeEvent *ee = (XExposeEvent *) event;
  621.   int scroll_slop_hack =
  622.     ((Scroller) CONTEXT_DATA (context)->scrolled)->swindow.pad;
  623.  
  624.   if (fe_globalData.fe_guffaw_scroll)
  625.     {
  626.       int new_x, new_y;
  627.       unsigned int new_width, new_height;
  628.  
  629.       new_x = ee->x;
  630.       new_y = ee->y;
  631.       new_width = ee->width;
  632.       new_height = ee->height;
  633.  
  634.       /*
  635.        * If this expose event has the same serial number as a configure
  636.        * event that moved the window away from 0,0 we need to adjust the x,y of
  637.        * this expose event to be in the proper location with respect to
  638.        * its parent.
  639.        */
  640.       if ((CONTEXT_DATA (context)->expose_x_offset != 0)||
  641.       (CONTEXT_DATA (context)->expose_y_offset != 0))
  642.     {
  643.       if (ee->serial == CONTEXT_DATA (context)->expose_serial)
  644.         {
  645.           new_x += CONTEXT_DATA (context)->expose_x_offset;
  646.           new_y += CONTEXT_DATA (context)->expose_y_offset;
  647.  
  648.           /*
  649.            * Correct for the presence of a horizontal or
  650.            * vertical scrollbar.
  651.            */
  652.               if (CONTEXT_DATA (context)->expose_y_offset < 0)
  653.                 {
  654.                         new_y -= scroll_slop_hack;
  655.                         new_height += scroll_slop_hack;
  656.                 }
  657.               if (CONTEXT_DATA (context)->expose_x_offset < 0)
  658.                 {
  659.                         new_x -= scroll_slop_hack;
  660.                         new_width += scroll_slop_hack;
  661.                 }
  662.         }
  663.     }
  664.  
  665.       /*
  666.        * Because we are scrolling a window that may have many small child
  667.        * widgets, we want to compress the many small exposes that happen around
  668.        * those widgets.  We don't want to compress discontinuous regions
  669.        * that happened to be exposed at the same time.
  670.        * We want to compress:
  671.        *
  672.        *         -----                  ---------
  673.        *         |   |------    and     |       |
  674.        *         |   ||    |            ---------
  675.        *         -----|    |                ---------
  676.        *              ------                |       |
  677.        *                                    ---------
  678.        *
  679.        *                    NOT
  680.        *
  681.        *           -----
  682.        *           |   |
  683.        *           -----
  684.        *
  685.        *                   -----
  686.        *                   |   |
  687.        *                   -----
  688.        */
  689.  
  690.       /*
  691.        * Non-zero counts are parts of multi-expose blocks, and might be
  692.        * held for later compression.
  693.        */
  694.       if (ee->count != 0)
  695.     {
  696.       /*
  697.        * If nothng held so far, just hold this one.
  698.        */
  699.       if (CONTEXT_DATA (context)->held_expose == FALSE)
  700.         {
  701.           CONTEXT_DATA (context)->held_expose = TRUE;
  702.           CONTEXT_DATA (context)->expose_x1 = new_x;
  703.           CONTEXT_DATA (context)->expose_y1 = new_y;
  704.           CONTEXT_DATA (context)->expose_x2 = new_x + new_width;
  705.           CONTEXT_DATA (context)->expose_y2 = new_y + new_height;
  706.         }
  707.       else
  708.         {
  709.           /*
  710.            * If we are adjacent to the held block, compress them together
  711.            */
  712.           if ((((new_y - 1) >= CONTEXT_DATA (context)->expose_y1)&&
  713.            ((new_y - 1) <= CONTEXT_DATA (context)->expose_y2))||
  714.           (((new_y + new_height + 1) >= CONTEXT_DATA (context)->expose_y1)&&
  715.            ((new_y + new_height + 1) <= CONTEXT_DATA (context)->expose_y2))||
  716.           ((CONTEXT_DATA (context)->expose_y1 >= (new_y - 1))&&
  717.            (CONTEXT_DATA (context)->expose_y1 <= (new_y + new_height + 1))))
  718.         {
  719.           if (new_x < CONTEXT_DATA (context)->expose_x1)
  720.             CONTEXT_DATA (context)->expose_x1 = new_x;
  721.           if (new_y < CONTEXT_DATA (context)->expose_y1)
  722.             CONTEXT_DATA (context)->expose_y1 = new_y;
  723.           if ((new_x + (int)new_width) > CONTEXT_DATA (context)->expose_x2)
  724.             CONTEXT_DATA (context)->expose_x2 = new_x + (int)new_width;
  725.           if ((new_y + (int)new_height) > CONTEXT_DATA (context)->expose_y2)
  726.             CONTEXT_DATA (context)->expose_y2 = new_y + (int)new_height;
  727.         }
  728.           /*
  729.            * We weren't adjacent.  Display the held block, and hold
  730.            * the new one.
  731.            */
  732.           else
  733.         {
  734.           unsigned int hold_width, hold_height;
  735.  
  736.           if (CONTEXT_DATA (context)->expose_x2
  737.               > CONTEXT_DATA (context)->scrolled_width)
  738.             CONTEXT_DATA (context)->expose_x2
  739.               = CONTEXT_DATA (context)->scrolled_width;
  740.           if (CONTEXT_DATA (context)->expose_y2
  741.               > CONTEXT_DATA (context)->scrolled_height)
  742.             CONTEXT_DATA (context)->expose_y2
  743.               = CONTEXT_DATA (context)->scrolled_height;
  744.           hold_width = (CONTEXT_DATA (context)->expose_x2 -
  745.                 CONTEXT_DATA (context)->expose_x1);
  746.           hold_height = (CONTEXT_DATA (context)->expose_y2 -
  747.                  CONTEXT_DATA (context)->expose_y1);
  748.           if (hold_width < 1)
  749.             hold_width = 1;
  750.           if (hold_height < 1)
  751.             hold_height = 1;
  752.  
  753.  
  754.           fe_RefreshArea (context,
  755.                                   (CONTEXT_DATA (context)->expose_x1 +
  756.                                    CONTEXT_DATA (context)->document_x),
  757.                                   (CONTEXT_DATA (context)->expose_y1 +
  758.                                    CONTEXT_DATA (context)->document_y),
  759.                                   hold_width, hold_height);
  760.           CONTEXT_DATA (context)->expose_x1 = new_x;
  761.           CONTEXT_DATA (context)->expose_y1 = new_y;
  762.           CONTEXT_DATA (context)->expose_x2 = new_x + new_width;
  763.           CONTEXT_DATA (context)->expose_y2 = new_y + new_height;
  764.         }
  765.         }
  766.     }
  767.       /*
  768.        * count = 0 is either a standalone expose, or part of a multipart
  769.        * expose.
  770.        */
  771.       else
  772.     {
  773.       /*
  774.        * If nothing held this is just a standalone expose, display it.
  775.        */
  776.       if (CONTEXT_DATA (context)->held_expose == FALSE)
  777.         {
  778.           if ((new_x + new_width) > CONTEXT_DATA (context)->scrolled_width)
  779.         new_width = CONTEXT_DATA (context)->scrolled_width - new_x;
  780.           if ((new_y + new_height) > CONTEXT_DATA (context)->scrolled_height)
  781.         new_height = CONTEXT_DATA (context)->scrolled_height - new_y;
  782.           if (new_width < 1)
  783.         new_width = 1;
  784.           if (new_height < 1)
  785.         new_height = 1;
  786.  
  787.           fe_RefreshArea (context,
  788.                               new_x + CONTEXT_DATA (context)->document_x,
  789.                               new_y + CONTEXT_DATA (context)->document_y,
  790.                               new_width, new_height);
  791.         }
  792.       else
  793.         {
  794.           CONTEXT_DATA (context)->held_expose = FALSE;
  795.           /*
  796.            * If we are adjacent to the held block, compress them together
  797.            * and display the combined chunk.
  798.            */
  799.           if ((((new_y - 1) >= CONTEXT_DATA (context)->expose_y1)&&
  800.            ((new_y - 1) <= CONTEXT_DATA (context)->expose_y2))||
  801.           (((new_y + new_height + 1) >= CONTEXT_DATA (context)->expose_y1)&&
  802.            ((new_y + new_height + 1) <= CONTEXT_DATA (context)->expose_y2))||
  803.           ((CONTEXT_DATA (context)->expose_y1 >= (new_y - 1))&&
  804.            (CONTEXT_DATA (context)->expose_y1 <= (new_y + new_height + 1))))
  805.         {
  806.           if (new_x < CONTEXT_DATA (context)->expose_x1)
  807.             CONTEXT_DATA (context)->expose_x1 = new_x;
  808.           if (new_y < CONTEXT_DATA (context)->expose_y1)
  809.             CONTEXT_DATA (context)->expose_y1 = new_y;
  810.           if ((new_x + new_width) > CONTEXT_DATA (context)->expose_x2)
  811.             CONTEXT_DATA (context)->expose_x2 = new_x + new_width;
  812.           if ((new_y + new_height) > CONTEXT_DATA (context)->expose_y2)
  813.             CONTEXT_DATA (context)->expose_y2 = new_y + new_height;
  814.  
  815.           if (CONTEXT_DATA (context)->expose_x2
  816.               > CONTEXT_DATA (context)->scrolled_width)
  817.             CONTEXT_DATA (context)->expose_x2
  818.               = CONTEXT_DATA (context)->scrolled_width;
  819.           if (CONTEXT_DATA (context)->expose_y2
  820.               > CONTEXT_DATA (context)->scrolled_height)
  821.             CONTEXT_DATA (context)->expose_y2
  822.               = CONTEXT_DATA (context)->scrolled_height;
  823.           new_width = (CONTEXT_DATA (context)->expose_x2 -
  824.                    CONTEXT_DATA (context)->expose_x1);
  825.           new_height = (CONTEXT_DATA (context)->expose_y2 -
  826.                 CONTEXT_DATA (context)->expose_y1);
  827.           if (new_width < 1)
  828.             new_width = 1;
  829.           if (new_height < 1)
  830.             new_height = 1;
  831.  
  832.           fe_RefreshArea (context,
  833.                                   (CONTEXT_DATA (context)->expose_x1 +
  834.                                    CONTEXT_DATA (context)->document_x),
  835.                                   (CONTEXT_DATA (context)->expose_y1 +
  836.                                    CONTEXT_DATA (context)->document_y),
  837.                                   new_width, new_height);
  838.         }
  839.           /*
  840.            * Else display the held block and this expose separately.
  841.            */
  842.           else
  843.         {
  844.           unsigned int hold_width, hold_height;
  845.  
  846.           if (CONTEXT_DATA (context)->expose_x2
  847.               > CONTEXT_DATA (context)->scrolled_width)
  848.             CONTEXT_DATA (context)->expose_x2
  849.               = CONTEXT_DATA (context)->scrolled_width;
  850.           if (CONTEXT_DATA (context)->expose_y2
  851.               > CONTEXT_DATA (context)->scrolled_height)
  852.             CONTEXT_DATA (context)->expose_y2
  853.               = CONTEXT_DATA (context)->scrolled_height;
  854.           hold_width = (CONTEXT_DATA (context)->expose_x2 -
  855.                 CONTEXT_DATA (context)->expose_x1);
  856.           hold_height = (CONTEXT_DATA (context)->expose_y2 -
  857.                  CONTEXT_DATA (context)->expose_y1);
  858.           if (hold_width < 1)
  859.             hold_width = 1;
  860.           if (hold_height < 1)
  861.             hold_height = 1;
  862.  
  863.           fe_RefreshArea (context,
  864.                                   (CONTEXT_DATA (context)->expose_x1 +
  865.                                    CONTEXT_DATA (context)->document_x),
  866.                                   (CONTEXT_DATA (context)->expose_y1 +
  867.                                    CONTEXT_DATA (context)->document_y),
  868.                                   hold_width, hold_height);
  869.  
  870.           if ((new_x + new_width) > CONTEXT_DATA (context)->scrolled_width)
  871.             new_width = CONTEXT_DATA (context)->scrolled_width - new_x;
  872.           if ((new_y + new_height) > CONTEXT_DATA (context)->scrolled_height)
  873.             new_height = CONTEXT_DATA (context)->scrolled_height - new_y;
  874.           if (new_width < 1)
  875.             new_width = 1;
  876.           if (new_height < 1)
  877.             new_height = 1;
  878.  
  879.           fe_RefreshArea (context,
  880.                                   new_x + CONTEXT_DATA (context)->document_x,
  881.                                   new_y + CONTEXT_DATA (context)->document_y,
  882.                                   new_width, new_height);
  883.         }
  884.         }
  885.     }
  886.     }
  887.   else
  888.     {
  889.       fe_RefreshArea (context,
  890.                       ee->x + CONTEXT_DATA (context)->document_x,
  891.                       ee->y + CONTEXT_DATA (context)->document_y,
  892.                       ee->width, ee->height);
  893.     }
  894. }
  895.  
  896. void
  897. fe_SyncExposures(MWContext* context)
  898. {
  899.     XEvent   event;
  900.     Widget   drawing_area = CONTEXT_DATA(context)->drawing_area;
  901.     Display* display = XtDisplay(drawing_area);
  902.     Window   window = XtWindow(drawing_area);
  903.     
  904.     XSync(display, FALSE);
  905.     
  906.     while (XCheckTypedWindowEvent(display, window, Expose, &event) == TRUE) {
  907.         fe_expose_eh(drawing_area, (XtPointer)context, &event);
  908.     }
  909.  
  910.     /*
  911.      *     Force compositor to sync.
  912.      */
  913.     if (context->compositor)
  914.     CL_CompositeNow(context->compositor);
  915. }
  916.  
  917. static void
  918. fe_hack_scrollbar (Widget sb, int max, int inc, int page_inc,
  919.            int slider_size, int value)
  920. {
  921.   if (value + slider_size > max)
  922.     value = max - slider_size;
  923.   if (value < 0)
  924.     value = 0;
  925.   if (inc < 1)
  926.     inc = 1;
  927.   if (page_inc < inc)
  928.     page_inc = inc;
  929.   XtVaSetValues (sb,
  930.          XmNmaximum, max,
  931.          XmNincrement, inc,
  932.          XmNpageIncrement, page_inc,
  933.          XmNsliderSize, slider_size,
  934.          XmNvalue, value,
  935.          0);
  936. }
  937.  
  938.  
  939. void
  940. fe_SetDocPosition (MWContext *context, unsigned long x, unsigned long y)
  941. {
  942.   unsigned long w = CONTEXT_DATA (context)->document_width;
  943.   unsigned long h = CONTEXT_DATA (context)->document_height;
  944.   unsigned long lh = CONTEXT_DATA (context)->line_height;
  945.   Dimension ww = 0, wh = 0;
  946.   XP_Bool are_scrollbars_active;
  947.   XP_Bool frame_scrolling_yes = False;
  948.  
  949.  
  950.   if (x >= w + 100) x = 0;
  951.   if (y >= h + lh)  y = ((h > lh) ? h - lh : 0);
  952.  
  953.   if (context->is_grid_cell &&
  954.       CONTEXT_DATA (context)->grid_scrolling == LO_SCROLL_NO) {
  955.     /* We're done */
  956.     CONTEXT_DATA (context)->document_x = x;
  957.     CONTEXT_DATA (context)->document_y = y;
  958.  
  959.     return;
  960.   }
  961.  
  962.   XP_ASSERT (CONTEXT_DATA (context)->drawing_area);
  963.   if (!CONTEXT_DATA (context)->drawing_area) return;
  964.  
  965.   XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
  966.          XmNwidth, &ww, XmNheight, &wh, 0);
  967.  
  968.   /*
  969.    * Fix for 4.0 bug 55350 (reported by ebina)
  970.    *
  971.    * <frame scrolling=yes> doesn't always have scrollbars.
  972.    *
  973.    * If grid_scrolling == LO_SCROLL_YES, then we force 
  974.    * both scrollbars to be on regardless of whether they
  975.    * are needed or not.
  976.    *
  977.    * -ramiro
  978.    */
  979.   if (context->is_grid_cell &&
  980.       CONTEXT_DATA (context)->grid_scrolling == LO_SCROLL_YES)
  981.   {
  982.       frame_scrolling_yes = True;
  983.   }
  984.  
  985.   are_scrollbars_active = CONTEXT_DATA(context)->are_scrollbars_active;
  986.  
  987.   if ( (h <= wh) || (are_scrollbars_active == FALSE) )
  988.     {
  989.       if (!frame_scrolling_yes)
  990.       {
  991.     y = 0;
  992.     XtUnmanageChild (CONTEXT_DATA (context)->vscroll);
  993.     fe_hack_scrollbar (CONTEXT_DATA (context)->vscroll,
  994.                1, 1, 1, 1, 0);
  995.       }
  996.     }
  997.   else
  998.     {
  999.       fe_hack_scrollbar (CONTEXT_DATA (context)->vscroll,
  1000.              h,        /* max */
  1001.              lh,        /* inc */
  1002.              wh - lh,    /* page_inc */
  1003.              wh,        /* slider_size */
  1004.              y        /* value */
  1005.              );
  1006.       XtManageChild (CONTEXT_DATA (context)->vscroll);
  1007.     }
  1008.  
  1009.   if ( (w <= ww) || (are_scrollbars_active == FALSE) )
  1010.     {
  1011.       if (!frame_scrolling_yes)
  1012.       {
  1013.     x = 0;
  1014.     XtUnmanageChild (CONTEXT_DATA (context)->hscroll);
  1015.     fe_hack_scrollbar (CONTEXT_DATA (context)->hscroll,
  1016.                1, 1, 1, 1, 0);
  1017.       }
  1018.     }
  1019.   else
  1020.     {
  1021.       fe_hack_scrollbar (CONTEXT_DATA (context)->hscroll,
  1022.              w,        /* max */
  1023.              lh,        /* inc */
  1024.              ww - lh,    /* page_inc */
  1025.              ww,        /* slider_size */
  1026.              x        /* value */
  1027.              );
  1028.       XtManageChild (CONTEXT_DATA (context)->hscroll);
  1029.     }
  1030.  
  1031.   if (frame_scrolling_yes)
  1032.   {
  1033.       XtManageChild (CONTEXT_DATA (context)->vscroll);
  1034.       XtManageChild (CONTEXT_DATA (context)->hscroll);
  1035.   }
  1036.  
  1037.   fe_find_scrollbar_sizes(context);
  1038.  
  1039.     CONTEXT_DATA (context)->document_x = x;
  1040.     CONTEXT_DATA (context)->document_y = y;
  1041.  
  1042.     if (context->compositor)
  1043.         CL_ScrollCompositorWindow(context->compositor, x, y);
  1044. }
  1045.  
  1046. void
  1047. FE_ScrollDocBy (MWContext *context, int iLocation, int32 deltax, int32 deltay)
  1048. {
  1049.   int32 x;
  1050.   int32 y;
  1051.   XFE_GetDocPosition (context, iLocation, &x, &y);
  1052.   x += deltax;
  1053.   y += deltay;
  1054.   fe_ScrollTo (context, x, y);
  1055. }
  1056.  
  1057. void
  1058. FE_ScrollDocTo (MWContext *context, int iLocation, int32 x, int32 y)
  1059. {
  1060.     fe_ScrollTo (context, x, y);
  1061. }
  1062.  
  1063. void
  1064. XFE_GetDocPosition (MWContext *context, int iLocation,
  1065.            int32 *iX, int32 *iY)
  1066. {
  1067.   *iX = (int32)CONTEXT_DATA (context)->document_x;
  1068.   *iY = (int32)CONTEXT_DATA (context)->document_y;
  1069. }
  1070.  
  1071. void
  1072. XFE_SetDocPosition (MWContext *context, int iLocation, int32 x, int32 y)
  1073. {
  1074. #if 0
  1075. #ifdef EDITOR
  1076.     if (EDT_IS_EDITOR(context)) {
  1077.         fe_ScrollTo (context, x, y);
  1078.     }
  1079.     else
  1080. #endif
  1081.     {
  1082.         fe_SetDocPosition (context, x, y);
  1083.     }
  1084. #else
  1085.     /*
  1086.      *    In WinFE (the standard), XFE_SetDocPosition() and FE_ScrollDocTo()
  1087.      *    do the same thing (one calls the other). We seem to have a number
  1088.      *    of bugs that are fixed by emulating WinFE's semantics, so our
  1089.      *    feeling is that the back-end is now weighted in that way.
  1090.      *    SO, rather than fight a losing battle, we think we'll just make
  1091.      *    this change and hope that nothing new breaks. For Bug #77767.
  1092.      *    - djw, vidur, mcafee, brendan (shared blame) July/20/1997.
  1093.      */
  1094.     fe_ScrollTo (context, x, y);
  1095. #endif
  1096. }
  1097.  
  1098. void
  1099. XFE_SetDocDimension (MWContext *context,
  1100.             int iLocation, int32 iWidth, int32 iLength)
  1101. {
  1102.   Widget widget = CONTEXT_DATA (context)->drawing_area;
  1103. #ifdef EDITOR
  1104.   unsigned long win_h;
  1105.   unsigned long old_h;
  1106. #endif
  1107.   unsigned long w, h;
  1108.   time_t now = time ((time_t) 0);
  1109.  
  1110.   if (! widget) abort ();
  1111.   w = iWidth;
  1112.   h = iLength;
  1113.   if (w < 1) w = 1;
  1114.   if (h < 1) h = 1;
  1115.  
  1116. #ifdef EDITOR
  1117.   win_h = CONTEXT_DATA (context)->scrolled_height;
  1118.   old_h = CONTEXT_DATA (context)->document_height;
  1119. #endif
  1120.  
  1121.   CONTEXT_DATA (context)->document_width = w;
  1122.   CONTEXT_DATA (context)->document_height = h;
  1123.  
  1124.   /* Only actually resize the window once a second, to avoid thrashing. */
  1125.   if (now <= CONTEXT_DATA (context)->doc_size_last_update_time)
  1126.     return;
  1127.  
  1128.   /* We just need to update the scrollbars; nothing visible has changed. */
  1129.   fe_SetDocPosition (context,
  1130.              CONTEXT_DATA (context)->document_x,
  1131.              CONTEXT_DATA (context)->document_y);
  1132.  
  1133.   CONTEXT_DATA (context)->doc_size_last_update_time = now;
  1134.  
  1135. #ifdef EDITOR
  1136.   /*
  1137.    * NOTE:  fix for redisplay bugs... [ 73704, 73705, 73688 ]
  1138.    *
  1139.    */
  1140.   if (EDT_IS_EDITOR(context)) {
  1141.       if (h < old_h) {
  1142.           /*
  1143.            * NOTE:  need to force a refresh if the we lost the scrollbars
  1144.            *        in the process of shrinking the document size...
  1145.            *
  1146.            */
  1147.           if (h < win_h && old_h > win_h) {
  1148. #ifdef DEBUG_rhess
  1149.               fprintf(stderr, "ForceRefresh::[ %d, %d ][ %d ][ %d ]\n",
  1150.                       w, h, old_h, win_h);
  1151. #endif
  1152.               fe_RefreshArea(context, 0, 0, w, h);
  1153.           }
  1154.       }
  1155.   }
  1156. #endif
  1157. }
  1158.  
  1159.  
  1160. #ifdef RESIZE_CALLBACK_WORKS
  1161.  
  1162. static void
  1163. fe_resize_cb (Widget widget, XtPointer closure, XtPointer call_data)
  1164. {
  1165.   XmDrawingAreaCallbackStruct *cb = (XmDrawingAreaCallbackStruct *) call_data;
  1166.  
  1167. #else
  1168.  
  1169. static void
  1170. fe_scroller_resize (Widget widget, XtPointer closure)
  1171. {
  1172. #endif
  1173.  
  1174.   MWContext *context = (MWContext *) closure;
  1175.   fe_ContextData *fep = CONTEXT_DATA(context);
  1176.   MWContextType type = context->type;
  1177.  
  1178.   /* I question the wisdom of having to do a reload every time the window
  1179.      size changes... */
  1180.   Dimension w = 0, h = 0;
  1181.   Boolean relayout_p = False;
  1182.  
  1183.   XtVaGetValues (widget, XmNwidth, &w, XmNheight, &h, 0);
  1184.  
  1185.   relayout_p = ((Dimension) fep->scrolled_width) != w;
  1186.  
  1187. /*
  1188.  * Inside FRAMES (and eventually elsewhere?) we DO want to reload, even if
  1189.  * just the height has changed.
  1190.  */
  1191.   if ((!relayout_p)&&(context->is_grid_cell ||
  1192.             (context->grid_children &&
  1193.             XP_ListTopObject (context->grid_children))))
  1194.     {
  1195.       relayout_p = ((Dimension) fep->scrolled_height) != h;
  1196.     }
  1197.  
  1198.   /* Well this is kinda bogus; don't do a relayout if we're displaying one
  1199.      of the magic internal-external images, since we know no wrapping can
  1200.      occur. */
  1201.   if (relayout_p)
  1202.     {
  1203.       History_entry *h = SHIST_GetCurrent (&context->hist);
  1204.       if (h && h->is_binary)
  1205.     relayout_p = False;
  1206.     }
  1207.  
  1208.   /* If we have just an image and we resize such that either the width
  1209.    * or the height of the window is bigger than the image, and we had
  1210.    * scrolled off from the left,top edge, then we will need to refresh
  1211.    * the entire image. If this doesn't happen, then in the exposed parts
  1212.    * the image that is repainted is off the document_x, document_y.
  1213.    */
  1214.   if (
  1215.       /* If there is a real resize going on */
  1216.       (fep->scrolled_height != h || fep->scrolled_width != w) &&
  1217.       /* and if either of width or height spans the full document */
  1218.       (h >= fep->document_height || w >= fep->document_width) &&
  1219.       /* and if the document is not at its (0,0) origin */
  1220.       (fep->document_x != 0 || fep->document_y != 0)) {
  1221.     relayout_p = True;
  1222.   }
  1223.  
  1224.   /* Fullpage plugins need be told about size changes. */
  1225.   if (CONTEXT_DATA(context)->is_fullpage_plugin)
  1226.     {
  1227.         fe_RefreshArea (context,
  1228.                         CONTEXT_DATA (context)->document_x,
  1229.                         CONTEXT_DATA (context)->document_y,
  1230.                         1, 1);
  1231.     relayout_p = False;
  1232.     }
  1233.  
  1234.   if (! XtIsRealized (widget))
  1235.     /* I'm not sure this is right, but otherwise layout happens while a
  1236.        new window is still getting created... */
  1237.     relayout_p = False;
  1238.  
  1239.   if (relayout_p)
  1240.     {
  1241.       /* If a document is currently being laid out, just update the
  1242.      scrollbars and flag it as needing to be re-figured at the end.
  1243.      Otherwise, re-lay out the document with the new width.
  1244.      Note: don't use CONTEXT_DATA (context)->active_url_count
  1245.      here, that only counts foreground transfers, not images.
  1246.        */
  1247.       if (XP_IsContextBusy (context)) {
  1248.     CONTEXT_DATA (context)->relayout_required = True;
  1249.       } else {
  1250.  
  1251.       /* This is unset in XFE_LayoutNewDocument. */
  1252.       CONTEXT_DATA (context)->is_resizing = TRUE;
  1253.  
  1254.           /*
  1255.        *    Need to update these before calling relayout, because the BE
  1256.        *    is going to ask us this stuff in FE_GetDocAndWindowPosition().
  1257.        *    Seems obvious I guess. Bug #27455.
  1258.        *
  1259.        *    I moved this out of the next EDT_IS_EDITOR if, since
  1260.        *    for the new relayout stuff, grid edges don't get moved
  1261.        *    if their x or y is greater than the window width and
  1262.        *    height.  I honestly can't imagine why you wouldn't
  1263.        *    want the size change reflected as early as possible
  1264.        *    anyway -- toshok
  1265.        */
  1266.       CONTEXT_DATA(context)->scrolled_width  = (unsigned long)w;
  1267.       CONTEXT_DATA(context)->scrolled_height = (unsigned long)h;
  1268.  
  1269. #ifdef EDITOR
  1270.     /*
  1271.      *    This edit_view_source_hack is so completely bogus,
  1272.      *    but it seems to only be edit for the editor view
  1273.      *    source window. Do this for bug #23375. djw 96/06/15.
  1274.      */
  1275.     if (EDT_IS_EDITOR(context) || context->edit_view_source_hack) {
  1276.  
  1277.       fe_EditorRefresh(context);
  1278.     }
  1279.     else
  1280. #endif /*EDITOR*/
  1281.  
  1282. #ifdef ENABLE_MARINER
  1283.       {
  1284.         int32 margin_w, margin_h;
  1285.         
  1286.         fe_GetMargin(context, &margin_w, &margin_h);
  1287.         
  1288.         LO_RelayoutOnResize(context, w, h, margin_w, margin_h);
  1289.       }
  1290. #else
  1291.     /*  As vidur suggested in Bug 59214: because JS generated content
  1292.     was not put into wysiwyg, hence this source was not be shown on a resize.
  1293.       The fix was to make the reload policy for Mail/News contexts NET_NORMAL_RELOAD */
  1294.         if ( (type == MWContextNews) || (type == MWContextMail) 
  1295.          || (type == MWContextNewsMsg) || (type == MWContextMailMsg) )
  1296.       fe_ReLayout (context, NET_NORMAL_RELOAD);
  1297.     else
  1298.       fe_ReLayout (context, NET_RESIZE_RELOAD);
  1299. #endif
  1300.       }
  1301.     }
  1302.   /* We just need to update the scrollbars; the other expose events
  1303.      which are coming will take care of repainting the text. */
  1304.   fe_SetDocPosition (context,
  1305.              CONTEXT_DATA (context)->document_x,
  1306.              CONTEXT_DATA (context)->document_y);
  1307.  
  1308.   /* 
  1309.   ** this is wretched and gross.  the assignments below are exactly the same as the ones
  1310.   ** about 20 lines above.  Why do I duplicate them here, you may ask.  Well, for some
  1311.   ** reason someplace in between the assignments above and the ones here (probably in
  1312.   ** fe_SetDocPosition), something happens to set the scrolled_width and scrolled_height
  1313.   ** to smaller values.
  1314.   ** this results in a band along the bottom and right hand sides of the document, where the
  1315.   ** scrollbars would normally be.
  1316.   **
  1317.   ** I am thoroughly disgusted.
  1318.   **
  1319.   ** - toshok
  1320.   */
  1321.   CONTEXT_DATA(context)->scrolled_width  = (unsigned long)w;
  1322.   CONTEXT_DATA(context)->scrolled_height = (unsigned long)h;
  1323.  
  1324.   /* We only need the composited area without the scrollbars.  However,
  1325.      since the scrollbars can become managed and then unmanaged during
  1326.      layout, it is not worth the effort of keeping track of when they
  1327.      are visible.  Instead we make the compositor the size of the drawing
  1328.      area and just let the scrollbars clip the background layer. */
  1329.   if (context->compositor)
  1330.       CL_ResizeCompositorWindow(context->compositor, w, h);
  1331. }
  1332.  
  1333.  
  1334. Boolean
  1335. fe_TestGravity (Widget widget)
  1336. {
  1337.   Widget area, element;
  1338.   Arg arg[10];
  1339.   Cardinal argcnt;
  1340.   int shift;
  1341.   int orig_x, orig_y;
  1342.   int x, y;
  1343.   unsigned int w, h, d1, d2;
  1344.   Window dummy;
  1345.   XSetWindowAttributes set_attr;
  1346.   unsigned long valuemask;
  1347.   Boolean works;
  1348.   Visual *v = 0;
  1349.   Colormap cmap = 0;
  1350.   Cardinal depth = 0;
  1351.  
  1352.   /*
  1353.    * OW 3.4 has some horrid bug so that it tests OK for
  1354.    * guffaws scrolling, but then when the user resizes the
  1355.    * window, it crashes the X server.  Sigh.
  1356.    */
  1357.   if ((!strcmp(XServerVendor(XtDisplay(widget)), "Sun Microsystems, Inc."))&&
  1358.       (VendorRelease(XtDisplay(widget)) == 3400))
  1359.   {
  1360.     return(False);
  1361.   }
  1362.  
  1363.   XtVaGetValues (widget, XtNvisual, &v, XtNcolormap, &cmap,
  1364.     XtNdepth, &depth, 0);
  1365.  
  1366.   shift = 10;
  1367.  
  1368.   argcnt = 0;
  1369.   XtSetArg(arg[argcnt], XmNvisual, v); argcnt++;
  1370.   XtSetArg(arg[argcnt], XmNcolormap, cmap); argcnt++;
  1371.   XtSetArg(arg[argcnt], XmNdepth, depth); argcnt++;
  1372.   XtSetArg(arg[argcnt], XtNwidth, 200); argcnt++;
  1373.   XtSetArg(arg[argcnt], XtNheight, 200); argcnt++;
  1374.   XtSetArg(arg[argcnt], XmNmappedWhenManaged, False); argcnt++;
  1375.   area = XmCreateDrawingArea(widget, "Area", arg, argcnt);
  1376.  
  1377.   argcnt = 0;
  1378.   XtSetArg(arg[argcnt], XmNvisual, v); argcnt++;
  1379.   XtSetArg(arg[argcnt], XmNcolormap, cmap); argcnt++;
  1380.   XtSetArg(arg[argcnt], XmNdepth, depth); argcnt++;
  1381.   XtSetArg(arg[argcnt], XtNx, 50); argcnt++;
  1382.   XtSetArg(arg[argcnt], XtNy, 80); argcnt++;
  1383.   XtSetArg(arg[argcnt], XmNmappedWhenManaged, False); argcnt++;
  1384.   element = fe_CreateTextField(area, "Element", arg, argcnt);
  1385.  
  1386.   XtManageChild(area);
  1387.   XtManageChild(element);
  1388.  
  1389.   valuemask = CWBitGravity | CWWinGravity;
  1390.   set_attr.win_gravity = StaticGravity;
  1391.   set_attr.bit_gravity = StaticGravity;
  1392.   XChangeWindowAttributes (XtDisplay(area), XtWindow(area),
  1393.     valuemask, &set_attr);
  1394.   XChangeWindowAttributes (XtDisplay(element), XtWindow(element),
  1395.     valuemask, &set_attr);
  1396.  
  1397.   XGetGeometry(XtDisplay(element), XtWindow(element), &dummy,
  1398.     &x, &y, &w, &h, &d1, &d2);
  1399.   orig_x = x;
  1400.   orig_y = y;
  1401.  
  1402.   XGetGeometry(XtDisplay(area), XtWindow(area), &dummy,
  1403.     &x, &y, &w, &h, &d1, &d2);
  1404.   XResizeWindow(XtDisplay(area), XtWindow(area), w, (h + shift));
  1405.   XMoveWindow(XtDisplay(area), XtWindow(area), x, (y - shift));
  1406.   XMoveResizeWindow(XtDisplay(area), XtWindow(area), x, y, w, h);
  1407.  
  1408.   XGetGeometry(XtDisplay(area), XtWindow(area), &dummy,
  1409.     &x, &y, &w, &h, &d1, &d2);
  1410.   XResizeWindow(XtDisplay(area), XtWindow(area), w, (h + shift));
  1411.   XMoveWindow(XtDisplay(area), XtWindow(area), x, (y - shift));
  1412.   XMoveResizeWindow(XtDisplay(area), XtWindow(area), x, y, w, h);
  1413.  
  1414.   XGetGeometry(XtDisplay(element), XtWindow(element), &dummy,
  1415.     &x, &y, &w, &h, &d1, &d2);
  1416.   if (y != (orig_y - (2 * shift)))
  1417.   {
  1418.     works = False;
  1419.   }
  1420.   else
  1421.   {
  1422.     works = True;
  1423.   }
  1424.  
  1425.   XtDestroyWidget(area);
  1426.   return(works);
  1427. }
  1428.  
  1429.  
  1430. int
  1431. fe_WindowGravityWorks (Widget toplevel, Widget widget)
  1432. {
  1433.   String str = 0;
  1434.   static XtResource res = { "windowGravityWorks", XtCString, XtRString,
  1435.                 sizeof (String), 0, XtRImmediate, "guess" };
  1436.   XtGetApplicationResources (toplevel, &str, &res, 1, 0, 0);
  1437.  
  1438.   if (str && (!XP_STRCASECMP(str, "yes") || !XP_STRCASECMP(str, "true")))
  1439.     {
  1440.       return 1;
  1441.     }
  1442.   else if (str && (!XP_STRCASECMP(str, "partial") || !XP_STRCASECMP(str, "kindof")))
  1443.     {
  1444.       return 2;
  1445.     }
  1446.   else if (str && (!XP_STRCASECMP(str, "no") || !XP_STRCASECMP(str, "false")))
  1447.     {
  1448.       return 0;
  1449.     }
  1450.   else
  1451.     {
  1452.       char *vendor = XServerVendor (XtDisplay (toplevel));
  1453.  
  1454.       if (str && XP_STRCASECMP(str, "guess"))
  1455.     {
  1456.       fprintf (stderr,
  1457.            XP_GetString(XFE_SCROLL_WINDOW_GRAVITY_WARNING),
  1458.            fe_progname, str);
  1459.     }
  1460.  
  1461.       /*
  1462.        * Short circuit all this other crap, and do the right thing.
  1463.        */
  1464.       if (fe_TestGravity(widget))
  1465.       {
  1466.     return 1;
  1467.       }
  1468.       else
  1469.       {
  1470.     return 2;
  1471.       }
  1472.  
  1473.       /* WindowGravity is known to be broken in the OpenWound 3.0 server
  1474.      and is known to work in the OpenWound 3.3 server.
  1475.        */
  1476.       if (!strcmp (vendor, "X11/NeWS - Sun Microsystems Inc."))
  1477. #if 0
  1478.     return (VendorRelease (XtDisplay (toplevel)) >= 3300);
  1479. #else
  1480.       /* Ok, all of Sun's code is just buggy as hell.  There are lurking X
  1481.      server crashes that happen when we mess with window gravity on OW 2.4,
  1482.      so forget it. */
  1483.       return 0;
  1484. #endif
  1485.       else if (!strncmp (vendor, "MacX", 4) || !strncmp (vendor, "eXodus", 6))
  1486.     /* The Mac X servers get this wrong (actually I'm not sure that both
  1487.        do, but at least one of them does.) */
  1488.     return 0;
  1489.  
  1490.       else if (!strcmp (vendor, "Sony Corporation"))
  1491.     /* Sony NEWS R4 is busted; later versions not *known* to work. */
  1492.     return (VendorRelease (XtDisplay (toplevel)) > 4);
  1493.  
  1494.       else if (!strcmp (vendor,
  1495.        "DECWINDOWS (Compatibility String) Network Computing Devices Inc."))
  1496.     /* NCD 2004 is busted; later versions not *known* to work. */
  1497.     return (VendorRelease (XtDisplay (toplevel)) > 2004);
  1498.  
  1499.       /* #### It has been suggested that all R4-based servers lose? */
  1500.  
  1501.       else
  1502.     return 1;
  1503.     }
  1504. }
  1505.  
  1506. void
  1507. FE_ShowScrollBars(MWContext *context, XP_Bool show)
  1508. {
  1509.     /* XXX implement me */
  1510. }
  1511.  
  1512.