#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/ShellP.h>
#include <X11/Xproto.h>
#include <stdlib.h>
#include <Xm/Xm.h>
#if XmVersion > 1001
#include <Xm/ManagerP.h>
#else
#include <Xm/XmP.h>
#endif
#include <Xm/DrawingA.h>
#include <Xm/ScrolledW.h>
#include <Xm/ScrollBar.h>
#include <DPS/dpsXclient.h>
#include "dpsXcommonI.h"
#include <DPS/dpsXshare.h>
#include "DSWwraps.h"
#include <stdio.h>
#include <DPS/DPSScrollWP.h>
#undef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#undef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#undef ABS
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#undef CEIL
#define CEIL(x) ((int) ((float)((int)(x)) == (x) ? (x) : (x) + 1))
#define LEFT(r) ((r)[0])
#define RIGHT(r) ((r)[0] + (r)[2])
#define BOTTOM(r) ((r)[1])
#define TOP(r) ((r)[1] + (r)[3])
#define WIDTH(r) ((r)[2])
#define HEIGHT(r) ((r)[3])
#define DELTA .001
#define Offset(field) XtOffsetOf(DPSScrolledWindowRec, sw.field)
static float initScale = 1.0;
static XtResource resources[] = {
{XtNcontext, XtCContext, XtRDPSContext, sizeof(DPSContext),
Offset(context), XtRImmediate, (XtPointer) NULL},
{XtNareaWidth, XtCAreaWidth, XtRInt, sizeof(int),
Offset(area_width), XtRImmediate, (XtPointer) ((int) (8.5*72))},
{XtNareaHeight, XtCAreaHeight, XtRInt, sizeof(int),
Offset(area_height), XtRImmediate, (XtPointer) (11*72)},
{XtNscale, XtCScale, XtRFloat, sizeof(float),
Offset(scale), XtRFloat, (XtPointer) &initScale},
{XtNctm, XtCCtm, XtRFloatArray, sizeof(float *),
Offset(ctm_ptr), XtRImmediate, (XtPointer) NULL},
{XtNinvCtm, XtCInvCtm, XtRFloatArray, sizeof(float *),
Offset(inv_ctm_ptr), XtRImmediate, (XtPointer) NULL},
{XtNuseBackingPixmap, XtCUseBackingPixmap, XtRBoolean, sizeof(Boolean),
Offset(use_backing_pixmap), XtRImmediate, (XtPointer) True},
{XtNuseFeedbackPixmap, XtCUseFeedbackPixmap, XtRBoolean, sizeof(Boolean),
Offset(use_feedback_pixmap), XtRImmediate, (XtPointer) True},
{XtNbackingPixmap, XtCBackingPixmap, XtRPixmap, sizeof(Pixmap),
Offset(backing_pixmap), XtRImmediate, (XtPointer) None},
{XtNfeedbackPixmap, XtCFeedbackPixmap, XtRPixmap, sizeof(Pixmap),
Offset(feedback_pixmap), XtRImmediate, (XtPointer) None},
{XtNdocumentSizePixmaps, XtCDocumentSizePixmaps,
XtRBoolean, sizeof(Boolean),
Offset(document_size_pixmaps), XtRImmediate, (XtPointer) False},
{XtNwindowGState, XtCWindowGState, XtRDPSGState, sizeof(DPSGState),
Offset(window_gstate), XtRImmediate, (XtPointer) 0},
{XtNbackingGState, XtCBackingGState, XtRDPSGState, sizeof(DPSGState),
Offset(backing_gstate), XtRImmediate, (XtPointer) 0},
{XtNfeedbackGState, XtCFeedbackGState, XtRDPSGState, sizeof(DPSGState),
Offset(feedback_gstate), XtRImmediate, (XtPointer) 0},
{XtNdirtyAreas, XtCDirtyAreas, XtRFloatArray, sizeof(float *),
Offset(dirty_areas), XtRImmediate, (XtPointer) NULL},
{XtNnumDirtyAreas, XtCNumDirtyAreas, XtRShort, sizeof(short),
Offset(num_dirty_areas), XtRImmediate, (XtPointer) 0},
{XtNpixmapLimit, XtCPixmapLimit, XtRInt, sizeof(int),
Offset(pixmap_limit), XtRImmediate, (XtPointer) -1},
{XtNabsolutePixmapLimit, XtCAbsolutePixmapLimit, XtRInt, sizeof(int),
Offset(absolute_pixmap_limit), XtRImmediate, (XtPointer) 0},
{XtNwatchProgress, XtCWatchProgress, XtRBoolean, sizeof(Boolean),
Offset(watch_progress), XtRImmediate, (XtPointer) False},
{XtNwatchProgressDelay, XtCWatchProgressDelay, XtRInt, sizeof(int),
Offset(watch_progress_delay), XtRImmediate, (XtPointer) 1000},
{XtNminimalDrawing, XtCMinimalDrawing, XtRBoolean, sizeof(Boolean),
Offset(minimal_drawing), XtRImmediate, (XtPointer) False},
{XtNapplicationScrolling, XtCApplicationScrolling,
XtRBoolean, sizeof(Boolean),
Offset(application_scrolling), XtRImmediate, (XtPointer) False},
{XtNsetupCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
Offset(setup_callback), XtRCallback, (XtPointer) NULL},
{XtNexposeCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
Offset(expose_callback), XtRCallback, (XtPointer) NULL},
{XtNbackgroundCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
Offset(background_callback), XtRCallback, (XtPointer) NULL},
{XtNfeedbackCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
Offset(feedback_callback), XtRCallback, (XtPointer) NULL},
{XtNresizeCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
Offset(resize_callback), XtRCallback, (XtPointer) NULL},
};
static Boolean GiveFeedbackPixmap(Widget w, Pixmap p, int width, int height, int depth, Screen *screen);
static Boolean SetValues(Widget old, Widget req, Widget new, ArgList args, Cardinal *num_args);
static Boolean TakeFeedbackPixmap(Widget w, Pixmap *p, int *width, int *height, int *depth, Screen **screen);
static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *desired, XtWidgetGeometry *allowed);
static XtGeometryResult QueryGeometry(Widget w, XtWidgetGeometry *desired, XtWidgetGeometry *allowed);
static void AbortPendingDrawing(Widget w);
static void AddExposureToPending(DPSScrolledWindowWidget dsw, XExposeEvent *ev);
static void AddRectsToDirtyArea(DPSScrolledWindowWidget dsw, float *newRect, int n);
static void AddRectsToPending(DPSScrolledWindowWidget dsw, int *newRect, int n);
static void AddToDirtyArea(Widget w, float *rect, long n);
static void AddUserSpaceRectsToPending(DPSScrolledWindowWidget dsw, float *newRect, int n);
static void CallFeedbackCallback(DPSScrolledWindowWidget dsw, float *r, int n);
static void CheckFeedbackPixmap(DPSScrolledWindowWidget dsw);
static void ClassPartInitialize(WidgetClass widget_class);
static void ConvertPSToX(Widget w, double psX, double psY, int *xX, int *xY);
static void ConvertToOrigPS(DPSScrolledWindowWidget dsw, int xX, int xY, float *psX, float *psY);
static void ConvertToPS(DPSScrolledWindowWidget dsw, float xX, float xY, float *psX, float *psY);
static void ConvertToX(DPSScrolledWindowWidget dsw, float psX, float psY, int *xX, int *xY);
static void ConvertXToPS(Widget w, long xX, long xY, float *psX, float *psY);
static void CopyRectsToCurrentDrawing(DPSScrolledWindowWidget dsw, float *newRect, int n);
static void CopyRectsToDirtyArea(DPSScrolledWindowWidget dsw, float *newRect, int n);
static void CopyToFeedbackPixmap(DPSScrolledWindowWidget dsw, float *rects, int n);
static void Destroy(Widget widget);
static void DrawingAreaExpose(Widget w, XtPointer clientData, XtPointer callData);
static void DrawingAreaGraphicsExpose(Widget w, XtPointer clientData, XEvent *event, Boolean *goOn);
static void EndFeedbackDrawing(Widget w, int restore);
static void FinishDrawing(DPSScrolledWindowWidget dsw);
static void FinishPendingDrawing(Widget w);
static void GetDrawingInfo(Widget w, DSWDrawableType *type, Drawable *drawable, DPSGState *gstate, DPSContext *context);
static void GetScrollInfo(Widget w, int *h_value, int *h_size, int *h_max, int *v_value, int *v_size, int *v_max);
static void HScrollCallback(Widget w, XtPointer clientData, XtPointer callData);
static void Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args);
static void Realize(Widget w, XtValueMask *mask, XSetWindowAttributes *attr);
static void Resize(Widget w);
static void ScrollBy(Widget w, long dx, long dy);
static void ScrollMoved(DPSScrolledWindowWidget dsw);
static void ScrollPoint(Widget w, double psX, double psY, long xX, long xY);
static void ScrollTo(Widget w, long x, long y);
static void SetFeedbackDirtyArea(Widget w, float *rects, int count, XtPointer continue_feedback_data);
static void SetScale(Widget w, double scale, long fixedX, long fixedY);
static void SetScaleAndScroll(Widget w, double scale, double psX, double psY, long xX, long xY);
static void StartFeedbackDrawing(Widget w, XtPointer start_feedback_data);
static void UpdateDrawing(Widget w, float *rects, int count);
static void VScrollCallback(Widget w, XtPointer clientData, XtPointer callData);
DPSScrolledWindowClassRec dpsScrolledWindowClassRec = {
{
(WidgetClass) &xmManagerClassRec,
"DPSScrolledWindow",
sizeof(DPSScrolledWindowRec),
NULL,
ClassPartInitialize,
False,
Initialize,
NULL,
Realize,
NULL,
0,
resources,
XtNumber(resources),
NULLQUARK,
True,
XtExposeCompressMultiple,
True,
False,
Destroy,
Resize,
NULL,
SetValues,
NULL,
XtInheritSetValuesAlmost,
NULL,
NULL,
XtVersion,
NULL,
NULL,
QueryGeometry,
NULL,
NULL,
},
{
GeometryManager,
NULL,
XtInheritInsertChild,
XtInheritDeleteChild,
NULL,
},
{
NULL,
0,
0,
NULL,
NULL,
NULL,
NULL,
},
{
XtInheritTranslations,
NULL,
0,
NULL,
0,
XmInheritParentProcess,
NULL,
},
{
SetScale,
ScrollPoint,
ScrollBy,
ScrollTo,
SetScaleAndScroll,
ConvertXToPS,
ConvertPSToX,
AddToDirtyArea,
TakeFeedbackPixmap,
GiveFeedbackPixmap,
StartFeedbackDrawing,
EndFeedbackDrawing,
SetFeedbackDirtyArea,
FinishPendingDrawing,
AbortPendingDrawing,
GetDrawingInfo,
UpdateDrawing,
GetScrollInfo,
NULL,
}
};
WidgetClass dpsScrolledWindowWidgetClass =
(WidgetClass) &dpsScrolledWindowClassRec;
static void PrintRectList(float *r, short num_r)
{
int i;
for (i = 0; i < num_r; i++) {
printf("Rectangle %d: ", i);
printf("X %g Y %g W %g H %g\n", r[0], r[1], r[2], r[3]);
r += 4;
}
}
static void GrowRectList(
float **r,
short *r_size,
short num_r,
int n, int min_grow)
{
if (*r_size < num_r + n) {
if (min_grow > 1 && num_r + n - *r_size < min_grow) {
*r_size += min_grow;
} else *r_size = num_r + n;
*r = (float *) XtRealloc((char *) *r, *r_size * 4 * sizeof(float));
}
}
static void GrowIntRectList(
int **r,
short *r_size,
short num_r,
int n, int min_grow)
{
if (*r_size < num_r + n) {
if (min_grow > 1 && num_r + n - *r_size < min_grow) {
*r_size += min_grow;
} else *r_size = num_r + n;
*r = (int *) XtRealloc((char *) *r, *r_size * 4 * sizeof(int));
}
}
static Boolean Intersects(float *r1, float *r2)
{
if (RIGHT(r1) <= LEFT(r2)) return False;
if (RIGHT(r2) <= LEFT(r1)) return False;
if (TOP(r1) <= BOTTOM(r2)) return False;
if (TOP(r2) <= BOTTOM(r1)) return False;
return True;
}
static int Subtract(float *src, float *sub, float *dst)
{
int n = 0;
if (BOTTOM(sub) > BOTTOM(src)) {
LEFT(dst) = LEFT(src);
BOTTOM(dst) = BOTTOM(src);
WIDTH(dst) = WIDTH(src);
HEIGHT(dst) = BOTTOM(sub) - BOTTOM(src);
n++;
dst += 4;
}
if (LEFT(sub) > LEFT(src)) {
LEFT(dst) = LEFT(src);
BOTTOM(dst) = MAX(BOTTOM(src), BOTTOM(sub));
WIDTH(dst) = LEFT(sub) - LEFT(src);
HEIGHT(dst) = MIN(TOP(src), TOP(sub)) - BOTTOM(dst);
n++;
dst += 4;
}
if (RIGHT(sub) < RIGHT(src)) {
LEFT(dst) = RIGHT(sub);
BOTTOM(dst) = MAX(BOTTOM(src), BOTTOM(sub));
WIDTH(dst) = RIGHT(src) - RIGHT(sub);
HEIGHT(dst) = MIN(TOP(src), TOP(sub)) - BOTTOM(dst);
n++;
dst += 4;
}
if (TOP(sub) < TOP(src)) {
LEFT(dst) = LEFT(src);
BOTTOM(dst) = TOP(sub);
WIDTH(dst) = WIDTH(src);
HEIGHT(dst) = TOP(src) - TOP(sub);
n++;
dst += 4;
}
return n;
}
static void Copy(float *src, float *dst)
{
LEFT(dst) = LEFT(src);
BOTTOM(dst) = BOTTOM(src);
WIDTH(dst) = WIDTH(src);
HEIGHT(dst) = HEIGHT(src);
}
static void Intersection(float *r1, float *r2, float *dst)
{
LEFT(dst) = MAX(LEFT(r1), LEFT(r2));
BOTTOM(dst) = MAX(BOTTOM(r1), BOTTOM(r2));
WIDTH(dst) = MIN(RIGHT(r1), RIGHT(r2)) - LEFT(dst);
HEIGHT(dst) = MIN(TOP(r1), TOP(r2)) - BOTTOM(dst);
}
static float *rbuf = NULL;
static short rbuf_size = 0;
#define GROW_BUF 10
static void SubtractRects(
float **src,
short *src_size,
short *num_src,
float *sub,
int num_sub)
{
short num_rbuf;
float *r;
int i;
while (num_sub > 0) {
num_rbuf = 0;
for (r = *src, i = 0; i < *num_src; r += 4, i++) {
if (Intersects(r, sub)) {
GrowRectList(&rbuf, &rbuf_size, num_rbuf, 4, GROW_BUF);
num_rbuf += Subtract(r, sub, rbuf + (num_rbuf*4));
} else {
GrowRectList(&rbuf, &rbuf_size, num_rbuf, 1, GROW_BUF);
Copy(r, rbuf + (num_rbuf*4));
num_rbuf++;
}
}
GrowRectList(src, src_size, 0, num_rbuf, 1);
for (i = 0; i < num_rbuf * 4; i++) (*src)[i] = rbuf[i];
*num_src = num_rbuf;
if (*num_src == 0) return;
num_sub--;
sub += 4;
}
}
static void IntersectRects(
float **r1,
short *r1_size,
short *num_r1,
float *r2,
int num_r2)
{
short num_rbuf = 0;
float *r;
int i;
while (num_r2 > 0) {
for (r = *r1, i = 0; i < *num_r1; r += 4, i++) {
if (Intersects(r, r2)) {
GrowRectList(&rbuf, &rbuf_size, num_rbuf, 1, GROW_BUF);
Intersection(r, r2, rbuf + (num_rbuf*4));
num_rbuf++;
}
}
num_r2--;
r2 += 4;
}
GrowRectList(r1, r1_size, 0, num_rbuf, 1);
for (i = 0; i < num_rbuf * 4; i++) (*r1)[i] = rbuf[i];
*num_r1 = num_rbuf;
}
static void SimplifyRects(float *rect, short *num)
{
int i, j, k;
float *r, *r1;
i = 0;
while (i < *num) {
r = rect + (i * 4);
if (WIDTH(r) == 0 || HEIGHT(r) == 0) {
for (k = 4*(i+1); k < *num * 4; k++) rect[k-4] = rect[k];
(*num)--;
goto LOOPEND;
}
j = i+1;
while (j < *num) {
r1 = rect + (j * 4);
if (TOP(r1) <= TOP(r) && BOTTOM(r1) >= BOTTOM(r) &&
LEFT(r1) >= LEFT(r) && RIGHT(r1) <= RIGHT(r)) {
for (k = 4*(j+1); k < *num * 4; k++) rect[k-4] = rect[k];
(*num)--;
} else if (TOP(r) <= TOP(r1) && BOTTOM(r) >= BOTTOM(r1) &&
LEFT(r) >= LEFT(r1) && RIGHT(r) <= RIGHT(r1)) {
for (k = 4*(i+1); k < *num * 4; k++) rect[k-4] = rect[k];
(*num)--;
goto LOOPEND;
} else j++;
}
i++;
LOOPEND:;
}
}
static void ComputeOffsets(DPSScrolledWindowWidget dsw, int *dx, int *dy)
{
if (dsw->sw.doing_feedback && dsw->sw.feedback_pixmap != None) {
*dx = *dy = 0;
} else {
if (dsw->sw.pixmap_width == dsw->sw.drawing_area->core.width) *dx = 0;
else *dx = -dsw->sw.origin_x;
if (dsw->sw.pixmap_height == dsw->sw.drawing_area->core.height) *dy = 0;
else *dy = CEIL(dsw->sw.drawing_height) - dsw->sw.origin_y;
}
}
static void ClassPartInitialize(WidgetClass widget_class)
{
register DPSScrolledWindowWidgetClass wc =
(DPSScrolledWindowWidgetClass) widget_class;
DPSScrolledWindowWidgetClass super =
(DPSScrolledWindowWidgetClass) wc->core_class.superclass;
if (wc->sw_class.set_scale == InheritSetScale) {
wc->sw_class.set_scale = super->sw_class.set_scale;
}
if (wc->sw_class.scroll_point == InheritScrollPoint) {
wc->sw_class.scroll_point = super->sw_class.scroll_point;
}
if (wc->sw_class.scroll_by == InheritScrollBy) {
wc->sw_class.scroll_by = super->sw_class.scroll_by;
}
if (wc->sw_class.scroll_to == InheritScrollTo) {
wc->sw_class.scroll_to = super->sw_class.scroll_to;
}
if (wc->sw_class.set_scale_and_scroll == InheritSetScaleAndScroll) {
wc->sw_class.set_scale_and_scroll =
super->sw_class.set_scale_and_scroll;
}
if (wc->sw_class.convert_x_to_ps == InheritConvertXToPS) {
wc->sw_class.convert_x_to_ps = super->sw_class.convert_x_to_ps;
}
if (wc->sw_class.convert_ps_to_x == InheritConvertPSToX) {
wc->sw_class.convert_ps_to_x = super->sw_class.convert_ps_to_x;
}
if (wc->sw_class.add_to_dirty_area == InheritAddToDirtyArea) {
wc->sw_class.add_to_dirty_area = super->sw_class.add_to_dirty_area;
}
if (wc->sw_class.take_feedback_pixmap == InheritTakeFeedbackPixmap) {
wc->sw_class.take_feedback_pixmap =
super->sw_class.take_feedback_pixmap;
}
if (wc->sw_class.give_feedback_pixmap == InheritGiveFeedbackPixmap) {
wc->sw_class.give_feedback_pixmap =
super->sw_class.give_feedback_pixmap;
}
if (wc->sw_class.start_feedback_drawing == InheritStartFeedbackDrawing) {
wc->sw_class.start_feedback_drawing =
super->sw_class.start_feedback_drawing;
}
if (wc->sw_class.end_feedback_drawing == InheritEndFeedbackDrawing) {
wc->sw_class.end_feedback_drawing =
super->sw_class.end_feedback_drawing;
}
if (wc->sw_class.set_feedback_dirty_area == InheritSetFeedbackDirtyArea) {
wc->sw_class.set_feedback_dirty_area =
super->sw_class.set_feedback_dirty_area;
}
if (wc->sw_class.finish_pending_drawing == InheritFinishPendingDrawing) {
wc->sw_class.finish_pending_drawing =
super->sw_class.finish_pending_drawing;
}
if (wc->sw_class.abort_pending_drawing == InheritAbortPendingDrawing) {
wc->sw_class.abort_pending_drawing =
super->sw_class.abort_pending_drawing;
}
if (wc->sw_class.get_drawing_info == InheritGetDrawingInfo) {
wc->sw_class.get_drawing_info = super->sw_class.get_drawing_info;
}
if (wc->sw_class.update_drawing == InheritUpdateDrawing) {
wc->sw_class.update_drawing = super->sw_class.update_drawing;
}
if (wc->sw_class.get_scroll_info == InheritGetScrollInfo) {
wc->sw_class.get_scroll_info = super->sw_class.get_scroll_info;
}
}
static void CreateChildren(DPSScrolledWindowWidget dsw)
{
Widget w;
w = dsw->sw.scrolled_window =
XtVaCreateManagedWidget("scrolledWindow",
xmScrolledWindowWidgetClass,
(Widget) dsw,
XtNwidth, dsw->core.width,
XtNheight, dsw->core.height,
XmNscrollingPolicy, XmAPPLICATION_DEFINED,
NULL);
dsw->sw.h_scroll =
XtVaCreateManagedWidget("horizontalScrollBar",
xmScrollBarWidgetClass, w,
XmNorientation, XmHORIZONTAL,
NULL);
XtAddCallback(dsw->sw.h_scroll, XmNvalueChangedCallback, HScrollCallback,
(XtPointer) dsw);
XtAddCallback(dsw->sw.h_scroll, XmNdragCallback, HScrollCallback,
(XtPointer) dsw);
dsw->sw.v_scroll =
XtVaCreateManagedWidget("verticalScrollBar",
xmScrollBarWidgetClass, w,
XmNorientation, XmVERTICAL,
NULL);
XtAddCallback(dsw->sw.v_scroll, XmNvalueChangedCallback, VScrollCallback,
(XtPointer) dsw);
XtAddCallback(dsw->sw.v_scroll, XmNdragCallback, VScrollCallback,
(XtPointer) dsw);
dsw->sw.drawing_area =
XtVaCreateManagedWidget("drawingArea",
xmDrawingAreaWidgetClass, w, NULL);
XtAddCallback(dsw->sw.drawing_area, XtNexposeCallback, DrawingAreaExpose,
(XtPointer) dsw);
XtAddRawEventHandler(dsw->sw.drawing_area, 0, True,
DrawingAreaGraphicsExpose, (XtPointer) dsw);
XmScrolledWindowSetAreas(w, dsw->sw.h_scroll, dsw->sw.v_scroll,
dsw->sw.drawing_area);
}
static void Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) new;
XGCValues gcVal;
Bool inited;
if (dsw->sw.area_width <= 0) dsw->sw.area_width = 8.5*72;
if (dsw->sw.area_height <= 0) dsw->sw.area_height = 11*72;
if (dsw->sw.scale <= 0) dsw->sw.scale = 1.0;
dsw->sw.ctm_ptr = dsw->sw.ctm;
dsw->sw.inv_ctm_ptr = dsw->sw.inv_ctm;
dsw->sw.backing_pixmap = None;
dsw->sw.feedback_pixmap = None;
dsw->sw.window_gstate = 0;
dsw->sw.backing_gstate = 0;
dsw->sw.feedback_gstate = 0;
dsw->sw.scrolling = False;
dsw->sw.num_pending_expose = dsw->sw.pending_expose_size = 0;
dsw->sw.pending_expose = NULL;
dsw->sw.num_pending_dirty = dsw->sw.pending_dirty_size = 0;
dsw->sw.pending_dirty = NULL;
dsw->sw.num_current_drawing = dsw->sw.current_drawing_size = 0;
dsw->sw.current_drawing = NULL;
dsw->sw.num_prev_dirty_areas = dsw->sw.prev_dirty_areas_size = 0;
dsw->sw.prev_dirty_areas = NULL;
dsw->sw.drawing_stage = DSWStart;
dsw->sw.work = 0;
dsw->sw.big_pixmap = False;
dsw->sw.dirty_areas_size = 0;
dsw->sw.dirty_areas = NULL;
GrowRectList(&dsw->sw.dirty_areas, &dsw->sw.dirty_areas_size, 0, 1, 1);
dsw->sw.num_dirty_areas = 1;
LEFT(dsw->sw.dirty_areas) = 0.0;
BOTTOM(dsw->sw.dirty_areas) = 0.0;
WIDTH(dsw->sw.dirty_areas) = dsw->sw.area_width;
HEIGHT(dsw->sw.dirty_areas) = dsw->sw.area_height;
dsw->sw.num_scratch = dsw->sw.scratch_size = 0;
dsw->sw.scratch = NULL;
GrowRectList(&dsw->sw.scratch, &dsw->sw.scratch_size, 0, 1, 1);
if (dsw->sw.context == NULL) {
dsw->sw.context = XDPSGetSharedContext(XtDisplay(dsw));
}
if (dsw->sw.watch_progress &&
XDPSSetEventDelivery(XtDisplay(dsw), dps_event_query) !=
dps_event_pass_through) dsw->sw.watch_progress = False;
if (_XDPSTestComponentInitialized(dsw->sw.context,
dps_init_bit_dsw, &inited) ==
dps_status_unregistered_context) {
XDPSRegisterContext(dsw->sw.context, False);
}
dsw->sw.use_saved_scroll = False;
dsw->sw.context_inited = False;
dsw->sw.doing_feedback = False;
dsw->sw.feedback_displayed = False;
CreateChildren(dsw);
dsw->sw.ge_gc = XtGetGC(dsw->sw.drawing_area, 0, (XGCValues *) NULL);
gcVal.graphics_exposures = False;
dsw->sw.no_ge_gc = XtGetGC(dsw->sw.drawing_area, GCGraphicsExposures,
&gcVal);
}
static void Destroy(Widget widget)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) widget;
if (dsw->sw.backing_pixmap != None) {
XFreePixmap(XtDisplay(dsw), dsw->sw.backing_pixmap);
}
if (dsw->sw.feedback_pixmap != None) {
XFreePixmap(XtDisplay(dsw), dsw->sw.feedback_pixmap);
}
if (dsw->sw.window_gstate != 0) {
XDPSFreeContextGState(dsw->sw.context, dsw->sw.window_gstate);
}
if (dsw->sw.backing_gstate != 0) {
XDPSFreeContextGState(dsw->sw.context, dsw->sw.backing_gstate);
}
if (dsw->sw.feedback_gstate != 0) {
XDPSFreeContextGState(dsw->sw.context, dsw->sw.feedback_gstate);
}
if (dsw->sw.pending_expose != NULL) {
XtFree((char *) dsw->sw.pending_expose);
}
if (dsw->sw.current_drawing != NULL) {
XtFree((char *) dsw->sw.current_drawing);
}
if (dsw->sw.prev_dirty_areas != NULL) {
XtFree((char *) dsw->sw.prev_dirty_areas);
}
if (dsw->sw.dirty_areas != NULL) XtFree((char *) dsw->sw.dirty_areas);
if (dsw->sw.pending_dirty != NULL) XtFree((char *) dsw->sw.pending_dirty);
if (dsw->sw.scratch != NULL) XtFree((char *) dsw->sw.scratch);
XtReleaseGC(widget, dsw->sw.ge_gc);
XtReleaseGC(widget, dsw->sw.no_ge_gc);
}
static void SetOriginAndGetTransform(DPSScrolledWindowWidget dsw)
{
float psX, psY;
ConvertToOrigPS(dsw, dsw->sw.origin_x, dsw->sw.origin_y, &psX, &psY);
_DPSSWSetMatrixAndGetTransform(dsw->sw.context, psX, psY, dsw->sw.scale,
dsw->sw.origin_x, dsw->sw.origin_y,
dsw->sw.ctm, dsw->sw.inv_ctm,
&dsw->sw.x_offset, &dsw->sw.y_offset);
}
static void SetPixmapOrigin(DPSScrolledWindowWidget dsw)
{
float psX, psY;
ConvertToOrigPS(dsw, dsw->sw.origin_x, dsw->sw.origin_y, &psX, &psY);
_DPSSWSetMatrix(dsw->sw.context, psX, psY, dsw->sw.scale,
dsw->sw.origin_x, dsw->sw.origin_y);
}
static void SetPixmapOffset(DPSScrolledWindowWidget dsw)
{
int ox, oy;
if (dsw->sw.pixmap_width <= (int) dsw->sw.drawing_area->core.width) ox = 0;
else ox = -dsw->sw.origin_x;
if (dsw->sw.pixmap_height <= (int) dsw->sw.drawing_area->core.height) {
oy = dsw->sw.drawing_area->core.height;
} else oy = dsw->sw.pixmap_height - dsw->sw.origin_y +
dsw->sw.drawing_area->core.height;
DPSsetXoffset(dsw->sw.context, ox, oy);
}
static Boolean pixmapError;
static int (*oldHandler)(Display *, XErrorEvent *);
static int PixmapHandler(Display *dpy, XErrorEvent *error)
{
if (error->error_code == BadAlloc &&
error->request_code == X_CreatePixmap) {
pixmapError = True;
return 0;
} else return (*oldHandler) (dpy, error);
}
static Pixmap AllocPixmap(DPSScrolledWindowWidget dsw, unsigned w, unsigned h)
{
Pixmap p;
unsigned int dBytes;
Widget wid = dsw->sw.drawing_area;
unsigned area = (w * h);
if (dsw->sw.pixmap_limit > 0) {
if (area > (unsigned)dsw->sw.pixmap_limit) return None;
} else if (dsw->sw.pixmap_limit < 0
&& area > (unsigned)(dsw->sw.unscaled_width * dsw->sw.unscaled_height)
&& area > (unsigned)(wid->core.width * wid->core.height)) return None;
if (dsw->sw.absolute_pixmap_limit > 0) {
dBytes = (wid->core.depth + 7) / 8;
if (area * dBytes > (unsigned)dsw->sw.absolute_pixmap_limit * 1024) {
return None;
}
}
XSync(XtDisplay(dsw), False);
oldHandler = XSetErrorHandler(PixmapHandler);
pixmapError = False;
p = XCreatePixmap(XtDisplay(dsw), XtWindow(dsw->sw.drawing_area), w, h,
wid->core.depth);
XSync(XtDisplay(dsw), False);
(void) XSetErrorHandler(oldHandler);
if (pixmapError) return None;
else return p;
}
static void CreateBackingPixmap(DPSScrolledWindowWidget dsw)
{
Pixmap p;
if (dsw->sw.document_size_pixmaps) {
dsw->sw.pixmap_width =
MAX(CEIL(dsw->sw.drawing_width),
(int) dsw->sw.drawing_area->core.width);
dsw->sw.pixmap_height =
MAX(CEIL(dsw->sw.drawing_height),
(int) dsw->sw.drawing_area->core.height);
p = dsw->sw.backing_pixmap =
AllocPixmap(dsw, dsw->sw.pixmap_width, dsw->sw.pixmap_height);
if (p != None) {
dsw->sw.big_pixmap =
dsw->sw.pixmap_width >
(int) dsw->sw.drawing_area->core.width ||
dsw->sw.pixmap_height >
(int) dsw->sw.drawing_area->core.height;
return;
}
}
dsw->sw.big_pixmap = False;
dsw->sw.pixmap_width = dsw->sw.drawing_area->core.width;
dsw->sw.pixmap_height = dsw->sw.drawing_area->core.height;
p = dsw->sw.backing_pixmap =
AllocPixmap(dsw, dsw->sw.pixmap_width, dsw->sw.pixmap_height);
if (p == None) dsw->sw.pixmap_width = dsw->sw.pixmap_height = 0;
}
static void FreeBackingPixmap(DPSScrolledWindowWidget dsw)
{
if (dsw->sw.backing_pixmap == None) return;
XFreePixmap(XtDisplay(dsw), dsw->sw.backing_pixmap);
dsw->sw.backing_pixmap = None;
dsw->sw.big_pixmap = False;
dsw->sw.pixmap_width = dsw->sw.pixmap_height = 0;
XDPSFreeContextGState(dsw->sw.context, dsw->sw.backing_gstate);
}
static void SetDrawingAreaPosition(
DPSScrolledWindowWidget dsw,
float ix,
float iy,
int vx,
int vy,
Boolean setOrigin)
{
int xoff, yoff;
int hSize, vSize;
float scrollX, scrollY;
ix *= dsw->sw.drawing_width / dsw->sw.area_width;
iy *= dsw->sw.drawing_height / dsw->sw.area_height;
if ((int)dsw->sw.drawing_area->core.width >= CEIL(dsw->sw.drawing_width)) {
xoff = ((int) dsw->sw.drawing_area->core.width -
CEIL(dsw->sw.drawing_width))
/ 2.0;
scrollX = 0;
hSize = CEIL(dsw->sw.drawing_width);
} else {
scrollX = ix - vx;
scrollX = MAX(scrollX, 0);
scrollX = MIN(scrollX, CEIL(dsw->sw.drawing_width) -
(int) dsw->sw.drawing_area->core.width);
hSize = dsw->sw.drawing_area->core.width;
xoff = -(int) (scrollX + 0.5);
}
if ((int) dsw->sw.drawing_area->core.height >=
CEIL(dsw->sw.drawing_height)) {
yoff = ((int) dsw->sw.drawing_area->core.height -
CEIL(dsw->sw.drawing_height)) / 2.0;
scrollY = CEIL(dsw->sw.drawing_height) -
(int) dsw->sw.drawing_area->core.height;
vSize = CEIL(dsw->sw.drawing_height);
} else {
scrollY = iy + vy - (int) dsw->sw.drawing_area->core.height;
scrollY = MAX(scrollY, 0);
scrollY = MIN(scrollY, CEIL(dsw->sw.drawing_height) -
(int) dsw->sw.drawing_area->core.height);
vSize = dsw->sw.drawing_area->core.height;
yoff = -(int) (scrollY + 0.5);
}
dsw->sw.scroll_x = (int) (scrollX + 0.5);
dsw->sw.scroll_y = (int) (CEIL(dsw->sw.drawing_height) -
(int) dsw->sw.drawing_area->core.height -
scrollY + 0.5);
yoff = dsw->sw.drawing_area->core.height - yoff;
dsw->sw.scroll_h_value = dsw->sw.scroll_x;
dsw->sw.scroll_h_size = hSize;
dsw->sw.scroll_h_max = CEIL(dsw->sw.drawing_width);
dsw->sw.scroll_v_value = dsw->sw.scroll_y;
dsw->sw.scroll_v_size = vSize;
dsw->sw.scroll_v_max = CEIL(dsw->sw.drawing_height);
if (!dsw->sw.application_scrolling) {
XtVaSetValues(dsw->sw.h_scroll, XmNmaximum, dsw->sw.scroll_h_max,
XmNvalue, dsw->sw.scroll_x, XmNsliderSize, hSize, NULL);
XtVaSetValues(dsw->sw.v_scroll, XmNmaximum, dsw->sw.scroll_v_max,
XmNvalue, dsw->sw.scroll_y, XmNsliderSize, vSize, NULL);
}
if (setOrigin) {
dsw->sw.origin_x = xoff;
dsw->sw.origin_y = yoff;
}
}
static void DrawBackground(
DPSScrolledWindowWidget dsw,
DSWDrawableType which)
{
DSWExposeCallbackRec e;
e.type = which;
e.directions = DSWFinish;
e.results = DSWUndefined;
e.first = True;
e.background = True;
if (which == DSWBackingPixmap) {
e.drawable = dsw->sw.backing_pixmap;
e.gstate = dsw->sw.backing_gstate;
} else if (which == DSWFeedbackPixmap) {
e.drawable = dsw->sw.feedback_pixmap;
e.gstate = dsw->sw.feedback_gstate;
} else {
e.drawable = XtWindow(dsw->sw.drawing_area);
e.gstate = dsw->sw.window_gstate;
}
e.context = dsw->sw.context;
SimplifyRects(dsw->sw.current_drawing, &dsw->sw.num_current_drawing);
XDPSSetContextGState(dsw->sw.context, e.gstate);
_DPSSWSetRectViewClip(dsw->sw.context, dsw->sw.current_drawing,
dsw->sw.num_current_drawing * 4);
e.rects = dsw->sw.current_drawing;
e.rect_count = dsw->sw.num_current_drawing;
do {
XtCallCallbackList((Widget) dsw, dsw->sw.background_callback,
(XtPointer) &e);
if (e.results == DSWUndefined) {
if (XtHasCallbacks((Widget) dsw, XtNbackgroundCallback) !=
XtCallbackHasNone) {
XtAppWarningMsg(XtWidgetToApplicationContext((Widget) dsw),
"returnError", "backgroundCallback",
"DPSScrollError",
"Background callback did not set result field",
(String *) NULL, (Cardinal *) NULL);
}
e.results = DSWFinished;
}
} while (e.results != DSWFinished);
DPSinitviewclip(dsw->sw.context);
}
static void ClipToDrawingSize(
DPSScrolledWindowWidget dsw,
DSWDrawableType which)
{
int i;
float r[4];
if (CEIL(dsw->sw.drawing_width) >= (int) dsw->sw.drawing_area->core.width &&
CEIL(dsw->sw.drawing_height) >= (int) dsw->sw.drawing_area->core.height) return;
GrowRectList(&dsw->sw.scratch, &dsw->sw.scratch_size, 0,
dsw->sw.num_current_drawing, 1);
dsw->sw.num_scratch = dsw->sw.num_current_drawing;
for (i = 0; i < dsw->sw.num_current_drawing * 4; i++) {
dsw->sw.scratch[i] = dsw->sw.current_drawing[i];
}
ConvertToPS(dsw, dsw->sw.origin_x + DELTA, dsw->sw.origin_y - DELTA,
r, r+1);
ConvertToPS(dsw, dsw->sw.origin_x + CEIL(dsw->sw.drawing_width) - DELTA,
dsw->sw.origin_y - CEIL(dsw->sw.drawing_height) + DELTA,
r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
SubtractRects(&dsw->sw.current_drawing, &dsw->sw.current_drawing_size,
&dsw->sw.num_current_drawing, r, 1);
if (dsw->sw.num_current_drawing != 0) {
DrawBackground(dsw, which);
IntersectRects(&dsw->sw.scratch, &dsw->sw.scratch_size,
&dsw->sw.num_scratch, r, 1);
if (dsw->sw.num_scratch == 0) DPSWaitContext(dsw->sw.context);
}
GrowRectList(&dsw->sw.current_drawing, &dsw->sw.current_drawing_size, 0,
dsw->sw.num_scratch, 1);
dsw->sw.num_current_drawing = dsw->sw.num_scratch;
for (i = 0; i < dsw->sw.num_scratch * 4; i++) {
dsw->sw.current_drawing[i] = dsw->sw.scratch[i];
}
}
static DSWResults ClipAndDraw(
DPSScrolledWindowWidget dsw,
DSWDrawableType which,
DSWDirections howMuch,
Boolean first)
{
DSWExposeCallbackRec e;
e.type = which;
e.directions = howMuch;
e.results = DSWUndefined;
e.first = first;
e.background = False;
if (which == DSWBackingPixmap) {
e.drawable = dsw->sw.backing_pixmap;
e.gstate = dsw->sw.backing_gstate;
} else if (which == DSWFeedbackPixmap) {
e.drawable = dsw->sw.feedback_pixmap;
e.gstate = dsw->sw.feedback_gstate;
} else {
e.drawable = XtWindow(dsw->sw.drawing_area);
e.gstate = dsw->sw.window_gstate;
}
e.context = dsw->sw.context;
if (first) {
XDPSSetContextGState(dsw->sw.context, e.gstate);
if (howMuch != DSWAbort) {
ClipToDrawingSize(dsw, which);
SimplifyRects(dsw->sw.current_drawing,
&dsw->sw.num_current_drawing);
if (dsw->sw.num_current_drawing == 0) return DSWFinished;
_DPSSWSetRectViewClip(dsw->sw.context, dsw->sw.current_drawing,
dsw->sw.num_current_drawing * 4);
}
}
e.rects = dsw->sw.current_drawing;
e.rect_count = dsw->sw.num_current_drawing;
do {
XtCallCallbackList((Widget) dsw, dsw->sw.expose_callback,
(XtPointer) &e);
if (e.results == DSWUndefined) {
if (XtHasCallbacks((Widget) dsw,
XtNexposeCallback) != XtCallbackHasNone) {
XtAppWarningMsg(XtWidgetToApplicationContext((Widget) dsw),
"returnError", "exposeCallback",
"DPSScrollError",
"Expose callback did not set result field",
(String *) NULL, (Cardinal *) NULL);
}
e.results = DSWFinished;
}
} while ((e.results != DSWFinished && howMuch == DSWFinish) ||
(e.results != DSWFinished && e.results != DSWAborted &&
howMuch == DSWAbortOrFinish) ||
(e.results != DSWAborted && howMuch == DSWAbort));
if (e.results == DSWFinished) {
DPSinitviewclip(dsw->sw.context);
DPSWaitContext(dsw->sw.context);
}
return e.results;
}
static void SplitExposeEvent(
DPSScrolledWindowWidget dsw,
XExposeEvent *ev)
{
float *r;
float llx, lly, urx, ury;
int xr[4];
int i;
int dx, dy;
ComputeOffsets(dsw, &dx, &dy);
dsw->sw.num_scratch = 1;
r = dsw->sw.scratch;
ConvertToPS(dsw, ev->x + DELTA, ev->y + ev->height - DELTA, &llx, &lly);
ConvertToPS(dsw, ev->x + ev->width - DELTA, ev->y + DELTA, &urx, &ury);
LEFT(r) = llx;
BOTTOM(r) = lly;
WIDTH(r) = urx - llx;
HEIGHT(r) = ury - lly;
SubtractRects(&dsw->sw.scratch, &dsw->sw.scratch_size,
&dsw->sw.num_scratch,
dsw->sw.dirty_areas, dsw->sw.num_dirty_areas);
for (i = 0; i < dsw->sw.num_scratch; i++) {
r = dsw->sw.scratch + 4*i;
ConvertToX(dsw, LEFT(r), TOP(r), xr, xr+1);
ConvertToX(dsw, RIGHT(r), BOTTOM(r), xr+2, xr+3);
xr[2] -= xr[0];
xr[3] -= xr[1];
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area), dsw->sw.no_ge_gc,
xr[0] + dx, xr[1] + dy, xr[2], xr[3], xr[0], xr[1]);
}
dsw->sw.num_scratch = 1;
r = dsw->sw.scratch;
LEFT(r) = llx;
BOTTOM(r) = lly;
WIDTH(r) = urx - llx;
HEIGHT(r) = ury - lly;
IntersectRects(&dsw->sw.scratch, &dsw->sw.scratch_size,
&dsw->sw.num_scratch,
dsw->sw.dirty_areas, dsw->sw.num_dirty_areas);
AddUserSpaceRectsToPending(dsw, dsw->sw.scratch, dsw->sw.num_scratch);
}
static Bool CheckWatchProgressEvent(
Display *dpy,
XEvent *e,
char *arg)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) arg;
return (e->xany.window == dsw->sw.backing_pixmap &&
(e->type == GraphicsExpose || e->type == NoExpose)) ||
(e->xany.window == XtWindow(dsw->sw.drawing_area) &&
e->type == Expose);
}
static void CopyWindowToBackingPixmap(
DPSScrolledWindowWidget dsw)
{
int llx, lly, urx, ury;
XEvent e;
XExposeEvent *ev = (XExposeEvent *) &e;
int i;
float *r;
int copies = 0;
int dx, dy;
ComputeOffsets(dsw, &dx, &dy);
for (i = 0; i < dsw->sw.num_dirty_areas; i++) {
r = dsw->sw.dirty_areas + i*4;
ConvertToX(dsw, LEFT(r), BOTTOM(r), &llx, &lly);
ConvertToX(dsw, RIGHT(r), TOP(r), &urx, &ury);
XCopyArea(XtDisplay(dsw), XtWindow(dsw->sw.drawing_area),
dsw->sw.backing_pixmap, dsw->sw.ge_gc,
llx, ury, urx-llx, lly-ury, llx + dx, ury + dy);
copies++;
}
while (copies > 0) {
XIfEvent(XtDisplay(dsw), &e, CheckWatchProgressEvent,
(char *) dsw);
if (e.type == Expose) {
SplitExposeEvent(dsw, ev);
continue;
} else if (e.type == GraphicsExpose) {
ev->x -= dx;
ev->y -= dy;
AddExposureToPending(dsw, ev);
if (ev->count == 0) copies--;
} else copies--;
}
CopyRectsToCurrentDrawing(dsw, dsw->sw.pending_dirty,
dsw->sw.num_pending_dirty);
dsw->sw.num_pending_dirty = 0;
dsw->sw.num_pending_expose = 0;
if (dsw->sw.num_current_drawing == 0) {
dsw->sw.drawing_stage = DSWDone;
dsw->sw.num_dirty_areas = 0;
} else {
IntersectRects(&dsw->sw.dirty_areas, &dsw->sw.dirty_areas_size,
&dsw->sw.num_dirty_areas,
dsw->sw.current_drawing, dsw->sw.num_current_drawing);
}
}
static void SetCurrentDrawingToBackground(
DPSScrolledWindowWidget dsw)
{
int i;
float r[4];
ConvertToPS(dsw, 0 + DELTA, dsw->sw.drawing_area->core.height - DELTA,
r, r+1);
ConvertToPS(dsw, dsw->sw.drawing_area->core.width - DELTA, 0 + DELTA,
r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
SubtractRects(&dsw->sw.dirty_areas, &dsw->sw.dirty_areas_size,
&dsw->sw.num_dirty_areas, r, 1);
GrowRectList(&dsw->sw.current_drawing, &dsw->sw.current_drawing_size,
0, dsw->sw.num_dirty_areas, 1);
for (i = 0; i < 4 * dsw->sw.num_dirty_areas; i++) {
dsw->sw.current_drawing[i] = dsw->sw.dirty_areas[i];
}
dsw->sw.num_current_drawing = dsw->sw.num_dirty_areas;
}
static void CopyPendingExpose(DPSScrolledWindowWidget dsw)
{
int dx, dy;
int i;
int *r;
ComputeOffsets(dsw, &dx, &dy);
for (i = 0; i < dsw->sw.num_pending_expose; i++) {
r = dsw->sw.pending_expose + 4*i;
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc,
LEFT(r) + dx, BOTTOM(r) + dy, WIDTH(r), HEIGHT(r),
LEFT(r), BOTTOM(r));
}
dsw->sw.num_pending_expose = dsw->sw.num_pending_dirty = 0;
}
static void UpdateWindowFromBackingPixmap(
DPSScrolledWindowWidget dsw,
float *rects,
int n)
{
int dx, dy;
int llx, lly, urx, ury;
int i;
float *r;
ComputeOffsets(dsw, &dx, &dy);
for (i = 0; i < n; i++) {
r = rects + 4*i;
ConvertToX(dsw, LEFT(r), BOTTOM(r), &llx, &lly);
ConvertToX(dsw, RIGHT(r), TOP(r), &urx, &ury);
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc,
llx+dx-1, ury+dy-1, urx-llx+2, lly-ury+2, llx-1, ury-1);
}
}
static void UpdateWindowFromFeedbackPixmap(
DPSScrolledWindowWidget dsw,
float *rects,
int n)
{
int llx, lly, urx, ury;
int i;
float *r;
for (i = 0; i < n; i++) {
r = rects + (i * 4);
ConvertToX(dsw, LEFT(r), BOTTOM(r), &llx, &lly);
ConvertToX(dsw, RIGHT(r), TOP(r), &urx, &ury);
XCopyArea(XtDisplay(dsw), dsw->sw.feedback_pixmap,
XtWindow(dsw->sw.drawing_area), dsw->sw.no_ge_gc,
llx-1, ury-1, urx-llx+2, lly-ury+2, llx-1, ury-1);
}
}
static Boolean DoDrawing(XtPointer clientData)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) clientData;
DSWResults results;
DSWDrawableType which;
if (dsw->sw.drawing_stage == DSWStart && dsw->sw.watch_progress &&
dsw->sw.backing_pixmap != None && dsw->sw.num_current_drawing == 0) {
dsw->sw.drawing_stage = DSWDrewVisible;
CopyWindowToBackingPixmap(dsw);
}
switch (dsw->sw.drawing_stage) {
case DSWStart:
case DSWDrawingVisible:
if (dsw->sw.watch_progress || dsw->sw.backing_pixmap == None) {
which = DSWWindow;
} else which = DSWBackingPixmap;
results = ClipAndDraw(dsw, which, DSWDrawSome,
(dsw->sw.drawing_stage == DSWStart));
if (results == DSWFinished) {
if (dsw->sw.watch_progress && dsw->sw.backing_pixmap != None) {
dsw->sw.drawing_stage = DSWDrewVisible;
CopyWindowToBackingPixmap(dsw);
} else {
if (dsw->sw.minimal_drawing && dsw->sw.big_pixmap) {
dsw->sw.drawing_stage = DSWDrewVisible;
SetCurrentDrawingToBackground(dsw);
} else {
dsw->sw.drawing_stage = DSWDone;
dsw->sw.num_dirty_areas = 0;
}
if (dsw->sw.num_pending_expose != 0 &&
dsw->sw.backing_pixmap != None) {
CopyPendingExpose(dsw);
}
}
} else dsw->sw.drawing_stage = DSWDrawingVisible;
break;
case DSWDrewVisible:
case DSWDrawingBackground:
results = ClipAndDraw(dsw, DSWBackingPixmap, DSWDrawSome,
(dsw->sw.drawing_stage == DSWDrewVisible));
if (results == DSWFinished) {
dsw->sw.drawing_stage = DSWDone;
dsw->sw.num_dirty_areas = 0;
}
else dsw->sw.drawing_stage = DSWDrawingBackground;
break;
case DSWDone:
break;
}
if (dsw->sw.drawing_stage == DSWDone && dsw->sw.num_pending_dirty != 0) {
CopyRectsToCurrentDrawing(dsw, dsw->sw.pending_dirty,
dsw->sw.num_pending_dirty);
CopyRectsToDirtyArea(dsw, dsw->sw.pending_dirty,
dsw->sw.num_pending_dirty);
dsw->sw.num_pending_dirty = 0;
dsw->sw.num_pending_expose = 0;
dsw->sw.drawing_stage = DSWStart;
}
if (dsw->sw.drawing_stage == DSWDone) {
dsw->sw.work = 0;
if (dsw->sw.watch_progress) {
UpdateWindowFromBackingPixmap(dsw, dsw->sw.current_drawing,
dsw->sw.num_current_drawing);
}
dsw->sw.num_current_drawing = 0;
if (dsw->sw.scrolling) {
dsw->sw.scrolling = False;
ScrollMoved(dsw);
}
return True;
} else return False;
}
static void StartDrawing(DPSScrolledWindowWidget dsw)
{
float r[4];
CopyRectsToCurrentDrawing(dsw, dsw->sw.dirty_areas,
dsw->sw.num_dirty_areas);
if (dsw->sw.watch_progress || dsw->sw.backing_pixmap == None) {
IntersectRects(&dsw->sw.current_drawing, &dsw->sw.current_drawing_size,
&dsw->sw.num_current_drawing,
dsw->sw.pending_dirty, dsw->sw.num_pending_dirty);
dsw->sw.num_pending_dirty = dsw->sw.num_pending_expose = 0;
} else {
if (!dsw->sw.big_pixmap || dsw->sw.minimal_drawing) {
ConvertToPS(dsw, 0 + DELTA,
dsw->sw.drawing_area->core.height - DELTA, r, r+1);
ConvertToPS(dsw, dsw->sw.drawing_area->core.width - DELTA,
0 + DELTA, r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
IntersectRects(&dsw->sw.current_drawing,
&dsw->sw.current_drawing_size,
&dsw->sw.num_current_drawing, r, 1);
}
}
if (dsw->sw.num_current_drawing == 0 && !dsw->sw.watch_progress) {
dsw->sw.drawing_stage = DSWFinished;
dsw->sw.num_dirty_areas = 0;
return;
}
dsw->sw.drawing_stage = DSWStart;
if (!DoDrawing((XtPointer) dsw)) {
dsw->sw.work =
XtAppAddWorkProc(XtWidgetToApplicationContext((Widget) dsw),
DoDrawing, (XtPointer) dsw);
}
}
static void RedisplaySliver(DPSScrolledWindowWidget dsw, int deltaX, int deltaY)
{
float r[8];
int xr[8];
int n;
int xllx, xlly, xurx, xury;
float llx, lly, urx, ury;
if (deltaX == 0 || deltaY == 0) {
if (deltaX == 0) {
xllx = 0;
xurx = dsw->sw.drawing_area->core.width;
if (deltaY > 0) {
xlly = dsw->sw.drawing_area->core.height;
xury = dsw->sw.drawing_area->core.height - deltaY;
} else {
xlly = -deltaY;
xury = 0;
}
} else if (deltaY == 0) {
xlly = dsw->sw.drawing_area->core.height;
xury = 0;
if (deltaX > 0) {
xllx = dsw->sw.drawing_area->core.width - deltaX;
xurx = dsw->sw.drawing_area->core.width;
} else {
xllx = 0;
xurx = -deltaX;
}
}
ConvertToPS(dsw, xllx + DELTA, xlly - DELTA, &llx, &lly);
ConvertToPS(dsw, xurx - DELTA, xury + DELTA, &urx, &ury);
r[0] = llx;
r[1] = lly;
r[2] = urx - llx;
r[3] = ury - lly;
xr[0] = xllx;
xr[1] = xury;
xr[2] = xurx - xllx;
xr[3] = xlly - xury;
n = 1;
} else {
xllx = 0;
xurx = dsw->sw.drawing_area->core.width;
if (deltaY > 0) {
xlly = dsw->sw.drawing_area->core.height;
xury = dsw->sw.drawing_area->core.height - deltaY;
} else {
xlly = -deltaY;
xury = 0;
}
ConvertToPS(dsw, xllx + DELTA, xlly - DELTA, &llx, &lly);
ConvertToPS(dsw, xurx - DELTA, xury + DELTA, &urx, &ury);
r[0] = llx;
r[1] = lly;
r[2] = urx - llx;
r[3] = ury - lly;
xr[0] = xllx;
xr[1] = xury;
xr[2] = xurx - xllx;
xr[3] = xlly - xury;
xlly = dsw->sw.drawing_area->core.height;
xury = 0;
if (deltaX > 0) {
xllx = dsw->sw.drawing_area->core.width - deltaX;
xurx = dsw->sw.drawing_area->core.width;
} else {
xllx = 0;
xurx = -deltaX;
}
ConvertToPS(dsw, xllx + DELTA, xlly - DELTA, &llx, &lly);
ConvertToPS(dsw, xurx - DELTA, xury + DELTA, &urx, &ury);
r[4] = llx;
r[5] = lly;
r[6] = urx - llx;
r[7] = ury - lly;
xr[4] = xllx;
xr[5] = xury;
xr[6] = xurx - xllx;
xr[7] = xlly - xury;
n = 2;
}
AddRectsToDirtyArea(dsw, r, n);
AddRectsToPending(dsw, xr, n);
StartDrawing(dsw);
}
static void SetUpInitialPixmap(DPSScrolledWindowWidget dsw)
{
float *r = dsw->sw.dirty_areas;
int llx, lly, urx, ury;
CreateBackingPixmap(dsw);
if (dsw->sw.backing_pixmap != None) {
XDPSSetContextDrawable(dsw->sw.context, dsw->sw.backing_pixmap,
dsw->sw.pixmap_height);
SetPixmapOffset(dsw);
SetPixmapOrigin(dsw);
XDPSCaptureContextGState(dsw->sw.context, &dsw->sw.backing_gstate);
if (dsw->sw.pixmap_width != CEIL(dsw->sw.drawing_width) ||
dsw->sw.pixmap_height != CEIL(dsw->sw.drawing_height)) {
if (dsw->sw.pixmap_width > (int)dsw->sw.drawing_area->core.width) {
llx = dsw->sw.origin_x;
urx = llx + CEIL(dsw->sw.drawing_width);
} else {
llx = 0;
urx = dsw->sw.drawing_area->core.width;
}
if (dsw->sw.pixmap_height >
(int) dsw->sw.drawing_area->core.height) {
lly = dsw->sw.origin_y;
ury = dsw->sw.origin_y - CEIL(dsw->sw.drawing_height);
} else {
lly = dsw->sw.drawing_area->core.height;
ury = 0;
}
ConvertToPS(dsw, llx + DELTA, lly - DELTA, r, r+1);
ConvertToPS(dsw, urx - DELTA, ury + DELTA, r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
dsw->sw.num_dirty_areas = 1;
}
if (dsw->sw.doing_feedback) {
CopyRectsToCurrentDrawing(dsw, dsw->sw.dirty_areas,
dsw->sw.num_dirty_areas);
FinishDrawing(dsw);
} else if (!dsw->sw.watch_progress) StartDrawing(dsw);
}
}
static void TimerStart(XtPointer clientData, XtIntervalId *id)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) clientData;
if (dsw->sw.drawing_stage == DSWStart) StartDrawing(dsw);
}
static void SetUpInitialInformation(DPSScrolledWindowWidget dsw)
{
int i;
float llx, lly, urx, ury;
float xScale, yScale;
XExposeEvent ev;
XStandardColormap colorCube, grayRamp;
int match;
_DPSSWColormapMatch(dsw->sw.context,
dsw->sw.drawing_area->core.colormap, &match);
if (match) {
XDPSSetContextParameters(dsw->sw.context, XtScreen(dsw),
dsw->sw.drawing_area->core.depth,
XtWindow(dsw->sw.drawing_area),
dsw->sw.drawing_area->core.height, NULL, NULL,
XDPSContextScreenDepth | XDPSContextDrawable);
} else {
grayRamp.colormap = colorCube.colormap =
dsw->sw.drawing_area->core.colormap;
XDPSCreateStandardColormaps(XtDisplay(dsw), XtWindow(dsw),
(Visual *) NULL, 0, 0, 0, 0,
&colorCube, &grayRamp, False);
XDPSSetContextParameters(dsw->sw.context, XtScreen(dsw),
dsw->sw.drawing_area->core.depth,
XtWindow(dsw->sw.drawing_area),
dsw->sw.drawing_area->core.height,
(XDPSStandardColormap *) &colorCube,
(XDPSStandardColormap *) &grayRamp,
XDPSContextScreenDepth | XDPSContextDrawable |
XDPSContextRGBMap | XDPSContextGrayMap);
}
DPSinitgraphics(dsw->sw.context);
_DPSSWGetTransform(dsw->sw.context, dsw->sw.ctm, dsw->sw.orig_inv_ctm);
dsw->sw.x_offset = 0;
dsw->sw.y_offset = dsw->sw.drawing_area->core.height;
for (i = 0; i < 6; i++) dsw->sw.inv_ctm[i] = dsw->sw.orig_inv_ctm[i];
ConvertToPS(dsw, 0.0, 100.0, &llx, &lly);
ConvertToPS(dsw, 100.0, 0.0, &urx, &ury);
xScale = ABS(100.0 / (urx - llx));
yScale = ABS(100.0 / (ury - lly));
if (dsw->sw.scale != 1.0) {
DPSscale(dsw->sw.context, dsw->sw.scale, dsw->sw.scale);
_DPSSWGetTransform(dsw->sw.context, dsw->sw.ctm, dsw->sw.inv_ctm);
}
dsw->sw.drawing_width = dsw->sw.area_width * xScale * dsw->sw.scale;
dsw->sw.drawing_height = dsw->sw.area_height * yScale * dsw->sw.scale;
dsw->sw.unscaled_width = dsw->sw.drawing_width / dsw->sw.scale + 1;
dsw->sw.unscaled_height = dsw->sw.drawing_height / dsw->sw.scale + 1;
if (!dsw->sw.use_saved_scroll) {
dsw->sw.scroll_pic_x = dsw->sw.area_width / 2;
dsw->sw.scroll_pic_y = dsw->sw.area_height / 2;
dsw->sw.scroll_win_x = dsw->sw.drawing_area->core.width / 2;
dsw->sw.scroll_win_y = dsw->sw.drawing_area->core.height / 2;
}
SetDrawingAreaPosition(dsw, dsw->sw.scroll_pic_x, dsw->sw.scroll_pic_y,
dsw->sw.scroll_win_x, dsw->sw.scroll_win_y, True);
SetOriginAndGetTransform(dsw);
XDPSCaptureContextGState(dsw->sw.context, &dsw->sw.window_gstate);
dsw->sw.drawing_stage = DSWStart;
if (dsw->sw.use_backing_pixmap) SetUpInitialPixmap(dsw);
if (dsw->sw.doing_feedback) return;
if (dsw->sw.watch_progress || dsw->sw.backing_pixmap == None) {
XClearArea(XtDisplay(dsw), XtWindow(dsw->sw.drawing_area),
0, 0, 0, 0, True);
XSync(XtDisplay(dsw), False);
if (dsw->sw.watch_progress && dsw->sw.watch_progress_delay > 0) {
(void) XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) dsw),
dsw->sw.watch_progress_delay,
TimerStart, (XtPointer) dsw);
}
} else {
ev.x = ev.y = 0;
ev.width = dsw->sw.drawing_area->core.width;
ev.height = dsw->sw.drawing_area->core.height;
SplitExposeEvent(dsw, &ev);
}
}
static void Realize(
Widget w,
XtValueMask *mask,
XSetWindowAttributes *attr)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
DSWSetupCallbackRec setup;
(*dpsScrolledWindowClassRec.core_class.superclass->core_class.realize)
(w, mask, attr);
setup.context = dsw->sw.context;
XtCallCallbackList((Widget) dsw, dsw->sw.setup_callback,
(XtPointer) &setup);
XtRealizeWidget(dsw->sw.scrolled_window);
SetUpInitialInformation(dsw);
}
static void AbortOrFinish(DPSScrolledWindowWidget dsw)
{
DSWResults results;
DSWDrawableType which;
if (dsw->sw.work != 0) {
XtRemoveWorkProc(dsw->sw.work);
dsw->sw.work = 0;
}
switch (dsw->sw.drawing_stage) {
case DSWStart:
return;
case DSWDrawingVisible:
if (dsw->sw.watch_progress || dsw->sw.backing_pixmap == None) {
which = DSWWindow;
} else which = DSWBackingPixmap;
results = ClipAndDraw(dsw, which, DSWAbortOrFinish, False);
if (results == DSWAborted) {
dsw->sw.drawing_stage = DSWStart;
if (dsw->sw.backing_pixmap == None || dsw->sw.watch_progress) {
AddUserSpaceRectsToPending(dsw, dsw->sw.current_drawing,
dsw->sw.num_current_drawing);
}
return;
}
if (dsw->sw.watch_progress && dsw->sw.backing_pixmap != None) {
dsw->sw.drawing_stage = DSWDrewVisible;
CopyWindowToBackingPixmap(dsw);
if (dsw->sw.num_current_drawing != 0) {
results = ClipAndDraw(dsw, DSWBackingPixmap,
DSWAbortOrFinish, True);
}
if (results == DSWAborted) {
dsw->sw.drawing_stage = DSWStart;
return;
}
} else {
if (dsw->sw.backing_pixmap != None) {
if (dsw->sw.num_pending_expose != 0) {
CopyPendingExpose(dsw);
}
if (dsw->sw.minimal_drawing && dsw->sw.big_pixmap) {
dsw->sw.drawing_stage = DSWDrewVisible;
SetCurrentDrawingToBackground(dsw);
results = ClipAndDraw(dsw, which,
DSWAbortOrFinish, True);
if (results == DSWAborted) {
dsw->sw.drawing_stage = DSWStart;
return;
}
}
}
}
break;
case DSWDrewVisible:
case DSWDrawingBackground:
results = ClipAndDraw(dsw, DSWBackingPixmap, DSWAbortOrFinish,
(dsw->sw.drawing_stage == DSWDrewVisible));
if (results == DSWAborted) {
dsw->sw.drawing_stage = DSWStart;
return;
}
break;
case DSWDone:
break;
}
dsw->sw.drawing_stage = DSWDone;
dsw->sw.num_dirty_areas = 0;
return;
}
static void AbortDrawing(DPSScrolledWindowWidget dsw)
{
DSWDrawableType which;
if (dsw->sw.work != 0) {
XtRemoveWorkProc(dsw->sw.work);
dsw->sw.work = 0;
}
switch (dsw->sw.drawing_stage) {
case DSWStart:
case DSWDone:
case DSWDrewVisible:
break;
case DSWDrawingVisible:
if (dsw->sw.watch_progress || dsw->sw.backing_pixmap == None) {
which = DSWWindow;
} else which = DSWBackingPixmap;
(void) ClipAndDraw(dsw, which, DSWAbort, False);
break;
case DSWDrawingBackground:
(void) ClipAndDraw(dsw, DSWBackingPixmap, DSWAbort, False);
break;
}
dsw->sw.num_pending_expose = dsw->sw.num_pending_dirty = 0;
}
static void FinishDrawing(DPSScrolledWindowWidget dsw)
{
DSWDrawableType which;
if (dsw->sw.work != 0) {
XtRemoveWorkProc(dsw->sw.work);
dsw->sw.work = 0;
}
switch (dsw->sw.drawing_stage) {
case DSWStart:
case DSWDrawingVisible:
if (dsw->sw.watch_progress || dsw->sw.backing_pixmap == None) {
which = DSWWindow;
} else which = DSWBackingPixmap;
if (dsw->sw.drawing_stage == DSWStart) {
ClipToDrawingSize(dsw, which);
if (dsw->sw.num_current_drawing == 0) return;
}
(void) ClipAndDraw(dsw, which, DSWFinish,
dsw->sw.drawing_stage == DSWStart);
if (dsw->sw.watch_progress && dsw->sw.backing_pixmap != None) {
dsw->sw.drawing_stage = DSWDrewVisible;
CopyWindowToBackingPixmap(dsw);
if (dsw->sw.num_current_drawing != 0) {
(void) ClipAndDraw(dsw, DSWBackingPixmap, DSWFinish, True);
}
} else {
if (dsw->sw.backing_pixmap != None) {
if (dsw->sw.num_pending_expose != 0) {
CopyPendingExpose(dsw);
}
if (dsw->sw.minimal_drawing && dsw->sw.big_pixmap) {
dsw->sw.drawing_stage = DSWDrewVisible;
SetCurrentDrawingToBackground(dsw);
(void) ClipAndDraw(dsw, which, DSWFinish, True);
}
}
}
break;
case DSWDrewVisible:
case DSWDrawingBackground:
(void) ClipAndDraw(dsw, DSWBackingPixmap, DSWFinish,
(dsw->sw.drawing_stage == DSWDrewVisible));
break;
case DSWDone:
break;
}
dsw->sw.drawing_stage = DSWDone;
dsw->sw.num_dirty_areas = 0;
}
static void DoScroll(
DPSScrolledWindowWidget dsw,
int deltaX, int deltaY)
{
dsw->sw.origin_x -= deltaX;
dsw->sw.origin_y -= deltaY;
(void) XDPSSetContextGState(dsw->sw.context, dsw->sw.window_gstate);
SetOriginAndGetTransform(dsw);
(void) XDPSUpdateContextGState(dsw->sw.context, dsw->sw.window_gstate);
if (dsw->sw.backing_pixmap != None && !dsw->sw.big_pixmap) {
(void) XDPSSetContextGState(dsw->sw.context, dsw->sw.backing_gstate);
SetPixmapOrigin(dsw);
(void) XDPSUpdateContextGState(dsw->sw.context,
dsw->sw.backing_gstate);
}
dsw->sw.scroll_x += deltaX;
dsw->sw.scroll_y += deltaY;
}
static void ShiftPendingExpose(
DPSScrolledWindowWidget dsw,
int deltaX, int deltaY)
{
int i;
int *r;
for (i = 0; i < dsw->sw.num_pending_expose; i++) {
r = dsw->sw.pending_expose + 4*i;
r[0] -= deltaX;
r[1] -= deltaY;
}
}
static void HScrollCallback(
Widget w,
XtPointer clientData, XtPointer callData)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) clientData;
XmScrollBarCallbackStruct *sb = (XmScrollBarCallbackStruct *) callData;
if (!dsw->sw.application_scrolling) {
dsw->sw.scroll_h_value = sb->value;
ScrollMoved(dsw);
}
}
static void VScrollCallback(
Widget w,
XtPointer clientData, XtPointer callData)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) clientData;
XmScrollBarCallbackStruct *sb = (XmScrollBarCallbackStruct *) callData;
if (!dsw->sw.application_scrolling) {
dsw->sw.scroll_v_value = sb->value;
ScrollMoved(dsw);
}
}
static void ScrollMoved(DPSScrolledWindowWidget dsw)
{
int deltaX, deltaY;
if (dsw->sw.scrolling && dsw->sw.drawing_stage == DSWStart) return;
deltaX = dsw->sw.scroll_h_value - dsw->sw.scroll_x;
deltaY = dsw->sw.scroll_v_value - dsw->sw.scroll_y;
if (deltaX == 0 && deltaY == 0) return;
ShiftPendingExpose(dsw, deltaX, deltaY);
AbortOrFinish(dsw);
DoScroll(dsw, deltaX, deltaY);
if (!dsw->sw.big_pixmap) {
if (dsw->sw.backing_pixmap != None) {
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
dsw->sw.backing_pixmap, dsw->sw.no_ge_gc,
deltaX, deltaY, dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height, 0, 0);
if (!dsw->sw.doing_feedback || dsw->sw.feedback_pixmap == None) {
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area), dsw->sw.no_ge_gc,
0, 0, dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height, 0, 0);
}
RedisplaySliver(dsw, deltaX, deltaY);
} else {
if (!dsw->sw.doing_feedback || dsw->sw.feedback_pixmap == None) {
XCopyArea(XtDisplay(dsw), XtWindow(dsw->sw.drawing_area),
XtWindow(dsw->sw.drawing_area), dsw->sw.ge_gc,
deltaX, deltaY, dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height, 0, 0);
}
if (dsw->sw.doing_feedback) RedisplaySliver(dsw, deltaX, deltaY);
else dsw->sw.drawing_stage = DSWStart;
}
}
if (dsw->sw.doing_feedback) {
float *r;
FinishDrawing(dsw);
r = dsw->sw.prev_dirty_areas;
ConvertToPS(dsw, 0 + DELTA, dsw->sw.drawing_area->core.height - DELTA,
r, r+1);
ConvertToPS(dsw, dsw->sw.drawing_area->core.width - DELTA, 0 + DELTA,
r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
dsw->sw.num_prev_dirty_areas = 1;
if (dsw->sw.feedback_pixmap != None) {
XDPSSetContextDrawable(dsw->sw.context, dsw->sw.feedback_pixmap,
dsw->sw.drawing_area->core.height);
SetPixmapOrigin(dsw);
XDPSCaptureContextGState(dsw->sw.context,
&dsw->sw.feedback_gstate);
if (dsw->sw.backing_pixmap != None) {
CopyToFeedbackPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
} else {
CopyRectsToCurrentDrawing(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
(void) ClipAndDraw(dsw, DSWFeedbackPixmap, DSWFinish, True);
}
if (!dsw->sw.feedback_displayed) {
XCopyArea(XtDisplay(dsw), dsw->sw.feedback_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc, 0, 0,
dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height, 0, 0);
}
}
if (dsw->sw.feedback_displayed) {
CallFeedbackCallback(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
}
if (dsw->sw.feedback_pixmap != None) {
UpdateWindowFromFeedbackPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
}
dsw->sw.num_pending_dirty = dsw->sw.num_pending_expose = 0;
} else {
if (dsw->sw.backing_pixmap != None &&
dsw->sw.drawing_stage == DSWDone) {
ComputeOffsets(dsw, &deltaX, &deltaY);
if (!dsw->sw.big_pixmap) dsw->sw.scrolling = True;
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area), dsw->sw.no_ge_gc,
deltaX, deltaY,
dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height, 0, 0);
} else dsw->sw.scrolling = True;
}
}
static void AddExposureToPending(
DPSScrolledWindowWidget dsw,
XExposeEvent *ev)
{
float *f;
int *i;
if (dsw->sw.backing_pixmap == None || dsw->sw.watch_progress ||
dsw->sw.doing_feedback) {
GrowRectList(&dsw->sw.pending_dirty, &dsw->sw.pending_dirty_size,
dsw->sw.num_pending_dirty, 1, 1);
f = dsw->sw.pending_dirty + (dsw->sw.num_pending_dirty * 4);
ConvertToPS(dsw, ev->x + DELTA, ev->y + ev->height - DELTA, f, f+1);
ConvertToPS(dsw, ev->x + ev->width - DELTA, ev->y + DELTA, f+2, f+3);
f[2] -= f[0];
f[3] -= f[1];
dsw->sw.num_pending_dirty++;
}
GrowIntRectList(&dsw->sw.pending_expose, &dsw->sw.pending_expose_size,
dsw->sw.num_pending_expose, 1, 1);
i = dsw->sw.pending_expose + (dsw->sw.num_pending_expose * 4);
i[0] = ev->x;
i[1] = ev->y;
i[2] = ev->width;
i[3] = ev->height;
dsw->sw.num_pending_expose++;
}
static void AddRectsToPending(
DPSScrolledWindowWidget dsw,
int *newRect,
int n)
{
int *r;
int i;
float *f;
if (dsw->sw.backing_pixmap == None || dsw->sw.watch_progress) {
GrowRectList(&dsw->sw.pending_dirty, &dsw->sw.pending_dirty_size,
dsw->sw.num_pending_dirty, n, 1);
for (i = 0; i < n; i++) {
f = dsw->sw.pending_dirty + (dsw->sw.num_pending_dirty * 4);
r = newRect + (i * 4);
ConvertToPS(dsw, r[0] + DELTA, r[1] + r[3] - DELTA, f, f+1);
ConvertToPS(dsw, r[0] + r[2] - DELTA, r[1] + DELTA, f+2, f+3);
f[2] -= f[0];
f[3] -= f[1];
dsw->sw.num_pending_dirty++;
}
}
GrowIntRectList(&dsw->sw.pending_expose, &dsw->sw.pending_expose_size,
dsw->sw.num_pending_expose, n, 1);
r = dsw->sw.pending_expose + (dsw->sw.num_pending_expose * 4);
for (i = 0; i < 4*n; i++) r[i] = newRect[i];
dsw->sw.num_pending_expose += n;
}
static void AddUserSpaceRectsToPending(
DPSScrolledWindowWidget dsw,
float *newRect,
int n)
{
int *r;
int i;
float *f;
if (dsw->sw.backing_pixmap == None || dsw->sw.watch_progress) {
GrowRectList(&dsw->sw.pending_dirty, &dsw->sw.pending_dirty_size,
dsw->sw.num_pending_dirty, n, 1);
f = dsw->sw.pending_dirty + (dsw->sw.num_pending_dirty * 4);
for (i = 0; i < 4*n; i++) f[i] = newRect[i];
dsw->sw.num_pending_dirty += n;
}
GrowIntRectList(&dsw->sw.pending_expose, &dsw->sw.pending_expose_size,
dsw->sw.num_pending_expose, n, 1);
for (i = 0; i < n; i++) {
r = dsw->sw.pending_expose + (dsw->sw.num_pending_expose * 4);
f = newRect + (i * 4);
ConvertToX(dsw, LEFT(f), TOP(f), r, r+1);
ConvertToX(dsw, RIGHT(f), BOTTOM(f), r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
dsw->sw.num_pending_expose++;
}
}
static void CopyRectsToCurrentDrawing(
DPSScrolledWindowWidget dsw,
float *newRect,
int n)
{
float *r;
int i;
GrowRectList(&dsw->sw.current_drawing, &dsw->sw.current_drawing_size,
0, n, 1);
r = dsw->sw.current_drawing;
for (i = 0; i < 4*n; i++) r[i] = newRect[i];
dsw->sw.num_current_drawing = n;
}
static void CopyRectsToDirtyArea(
DPSScrolledWindowWidget dsw,
float *newRect,
int n)
{
float *r;
int i;
GrowRectList(&dsw->sw.dirty_areas, &dsw->sw.dirty_areas_size, 0, n, 1);
r = dsw->sw.dirty_areas;
for (i = 0; i < 4*n; i++) r[i] = newRect[i];
dsw->sw.num_dirty_areas = n;
}
static void AddRectsToDirtyArea(
DPSScrolledWindowWidget dsw,
float *newRect,
int n)
{
float *r;
int i;
GrowRectList(&dsw->sw.dirty_areas, &dsw->sw.dirty_areas_size,
dsw->sw.num_dirty_areas, n, 1);
r = dsw->sw.dirty_areas + (4 * dsw->sw.num_dirty_areas);
for (i = 0; i < 4*n; i++) r[i] = newRect[i];
dsw->sw.num_dirty_areas += n;
}
static void CopyRectsToPrevDirtyArea(
DPSScrolledWindowWidget dsw,
float *newRect,
int n)
{
float *r;
int i;
GrowRectList(&dsw->sw.prev_dirty_areas,
&dsw->sw.prev_dirty_areas_size, 0, n, 1);
r = dsw->sw.prev_dirty_areas;
for (i = 0; i < 4*n; i++) r[i] = newRect[i];
dsw->sw.num_prev_dirty_areas = n;
}
static void DrawingAreaGraphicsExpose(
Widget w,
XtPointer clientData,
XEvent *event,
Boolean *goOn)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) clientData;
XExposeEvent *ev = (XExposeEvent *) event;
switch (event->type) {
case GraphicsExpose:
if (dsw->sw.backing_pixmap == None && dsw->sw.scrolling) {
AddExposureToPending(dsw, ev);
if (ev->count == 0) {
AddRectsToDirtyArea(dsw, dsw->sw.pending_dirty,
dsw->sw.num_pending_dirty);
StartDrawing(dsw);
dsw->sw.num_pending_dirty = dsw->sw.num_pending_expose = 0;
}
}
break;
}
}
static Boolean MoreExposes(Widget w)
{
XEvent event;
if (XPending(XtDisplay(w)) > 0) {
if (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w),
Expose, &event)) {
XPutBackEvent(XtDisplay(w), &event);
return True;;
}
}
return False;
}
static void DrawingAreaExpose(
Widget w,
XtPointer clientData, XtPointer callData)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) clientData;
XmDrawingAreaCallbackStruct *d = (XmDrawingAreaCallbackStruct *) callData;
XExposeEvent *ev = (XExposeEvent *) d->event;
int dx, dy;
if (dsw->sw.doing_feedback) {
if (dsw->sw.feedback_pixmap != None) {
XCopyArea(XtDisplay(dsw), dsw->sw.feedback_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc,
ev->x, ev->y, ev->width, ev->height, ev->x, ev->y);
} else {
if (dsw->sw.backing_pixmap != None) {
ComputeOffsets(dsw, &dx, &dy);
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc, ev->x + dx, ev->y + dy,
ev->width, ev->height, ev->x, ev->y);
}
AddExposureToPending(dsw, ev);
if (ev->count != 0 || MoreExposes(w)) return;
if (dsw->sw.backing_pixmap == None) {
CopyRectsToCurrentDrawing(dsw, dsw->sw.pending_dirty,
dsw->sw.num_pending_dirty);
dsw->sw.drawing_stage = DSWStart;
FinishDrawing(dsw);
}
if (dsw->sw.feedback_displayed) {
CallFeedbackCallback(dsw, dsw->sw.pending_dirty,
dsw->sw.num_pending_dirty);
}
dsw->sw.num_pending_dirty = dsw->sw.num_pending_expose = 0;
}
return;
}
if (dsw->sw.backing_pixmap != None) {
if (dsw->sw.drawing_stage == DSWStart && dsw->sw.watch_progress) {
SplitExposeEvent(dsw, ev);
if (ev->count == 0) {
if (MoreExposes(w)) return;
StartDrawing(dsw);
dsw->sw.num_pending_dirty = dsw->sw.num_pending_expose = 0;
}
return;
}
if (dsw->sw.drawing_stage < DSWDrewVisible) {
SplitExposeEvent(dsw, ev);
return;
}
ComputeOffsets(dsw, &dx, &dy);
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc,
ev->x + dx, ev->y + dy, ev->width, ev->height, ev->x, ev->y);
} else {
AddExposureToPending(dsw, ev);
if (ev->count == 0) {
if (MoreExposes(w)) return;
if (dsw->sw.drawing_stage == DSWDone ||
dsw->sw.drawing_stage == DSWStart) {
CopyRectsToDirtyArea(dsw, dsw->sw.pending_dirty,
dsw->sw.num_pending_dirty);
StartDrawing(dsw);
dsw->sw.num_pending_dirty = dsw->sw.num_pending_expose = 0;
}
}
}
}
static void Resize(Widget w)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
DSWResizeCallbackRec r;
float x, y;
if (XtIsRealized(w)) (void) AbortOrFinish(dsw);
r.oldw = dsw->sw.scrolled_window->core.width;
r.oldh = dsw->sw.scrolled_window->core.height;
r.neww = dsw->core.width;
r.newh = dsw->core.height;
r.x = r.y = 0;
XtCallCallbackList(w, dsw->sw.resize_callback, (XtPointer) &r);
if (XtIsRealized(w)) {
ConvertToPS(dsw, (float) r.x, (float) r.y, &x, &y);
} else if (r.x != 0 || r.y != 0) ScrollBy(w, r.x, r.y);
XtResizeWidget(dsw->sw.scrolled_window, w->core.width, w->core.height, 0);
if (!XtIsRealized(w)) return;
if (dsw->sw.backing_pixmap != None &&
dsw->sw.pixmap_width == CEIL(dsw->sw.drawing_width) &&
dsw->sw.pixmap_height == CEIL(dsw->sw.drawing_height) &&
dsw->sw.pixmap_width >= (int) dsw->sw.drawing_area->core.width &&
dsw->sw.pixmap_height >= (int) dsw->sw.drawing_area->core.width) {
XDPSSetContextGState(dsw->sw.context, dsw->sw.window_gstate);
DPSinitclip(dsw->sw.context);
DPSinitviewclip(dsw->sw.context);
SetDrawingAreaPosition(dsw, x, y, r.x, r.y, True);
SetOriginAndGetTransform(dsw);
XDPSUpdateContextGState(dsw->sw.context, dsw->sw.window_gstate);
XClearArea(XtDisplay(dsw), XtWindow(dsw->sw.drawing_area),
0, 0, 0, 0, True);
} else {
dsw->sw.use_saved_scroll = True;
dsw->sw.scroll_pic_x = x;
dsw->sw.scroll_pic_y = y;
dsw->sw.scroll_win_x = r.x;
dsw->sw.scroll_win_y = r.y;
if (dsw->sw.backing_pixmap != None) {
XFreePixmap(XtDisplay(dsw), dsw->sw.backing_pixmap);
XDPSFreeContextGState(dsw->sw.context, dsw->sw.backing_gstate);
}
dsw->sw.backing_pixmap = None;
dsw->sw.big_pixmap = False;
dsw->sw.pixmap_width = dsw->sw.pixmap_height = 0;
dsw->sw.num_dirty_areas = 1;
LEFT(dsw->sw.dirty_areas) = 0.0;
BOTTOM(dsw->sw.dirty_areas) = 0.0;
WIDTH(dsw->sw.dirty_areas) = dsw->sw.area_width;
HEIGHT(dsw->sw.dirty_areas) = dsw->sw.area_height;
SetUpInitialInformation(dsw);
}
if (dsw->sw.doing_feedback) {
float *r;
int dx, dy;
CheckFeedbackPixmap(dsw);
r = dsw->sw.prev_dirty_areas;
ConvertToPS(dsw, 0 + DELTA, dsw->sw.drawing_area->core.height - DELTA,
r, r+1);
ConvertToPS(dsw, dsw->sw.drawing_area->core.width - DELTA, 0 + DELTA,
r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
dsw->sw.num_prev_dirty_areas = 1;
if (dsw->sw.feedback_pixmap != None) {
if (dsw->sw.backing_pixmap != None) {
CopyToFeedbackPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
} else {
CopyRectsToCurrentDrawing(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
(void) ClipAndDraw(dsw, DSWFeedbackPixmap, DSWFinish, True);
}
XCopyArea(XtDisplay(dsw), dsw->sw.feedback_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc, 0, 0,
dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height, 0, 0);
} else {
if (dsw->sw.backing_pixmap != None) {
ComputeOffsets(dsw, &dx, &dy);
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
XtWindow(dsw->sw.drawing_area),
dsw->sw.no_ge_gc, dx, dy,
dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height, 0, 0);
} else {
CopyRectsToCurrentDrawing(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
dsw->sw.drawing_stage = DSWStart;
FinishDrawing(dsw);
}
}
if (dsw->sw.feedback_displayed) {
CallFeedbackCallback(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
}
if (dsw->sw.feedback_pixmap != None) {
UpdateWindowFromFeedbackPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
}
dsw->sw.num_pending_dirty = dsw->sw.num_pending_expose = 0;
}
}
static void CheckFeedbackPixmap(DPSScrolledWindowWidget dsw)
{
if (dsw->sw.feedback_pixmap != None &&
(dsw->sw.feedback_width < (int) dsw->sw.drawing_area->core.width ||
dsw->sw.feedback_height < (int) dsw->sw.drawing_area->core.height)) {
XFreePixmap(XtDisplay(dsw), dsw->sw.feedback_pixmap);
dsw->sw.feedback_pixmap = None;
dsw->sw.feedback_width = dsw->sw.feedback_height = 0;
}
if (dsw->sw.use_feedback_pixmap && dsw->sw.feedback_pixmap == None) {
dsw->sw.feedback_pixmap =
AllocPixmap(dsw, dsw->sw.drawing_area->core.width,
dsw->sw.drawing_area->core.height);
if (dsw->sw.feedback_pixmap != None) {
dsw->sw.feedback_width = dsw->sw.drawing_area->core.width;
dsw->sw.feedback_height = dsw->sw.drawing_area->core.height;
}
}
if (dsw->sw.feedback_pixmap != None) {
XDPSSetContextDrawable(dsw->sw.context, dsw->sw.feedback_pixmap,
dsw->sw.drawing_area->core.height);
SetPixmapOrigin(dsw);
XDPSCaptureContextGState(dsw->sw.context, &dsw->sw.feedback_gstate);
}
}
static void UpdateGStates(DPSScrolledWindowWidget dsw)
{
XDPSSetContextDrawable(dsw->sw.context, XtWindow(dsw->sw.drawing_area),
dsw->sw.drawing_area->core.height);
DPSinitgraphics(dsw->sw.context);
if (dsw->sw.scale != 1.0) {
DPSscale(dsw->sw.context, dsw->sw.scale, dsw->sw.scale);
}
SetOriginAndGetTransform(dsw);
(void) XDPSCaptureContextGState(dsw->sw.context, &dsw->sw.window_gstate);
if (dsw->sw.backing_pixmap != None) {
XDPSSetContextDrawable(dsw->sw.context, dsw->sw.backing_pixmap,
dsw->sw.pixmap_height);
SetPixmapOffset(dsw);
SetPixmapOrigin(dsw);
XDPSCaptureContextGState(dsw->sw.context, &dsw->sw.backing_gstate);
}
}
static void CheckPixmapSize(DPSScrolledWindowWidget dsw)
{
Boolean freeIt = False;
int w = dsw->sw.pixmap_width, h = dsw->sw.pixmap_height;
Widget wid = dsw->sw.drawing_area;
unsigned int dBytes;
if (dsw->sw.pixmap_limit > 0) {
if (w * h > dsw->sw.pixmap_limit) freeIt = True;
} else if (dsw->sw.pixmap_limit < 0 &&
w * h > dsw->sw.unscaled_width * dsw->sw.unscaled_height &&
w * h > (int) wid->core.width * (int) wid->core.height) {
freeIt = True;
}
if (dsw->sw.absolute_pixmap_limit > 0) {
dBytes = (wid->core.depth + 7) / 8;
if (w * h * dBytes > (unsigned)dsw->sw.absolute_pixmap_limit * 1024) {
freeIt = True;
}
}
if (freeIt) {
XFreePixmap(XtDisplay(dsw), dsw->sw.backing_pixmap);
dsw->sw.backing_pixmap = None;
dsw->sw.big_pixmap = False;
dsw->sw.pixmap_width = dsw->sw.pixmap_height = 0;
XDPSFreeContextGState(dsw->sw.context, dsw->sw.backing_gstate);
}
}
static void ResizeArea(DPSScrolledWindowWidget dsw)
{
AbortDrawing(dsw);
dsw->sw.num_dirty_areas = 1;
LEFT(dsw->sw.dirty_areas) = 0.0;
BOTTOM(dsw->sw.dirty_areas) = 0.0;
WIDTH(dsw->sw.dirty_areas) = dsw->sw.area_width;
HEIGHT(dsw->sw.dirty_areas) = dsw->sw.area_height;
if (dsw->sw.big_pixmap) {
XFreePixmap(XtDisplay(dsw), dsw->sw.backing_pixmap);
dsw->sw.backing_pixmap = None;
dsw->sw.big_pixmap = False;
dsw->sw.pixmap_width = dsw->sw.pixmap_height = 0;
XDPSFreeContextGState(dsw->sw.context, dsw->sw.backing_gstate);
}
if (!dsw->sw.use_saved_scroll) {
dsw->sw.scroll_win_x = 0;
dsw->sw.scroll_win_y = 0;
ConvertToPS(dsw, 0.0, 0.0,
&dsw->sw.scroll_pic_x, &dsw->sw.scroll_pic_y);
dsw->sw.use_saved_scroll = True;
}
SetUpInitialInformation(dsw);
}
static void ClearDirtyAreas(DPSScrolledWindowWidget dsw)
{
int i;
float *r;
int llx, lly, urx, ury;
for (i = 0; i < dsw->sw.num_dirty_areas; i++) {
r = dsw->sw.dirty_areas + (i * 4);
ConvertToX(dsw, LEFT(r), BOTTOM(r), &llx, &lly);
ConvertToX(dsw, RIGHT(r), TOP(r), &urx, &ury);
XClearArea(XtDisplay(dsw), XtWindow(dsw->sw.drawing_area),
llx, ury, urx-llx, lly-ury, True);
}
}
static void HandleFeedbackPixmapChange(DPSScrolledWindowWidget dsw)
{
if (!dsw->sw.use_feedback_pixmap) {
if (dsw->sw.feedback_pixmap != None) {
XFreePixmap(XtDisplay(dsw), dsw->sw.feedback_pixmap);
dsw->sw.feedback_pixmap = None;
dsw->sw.feedback_width = dsw->sw.feedback_height = 0;
}
} else {
if (dsw->sw.doing_feedback) {
float *r;
CheckFeedbackPixmap(dsw);
if (dsw->sw.feedback_pixmap == None) return;
r = dsw->sw.prev_dirty_areas;
ConvertToPS(dsw, 0 + DELTA,
dsw->sw.drawing_area->core.height - DELTA, r, r+1);
ConvertToPS(dsw, dsw->sw.drawing_area->core.width - DELTA,
0 + DELTA, r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
dsw->sw.num_prev_dirty_areas = 1;
if (dsw->sw.backing_pixmap != None) {
CopyToFeedbackPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
} else {
CopyRectsToCurrentDrawing(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
(void) ClipAndDraw(dsw, DSWFeedbackPixmap, DSWFinish, True);
}
if (dsw->sw.feedback_displayed) {
CallFeedbackCallback(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
}
}
}
}
static Boolean SetValues(
Widget old, Widget req, Widget new,
ArgList args,
Cardinal *num_args)
{
DPSScrolledWindowWidget olddsw = (DPSScrolledWindowWidget) old;
DPSScrolledWindowWidget newdsw = (DPSScrolledWindowWidget) new;
Bool inited;
#define NE(field) newdsw->sw.field != olddsw->sw.field
#define DONT_CHANGE(field) \
if (NE(field)) newdsw->sw.field = olddsw->sw.field;
DONT_CHANGE(ctm_ptr);
DONT_CHANGE(inv_ctm_ptr);
DONT_CHANGE(backing_pixmap);
DONT_CHANGE(feedback_pixmap);
DONT_CHANGE(window_gstate);
DONT_CHANGE(backing_gstate);
DONT_CHANGE(feedback_gstate);
if (NE(context)) {
DSWSetupCallbackRec setup;
if (newdsw->sw.context == NULL) {
newdsw->sw.context = XDPSGetSharedContext(XtDisplay(newdsw));
}
if (_XDPSTestComponentInitialized(newdsw->sw.context,
dps_init_bit_dsw, &inited) ==
dps_status_unregistered_context) {
XDPSRegisterContext(newdsw->sw.context, False);
}
if (XtIsRealized(newdsw)) {
setup.context = newdsw->sw.context;
XtCallCallbackList((Widget) newdsw, newdsw->sw.setup_callback,
(XtPointer) &setup);
}
UpdateGStates(newdsw);
}
if (NE(watch_progress)) {
if (newdsw->sw.watch_progress &&
XDPSSetEventDelivery(XtDisplay(newdsw), dps_event_query) !=
dps_event_pass_through) newdsw->sw.watch_progress = False;
}
if (NE(application_scrolling) && !newdsw->sw.application_scrolling) {
XtVaSetValues(newdsw->sw.h_scroll, XmNmaximum, newdsw->sw.scroll_h_max,
XmNvalue, newdsw->sw.scroll_h_value,
XmNsliderSize, newdsw->sw.scroll_h_size, NULL);
XtVaSetValues(newdsw->sw.v_scroll, XmNmaximum, newdsw->sw.scroll_v_max,
XmNvalue, newdsw->sw.scroll_v_value,
XmNsliderSize, newdsw->sw.scroll_v_size, NULL);
}
if (newdsw->sw.doing_feedback) {
DONT_CHANGE(scale);
DONT_CHANGE(area_width);
DONT_CHANGE(area_height);
}
if (NE(pixmap_limit) || NE(absolute_pixmap_limit)) CheckPixmapSize(newdsw);
if (NE(area_width) || NE(area_height) || NE(scale)) ResizeArea(newdsw);
if (NE(use_backing_pixmap) || NE(watch_progress) ||
NE(minimal_drawing) || NE(document_size_pixmaps)) {
Boolean freeIt = False, setUp = False;
AbortOrFinish(newdsw);
if (NE(use_backing_pixmap)) {
if (newdsw->sw.use_backing_pixmap) setUp = True;
else freeIt = True;
}
if (NE(document_size_pixmaps)) {
if (newdsw->sw.backing_pixmap != None) freeIt = True;
setUp = True;
}
if (freeIt) FreeBackingPixmap(newdsw);
if (setUp) SetUpInitialPixmap(newdsw);
}
if (NE(dirty_areas)) {
float *r = newdsw->sw.dirty_areas;
int n = newdsw->sw.num_dirty_areas;
DONT_CHANGE(dirty_areas);
DONT_CHANGE(num_dirty_areas);
AbortOrFinish(newdsw);
AddRectsToDirtyArea(newdsw, r, n);
if (newdsw->sw.watch_progress || newdsw->sw.backing_pixmap == None) {
ClearDirtyAreas(newdsw);
newdsw->sw.drawing_stage = DSWStart;
} else {
AddUserSpaceRectsToPending(newdsw, r, n);
StartDrawing(newdsw);
}
}
if (NE(use_feedback_pixmap)) HandleFeedbackPixmapChange(newdsw);
return False;
#undef DONT_CHANGE
}
static XtGeometryResult GeometryManager(
Widget w,
XtWidgetGeometry *desired, XtWidgetGeometry *allowed)
{
return XtMakeGeometryRequest(XtParent(w), desired, allowed);
}
static XtGeometryResult QueryGeometry(
Widget w,
XtWidgetGeometry *desired, XtWidgetGeometry *allowed)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
return XtQueryGeometry(dsw->sw.scrolled_window, desired, allowed);
}
static void CopyToFeedbackPixmap(
DPSScrolledWindowWidget dsw,
float *rects,
int n)
{
int llx, lly, urx, ury;
int dx, dy;
int i;
float *r;
ComputeOffsets(dsw, &dx, &dy);
for (i = 0; i < n; i++) {
r = rects + (i * 4);
ConvertToX(dsw, LEFT(r), BOTTOM(r), &llx, &lly);
ConvertToX(dsw, RIGHT(r), TOP(r), &urx, &ury);
XCopyArea(XtDisplay(dsw), dsw->sw.backing_pixmap,
dsw->sw.feedback_pixmap, dsw->sw.no_ge_gc,
llx+dx-1, ury+dy-1, urx-llx+2, lly-ury+2, llx-1, ury-1);
}
}
static void CallFeedbackCallback(
DPSScrolledWindowWidget dsw,
float *r,
int n)
{
DSWFeedbackCallbackRec f;
f.start_feedback_data = dsw->sw.start_feedback_data;
f.continue_feedback_data = dsw->sw.continue_feedback_data;
if (dsw->sw.feedback_pixmap == None) {
f.type = DSWWindow;
f.drawable = XtWindow(dsw->sw.drawing_area);
f.gstate = dsw->sw.window_gstate;
} else {
f.type = DSWFeedbackPixmap;
f.drawable = dsw->sw.feedback_pixmap;
f.gstate = dsw->sw.feedback_gstate;
}
f.context = dsw->sw.context;
f.dirty_rects = r;
f.dirty_count = n;
XDPSSetContextGState(dsw->sw.context, f.gstate);
_DPSSWSetRectViewClip(dsw->sw.context, r, n * 4);
XtCallCallbackList((Widget) dsw, dsw->sw.feedback_callback,
(XtPointer) &f);
DPSWaitContext(dsw->sw.context);
}
static void SetScale(
Widget w,
double scale,
long fixedX, long fixedY)
{
float psX, psY;
ConvertToPS((DPSScrolledWindowWidget) w, (float) fixedX, (float) fixedY,
&psX, &psY);
SetScaleAndScroll(w, scale, psX, psY, fixedX, fixedY);
}
void DSWSetScale(
Widget w,
double scale,
long fixedX, long fixedY)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.set_scale) (w, scale, fixedX, fixedY);
}
static void ScrollPoint(
Widget w,
double psX, double psY,
long xX, long xY)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
if (!XtIsRealized(w)) {
dsw->sw.use_saved_scroll = True;
dsw->sw.scroll_pic_x = psX;
dsw->sw.scroll_pic_y = psY;
dsw->sw.scroll_win_x = xX;
dsw->sw.scroll_win_y = xY;
return;
} else {
SetDrawingAreaPosition(dsw, psX, psY, xX, xY, False);
ScrollMoved(dsw);
}
}
void DSWScrollPoint(
Widget w,
double psX, double psY,
long xX, long xY)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.scroll_point) (w, psX, psY, xX, xY);
}
static void ScrollBy(Widget w, long dx, long dy)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
int value;
if (dx == 0 && dy == 0) return;
if (!XtIsRealized(w) && dsw->sw.use_saved_scroll) {
dsw->sw.scroll_win_x += dx;
dsw->sw.scroll_win_y += dy;
} else {
value = dsw->sw.scroll_h_value + dx;
if (value < 0) value = 0;
else if (value > dsw->sw.scroll_h_max - dsw->sw.scroll_h_size) {
value = dsw->sw.scroll_h_max - dsw->sw.scroll_h_size;
}
dsw->sw.scroll_h_value = value;
if (!dsw->sw.application_scrolling) {
XtVaSetValues(dsw->sw.h_scroll, XmNvalue, value, NULL);
}
value = dsw->sw.scroll_v_value + dy;
if (value < 0) value = 0;
else if (value > dsw->sw.scroll_v_max - dsw->sw.scroll_v_size) {
value = dsw->sw.scroll_v_max - dsw->sw.scroll_v_size;
}
dsw->sw.scroll_v_value = value;
if (!dsw->sw.application_scrolling) {
XtVaSetValues(dsw->sw.v_scroll, XmNvalue, value, NULL);
}
ScrollMoved(dsw);
}
}
void DSWScrollBy(Widget w, long dx, long dy)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.scroll_by) (w, dx, dy);
}
static void ScrollTo(Widget w, long x, long y)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
int max, size;
if (XtIsRealized(w)) {
if (x < 0) x = 0;
else if (x > dsw->sw.scroll_h_max - dsw->sw.scroll_h_size) {
x = dsw->sw.scroll_h_max - dsw->sw.scroll_h_size;
}
dsw->sw.scroll_h_value = x;
if (y < 0) y = 0;
else if (y > dsw->sw.scroll_v_max - dsw->sw.scroll_v_size) {
y = dsw->sw.scroll_v_max - dsw->sw.scroll_v_size;
}
dsw->sw.scroll_v_value = y;
if (!dsw->sw.application_scrolling) {
XtVaSetValues(dsw->sw.h_scroll, XmNvalue, x, NULL);
XtVaSetValues(dsw->sw.v_scroll, XmNvalue, y, NULL);
}
ScrollMoved(dsw);
}
}
void DSWScrollTo(Widget w, long x, long y)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.scroll_to) (w, x, y);
}
static void SetScaleAndScroll(
Widget w,
double scale,
double psX, double psY,
long xX, long xY)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
Arg arg;
union {
int i;
float f;
} kludge;
dsw->sw.use_saved_scroll = True;
dsw->sw.scroll_pic_x = psX;
dsw->sw.scroll_pic_y = psY;
dsw->sw.scroll_win_x = xX;
dsw->sw.scroll_win_y = xY;
kludge.f = scale;
arg.name = XtNscale;
if (sizeof(float) > sizeof(XtArgVal)) arg.value = (XtArgVal) &kludge.f;
else arg.value = (XtArgVal) kludge.i;
XtSetValues(w, &arg, 1);
}
void DSWSetScaleAndScroll(
Widget w,
double scale,
double psX, double psY,
long xX, long xY)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.set_scale_and_scroll) (w, scale, psX, psY, xX, xY);
}
static void ConvertXToPS(
Widget w,
long xX, long xY,
float *psX, float *psY)
{
ConvertToPS((DPSScrolledWindowWidget) w, (float) xX, (float) xY, psX, psY);
}
void DSWConvertXToPS(
Widget w,
long xX, long xY,
float *psX, float *psY)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.convert_x_to_ps) (w, xX, xY, psX, psY);
}
static void ConvertPSToX(
Widget w,
double psX, double psY,
int *xX, int *xY)
{
ConvertToX((DPSScrolledWindowWidget) w, psX, psY, xX, xY);
}
void DSWConvertPSToX(
Widget w,
double psX, double psY,
int *xX, int *xY)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.convert_ps_to_x) (w, psX, psY, xX, xY);
}
static void AddToDirtyArea(
Widget w,
float *rect,
long n)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
if (n == 1 && rect[0] == 0 && rect[1] == 0 &&
rect[2] == -1 && rect[2] == -1) {
rect[2] = dsw->sw.area_width;
rect[3] = dsw->sw.area_height;
}
XtVaSetValues(w, XtNdirtyAreas, rect, XtNnumDirtyAreas, n, NULL);
}
void DSWAddToDirtyArea(
Widget w,
float *rect,
long n)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.add_to_dirty_area) (w, rect, n);
}
static Boolean TakeFeedbackPixmap(
Widget w,
Pixmap *p,
int *width, int *height, int *depth,
Screen **screen)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
if (dsw->sw.doing_feedback) return False;
*p = dsw->sw.feedback_pixmap;
if (*p == None) {
*width = *height = *depth;
*screen = NULL;
return True;
}
*width = dsw->sw.feedback_width;
*height = dsw->sw.feedback_height;
*depth = dsw->sw.drawing_area->core.depth;
*screen = dsw->core.screen;
dsw->sw.feedback_pixmap = None;
dsw->sw.feedback_width = dsw->sw.feedback_height = 0;
return True;
}
Boolean DSWTakeFeedbackPixmap(
Widget w,
Pixmap *p,
int *width, int *height, int *depth,
Screen **screen)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
return (*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.take_feedback_pixmap) (w, p, width, height,
depth, screen);
}
static void StartFeedbackDrawing(
Widget w,
XtPointer start_feedback_data)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
float *r;
FinishDrawing(dsw);
CheckFeedbackPixmap(dsw);
if (dsw->sw.feedback_pixmap != None) {
GrowRectList(&dsw->sw.prev_dirty_areas, &dsw->sw.prev_dirty_areas_size,
0, 1, 1);
r = dsw->sw.prev_dirty_areas;
ConvertToPS(dsw, 0 + DELTA, dsw->sw.drawing_area->core.height - DELTA,
r, r+1);
ConvertToPS(dsw, dsw->sw.drawing_area->core.width - DELTA, 0 + DELTA,
r+2, r+3);
r[2] -= r[0];
r[3] -= r[1];
dsw->sw.num_prev_dirty_areas = 1;
if (dsw->sw.backing_pixmap != None) {
CopyToFeedbackPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
} else {
CopyRectsToCurrentDrawing(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
(void) ClipAndDraw(dsw, DSWFeedbackPixmap, DSWFinish, True);
}
}
dsw->sw.num_prev_dirty_areas = 0;
dsw->sw.doing_feedback = True;
dsw->sw.start_feedback_data = start_feedback_data;
}
void DSWStartFeedbackDrawing(
Widget w,
XtPointer start_feedback_data)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.start_feedback_drawing) (w, start_feedback_data);
}
static void EndFeedbackDrawing(
Widget w,
int restore)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
if (restore) {
if (dsw->sw.backing_pixmap != None) {
UpdateWindowFromBackingPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
} else {
CopyRectsToCurrentDrawing(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
(void) ClipAndDraw(dsw, DSWWindow, DSWFinish, True);
}
}
if (dsw->sw.feedback_gstate != 0) {
XDPSFreeContextGState(dsw->sw.context, dsw->sw.feedback_gstate);
}
dsw->sw.doing_feedback = dsw->sw.feedback_displayed = False;
}
void DSWEndFeedbackDrawing(
Widget w,
Bool restore)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.end_feedback_drawing) (w, restore);
}
static void SetFeedbackDirtyArea(
Widget w,
float *rects,
int count,
XtPointer continue_feedback_data)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
int i;
float *r;
for (i = 0; i < count; i++) {
r = rects + (i * 4);
if (WIDTH(r) < 0) {
LEFT(r) += WIDTH(r);
WIDTH(r) = -WIDTH(r);
}
if (HEIGHT(r) < 0) {
BOTTOM(r) += HEIGHT(r);
HEIGHT(r) = -HEIGHT(r);
}
}
if (dsw->sw.backing_pixmap != None) {
if (dsw->sw.feedback_pixmap != None) {
CopyToFeedbackPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
} else {
UpdateWindowFromBackingPixmap(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
}
} else {
CopyRectsToCurrentDrawing(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
(void) ClipAndDraw(dsw, (dsw->sw.feedback_pixmap == None ?
DSWWindow : DSWFeedbackPixmap),
DSWFinish, True);
}
dsw->sw.continue_feedback_data = continue_feedback_data;
CallFeedbackCallback(dsw, rects, count);
if (dsw->sw.feedback_pixmap != None) {
CopyRectsToDirtyArea(dsw, dsw->sw.prev_dirty_areas,
dsw->sw.num_prev_dirty_areas);
AddRectsToDirtyArea(dsw, rects, count);
SimplifyRects(dsw->sw.dirty_areas, &dsw->sw.num_dirty_areas);
UpdateWindowFromFeedbackPixmap(dsw, dsw->sw.dirty_areas,
dsw->sw.num_dirty_areas);
dsw->sw.num_dirty_areas = 0;
}
CopyRectsToPrevDirtyArea(dsw, rects, count);
dsw->sw.feedback_displayed = True;
}
void DSWSetFeedbackDirtyArea(
Widget w,
float *rects,
int count,
XtPointer continue_feedback_data)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.set_feedback_dirty_area) (w, rects, count,
continue_feedback_data);
}
static void FinishPendingDrawing(Widget w)
{
FinishDrawing((DPSScrolledWindowWidget) w);
}
void DSWFinishPendingDrawing(Widget w)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.finish_pending_drawing) (w);
}
static void AbortPendingDrawing(Widget w)
{
AbortDrawing((DPSScrolledWindowWidget) w);
}
void DSWAbortPendingDrawing(Widget w)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.abort_pending_drawing) (w);
}
static void UpdateDrawing(
Widget w,
float *rects,
int count)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
int i;
float *r;
int llx, lly, urx, ury;
int dx, dy;
if (dsw->sw.backing_pixmap == None) {
AddToDirtyArea(w, rects, count);
return;
}
ComputeOffsets(dsw, &dx, &dy);
for (i = 0; i < count; i++) {
r = rects + (i * 4);
ConvertToX(dsw, LEFT(r), BOTTOM(r), &llx, &lly);
ConvertToX(dsw, RIGHT(r), TOP(r), &urx, &ury);
XCopyArea(XtDisplay(dsw), XtWindow(dsw->sw.drawing_area),
dsw->sw.backing_pixmap, dsw->sw.no_ge_gc,
llx-1, ury-1, urx-llx+2, lly-ury+2, llx+dx-1, ury+dy-1);
}
}
void DSWUpdateDrawing(
Widget w,
float *rects,
int count)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.update_drawing) (w, rects, count);
}
static void GetScrollInfo(
Widget w,
int *h_value, int *h_size, int *h_max, int *v_value, int *v_size, int *v_max)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
if (h_value != NULL) *h_value = dsw->sw.scroll_h_value;
if (h_size != NULL) *h_size = dsw->sw.scroll_h_size;
if (h_max != NULL) *h_max = dsw->sw.scroll_h_max;
if (v_value != NULL) *v_value = dsw->sw.scroll_v_value;
if (v_size != NULL) *v_size = dsw->sw.scroll_v_size;
if (v_max != NULL) *v_max = dsw->sw.scroll_v_max;
}
void DSWGetScrollInfo(
Widget w,
int *h_value, int *h_size, int *h_max, int *v_value, int *v_size, int *v_max)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.get_scroll_info) (w, h_value, h_size, h_max,
v_value, v_size, v_max);
}
static void GetDrawingInfo(
Widget w,
DSWDrawableType *type,
Drawable *drawable,
DPSGState *gstate,
DPSContext *context)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
if (dsw->sw.backing_pixmap != None) {
*type = DSWBackingPixmap;
*drawable = dsw->sw.backing_pixmap;
*gstate = dsw->sw.backing_gstate;
} else {
*type = DSWWindow;
*drawable = XtWindow(dsw->sw.drawing_area);
*gstate = dsw->sw.window_gstate;
}
*context = dsw->sw.context;
}
void DSWGetDrawingInfo(
Widget w,
DSWDrawableType *type,
Drawable *drawable,
DPSGState *gstate,
DPSContext *context)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
(*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.get_drawing_info) (w, type, drawable, gstate, context);
}
static Boolean GiveFeedbackPixmap(
Widget w,
Pixmap p,
int width, int height, int depth,
Screen *screen)
{
DPSScrolledWindowWidget dsw = (DPSScrolledWindowWidget) w;
if ((unsigned) depth != dsw->sw.drawing_area->core.depth
|| screen != dsw->core.screen
|| dsw->sw.feedback_pixmap != None) return False;
dsw->sw.feedback_pixmap = p;
dsw->sw.feedback_width = width;
dsw->sw.feedback_height = height;
return True;
}
Boolean DSWGiveFeedbackPixmap(
Widget w,
Pixmap p,
int width, int height, int depth,
Screen *screen)
{
XtCheckSubclass(w, dpsScrolledWindowWidgetClass, NULL);
return (*((DPSScrolledWindowWidgetClass) XtClass(w))->
sw_class.give_feedback_pixmap) (w, p, width, height,
depth, screen);
}
static void ConvertToX(
DPSScrolledWindowWidget dsw,
float psX,
float psY,
int *xX,
int *xY)
{
*xX = dsw->sw.ctm[0] * psX + dsw->sw.ctm[2] * psY + dsw->sw.ctm[4] +
dsw->sw.x_offset + 0.5;
*xY = dsw->sw.ctm[1] * psX + dsw->sw.ctm[3] * psY + dsw->sw.ctm[5] +
dsw->sw.y_offset + 0.5;
}
static void ConvertToPS(
DPSScrolledWindowWidget dsw,
float xX, float xY,
float *psX, float *psY)
{
xX -= dsw->sw.x_offset;
xY -= dsw->sw.y_offset;
*psX = dsw->sw.inv_ctm[0] * xX + dsw->sw.inv_ctm[2] * xY +
dsw->sw.inv_ctm[4];
*psY = dsw->sw.inv_ctm[1] * xX + dsw->sw.inv_ctm[3] * xY +
dsw->sw.inv_ctm[5];
}
static void ConvertToOrigPS(
DPSScrolledWindowWidget dsw,
int xX, int xY,
float *psX, float *psY)
{
xX -= dsw->sw.x_offset;
xY -= dsw->sw.y_offset;
*psX = dsw->sw.orig_inv_ctm[0] * xX + dsw->sw.orig_inv_ctm[2] * xY +
dsw->sw.orig_inv_ctm[4];
*psY = dsw->sw.orig_inv_ctm[1] * xX + dsw->sw.orig_inv_ctm[3] * xY +
dsw->sw.orig_inv_ctm[5];
}