mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
1512 lines
46 KiB
C
1512 lines
46 KiB
C
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
/*
|
||
scroll.c --- managing the scrolled area
|
||
Created: Jamie Zawinski <jwz@netscape.com>, 23-Jul-94.
|
||
*/
|
||
|
||
|
||
#include "mozilla.h"
|
||
#include "xfe.h"
|
||
#include "scroller.h"
|
||
#include "scrollerP.h"
|
||
#include "new_manage.h"
|
||
#include "new_manageP.h"
|
||
|
||
/* for XP_GetString() */
|
||
#include <xpgetstr.h>
|
||
|
||
extern int XFE_SCROLL_WINDOW_GRAVITY_WARNING;
|
||
|
||
/* C entry point to XFE_HTMLDrag class in xfe/src/HTMLDrag.cpp */
|
||
extern void XFE_HTMLDragCreate(Widget,MWContext*);
|
||
|
||
#ifdef EDITOR
|
||
#include "xeditor.h"
|
||
extern void fe_EditorReload(MWContext* context, Boolean super_reload);
|
||
#endif /*EDITOR*/
|
||
|
||
/* Layering support - LO_RefreshArea is called through compositor */
|
||
#include "layers.h"
|
||
|
||
void fe_find_scrollbar_sizes(MWContext *context); /* in xfe.h */
|
||
|
||
static void fe_expose_eh (Widget, XtPointer, XEvent *);
|
||
/* static void fe_expose_cb (Widget, XtPointer, XtPointer); */
|
||
static void fe_scroll_cb (Widget, XtPointer, XtPointer);
|
||
|
||
#ifdef RESIZE_CALLBACK_WORKS
|
||
static void fe_resize_cb (Widget, XtPointer, XtPointer);
|
||
#else
|
||
static void fe_scroller_resize (Widget, XtPointer);
|
||
#endif
|
||
|
||
static void guffaw (MWContext *context);
|
||
static void unguffaw (MWContext *context);
|
||
|
||
void
|
||
fe_InitScrolling (MWContext *context)
|
||
{
|
||
if (CONTEXT_DATA (context)->drawing_area == NULL) return;
|
||
/*
|
||
* Guffaws has 3 states now. If 0 it is just off. If 1 it uses
|
||
* static gravity, if 2 it uses a combination of N, S, E, W gravities.
|
||
* Any method that uses gravity needs the configure handler. Only
|
||
* static uses the guffaw function.
|
||
*/
|
||
if (fe_globalData.fe_guffaw_scroll > 0)
|
||
{
|
||
XtAddEventHandler (CONTEXT_DATA (context)->drawing_area,
|
||
StructureNotifyMask, FALSE,
|
||
(XtEventHandler)fe_config_eh, context);
|
||
}
|
||
if (fe_globalData.fe_guffaw_scroll == 1)
|
||
{
|
||
guffaw (context);
|
||
}
|
||
fe_NukeBackingStore (CONTEXT_DATA (context)->drawing_area);
|
||
}
|
||
|
||
|
||
/*
|
||
* Reverse the actions of fe_InitScrolling(). For when a normal
|
||
* document context is turned into a FRAME parent context.
|
||
*/
|
||
void
|
||
fe_DisableScrolling (MWContext *context)
|
||
{
|
||
if (CONTEXT_DATA (context)->drawing_area == NULL) return;
|
||
/*
|
||
* Turn off guffaws for a context's drawing area.
|
||
*/
|
||
if (fe_globalData.fe_guffaw_scroll > 0)
|
||
{
|
||
XtRemoveEventHandler (CONTEXT_DATA (context)->drawing_area,
|
||
StructureNotifyMask, FALSE,
|
||
(XtEventHandler)fe_config_eh, context);
|
||
}
|
||
if (fe_globalData.fe_guffaw_scroll == 1)
|
||
{
|
||
unguffaw (context);
|
||
}
|
||
}
|
||
|
||
|
||
Widget
|
||
fe_MakeScrolledWindow (MWContext *context, Widget parent, const char *name)
|
||
{
|
||
Widget scroller, drawing_area, hscroll, vscroll;
|
||
Arg av [20];
|
||
int ac = 0;
|
||
|
||
ac = 0;
|
||
XtSetArg (av[ac], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ac++;
|
||
/* The background of this widget is the color that shows up in the square
|
||
at the bottom right where the horizontal and vertical scrollbars come
|
||
together, and of the "pad" border between the scrollbars and the document
|
||
area (which we'd like to be of size 0, see below.) This should be in the
|
||
background color of the widgets, not the background color of the document.
|
||
*/
|
||
XtSetArg (av[ac], XmNbackground, parent->core.background_pixel); ac++;
|
||
/* scroller = XmCreateScrolledWindow (parent, name, av, ac);*/
|
||
scroller = XtCreateWidget((char *) name, scrollerClass, parent, av, ac);
|
||
#ifndef RESIZE_CALLBACK_WORKS
|
||
((Scroller) scroller)->scroller.resize_arg = (void *) context;
|
||
((Scroller) scroller)->scroller.resize_hook = fe_scroller_resize;
|
||
#endif
|
||
|
||
/* This is a kludge - there ought to be a resource to control this, but
|
||
I can't find it. This controls the extra space between the scrollbars
|
||
and the area being scrolled. If this isn't 0, then there's a 4-pixel
|
||
border between the document background and the scrollbar, which ends
|
||
up in the user's background instead, which looks stupid.
|
||
*/
|
||
((Scroller) scroller)->swindow.pad = 0;
|
||
|
||
ac = 0;
|
||
XtSetArg (av[ac], XmNminimum, 0); ac++;
|
||
XtSetArg (av[ac], XmNmaximum, 1); ac++;
|
||
XtSetArg (av[ac], XmNorientation, XmHORIZONTAL); ac++;
|
||
hscroll = XmCreateScrollBar (scroller, "hscroll", av, ac);
|
||
ac = 0;
|
||
XtSetArg (av[ac], XmNminimum, 0); ac++;
|
||
XtSetArg (av[ac], XmNmaximum, 1); ac++;
|
||
XtSetArg (av[ac], XmNorientation, XmVERTICAL); ac++;
|
||
vscroll = XmCreateScrollBar (scroller, "vscroll", av, ac);
|
||
ac = 0;
|
||
|
||
/* The drawing area we're about to create is the actual document window,
|
||
so its background should be the document background pixel. */
|
||
XtSetArg (av[ac], XmNbackground,
|
||
CONTEXT_DATA (context)->default_bg_pixel); ac++;
|
||
/*
|
||
XtSetArg (av[ac], XmNautoUnmanage, FALSE); ac++;
|
||
XtSetArg (av[ac], XmNdefaultPosition, FALSE); ac++;
|
||
XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_WORK_AREA); ac++;
|
||
XtSetArg (av[ac], XmNmarginHeight, 0); ac++;
|
||
XtSetArg (av[ac], XmNmarginWidth, 0); ac++;
|
||
*/
|
||
#ifdef EDITOR
|
||
if (EDT_IS_EDITOR(context)) {
|
||
/* Let's try using the managed widget */
|
||
drawing_area = XtCreateWidget("editorDrawingArea", newManageClass,
|
||
scroller, av, ac);
|
||
}
|
||
else
|
||
#endif /* EDITOR */
|
||
drawing_area = XtCreateWidget("drawingArea", newManageClass, scroller, av, ac);
|
||
|
||
/*
|
||
drawing_area = XtCreateWidget("drawingArea", xmManagerWidgetClass, scroller, av, ac);
|
||
drawing_area = XtCreateWidget("drawingArea", xmBulletinBoardWidgetClass, scroller, av, ac);
|
||
*/
|
||
/* XtAddCallback (drawing_area, XmNexposeCallback, fe_expose_cb, context); */
|
||
XtAddEventHandler(drawing_area, ExposureMask, FALSE,
|
||
(XtEventHandler)fe_expose_eh, context);
|
||
/* This is now added later in xfe.c, because we don't know fe_guffaw_scroll
|
||
* yet.
|
||
if (fe_globalData.fe_guffaw_scroll)
|
||
{
|
||
XtAddEventHandler(drawing_area, StructureNotifyMask, FALSE,
|
||
(XtEventHandler)fe_config_eh, context);
|
||
}
|
||
*/
|
||
#ifdef RESIZE_CALLBACK_WORKS
|
||
XtAddCallback (drawing_area, XmNresizeCallback, fe_resize_cb, context);
|
||
#endif
|
||
|
||
XtManageChild (drawing_area);
|
||
SCROLLER_SET_AREAS (scroller, hscroll, vscroll, drawing_area);
|
||
|
||
XtAddCallback (hscroll, XmNvalueChangedCallback, fe_scroll_cb, context);
|
||
XtAddCallback (vscroll, XmNvalueChangedCallback, fe_scroll_cb, context);
|
||
XtAddCallback (hscroll, XmNdragCallback, fe_scroll_cb, context);
|
||
XtAddCallback (vscroll, XmNdragCallback, fe_scroll_cb, context);
|
||
|
||
CONTEXT_DATA (context)->scrolled = scroller;
|
||
CONTEXT_DATA (context)->drawing_area = drawing_area;
|
||
CONTEXT_DATA (context)->hscroll = hscroll;
|
||
CONTEXT_DATA (context)->vscroll = vscroll;
|
||
|
||
XtManageChild (hscroll);
|
||
XtManageChild (vscroll);
|
||
|
||
/* add drag source via C API */
|
||
XFE_HTMLDragCreate(drawing_area,context);
|
||
|
||
return scroller;
|
||
}
|
||
|
||
static void
|
||
guffaw (MWContext *context)
|
||
{
|
||
Widget widget = CONTEXT_DATA (context)->drawing_area;
|
||
XSetWindowAttributes attr;
|
||
unsigned long valuemask;
|
||
valuemask = CWBitGravity | CWWinGravity;
|
||
attr.win_gravity = StaticGravity;
|
||
attr.bit_gravity = StaticGravity;
|
||
if (! XtWindow (widget)) abort ();
|
||
XChangeWindowAttributes (XtDisplay (widget), XtWindow (widget),
|
||
valuemask, &attr);
|
||
}
|
||
|
||
static void
|
||
unguffaw (MWContext *context)
|
||
{
|
||
Widget widget = CONTEXT_DATA (context)->drawing_area;
|
||
XSetWindowAttributes attr;
|
||
unsigned long valuemask;
|
||
valuemask = CWBitGravity | CWWinGravity;
|
||
attr.win_gravity = NorthWestGravity;
|
||
attr.bit_gravity = NorthWestGravity;
|
||
if (! XtWindow (widget)) abort ();
|
||
XChangeWindowAttributes (XtDisplay (widget), XtWindow (widget),
|
||
valuemask, &attr);
|
||
}
|
||
|
||
/*
|
||
* Toggle on and off the bit and window gravity effects
|
||
* of guffaws scrolling.
|
||
*/
|
||
void
|
||
fe_SetGuffaw(MWContext *context, Boolean on)
|
||
{
|
||
if (fe_globalData.fe_guffaw_scroll == 1)
|
||
{
|
||
if (on)
|
||
guffaw (context);
|
||
else
|
||
unguffaw (context);
|
||
}
|
||
}
|
||
|
||
static void
|
||
fe_scroll_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
||
{
|
||
MWContext *context = (MWContext *) closure;
|
||
XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *) call_data;
|
||
Widget da = CONTEXT_DATA (context)->drawing_area;
|
||
int scroll_slop_hack =
|
||
((Scroller) CONTEXT_DATA (context)->scrolled)->swindow.pad;
|
||
unsigned long lh = CONTEXT_DATA (context)->line_height;
|
||
unsigned long old_x = CONTEXT_DATA (context)->document_x;
|
||
unsigned long old_y = CONTEXT_DATA (context)->document_y;
|
||
unsigned long new_x = old_x;
|
||
unsigned long new_y = old_y;
|
||
Dimension w = 0, h = 0;
|
||
Boolean horiz_p;
|
||
XGCValues gcv;
|
||
GC gc;
|
||
|
||
fe_UserActivity (context);
|
||
if (widget == CONTEXT_DATA (context)->hscroll)
|
||
new_x = cb->value;
|
||
else if (widget == CONTEXT_DATA (context)->vscroll)
|
||
new_y = cb->value;
|
||
else
|
||
abort ();
|
||
horiz_p = (new_x != old_x);
|
||
|
||
fe_SetDocPosition (context, new_x, new_y);
|
||
|
||
/* XtVaGetValues (da, XmNwidth, &w, XmNheight, &h, 0); */
|
||
w = da->core.width;
|
||
h = da->core.height;
|
||
|
||
memset (&gcv, ~0, sizeof (gcv));
|
||
gcv.function = GXcopy;
|
||
gc = fe_GetGC (da, GCFunction, &gcv);
|
||
|
||
if (horiz_p)
|
||
{
|
||
if (new_x >= old_x)
|
||
{
|
||
int shift = (new_x - old_x);
|
||
int sb_w = CONTEXT_DATA (context)->sb_w;
|
||
if (fe_globalData.fe_guffaw_scroll == 1)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
XResizeWindow(XtDisplay(da), XtWindow(da),
|
||
(w + shift + scroll_slop_hack), h);
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), (x - shift), y);
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
|
||
fe_GravityCorrectForms (context, -shift, 0);
|
||
}
|
||
else if (fe_globalData.fe_guffaw_scroll == 2)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
fe_SetFormsGravity(context, WestGravity);
|
||
XResizeWindow(XtDisplay(da), XtWindow(da),
|
||
(w + shift), h);
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), (x - shift), y);
|
||
fe_SetFormsGravity(context, EastGravity);
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
|
||
fe_SetFormsGravity(context, NorthWestGravity);
|
||
fe_GravityCorrectForms (context, -shift, 0);
|
||
}
|
||
else
|
||
{
|
||
XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
|
||
shift, 0,
|
||
w - shift, h,
|
||
0, 0);
|
||
fe_ScrollForms (context, old_x - new_x, old_y - new_y);
|
||
fe_RefreshArea (context,
|
||
new_x + w - (shift+lh+lh),
|
||
new_y, shift+lh, h);
|
||
}
|
||
if (shift > w)
|
||
{
|
||
shift = w;
|
||
}
|
||
|
||
#ifdef DONT_rhess
|
||
/*
|
||
* NOTE: we always need to refresh the delta of the scrolled area...
|
||
* [ bug: improper redisplay during scrolling ]
|
||
*/
|
||
|
||
if (fe_globalData.fe_guffaw_scroll == 0)
|
||
#endif
|
||
fe_RefreshArea (context,
|
||
new_x + w - sb_w - shift,
|
||
new_y, shift + sb_w, h);
|
||
}
|
||
else
|
||
{
|
||
int shift = (old_x - new_x);
|
||
if (fe_globalData.fe_guffaw_scroll == 1)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da),
|
||
(x - shift), y, (w + shift), h);
|
||
XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
|
||
fe_GravityCorrectForms (context, shift, 0);
|
||
}
|
||
else if (fe_globalData.fe_guffaw_scroll == 2)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
fe_SetFormsGravity(context, EastGravity);
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da),
|
||
(x - shift), y, (w + shift), h);
|
||
fe_SetFormsGravity(context, WestGravity);
|
||
XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
|
||
fe_SetFormsGravity(context, NorthWestGravity);
|
||
fe_GravityCorrectForms (context, shift, 0);
|
||
}
|
||
else
|
||
{
|
||
XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
|
||
0, 0,
|
||
w - (old_x - new_x), h,
|
||
(old_x - new_x), 0);
|
||
fe_ScrollForms (context, old_x - new_x, old_y - new_y);
|
||
}
|
||
if (shift > w)
|
||
{
|
||
shift = w;
|
||
}
|
||
|
||
#ifdef DONT_rhess
|
||
if (fe_globalData.fe_guffaw_scroll == 0)
|
||
#endif
|
||
fe_RefreshArea (context, new_x, new_y, shift, h);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (new_y >= old_y)
|
||
{
|
||
int shift = (new_y - old_y);
|
||
int sb_h = CONTEXT_DATA (context)->sb_h;
|
||
if (fe_globalData.fe_guffaw_scroll == 1)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
XResizeWindow(XtDisplay(da), XtWindow(da), w,
|
||
(h + shift + scroll_slop_hack));
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), x, (y - shift));
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
|
||
fe_GravityCorrectForms (context, 0, -shift);
|
||
}
|
||
else if (fe_globalData.fe_guffaw_scroll == 2)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
fe_SetFormsGravity(context, NorthGravity);
|
||
XResizeWindow(XtDisplay(da), XtWindow(da), w,
|
||
(h + shift));
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), x, (y - shift));
|
||
fe_SetFormsGravity(context, SouthGravity);
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da), x, y, w, h);
|
||
fe_SetFormsGravity(context, NorthWestGravity);
|
||
fe_GravityCorrectForms (context, 0, -shift);
|
||
}
|
||
else
|
||
{
|
||
XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
|
||
0, shift,
|
||
w, h - shift,
|
||
0, 0);
|
||
fe_ScrollForms (context, old_x - new_x, old_y - new_y);
|
||
}
|
||
if (shift > h)
|
||
{
|
||
shift = h;
|
||
}
|
||
|
||
#ifdef DONT_rhess
|
||
if (fe_globalData.fe_guffaw_scroll == 0)
|
||
#endif
|
||
fe_RefreshArea (context, new_x, new_y + h - sb_h - shift,
|
||
w, shift + sb_h);
|
||
}
|
||
else
|
||
{
|
||
int shift = (old_y - new_y);
|
||
if (fe_globalData.fe_guffaw_scroll == 1)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da),
|
||
x, (y - shift), w, (h + shift));
|
||
XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
|
||
fe_GravityCorrectForms (context, 0, shift);
|
||
}
|
||
else if (fe_globalData.fe_guffaw_scroll == 2)
|
||
{
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
|
||
XGetGeometry(XtDisplay(da), XtWindow(da), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
fe_SetFormsGravity(context, SouthGravity);
|
||
XMoveResizeWindow(XtDisplay(da), XtWindow(da),
|
||
x, (y - shift), w, (h + shift));
|
||
fe_SetFormsGravity(context, NorthGravity);
|
||
XResizeWindow(XtDisplay(da), XtWindow(da), w, h);
|
||
XMoveWindow(XtDisplay(da), XtWindow(da), x, y);
|
||
fe_SetFormsGravity(context, NorthWestGravity);
|
||
fe_GravityCorrectForms (context, 0, shift);
|
||
}
|
||
else
|
||
{
|
||
XCopyArea (XtDisplay (da), XtWindow (da), XtWindow (da), gc,
|
||
0, 0,
|
||
w, h - (old_y - new_y),
|
||
0, (old_y - new_y));
|
||
fe_ScrollForms (context, old_x - new_x, old_y - new_y);
|
||
}
|
||
if (shift > h)
|
||
{
|
||
shift = h;
|
||
}
|
||
|
||
#ifdef DONT_rhess
|
||
if (fe_globalData.fe_guffaw_scroll == 0)
|
||
#endif
|
||
fe_RefreshArea (context, new_x, new_y, w, shift);
|
||
}
|
||
}
|
||
|
||
#ifdef PERFECT_SCROLL
|
||
/*
|
||
* In any X scrolling, there is the possibility of getting multiple
|
||
* scrolling events before any of the exposure events they
|
||
* generate appear. The results in improperly placed
|
||
* exposures because the values fo document_x and document_y in the
|
||
* context are different at the time the exposure is processed than
|
||
* they were at the time the exposure was created.
|
||
* The followind code elminates this. It first flushes all exposures
|
||
* generated by this scroll event, and then removes all motion events
|
||
* That might potentially cause another scroll to get processed before
|
||
* these exposures. Throwing out these extra motions in theory makes
|
||
* scrolling a little more jerky. In practice I notice no difference.
|
||
*/
|
||
XSync(XtDisplay(widget), FALSE);
|
||
if (cb->event)
|
||
{
|
||
XEvent new_event;
|
||
while (XCheckTypedWindowEvent(XtDisplay(widget), XtWindow(widget),
|
||
MotionNotify, &new_event) == TRUE);
|
||
}
|
||
#endif /* PERFECT_SCROLL */
|
||
}
|
||
|
||
void
|
||
fe_ScrollTo (MWContext *context, unsigned long x, unsigned long y)
|
||
{
|
||
if (x != CONTEXT_DATA (context)->document_x)
|
||
{
|
||
XmScrollBarCallbackStruct cb;
|
||
{
|
||
int nx = x;
|
||
int max = 0;
|
||
int size = 0;
|
||
XtVaGetValues (CONTEXT_DATA (context)->hscroll,
|
||
XmNmaximum, &max, XmNsliderSize, &size, 0);
|
||
if (nx > max - size) nx = max - size;
|
||
if (nx < 0) nx = 0;
|
||
XtVaSetValues (CONTEXT_DATA (context)->hscroll, XmNvalue, nx, 0);
|
||
x = nx;
|
||
}
|
||
memset (&cb, 0, sizeof (cb));
|
||
cb.value = x;
|
||
fe_scroll_cb (CONTEXT_DATA (context)->hscroll,
|
||
(XtPointer)context, (XtPointer)&cb);
|
||
}
|
||
if (y != CONTEXT_DATA (context)->document_y)
|
||
{
|
||
XmScrollBarCallbackStruct cb;
|
||
{
|
||
int ny = y;
|
||
int max = 0;
|
||
int size = 0;
|
||
XtVaGetValues (CONTEXT_DATA (context)->vscroll,
|
||
XmNmaximum, &max, XmNsliderSize, &size, 0);
|
||
if (ny > max - size) ny = max - size;
|
||
if (ny < 0) ny = 0;
|
||
XtVaSetValues (CONTEXT_DATA (context)->vscroll, XmNvalue, ny, 0);
|
||
y = ny;
|
||
}
|
||
memset (&cb, 0, sizeof (cb));
|
||
cb.value = y;
|
||
fe_scroll_cb (CONTEXT_DATA (context)->vscroll,
|
||
(XtPointer)context, (XtPointer)&cb);
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* When scrolling by moving the window, some expose events are generated
|
||
* when the window is NOT at 0,0 which need to be translated to 0,0
|
||
* when those exposes are processed. We can locate these exposes because the
|
||
* will have the same serial number as the configure that created them.
|
||
* Thus we need to save that serial number and offset here.
|
||
*/
|
||
void
|
||
fe_config_eh (Widget widget, XtPointer closure, XEvent *event)
|
||
{
|
||
MWContext *context = (MWContext *) closure;
|
||
XConfigureEvent *ce = (XConfigureEvent *) event;
|
||
|
||
if (ce->type != ConfigureNotify)
|
||
{
|
||
return;
|
||
}
|
||
|
||
CONTEXT_DATA (context)->expose_x_offset = ce->x;
|
||
CONTEXT_DATA (context)->expose_y_offset = ce->y;
|
||
CONTEXT_DATA (context)->expose_serial = ce->serial;
|
||
}
|
||
|
||
|
||
static void
|
||
fe_expose_eh (Widget widget, XtPointer closure, XEvent *event)
|
||
{
|
||
MWContext *context = (MWContext *) closure;
|
||
XExposeEvent *ee = (XExposeEvent *) event;
|
||
int scroll_slop_hack =
|
||
((Scroller) CONTEXT_DATA (context)->scrolled)->swindow.pad;
|
||
|
||
if (fe_globalData.fe_guffaw_scroll)
|
||
{
|
||
int new_x, new_y;
|
||
unsigned int new_width, new_height;
|
||
|
||
new_x = ee->x;
|
||
new_y = ee->y;
|
||
new_width = ee->width;
|
||
new_height = ee->height;
|
||
|
||
/*
|
||
* If this expose event has the same serial number as a configure
|
||
* event that moved the window away from 0,0 we need to adjust the x,y of
|
||
* this expose event to be in the proper location with respect to
|
||
* its parent.
|
||
*/
|
||
if ((CONTEXT_DATA (context)->expose_x_offset != 0)||
|
||
(CONTEXT_DATA (context)->expose_y_offset != 0))
|
||
{
|
||
if (ee->serial == CONTEXT_DATA (context)->expose_serial)
|
||
{
|
||
new_x += CONTEXT_DATA (context)->expose_x_offset;
|
||
new_y += CONTEXT_DATA (context)->expose_y_offset;
|
||
|
||
/*
|
||
* Correct for the presence of a horizontal or
|
||
* vertical scrollbar.
|
||
*/
|
||
if (CONTEXT_DATA (context)->expose_y_offset < 0)
|
||
{
|
||
new_y -= scroll_slop_hack;
|
||
new_height += scroll_slop_hack;
|
||
}
|
||
if (CONTEXT_DATA (context)->expose_x_offset < 0)
|
||
{
|
||
new_x -= scroll_slop_hack;
|
||
new_width += scroll_slop_hack;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Because we are scrolling a window that may have many small child
|
||
* widgets, we want to compress the many small exposes that happen around
|
||
* those widgets. We don't want to compress discontinuous regions
|
||
* that happened to be exposed at the same time.
|
||
* We want to compress:
|
||
*
|
||
* ----- ---------
|
||
* | |------ and | |
|
||
* | || | ---------
|
||
* -----| | ---------
|
||
* ------ | |
|
||
* ---------
|
||
*
|
||
* NOT
|
||
*
|
||
* -----
|
||
* | |
|
||
* -----
|
||
*
|
||
* -----
|
||
* | |
|
||
* -----
|
||
*/
|
||
|
||
/*
|
||
* Non-zero counts are parts of multi-expose blocks, and might be
|
||
* held for later compression.
|
||
*/
|
||
if (ee->count != 0)
|
||
{
|
||
/*
|
||
* If nothng held so far, just hold this one.
|
||
*/
|
||
if (CONTEXT_DATA (context)->held_expose == FALSE)
|
||
{
|
||
CONTEXT_DATA (context)->held_expose = TRUE;
|
||
CONTEXT_DATA (context)->expose_x1 = new_x;
|
||
CONTEXT_DATA (context)->expose_y1 = new_y;
|
||
CONTEXT_DATA (context)->expose_x2 = new_x + new_width;
|
||
CONTEXT_DATA (context)->expose_y2 = new_y + new_height;
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* If we are adjacent to the held block, compress them together
|
||
*/
|
||
if ((((new_y - 1) >= CONTEXT_DATA (context)->expose_y1)&&
|
||
((new_y - 1) <= CONTEXT_DATA (context)->expose_y2))||
|
||
(((new_y + new_height + 1) >= CONTEXT_DATA (context)->expose_y1)&&
|
||
((new_y + new_height + 1) <= CONTEXT_DATA (context)->expose_y2))||
|
||
((CONTEXT_DATA (context)->expose_y1 >= (new_y - 1))&&
|
||
(CONTEXT_DATA (context)->expose_y1 <= (new_y + new_height + 1))))
|
||
{
|
||
if (new_x < CONTEXT_DATA (context)->expose_x1)
|
||
CONTEXT_DATA (context)->expose_x1 = new_x;
|
||
if (new_y < CONTEXT_DATA (context)->expose_y1)
|
||
CONTEXT_DATA (context)->expose_y1 = new_y;
|
||
if ((new_x + (int)new_width) > CONTEXT_DATA (context)->expose_x2)
|
||
CONTEXT_DATA (context)->expose_x2 = new_x + (int)new_width;
|
||
if ((new_y + (int)new_height) > CONTEXT_DATA (context)->expose_y2)
|
||
CONTEXT_DATA (context)->expose_y2 = new_y + (int)new_height;
|
||
}
|
||
/*
|
||
* We weren't adjacent. Display the held block, and hold
|
||
* the new one.
|
||
*/
|
||
else
|
||
{
|
||
unsigned int hold_width, hold_height;
|
||
|
||
if (CONTEXT_DATA (context)->expose_x2
|
||
> CONTEXT_DATA (context)->scrolled_width)
|
||
CONTEXT_DATA (context)->expose_x2
|
||
= CONTEXT_DATA (context)->scrolled_width;
|
||
if (CONTEXT_DATA (context)->expose_y2
|
||
> CONTEXT_DATA (context)->scrolled_height)
|
||
CONTEXT_DATA (context)->expose_y2
|
||
= CONTEXT_DATA (context)->scrolled_height;
|
||
hold_width = (CONTEXT_DATA (context)->expose_x2 -
|
||
CONTEXT_DATA (context)->expose_x1);
|
||
hold_height = (CONTEXT_DATA (context)->expose_y2 -
|
||
CONTEXT_DATA (context)->expose_y1);
|
||
if (hold_width < 1)
|
||
hold_width = 1;
|
||
if (hold_height < 1)
|
||
hold_height = 1;
|
||
|
||
|
||
fe_RefreshArea (context,
|
||
(CONTEXT_DATA (context)->expose_x1 +
|
||
CONTEXT_DATA (context)->document_x),
|
||
(CONTEXT_DATA (context)->expose_y1 +
|
||
CONTEXT_DATA (context)->document_y),
|
||
hold_width, hold_height);
|
||
CONTEXT_DATA (context)->expose_x1 = new_x;
|
||
CONTEXT_DATA (context)->expose_y1 = new_y;
|
||
CONTEXT_DATA (context)->expose_x2 = new_x + new_width;
|
||
CONTEXT_DATA (context)->expose_y2 = new_y + new_height;
|
||
}
|
||
}
|
||
}
|
||
/*
|
||
* count = 0 is either a standalone expose, or part of a multipart
|
||
* expose.
|
||
*/
|
||
else
|
||
{
|
||
/*
|
||
* If nothing held this is just a standalone expose, display it.
|
||
*/
|
||
if (CONTEXT_DATA (context)->held_expose == FALSE)
|
||
{
|
||
if ((new_x + new_width) > CONTEXT_DATA (context)->scrolled_width)
|
||
new_width = CONTEXT_DATA (context)->scrolled_width - new_x;
|
||
if ((new_y + new_height) > CONTEXT_DATA (context)->scrolled_height)
|
||
new_height = CONTEXT_DATA (context)->scrolled_height - new_y;
|
||
if (new_width < 1)
|
||
new_width = 1;
|
||
if (new_height < 1)
|
||
new_height = 1;
|
||
|
||
fe_RefreshArea (context,
|
||
new_x + CONTEXT_DATA (context)->document_x,
|
||
new_y + CONTEXT_DATA (context)->document_y,
|
||
new_width, new_height);
|
||
}
|
||
else
|
||
{
|
||
CONTEXT_DATA (context)->held_expose = FALSE;
|
||
/*
|
||
* If we are adjacent to the held block, compress them together
|
||
* and display the combined chunk.
|
||
*/
|
||
if ((((new_y - 1) >= CONTEXT_DATA (context)->expose_y1)&&
|
||
((new_y - 1) <= CONTEXT_DATA (context)->expose_y2))||
|
||
(((new_y + new_height + 1) >= CONTEXT_DATA (context)->expose_y1)&&
|
||
((new_y + new_height + 1) <= CONTEXT_DATA (context)->expose_y2))||
|
||
((CONTEXT_DATA (context)->expose_y1 >= (new_y - 1))&&
|
||
(CONTEXT_DATA (context)->expose_y1 <= (new_y + new_height + 1))))
|
||
{
|
||
if (new_x < CONTEXT_DATA (context)->expose_x1)
|
||
CONTEXT_DATA (context)->expose_x1 = new_x;
|
||
if (new_y < CONTEXT_DATA (context)->expose_y1)
|
||
CONTEXT_DATA (context)->expose_y1 = new_y;
|
||
if ((new_x + new_width) > CONTEXT_DATA (context)->expose_x2)
|
||
CONTEXT_DATA (context)->expose_x2 = new_x + new_width;
|
||
if ((new_y + new_height) > CONTEXT_DATA (context)->expose_y2)
|
||
CONTEXT_DATA (context)->expose_y2 = new_y + new_height;
|
||
|
||
if (CONTEXT_DATA (context)->expose_x2
|
||
> CONTEXT_DATA (context)->scrolled_width)
|
||
CONTEXT_DATA (context)->expose_x2
|
||
= CONTEXT_DATA (context)->scrolled_width;
|
||
if (CONTEXT_DATA (context)->expose_y2
|
||
> CONTEXT_DATA (context)->scrolled_height)
|
||
CONTEXT_DATA (context)->expose_y2
|
||
= CONTEXT_DATA (context)->scrolled_height;
|
||
new_width = (CONTEXT_DATA (context)->expose_x2 -
|
||
CONTEXT_DATA (context)->expose_x1);
|
||
new_height = (CONTEXT_DATA (context)->expose_y2 -
|
||
CONTEXT_DATA (context)->expose_y1);
|
||
if (new_width < 1)
|
||
new_width = 1;
|
||
if (new_height < 1)
|
||
new_height = 1;
|
||
|
||
fe_RefreshArea (context,
|
||
(CONTEXT_DATA (context)->expose_x1 +
|
||
CONTEXT_DATA (context)->document_x),
|
||
(CONTEXT_DATA (context)->expose_y1 +
|
||
CONTEXT_DATA (context)->document_y),
|
||
new_width, new_height);
|
||
}
|
||
/*
|
||
* Else display the held block and this expose separately.
|
||
*/
|
||
else
|
||
{
|
||
unsigned int hold_width, hold_height;
|
||
|
||
if (CONTEXT_DATA (context)->expose_x2
|
||
> CONTEXT_DATA (context)->scrolled_width)
|
||
CONTEXT_DATA (context)->expose_x2
|
||
= CONTEXT_DATA (context)->scrolled_width;
|
||
if (CONTEXT_DATA (context)->expose_y2
|
||
> CONTEXT_DATA (context)->scrolled_height)
|
||
CONTEXT_DATA (context)->expose_y2
|
||
= CONTEXT_DATA (context)->scrolled_height;
|
||
hold_width = (CONTEXT_DATA (context)->expose_x2 -
|
||
CONTEXT_DATA (context)->expose_x1);
|
||
hold_height = (CONTEXT_DATA (context)->expose_y2 -
|
||
CONTEXT_DATA (context)->expose_y1);
|
||
if (hold_width < 1)
|
||
hold_width = 1;
|
||
if (hold_height < 1)
|
||
hold_height = 1;
|
||
|
||
fe_RefreshArea (context,
|
||
(CONTEXT_DATA (context)->expose_x1 +
|
||
CONTEXT_DATA (context)->document_x),
|
||
(CONTEXT_DATA (context)->expose_y1 +
|
||
CONTEXT_DATA (context)->document_y),
|
||
hold_width, hold_height);
|
||
|
||
if ((new_x + new_width) > CONTEXT_DATA (context)->scrolled_width)
|
||
new_width = CONTEXT_DATA (context)->scrolled_width - new_x;
|
||
if ((new_y + new_height) > CONTEXT_DATA (context)->scrolled_height)
|
||
new_height = CONTEXT_DATA (context)->scrolled_height - new_y;
|
||
if (new_width < 1)
|
||
new_width = 1;
|
||
if (new_height < 1)
|
||
new_height = 1;
|
||
|
||
fe_RefreshArea (context,
|
||
new_x + CONTEXT_DATA (context)->document_x,
|
||
new_y + CONTEXT_DATA (context)->document_y,
|
||
new_width, new_height);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fe_RefreshArea (context,
|
||
ee->x + CONTEXT_DATA (context)->document_x,
|
||
ee->y + CONTEXT_DATA (context)->document_y,
|
||
ee->width, ee->height);
|
||
}
|
||
}
|
||
|
||
void
|
||
fe_SyncExposures(MWContext* context)
|
||
{
|
||
XEvent event;
|
||
Widget drawing_area = CONTEXT_DATA(context)->drawing_area;
|
||
Display* display = XtDisplay(drawing_area);
|
||
Window window = XtWindow(drawing_area);
|
||
|
||
XSync(display, FALSE);
|
||
|
||
while (XCheckTypedWindowEvent(display, window, Expose, &event) == TRUE) {
|
||
fe_expose_eh(drawing_area, (XtPointer)context, &event);
|
||
}
|
||
|
||
/*
|
||
* Force compositor to sync.
|
||
*/
|
||
if (context->compositor)
|
||
CL_CompositeNow(context->compositor);
|
||
}
|
||
|
||
static void
|
||
fe_hack_scrollbar (Widget sb, int max, int inc, int page_inc,
|
||
int slider_size, int value)
|
||
{
|
||
if (value + slider_size > max)
|
||
value = max - slider_size;
|
||
if (value < 0)
|
||
value = 0;
|
||
if (inc < 1)
|
||
inc = 1;
|
||
if (page_inc < inc)
|
||
page_inc = inc;
|
||
XtVaSetValues (sb,
|
||
XmNmaximum, max,
|
||
XmNincrement, inc,
|
||
XmNpageIncrement, page_inc,
|
||
XmNsliderSize, slider_size,
|
||
XmNvalue, value,
|
||
0);
|
||
}
|
||
|
||
|
||
void
|
||
fe_SetDocPosition (MWContext *context, unsigned long x, unsigned long y)
|
||
{
|
||
unsigned long w = CONTEXT_DATA (context)->document_width;
|
||
unsigned long h = CONTEXT_DATA (context)->document_height;
|
||
unsigned long lh = CONTEXT_DATA (context)->line_height;
|
||
Dimension ww = 0, wh = 0;
|
||
XP_Bool are_scrollbars_active;
|
||
XP_Bool frame_scrolling_yes = False;
|
||
|
||
|
||
if (x >= w + 100) x = 0;
|
||
if (y >= h + lh) y = ((h > lh) ? h - lh : 0);
|
||
|
||
if (context->is_grid_cell &&
|
||
CONTEXT_DATA (context)->grid_scrolling == LO_SCROLL_NO) {
|
||
/* We're done */
|
||
CONTEXT_DATA (context)->document_x = x;
|
||
CONTEXT_DATA (context)->document_y = y;
|
||
|
||
return;
|
||
}
|
||
|
||
XP_ASSERT (CONTEXT_DATA (context)->drawing_area);
|
||
if (!CONTEXT_DATA (context)->drawing_area) return;
|
||
|
||
XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
|
||
XmNwidth, &ww, XmNheight, &wh, 0);
|
||
|
||
/*
|
||
* Fix for 4.0 bug 55350 (reported by ebina)
|
||
*
|
||
* <frame scrolling=yes> doesn't always have scrollbars.
|
||
*
|
||
* If grid_scrolling == LO_SCROLL_YES, then we force
|
||
* both scrollbars to be on regardless of whether they
|
||
* are needed or not.
|
||
*
|
||
* -ramiro
|
||
*/
|
||
if (context->is_grid_cell &&
|
||
CONTEXT_DATA (context)->grid_scrolling == LO_SCROLL_YES)
|
||
{
|
||
frame_scrolling_yes = True;
|
||
}
|
||
|
||
are_scrollbars_active = CONTEXT_DATA(context)->are_scrollbars_active;
|
||
|
||
if ( (h <= wh) || (are_scrollbars_active == FALSE) )
|
||
{
|
||
if (!frame_scrolling_yes)
|
||
{
|
||
y = 0;
|
||
XtUnmanageChild (CONTEXT_DATA (context)->vscroll);
|
||
fe_hack_scrollbar (CONTEXT_DATA (context)->vscroll,
|
||
1, 1, 1, 1, 0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fe_hack_scrollbar (CONTEXT_DATA (context)->vscroll,
|
||
h, /* max */
|
||
lh, /* inc */
|
||
wh - lh, /* page_inc */
|
||
wh, /* slider_size */
|
||
y /* value */
|
||
);
|
||
XtManageChild (CONTEXT_DATA (context)->vscroll);
|
||
}
|
||
|
||
if ( (w <= ww) || (are_scrollbars_active == FALSE) )
|
||
{
|
||
if (!frame_scrolling_yes)
|
||
{
|
||
x = 0;
|
||
XtUnmanageChild (CONTEXT_DATA (context)->hscroll);
|
||
fe_hack_scrollbar (CONTEXT_DATA (context)->hscroll,
|
||
1, 1, 1, 1, 0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fe_hack_scrollbar (CONTEXT_DATA (context)->hscroll,
|
||
w, /* max */
|
||
lh, /* inc */
|
||
ww - lh, /* page_inc */
|
||
ww, /* slider_size */
|
||
x /* value */
|
||
);
|
||
XtManageChild (CONTEXT_DATA (context)->hscroll);
|
||
}
|
||
|
||
if (frame_scrolling_yes)
|
||
{
|
||
XtManageChild (CONTEXT_DATA (context)->vscroll);
|
||
XtManageChild (CONTEXT_DATA (context)->hscroll);
|
||
}
|
||
|
||
fe_find_scrollbar_sizes(context);
|
||
|
||
CONTEXT_DATA (context)->document_x = x;
|
||
CONTEXT_DATA (context)->document_y = y;
|
||
|
||
if (context->compositor)
|
||
CL_ScrollCompositorWindow(context->compositor, x, y);
|
||
}
|
||
|
||
void
|
||
FE_ScrollDocBy (MWContext *context, int iLocation, int32 deltax, int32 deltay)
|
||
{
|
||
int32 x;
|
||
int32 y;
|
||
XFE_GetDocPosition (context, iLocation, &x, &y);
|
||
x += deltax;
|
||
y += deltay;
|
||
fe_ScrollTo (context, x, y);
|
||
}
|
||
|
||
void
|
||
FE_ScrollDocTo (MWContext *context, int iLocation, int32 x, int32 y)
|
||
{
|
||
fe_ScrollTo (context, x, y);
|
||
}
|
||
|
||
void
|
||
XFE_GetDocPosition (MWContext *context, int iLocation,
|
||
int32 *iX, int32 *iY)
|
||
{
|
||
*iX = (int32)CONTEXT_DATA (context)->document_x;
|
||
*iY = (int32)CONTEXT_DATA (context)->document_y;
|
||
}
|
||
|
||
void
|
||
XFE_SetDocPosition (MWContext *context, int iLocation, int32 x, int32 y)
|
||
{
|
||
#if 0
|
||
#ifdef EDITOR
|
||
if (EDT_IS_EDITOR(context)) {
|
||
fe_ScrollTo (context, x, y);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
fe_SetDocPosition (context, x, y);
|
||
}
|
||
#else
|
||
/*
|
||
* In WinFE (the standard), XFE_SetDocPosition() and FE_ScrollDocTo()
|
||
* do the same thing (one calls the other). We seem to have a number
|
||
* of bugs that are fixed by emulating WinFE's semantics, so our
|
||
* feeling is that the back-end is now weighted in that way.
|
||
* SO, rather than fight a losing battle, we think we'll just make
|
||
* this change and hope that nothing new breaks. For Bug #77767.
|
||
* - djw, vidur, mcafee, brendan (shared blame) July/20/1997.
|
||
*/
|
||
fe_ScrollTo (context, x, y);
|
||
#endif
|
||
}
|
||
|
||
void
|
||
XFE_SetDocDimension (MWContext *context,
|
||
int iLocation, int32 iWidth, int32 iLength)
|
||
{
|
||
Widget widget = CONTEXT_DATA (context)->drawing_area;
|
||
#ifdef EDITOR
|
||
unsigned long win_h;
|
||
unsigned long old_h;
|
||
#endif
|
||
unsigned long w, h;
|
||
time_t now = time ((time_t) 0);
|
||
|
||
if (! widget) abort ();
|
||
w = iWidth;
|
||
h = iLength;
|
||
if (w < 1) w = 1;
|
||
if (h < 1) h = 1;
|
||
|
||
#ifdef EDITOR
|
||
win_h = CONTEXT_DATA (context)->scrolled_height;
|
||
old_h = CONTEXT_DATA (context)->document_height;
|
||
#endif
|
||
|
||
CONTEXT_DATA (context)->document_width = w;
|
||
CONTEXT_DATA (context)->document_height = h;
|
||
|
||
/* Only actually resize the window once a second, to avoid thrashing. */
|
||
if (now <= CONTEXT_DATA (context)->doc_size_last_update_time)
|
||
return;
|
||
|
||
/* We just need to update the scrollbars; nothing visible has changed. */
|
||
fe_SetDocPosition (context,
|
||
CONTEXT_DATA (context)->document_x,
|
||
CONTEXT_DATA (context)->document_y);
|
||
|
||
CONTEXT_DATA (context)->doc_size_last_update_time = now;
|
||
|
||
#ifdef EDITOR
|
||
/*
|
||
* NOTE: fix for redisplay bugs... [ 73704, 73705, 73688 ]
|
||
*
|
||
*/
|
||
if (EDT_IS_EDITOR(context)) {
|
||
if (h < old_h) {
|
||
/*
|
||
* NOTE: need to force a refresh if the we lost the scrollbars
|
||
* in the process of shrinking the document size...
|
||
*
|
||
*/
|
||
if (h < win_h && old_h > win_h) {
|
||
#ifdef DEBUG_rhess
|
||
fprintf(stderr, "ForceRefresh::[ %d, %d ][ %d ][ %d ]\n",
|
||
w, h, old_h, win_h);
|
||
#endif
|
||
fe_RefreshArea(context, 0, 0, w, h);
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
#ifdef RESIZE_CALLBACK_WORKS
|
||
|
||
static void
|
||
fe_resize_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
||
{
|
||
XmDrawingAreaCallbackStruct *cb = (XmDrawingAreaCallbackStruct *) call_data;
|
||
|
||
#else
|
||
|
||
static void
|
||
fe_scroller_resize (Widget widget, XtPointer closure)
|
||
{
|
||
#endif
|
||
|
||
MWContext *context = (MWContext *) closure;
|
||
fe_ContextData *fep = CONTEXT_DATA(context);
|
||
MWContextType type = context->type;
|
||
|
||
/* I question the wisdom of having to do a reload every time the window
|
||
size changes... */
|
||
Dimension w = 0, h = 0;
|
||
Boolean relayout_p = False;
|
||
|
||
XtVaGetValues (widget, XmNwidth, &w, XmNheight, &h, 0);
|
||
|
||
relayout_p = ((Dimension) fep->scrolled_width) != w;
|
||
|
||
/*
|
||
* Inside FRAMES (and eventually elsewhere?) we DO want to reload, even if
|
||
* just the height has changed.
|
||
*/
|
||
if ((!relayout_p)&&(context->is_grid_cell ||
|
||
(context->grid_children &&
|
||
XP_ListTopObject (context->grid_children))))
|
||
{
|
||
relayout_p = ((Dimension) fep->scrolled_height) != h;
|
||
}
|
||
|
||
/* Well this is kinda bogus; don't do a relayout if we're displaying one
|
||
of the magic internal-external images, since we know no wrapping can
|
||
occur. */
|
||
if (relayout_p)
|
||
{
|
||
History_entry *h = SHIST_GetCurrent (&context->hist);
|
||
if (h && h->is_binary)
|
||
relayout_p = False;
|
||
}
|
||
|
||
/* If we have just an image and we resize such that either the width
|
||
* or the height of the window is bigger than the image, and we had
|
||
* scrolled off from the left,top edge, then we will need to refresh
|
||
* the entire image. If this doesn't happen, then in the exposed parts
|
||
* the image that is repainted is off the document_x, document_y.
|
||
*/
|
||
if (
|
||
/* If there is a real resize going on */
|
||
(fep->scrolled_height != h || fep->scrolled_width != w) &&
|
||
/* and if either of width or height spans the full document */
|
||
(h >= fep->document_height || w >= fep->document_width) &&
|
||
/* and if the document is not at its (0,0) origin */
|
||
(fep->document_x != 0 || fep->document_y != 0)) {
|
||
relayout_p = True;
|
||
}
|
||
|
||
/* Fullpage plugins need be told about size changes. */
|
||
if (CONTEXT_DATA(context)->is_fullpage_plugin)
|
||
{
|
||
fe_RefreshArea (context,
|
||
CONTEXT_DATA (context)->document_x,
|
||
CONTEXT_DATA (context)->document_y,
|
||
1, 1);
|
||
relayout_p = False;
|
||
}
|
||
|
||
if (! XtIsRealized (widget))
|
||
/* I'm not sure this is right, but otherwise layout happens while a
|
||
new window is still getting created... */
|
||
relayout_p = False;
|
||
|
||
if (relayout_p)
|
||
{
|
||
/* If a document is currently being laid out, just update the
|
||
scrollbars and flag it as needing to be re-figured at the end.
|
||
Otherwise, re-lay out the document with the new width.
|
||
Note: don't use CONTEXT_DATA (context)->active_url_count
|
||
here, that only counts foreground transfers, not images.
|
||
*/
|
||
if (XP_IsContextBusy (context)) {
|
||
CONTEXT_DATA (context)->relayout_required = True;
|
||
} else {
|
||
|
||
/* This is unset in XFE_LayoutNewDocument. */
|
||
CONTEXT_DATA (context)->is_resizing = TRUE;
|
||
|
||
/*
|
||
* Need to update these before calling relayout, because the BE
|
||
* is going to ask us this stuff in FE_GetDocAndWindowPosition().
|
||
* Seems obvious I guess. Bug #27455.
|
||
*
|
||
* I moved this out of the next EDT_IS_EDITOR if, since
|
||
* for the new relayout stuff, grid edges don't get moved
|
||
* if their x or y is greater than the window width and
|
||
* height. I honestly can't imagine why you wouldn't
|
||
* want the size change reflected as early as possible
|
||
* anyway -- toshok
|
||
*/
|
||
CONTEXT_DATA(context)->scrolled_width = (unsigned long)w;
|
||
CONTEXT_DATA(context)->scrolled_height = (unsigned long)h;
|
||
|
||
#ifdef EDITOR
|
||
/*
|
||
* This edit_view_source_hack is so completely bogus,
|
||
* but it seems to only be edit for the editor view
|
||
* source window. Do this for bug #23375. djw 96/06/15.
|
||
*/
|
||
if (EDT_IS_EDITOR(context) || context->edit_view_source_hack) {
|
||
|
||
fe_EditorRefresh(context);
|
||
}
|
||
else
|
||
#endif /*EDITOR*/
|
||
|
||
#ifdef ENABLE_MARINER
|
||
{
|
||
int32 margin_w, margin_h;
|
||
|
||
fe_GetMargin(context, &margin_w, &margin_h);
|
||
|
||
LO_RelayoutOnResize(context, w, h, margin_w, margin_h);
|
||
}
|
||
#else
|
||
/* As vidur suggested in Bug 59214: because JS generated content
|
||
was not put into wysiwyg, hence this source was not be shown on a resize.
|
||
The fix was to make the reload policy for Mail/News contexts NET_NORMAL_RELOAD */
|
||
if ( (type == MWContextNews) || (type == MWContextMail)
|
||
|| (type == MWContextNewsMsg) || (type == MWContextMailMsg) )
|
||
fe_ReLayout (context, NET_NORMAL_RELOAD);
|
||
else
|
||
fe_ReLayout (context, NET_RESIZE_RELOAD);
|
||
#endif
|
||
}
|
||
}
|
||
/* We just need to update the scrollbars; the other expose events
|
||
which are coming will take care of repainting the text. */
|
||
fe_SetDocPosition (context,
|
||
CONTEXT_DATA (context)->document_x,
|
||
CONTEXT_DATA (context)->document_y);
|
||
|
||
/*
|
||
** this is wretched and gross. the assignments below are exactly the same as the ones
|
||
** about 20 lines above. Why do I duplicate them here, you may ask. Well, for some
|
||
** reason someplace in between the assignments above and the ones here (probably in
|
||
** fe_SetDocPosition), something happens to set the scrolled_width and scrolled_height
|
||
** to smaller values.
|
||
** this results in a band along the bottom and right hand sides of the document, where the
|
||
** scrollbars would normally be.
|
||
**
|
||
** I am thoroughly disgusted.
|
||
**
|
||
** - toshok
|
||
*/
|
||
CONTEXT_DATA(context)->scrolled_width = (unsigned long)w;
|
||
CONTEXT_DATA(context)->scrolled_height = (unsigned long)h;
|
||
|
||
/* We only need the composited area without the scrollbars. However,
|
||
since the scrollbars can become managed and then unmanaged during
|
||
layout, it is not worth the effort of keeping track of when they
|
||
are visible. Instead we make the compositor the size of the drawing
|
||
area and just let the scrollbars clip the background layer. */
|
||
if (context->compositor)
|
||
CL_ResizeCompositorWindow(context->compositor, w, h);
|
||
}
|
||
|
||
|
||
Boolean
|
||
fe_TestGravity (Widget widget)
|
||
{
|
||
Widget area, element;
|
||
Arg arg[10];
|
||
Cardinal argcnt;
|
||
int shift;
|
||
int orig_x, orig_y;
|
||
int x, y;
|
||
unsigned int w, h, d1, d2;
|
||
Window dummy;
|
||
XSetWindowAttributes set_attr;
|
||
unsigned long valuemask;
|
||
Boolean works;
|
||
Visual *v = 0;
|
||
Colormap cmap = 0;
|
||
Cardinal depth = 0;
|
||
|
||
/*
|
||
* OW 3.4 has some horrid bug so that it tests OK for
|
||
* guffaws scrolling, but then when the user resizes the
|
||
* window, it crashes the X server. Sigh.
|
||
*/
|
||
if ((!strcmp(XServerVendor(XtDisplay(widget)), "Sun Microsystems, Inc."))&&
|
||
(VendorRelease(XtDisplay(widget)) == 3400))
|
||
{
|
||
return(False);
|
||
}
|
||
|
||
XtVaGetValues (widget, XtNvisual, &v, XtNcolormap, &cmap,
|
||
XtNdepth, &depth, 0);
|
||
|
||
shift = 10;
|
||
|
||
argcnt = 0;
|
||
XtSetArg(arg[argcnt], XmNvisual, v); argcnt++;
|
||
XtSetArg(arg[argcnt], XmNcolormap, cmap); argcnt++;
|
||
XtSetArg(arg[argcnt], XmNdepth, depth); argcnt++;
|
||
XtSetArg(arg[argcnt], XtNwidth, 200); argcnt++;
|
||
XtSetArg(arg[argcnt], XtNheight, 200); argcnt++;
|
||
XtSetArg(arg[argcnt], XmNmappedWhenManaged, False); argcnt++;
|
||
area = XmCreateDrawingArea(widget, "Area", arg, argcnt);
|
||
|
||
argcnt = 0;
|
||
XtSetArg(arg[argcnt], XmNvisual, v); argcnt++;
|
||
XtSetArg(arg[argcnt], XmNcolormap, cmap); argcnt++;
|
||
XtSetArg(arg[argcnt], XmNdepth, depth); argcnt++;
|
||
XtSetArg(arg[argcnt], XtNx, 50); argcnt++;
|
||
XtSetArg(arg[argcnt], XtNy, 80); argcnt++;
|
||
XtSetArg(arg[argcnt], XmNmappedWhenManaged, False); argcnt++;
|
||
element = fe_CreateTextField(area, "Element", arg, argcnt);
|
||
|
||
XtManageChild(area);
|
||
XtManageChild(element);
|
||
|
||
valuemask = CWBitGravity | CWWinGravity;
|
||
set_attr.win_gravity = StaticGravity;
|
||
set_attr.bit_gravity = StaticGravity;
|
||
XChangeWindowAttributes (XtDisplay(area), XtWindow(area),
|
||
valuemask, &set_attr);
|
||
XChangeWindowAttributes (XtDisplay(element), XtWindow(element),
|
||
valuemask, &set_attr);
|
||
|
||
XGetGeometry(XtDisplay(element), XtWindow(element), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
orig_x = x;
|
||
orig_y = y;
|
||
|
||
XGetGeometry(XtDisplay(area), XtWindow(area), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
XResizeWindow(XtDisplay(area), XtWindow(area), w, (h + shift));
|
||
XMoveWindow(XtDisplay(area), XtWindow(area), x, (y - shift));
|
||
XMoveResizeWindow(XtDisplay(area), XtWindow(area), x, y, w, h);
|
||
|
||
XGetGeometry(XtDisplay(area), XtWindow(area), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
XResizeWindow(XtDisplay(area), XtWindow(area), w, (h + shift));
|
||
XMoveWindow(XtDisplay(area), XtWindow(area), x, (y - shift));
|
||
XMoveResizeWindow(XtDisplay(area), XtWindow(area), x, y, w, h);
|
||
|
||
XGetGeometry(XtDisplay(element), XtWindow(element), &dummy,
|
||
&x, &y, &w, &h, &d1, &d2);
|
||
if (y != (orig_y - (2 * shift)))
|
||
{
|
||
works = False;
|
||
}
|
||
else
|
||
{
|
||
works = True;
|
||
}
|
||
|
||
XtDestroyWidget(area);
|
||
return(works);
|
||
}
|
||
|
||
|
||
int
|
||
fe_WindowGravityWorks (Widget toplevel, Widget widget)
|
||
{
|
||
String str = 0;
|
||
static XtResource res = { "windowGravityWorks", XtCString, XtRString,
|
||
sizeof (String), 0, XtRImmediate, "guess" };
|
||
XtGetApplicationResources (toplevel, &str, &res, 1, 0, 0);
|
||
|
||
if (str && (!XP_STRCASECMP(str, "yes") || !XP_STRCASECMP(str, "true")))
|
||
{
|
||
return 1;
|
||
}
|
||
else if (str && (!XP_STRCASECMP(str, "partial") || !XP_STRCASECMP(str, "kindof")))
|
||
{
|
||
return 2;
|
||
}
|
||
else if (str && (!XP_STRCASECMP(str, "no") || !XP_STRCASECMP(str, "false")))
|
||
{
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
char *vendor = XServerVendor (XtDisplay (toplevel));
|
||
|
||
if (str && XP_STRCASECMP(str, "guess"))
|
||
{
|
||
fprintf (stderr,
|
||
XP_GetString(XFE_SCROLL_WINDOW_GRAVITY_WARNING),
|
||
fe_progname, str);
|
||
}
|
||
|
||
/*
|
||
* Short circuit all this other crap, and do the right thing.
|
||
*/
|
||
if (fe_TestGravity(widget))
|
||
{
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
return 2;
|
||
}
|
||
|
||
/* WindowGravity is known to be broken in the OpenWound 3.0 server
|
||
and is known to work in the OpenWound 3.3 server.
|
||
*/
|
||
if (!strcmp (vendor, "X11/NeWS - Sun Microsystems Inc."))
|
||
#if 0
|
||
return (VendorRelease (XtDisplay (toplevel)) >= 3300);
|
||
#else
|
||
/* Ok, all of Sun's code is just buggy as hell. There are lurking X
|
||
server crashes that happen when we mess with window gravity on OW 2.4,
|
||
so forget it. */
|
||
return 0;
|
||
#endif
|
||
else if (!strncmp (vendor, "MacX", 4) || !strncmp (vendor, "eXodus", 6))
|
||
/* The Mac X servers get this wrong (actually I'm not sure that both
|
||
do, but at least one of them does.) */
|
||
return 0;
|
||
|
||
else if (!strcmp (vendor, "Sony Corporation"))
|
||
/* Sony NEWS R4 is busted; later versions not *known* to work. */
|
||
return (VendorRelease (XtDisplay (toplevel)) > 4);
|
||
|
||
else if (!strcmp (vendor,
|
||
"DECWINDOWS (Compatibility String) Network Computing Devices Inc."))
|
||
/* NCD 2004 is busted; later versions not *known* to work. */
|
||
return (VendorRelease (XtDisplay (toplevel)) > 2004);
|
||
|
||
/* #### It has been suggested that all R4-based servers lose? */
|
||
|
||
else
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
void
|
||
FE_ShowScrollBars(MWContext *context, XP_Bool show)
|
||
{
|
||
/* XXX implement me */
|
||
}
|
||
|