chuck@Morgan.COM (Chuck Ocheret) (05/16/91)
There has been some discussion on the motif-talk mailing list about scrolled windows and how to accomplish scrolling. A few people have suggested that the code I describe below should be presented to the net since it is of general utility. > From my experience(my text widget with smooth scrolling in both directions) > I believe it is possible to write a set of convenience routines that would > be a great assistance to "Application Defined Scroll". > In fact, this type of scrolling can be built into XmScrolled window.... : : > almost readable... However, the computations of the copied/exposed areas > are never pretty - therefore a Motif support here would help a lot. I wrote something which I call the PanHandler which does the calculations you want. In addition it takes care of a problem which burns a lot of people who don't think the scrolling problem through. This problem is the result of the asynchronous nature of X. If you have an occluding window over the rectangle you are trying to pan, the your XCopyArea() calls can result in GraphicsExpose events since some areas couldn't get copied. However, you might not see those GraphicsExpose events until after you have done a bunch of pans. When the GraphicsExpose events eventually get to your client, you have already scrolled the damaged areas to new locations, so that the x, y members of the GraphicsExpose events need to be adjusted. This is what the PanHandler fixes for you. It maintains a queue of your pan requests and keeps it up to date with respect to incoming Expose, GraphicsExpose and NoExpose events. It adjusts the Expose and GraphicsExpose events accordingly so that you repair the right portions of your window. I have seen very few programs which scroll properly when there is an occluding window. Below is a shar file which contains source for the PanHandler (with a simple Imakefile) and a brief description of the functionality (in README). The (ugly) Xlib program PanHandlerUT displays a quarter-infinite grid which you can pan around by dragging it with btn1motion. The PanHandler is a public component of the Widget set I am writing for Morgan Stanley to replace Motif. PanHandlerUT is an Xlib program because I didn't want to be bound to any particular widget set for unit test programs for general utilites. By the way, there is something very silly in this implementation...can anyone find it? Let me know if you find this useful. +--------------------+ Chuck Ocheret +---------------+ |chuck@fid.Morgan.COM| Morgan Stanley & Co., Inc. |(212) 703-4474 | | Duty now ... |19th Floor, 1251 Avenue of the Americas|for the future.| +--------------------+ New York, N.Y. 10020 USA +---------------+ #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # Imakefile # Node.c # Node.h # PanHandler.c # PanHandler.h # PanHandlerI.h # PanHandlerUT.c # This archive created: Tue May 14 19:21:59 1991 export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(2973 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else sed 's/^ X//' << \SHAR_EOF > 'README' XXcPanHandler XcCreatePanHandler() - allocates a PanHandler X Xvoid XcPanRectangle(panHandler, display, window, gc, x, y, width, height, X src_x, src_y, dest_x, dest_y, panExposeCB, client) X XcPanHandler panHandler; /* it */ X Display *display; /* duh? */ X Window window; /* dubudoy? */ X GC gc; /* gee. see. */ X int x, y; /* origin of rectangle */ X unsigned int width, height; /* extent of rectangle */ X int src_x, src_y; /* pan start */ X int dest_x, dest_y; /* pan end */ X void (*panExposeCB)(); /* see below */ X XtPointer client; /* client data for panExposeCB */ X XWhen panning a rectangle you end up doing 1 copy and up to 2 exposes. XSince you can compute which regions get exposed, it is more efficient Xto just draw them rather than generating an expose event via a round Xtrip to the server. The panExposeCB, if non-NULL, gets called with an XXcPanAccomplish structure which describes the regions to draw (see Xbelow). If panExposeCB is NULL, XClearArea calls are made as needed Xto generate expose events. X Xvoid XcPanEvent(panHandler, event) X XcPanHandler panHandler; /* it */ X XEvent *event; /* Expose, GraphicsExpose, or NoExpose event */ X XWhen you get such events for the window you are panning, pass the Xevents to XcPanEvent and they will get their x, y members adjusted. XIt is important to pass all such events so that the PanHandler can Xkeep track of what pans are still pending. X XThere are two other utility routines: X Xvoid XcPanCompute(x, y, width, height, delta_x, delta_y, how) X int x, y; X unsigned int width, height; X int delta_x, delta_y; X XcPanAccomplish *how; X XThis fills in the XcPanAccomplish structure with information about the Xcopy and exposes needed to accomplish the pan. XcPanRectangle() uses XXcPanCompute(). X Xtypedef struct xcPanAccomplish { X int copy_src_x, copy_src_y; /* copy info */ X unsigned int copy_width, copy_height; X int copy_dst_x, copy_dst_y; X int expose_1_x, expose_1_y; /* 1st expose info */ X unsigned int expose_1_width, expose_1_height; X int expose_2_x, expose_2_y; /* 2nd exopse info */ X unsigned int expose_2_width, expose_2_height; X} XcPanAccomplish; X XIf copy_width, expose_1_width, or expose_2_width are 0 then the Xcorresponding copy or expose should not be performed. X Xvoid XcPanAccrue(panHandler, delta_x, delta_y) X XcPanHandler panHandler; X int delta_x, delta_y; X XPretty obvious. X XThe unit test program (Xlib) included, PanHandlerUT, lets you click Xthe left mouse on a grid and drag it around. Initially you can't drag Xto the right or down (I didn't feel like dealing with negative numbers Xfor a test program). Put up some occluding windows and try to make it Xbreak. You can make it fall behind and look ugly, but it will Xeventually catch up. Note that the MIT X server does some really Xdifferent things when an occluding window is a shaped one like oclock. XIt still works but it gets much slower and the exposed regions are Xmuch larger than I would expect. SHAR_EOF if test 2973 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 2973 characters)' fi fi # end of overwriting check echo shar: extracting "'Imakefile'" '(285 characters)' if test -f 'Imakefile' then echo shar: will not over-write existing file "'Imakefile'" else sed 's/^ X//' << \SHAR_EOF > 'Imakefile' XHEADERS = Node.h PanHandler.h PanHandlerP.h X SRCS = Node.c PanHandler.c X OBJS = ${SRCS:%.c=%.o} X XNormalLibraryObjectRule() XNormalLibraryTarget(chuck,$(OBJS)) X XDependTarget() X XAllTarget(PanHandlerUT) XNormalProgramTarget(PanHandlerUT,PanHandlerUT.o,libchuck.a,libchuck.a,-lXt -lX11) SHAR_EOF if test 285 -ne "`wc -c < 'Imakefile'`" then echo shar: error transmitting "'Imakefile'" '(should have been 285 characters)' fi fi # end of overwriting check echo shar: extracting "'Node.c'" '(1703 characters)' if test -f 'Node.c' then echo shar: will not over-write existing file "'Node.c'" else sed 's/^ X//' << \SHAR_EOF > 'Node.c' X#ifndef lint Xstatic char rcsid[] = "@(#) $Id$"; X#endif X/* X * Copyright 1991 Gigadactyl, Inc. X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, provided X * that the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation, and that the name of Gigadactyl, Inc. not be used in X * advertising or publicity pertaining to distribution of the software X * without specific, written prior permission. Gigadactyl, Inc. makes no X * representations about the suitability of this software for any purpose. X * It is provided "as is" without express or implied warranty. X * X * Author: Charles A. Ocheret <chuck@fid.morgan.com> X */ X X#include "Node.h" X XXcNode *XcNodeAlloc() X{ X register XcNode *p; X X p = (XcNode *)XtMalloc(sizeof(*p)); X p->f = p->b = p; X p->d = (XtPointer)(0); X return p; X} X X/* cuts head circular list before h and inserts new circular list, X * making large circular list. This operation is semetrical with X * respect to interchange of h and p. X */ X Xvoid XcNodeInsert(p, h) X register XcNode *p; X register XcNode *h; X{ X if ((p != (XcNode *)(0)) && (h != (XcNode *)(0))) { X register XcNode *t = p->b; X X p->b->f = h; X p->b = h->b; X h->b->f = p; X h->b = t; X } X} X Xvoid XcNodeRemove(p) X register XcNode *p; X{ X if (p != (XcNode*)(0)) { X p->b->f = p->f; X p->f->b = p->b; X p->b = p; X p->f = p; X } X return; X} X Xvoid XcNodeToad(p) X register XcNode *p; X{ X if (p != (XcNode*)(0)) { X XcNode *o = p->b; X XcNode *q = p->f; X XcNode *r; X X o->f = q; X q->b = o; X p->f = r = q->f; X p->b = q; X q->f = p; X r->b = p; X } X} SHAR_EOF if test 1703 -ne "`wc -c < 'Node.c'`" then echo shar: error transmitting "'Node.c'" '(should have been 1703 characters)' fi fi # end of overwriting check echo shar: extracting "'Node.h'" '(1093 characters)' if test -f 'Node.h' then echo shar: will not over-write existing file "'Node.h'" else sed 's/^ X//' << \SHAR_EOF > 'Node.h' X/* X * @(#) $Id$ X */ X/* X * Copyright 1991 Gigadactyl, Inc. X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, provided X * that the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation, and that the name of Gigadactyl, Inc. not be used in X * advertising or publicity pertaining to distribution of the software X * without specific, written prior permission. Gigadactyl, Inc. makes no X * representations about the suitability of this software for any purpose. X * It is provided "as is" without express or implied warranty. X * X * Author: Charles A. Ocheret <chuck@fid.morgan.com> X */ X X#ifndef _Node_h_ X#define _Node_h_ X X#include <X11/Intrinsic.h> X X#define XcNodeAt(np) ((Node *)((np)->d)) X Xtypedef struct xcNode XcNode; Xstruct xcNode { X XcNode *f; X XcNode *b; X XtPointer d; X}; X Xextern XcNode *XcNodeAlloc(); Xextern void XcNodeInsert(); Xextern void XcNodeRemove(); Xextern void XcNodeToad(); X X#endif _Node_h_ SHAR_EOF if test 1093 -ne "`wc -c < 'Node.h'`" then echo shar: error transmitting "'Node.h'" '(should have been 1093 characters)' fi fi # end of overwriting check echo shar: extracting "'PanHandler.c'" '(7144 characters)' if test -f 'PanHandler.c' then echo shar: will not over-write existing file "'PanHandler.c'" else sed 's/^ X//' << \SHAR_EOF > 'PanHandler.c' X#ifndef lint Xstatic char rcsid[] = "@(#) $Id$"; X#endif X/* X * Copyright 1991 Gigadactyl, Inc. X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, provided X * that the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation, and that the name of Gigadactyl, Inc. not be used in X * advertising or publicity pertaining to distribution of the software X * without specific, written prior permission. Gigadactyl, Inc. makes no X * representations about the suitability of this software for any purpose. X * It is provided "as is" without express or implied warranty. X * X * Author: Charles A. Ocheret <chuck@fid.morgan.com> X */ X X/* X * A scroll manager solves an edge condition problem relating to Expose X * and GraphicsExpose events occurring among a series of XCopy(Area|Plane) X * requests. When an area is copied, maybe to accomplish scrolling or X * panning, occluding windows will cause GraphicsExpose events for the X * regions which couldn't be copied. If there were no occluding windows X * then a NoExpose event is generated. Also the removal of an occluding X * window will cause an Expose event. If a number of XCopyArea requests X * are performed in rapid succession, perhaps in response to scrollBar X * activity, these expose events contain obsolete x and y information X * since the virtual coordinates have been scrolled to a new location. X * The scroll manager is an object which keeps track of the scrolls X * performed and and the offsets required to relocate expose events to X * the current coordinate system. X */ X X#include <X11/Intrinsic.h> X#include "PanHandlerI.h" X XXcPanHandler XcCreatePanHandler() X{ X XcPanHandler panHandler; X X panHandler = XtNew(struct xcPanHandler); X panHandler->offset_x = 0; X panHandler->offset_y = 0; X panHandler->pan_count = 0; X panHandler->pan_queue = XcNodeAlloc(); X panHandler->pan_handling = FALSE; X return panHandler; X} X Xstatic void RemovePan(panHandler) X XcPanHandler panHandler; X{ X XcPanAmount *panAmount; X XcNode *node; X X if (panHandler->pan_count != 0) { X /* Remove a pan from the queue */ X node = panHandler->pan_queue->f; X panAmount = (XcPanAmount *)node->d; X panHandler->offset_x -= panAmount->x; X panHandler->offset_y -= panAmount->y; X XcNodeRemove(node); X XtFree((char *)panAmount); X XtFree((char *)node); X panHandler->pan_count--; X } X} X Xvoid XcPanEvent(panHandler, event) X XcPanHandler panHandler; X XEvent *event; X{ X int x, y; X X switch (event->type) { X case Expose: X event->xexpose.x += panHandler->offset_x; X event->xexpose.y += panHandler->offset_y; X break; X case GraphicsExpose: X if (panHandler->pan_handling == FALSE) { X RemovePan(panHandler); X if (event->xgraphicsexpose.count != 0) { X panHandler->pan_handling = TRUE; X } X } else if (event->xgraphicsexpose.count == 0) { X panHandler->pan_handling = FALSE; X } X event->xgraphicsexpose.x += panHandler->offset_x; X event->xgraphicsexpose.y += panHandler->offset_y; X break; X case NoExpose: X RemovePan(panHandler); X panHandler->pan_handling = FALSE; X default: X break; X } X} X X/* X * Records a new pan request in a pan handler X */ Xvoid XcPanAccrue(panHandler, delta_x, delta_y) X XcPanHandler panHandler; X int delta_x, delta_y; X{ X XcNode *node; X XcPanAmount *panAmount; X X /* Place new pan onto the queue */ X panAmount = XtNew(XcPanAmount); X panAmount->x = delta_x; X panAmount->y = delta_y; X panHandler->offset_x += delta_x; X panHandler->offset_y += delta_y; X panHandler->pan_count++; X node = XcNodeAlloc(); X node->d = (XtPointer)panAmount; X XcNodeInsert(panHandler->pan_queue, node); X} X Xvoid XcPanCompute(x, y, width, height, delta_x, delta_y, how) X int x, y; X unsigned int width, height; X int delta_x, delta_y; X XcPanAccomplish *how; X{ X int tx, ty; X int code; X X if (delta_x == 0 && delta_y == 0) { X /* No real pan was made so don't do anything */ X how->copy_width=how->expose_1_width = how->expose_2_width = 0; X } else if (ABS(delta_x) > width || ABS(delta_y) > height) { X /* A delta is large enough that the entire X rectangle must be repainted */ X how->copy_width = how->expose_2_width = 0; X how->expose_1_x = x; X how->expose_1_y = y; X how->expose_1_width = width; X how->expose_1_height = height; X } else { X /* Since we've taken care of the above 2 X cases we can do the following */ X if (delta_x < 0) { X how->copy_src_x = x - delta_x; X how->copy_width = width + delta_x; X how->copy_dst_x = x; X how->expose_2_x = x + width + delta_x; X how->expose_2_width = -delta_x; X } else if (delta_x == 0) { X how->copy_src_x = x; X how->copy_width = width; X how->copy_dst_x = x; X how->expose_2_width = 0; X } else { /* delta_x > 0 */ X how->copy_src_x = x; X how->copy_width = width - delta_x; X how->copy_dst_x = x + delta_x; X how->expose_2_x = x; X how->expose_2_width = delta_x; X } X if (delta_y < 0) { X how->copy_src_y = y - delta_y; X how->copy_height = height + delta_y; X how->copy_dst_y = y; X how->expose_1_x = x; X how->expose_1_y = y + height + delta_y; X how->expose_1_width = width; X how->expose_1_height = -delta_y; X how->expose_2_y = y; X how->expose_2_height = height + delta_y; X } else if (delta_y == 0) { X how->copy_src_y = y; X how->copy_height = height; X how->copy_dst_y = y; X how->expose_1_width = 0; X how->expose_2_y = y; X how->expose_2_height = height; X } else { /* delta_y > 0 */ X how->copy_src_y = y; X how->copy_height = height - delta_y; X how->copy_dst_y = y + delta_y; X how->expose_1_x = x; X how->expose_1_y = y; X how->expose_1_width = width; X how->expose_1_height = delta_y; X how->expose_2_y = y + delta_y; X how->expose_2_height = height - delta_y; X } X } X} X X/* X * Convenience function to pan a rectangle and update its pan handler X */ Xvoid XcPanRectangle(panHandler, display, window, gc, x, y, width, height, X src_x, src_y, dest_x, dest_y, panExposeCB, client) X XcPanHandler panHandler; X Display *display; X Window window; X GC gc; X int x, y; X unsigned int width, height; X int src_x, src_y; X int dest_x, dest_y; X void (*panExposeCB)(); X XtPointer client; X{ X int delta_x, delta_y; X XcPanAccomplish how; X X delta_x = dest_x - src_x; X delta_y = dest_y - src_y; X XcPanCompute(x, y, width, height, delta_x, delta_y, &how); X X if (how.copy_width != 0) { X /* We shouldn't accrue pan info if we are not doing a copy */ X /* XXX - Is this right? Can we get out of sync here? */ X XcPanAccrue(panHandler, delta_x, delta_y); X XCopyArea(display, window, window, gc, X how.copy_src_x, how.copy_src_y, X how.copy_width, how.copy_height, X how.copy_dst_x, how.copy_dst_y); X } X if (panExposeCB != (void(*)())0) { X (*panExposeCB)(display, window, gc, &how, client); X } else { X if (how.expose_1_width != 0) { X XClearArea(display, window, X how.expose_1_x, how.expose_1_y, X how.expose_1_width, how.expose_1_height, X TRUE); X } X if (how.expose_2_width != 0) { X XClearArea(display, window, X how.expose_2_x, how.expose_2_y, X how.expose_2_width, how.expose_2_height, X TRUE); X } X } X} SHAR_EOF if test 7144 -ne "`wc -c < 'PanHandler.c'`" then echo shar: error transmitting "'PanHandler.c'" '(should have been 7144 characters)' fi fi # end of overwriting check echo shar: extracting "'PanHandler.h'" '(1823 characters)' if test -f 'PanHandler.h' then echo shar: will not over-write existing file "'PanHandler.h'" else sed 's/^ X//' << \SHAR_EOF > 'PanHandler.h' X/* X * @(#) $Id$ X */ X/* X * Copyright 1991 Gigadactyl, Inc. X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, provided X * that the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation, and that the name of Gigadactyl, Inc. not be used in X * advertising or publicity pertaining to distribution of the software X * without specific, written prior permission. Gigadactyl, Inc. makes no X * representations about the suitability of this software for any purpose. X * It is provided "as is" without express or implied warranty. X * X * Author: Charles A. Ocheret <chuck@fid.morgan.com> X */ X X#ifndef _PanHandler_h_ X#define _PanHandler_h_ X X/* X * This structure describes how to accomplish a pan of a certain rectangular X * area. The normal semantics mean to perform a copy of an area followed by X * the exposure of up to 2 regions. The routine XcPanCompute() fills in this X * structure. The convenience function XcPanRectangle() uses XcPanCompute(). X */ Xtypedef struct xcPanAccomplish { X int copy_src_x, copy_src_y; X unsigned int copy_width, copy_height; X int copy_dst_x, copy_dst_y; X int expose_1_x, expose_1_y; X unsigned int expose_1_width, expose_1_height; X int expose_2_x, expose_2_y; X unsigned int expose_2_width, expose_2_height; X} XcPanAccomplish; X Xtypedef struct xcPanAmount { X int x; /* distance in x moved by pan */ X int y; /* distance in y moved by pan */ X} XcPanAmount; X X/* Opaque type XcPanHandler */ Xtypedef struct xcPanHandler *XcPanHandler; X Xextern XcPanHandler XcCreatePanHandler(); Xextern void XcPanEvent(); Xextern void XcPanAccrue(); Xextern void XcPanCompute(); Xextern void XcPanRectangle(); X X#endif _PanHandler_h_ SHAR_EOF if test 1823 -ne "`wc -c < 'PanHandler.h'`" then echo shar: error transmitting "'PanHandler.h'" '(should have been 1823 characters)' fi fi # end of overwriting check echo shar: extracting "'PanHandlerI.h'" '(541 characters)' if test -f 'PanHandlerI.h' then echo shar: will not over-write existing file "'PanHandlerI.h'" else sed 's/^ X//' << \SHAR_EOF > 'PanHandlerI.h' X/* X * @(#) $Id$ X */ X X#ifndef _PanHandlerI_h_ X#define _PanHandlerI_h_ X X#include "Node.h" X#include "PanHandler.h" X X#ifndef ABS X#define ABS(x) (((x) < 0) ? (-(x)) : (x)) X#endif ABS X Xstruct xcPanHandler { X int offset_x; /* Amount to correct expose event in x */ X int offset_y; /* Amount to correct expose event in y */ X Cardinal pan_count; /* Number of pans still outstanding */ X XcNode *pan_queue; /* Linked list representing pans done */ X Boolean pan_handling; /* Has 1st GraphicsExpose for pan been seen? */ X}; X X#endif _PanHandlerI_h_ SHAR_EOF if test 541 -ne "`wc -c < 'PanHandlerI.h'`" then echo shar: error transmitting "'PanHandlerI.h'" '(should have been 541 characters)' fi fi # end of overwriting check echo shar: extracting "'PanHandlerUT.c'" '(5744 characters)' if test -f 'PanHandlerUT.c' then echo shar: will not over-write existing file "'PanHandlerUT.c'" else sed 's/^ X//' << \SHAR_EOF > 'PanHandlerUT.c' X#ifndef lint Xstatic char rcsid[] = "@(#) $Id$"; X#endif X/* X * Copyright 1991 Gigadactyl, Inc. X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, provided X * that the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation, and that the name of Gigadactyl, Inc. not be used in X * advertising or publicity pertaining to distribution of the software X * without specific, written prior permission. Gigadactyl, Inc. makes no X * representations about the suitability of this software for any purpose. X * It is provided "as is" without express or implied warranty. X * X * Author: Charles A. Ocheret <chuck@fid.morgan.com> X */ X X#include <stdio.h> X#include <X11/Intrinsic.h> X#include "PanHandler.h" X X#define INCREMENT 50 X Xvoid patternRectangle(display, window, gc, origin, x, y, width, height) X Display *display; X Window window; X GC gc; X XcPanAmount *origin; X int x, y; X unsigned int width, height; X{ X XSegment *segments, *sp; X int i, xstart, xend, ystart, yend, count; X XClearArea(display, window, x, y, width, height, FALSE); X x += origin->x; X y += origin->y; X xstart = (((x+INCREMENT-1)/INCREMENT) * INCREMENT) - origin->x; X ystart = (((y+INCREMENT-1)/INCREMENT) * INCREMENT) - origin->y; X xend = (((x + width - 1)/INCREMENT) * INCREMENT) - origin->x; X yend = (((y + height - 1)/INCREMENT) * INCREMENT) - origin->y; X x -= origin->x; X y -= origin->y; X if (xstart <= xend) X count = 1 + ((xend - xstart)/INCREMENT); X else X count = 0; X if (ystart <= yend) X count += 1 + ((yend - ystart)/INCREMENT); X if (count == 0) X return; X sp = segments = (XSegment *)XtMalloc(count * sizeof(*segments)); X for (i = xstart; i <= xend; i += INCREMENT) { X sp->x1 = sp->x2 = i; X sp->y1 = y; X sp->y2 = y + height; X sp++; X } X for (i = ystart; i <= yend; i += INCREMENT) { X sp->y1 = sp->y2 = i; X sp->x1 = x; X sp->x2 = x + width; X sp++; X } X XDrawSegments(display, window, gc, segments, count, CoordModeOrigin); X XtFree((char *)segments); X} X Xvoid panExposeCB(display, window, gc, how, client) X Display *display; X Window window; X GC gc; X XcPanAccomplish *how; X XtPointer client; X{ X if (how->expose_1_width != 0) { X patternRectangle(display, window, gc, client, X how->expose_1_x, how->expose_1_y, X how->expose_1_width, how->expose_1_height); X } X if (how->expose_2_width != 0) { X patternRectangle(display, window, gc, client, X how->expose_2_x, how->expose_2_y, X how->expose_2_width, how->expose_2_height); X } X} X Xmain(argc, argv) X int argc; X char *argv[]; X{ X Display *display; X int screen; X XSetWindowAttributes winAtts; X unsigned long MrMask; X Window win, root; X XGCValues gcval; X GC white_gc; X char cp[10]; X KeySym ksym; X XEvent e; X XcPanHandler panHandler; X int x, y, i, k; X unsigned int width, height; X XcPanAmount origin; X X XtToolkitInitialize(); X if ((display = XOpenDisplay(NULL)) == NULL) { X (void)fprintf(stderr, "Couldn't open display '%s'\n", X XDisplayName(NULL)); X exit(1); X } X screen = DefaultScreen(display); X X MrMask = CWBackPixel | CWBorderPixel; X winAtts.border_pixel = WhitePixel(display, screen); X winAtts.background_pixel = BlackPixel(display, screen); X win = XCreateSimpleWindow(display, X RootWindow(display, screen), X 0, 0, X 500, 500, X 2, X DefaultDepth(display, screen), X InputOutput, X CopyFromParent, X MrMask, X winAtts); X X MrMask = GCForeground |GCBackground | GCGraphicsExposures | GCFunction; X gcval.foreground = WhitePixel(display, screen); X gcval.background = BlackPixel(display, screen); X gcval.graphics_exposures = True; X gcval.function = GXcopy; X white_gc = XCreateGC(display, win, MrMask, gcval); X X XSelectInput(display, win, X Button1MotionMask | X KeyPressMask | X ButtonPressMask | X StructureNotifyMask | X ExposureMask); X XMapWindow(display, win); X XGetGeometry(display, win, &root, &i, &i, &width, &height, &i, &i); X X panHandler = XcCreatePanHandler(); X origin.x = origin.y = 0; X X for (;;) { X XFlush(display); X XNextEvent(display, &e); X switch (e.type) { X case ButtonPress: X x = e.xbutton.x; X y = e.xbutton.y; X break; X case MotionNotify: X origin.x += x - e.xmotion.x; X if (origin.x < 0) { X x -= origin.x; X origin.x = 0; X } X origin.y += y - e.xmotion.y; X if (origin.y < 0) { X y -= origin.y; X origin.y = 0; X } X XcPanRectangle(panHandler, display, win, white_gc, X 0, 0, width, height, X x, y, e.xmotion.x, e.xmotion.y, X panExposeCB, &origin); X x = e.xmotion.x; X y = e.xmotion.y; X break; X case Expose: X XcPanEvent(panHandler, &e); X patternRectangle(display, win, white_gc, &origin, X e.xexpose.x, e.xexpose.y, X e.xexpose.width, e.xexpose.height); X break; X case GraphicsExpose: X XcPanEvent(panHandler, &e); X patternRectangle(display, win, white_gc, &origin, X e.xgraphicsexpose.x, X e.xgraphicsexpose.y, X e.xgraphicsexpose.width, X e.xgraphicsexpose.height); X break; X case NoExpose: X XcPanEvent(panHandler, &e); X break; X case ConfigureNotify: X width = e.xconfigure.width; X height = e.xconfigure.height; X break; X case KeyPress: X k = XLookupString(&e, cp, sizeof(cp)-1, &ksym, NULL); X cp[k] = '\0'; X if (!strcmp(cp, "q")) { X exit(0); X } else if (!strcmp(cp, "l")) { X XClearArea(display, win, 0, 0, X width, height, TRUE); X } else if (!strcmp(cp, "r")) { X origin.x = origin.y = 0; X XClearArea(display, win, 0, 0, X width, height, FALSE); X patternRectangle(display, win, white_gc, X &origin, 0, 0, width, height); X } X break; X default: X break; X } X } X} SHAR_EOF if test 5744 -ne "`wc -c < 'PanHandlerUT.c'`" then echo shar: error transmitting "'PanHandlerUT.c'" '(should have been 5744 characters)' fi fi # end of overwriting check # End of shell archive exit 0 -- +--------------------+ Chuck Ocheret +---------------+ |chuck@fid.Morgan.COM| Morgan Stanley & Co., Inc. |(212) 703-4474 | | Duty now ... |19th Floor, 1251 Avenue of the Americas|for the future.| +--------------------+ New York, N.Y. 10020 USA +---------------+