|
|
1.1 root 1: /* $Header: ScrollWin.c,v 1.1 87/09/11 07:59:43 toddb Exp $ */
2: #ifndef lint
3: static char *sccsid = "@(#)ScrolledWin.c 1.4 2/25/87";
4: #endif lint
5:
6: /*
7: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
8: *
9: * All Rights Reserved
10: *
11: * Permission to use, copy, modify, and distribute this software and its
12: * documentation for any purpose and without fee is hereby granted,
13: * provided that the above copyright notice appear in all copies and that
14: * both that copyright notice and this permission notice appear in
15: * supporting documentation, and that the name of Digital Equipment
16: * Corporation not be used in advertising or publicity pertaining to
17: * distribution of the software without specific, written prior permission.
18: *
19: *
20: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26: * SOFTWARE.
27: */
28:
29:
30: /* File: ScrolledWin.c */
31:
32: #include "Xlib.h"
33: #include "Intrinsic.h"
34: #include "Scroll.h"
35: #include "Atoms.h"
36:
37: typedef struct _WidgetDataRec{
38: Display *dpy; /* Display connection for this widget */
39: Window outer; /* Encompassing window including scrollbars */
40: Window frame; /* Window containing the view of the data */
41: Window inner; /* Window with the data itself */
42: Position x, y; /* Location of outer within parent. */
43: Dimension outerwidth, outerheight; /* Dimensions of encompassing window */
44: WindowBox framebox; /* Dimensions of framing (clipping) window */
45: WindowBox innerbox; /* Dimensions of the data */
46: Dimension thickness; /* Thickness of scroll bars */
47: Boolean forcebars; /* Whether we should always display */
48: /* the selected bars. */
49: Boolean allowhoriz; /* Whether we allow horizontal scrollbars. */
50: Boolean allowvert; /* Whether we allow vertical scrollbars. */
51: Boolean usebottom; /* True iff horiz bars appear at bottom. */
52: Boolean useright; /* True iff vert bars appear at right. */
53: Window horizinuse, vertinuse; /* What scrollbars we currently have */
54: } WidgetDataRec, *WidgetData;
55:
56: static WidgetDataRec globaldata;
57: static WidgetDataRec globalinit = {
58: NULL, /* Display dpy; */
59: NULL, /* Encompassing window including scrollbars */
60: NULL, /* Window containing the view of the data */
61: NULL, /* Window with the data itself */
62: 0,0, /* Location of outer within parent. */
63: 1,1, /* Dimensions of encompassing window */
64: {0,0,1,1,0}, /* framebox location, dimensions, border width */
65: {0,0,1,1,0}, /* innerbox location, dimensions, border width */
66: 0, /* Thickness of scroll bars */
67: FALSE, /* Whether we should always display */
68: /* the selected bars. */
69: FALSE, /* Whether we allow horizontal scrollbars. */
70: FALSE, /* Whether we allow vertical scrollbars. */
71: FALSE, /* True iff horiz bars appear at bottom. */
72: FALSE, /* True iff vert bars appear at right. */
73: (Window)NULL,(Window)NULL, /* What scrollbars we currently have */
74: };
75:
76:
77:
78: extern int ScrollUpDownProc(), ThumbProc();
79:
80: static Arg addBarArgs[] = {
81: {XtNorientation, (XtArgVal) NULL},
82: {XtNlowerRight, (XtArgVal) NULL},
83: {XtNvalue, (XtArgVal) NULL},
84: {XtNscrollUpDownProc, (XtArgVal) ScrollUpDownProc},
85: {XtNthumbProc, (XtArgVal) ThumbProc},
86: };
87:
88: static Resource resources[] = {
89: {XtNinnerWidth, XtCWidth, XrmRInt, sizeof(int),
90: (caddr_t)&globaldata.innerbox.width, NULL},
91: {XtNinnerHeight, XtCHeight, XrmRInt, sizeof(int),
92: (caddr_t)&globaldata.innerbox.height, NULL},
93: {XtNinnerWindow, XtCWindow, XrmRWindow, sizeof(Window),
94: (caddr_t)&globaldata.inner, NULL},
95: {XtNforceBars, XtCBoolean, XrmRBoolean, sizeof(Boolean),
96: (caddr_t)&globaldata.forcebars, NULL},
97: {XtNallowHoriz, XtCBoolean, XrmRBoolean, sizeof(Boolean),
98: (caddr_t)&globaldata.allowhoriz, NULL},
99: {XtNallowVert, XtCBoolean, XrmRBoolean, sizeof(Boolean),
100: (caddr_t)&globaldata.allowvert, NULL},
101: {XtNuseBottom, XtCBoolean, XrmRBoolean, sizeof(Boolean),
102: (caddr_t)&globaldata.usebottom, NULL},
103: {XtNuseRight, XtCBoolean, XrmRBoolean, sizeof(Boolean),
104: (caddr_t)&globaldata.useright, NULL},
105: };
106:
107: static XContext scrolledWindowContext;
108:
109: static Boolean initialized = FALSE;
110:
111: static void ScrolledWindowInitialize ()
112: {
113: if (initialized)
114: return;
115: initialized = TRUE;
116:
117: scrolledWindowContext = XUniqueContext();
118: globalinit.forcebars = globalinit.allowhoriz = globalinit.allowvert = FALSE;
119: globalinit.usebottom = globalinit.useright = FALSE;
120: }
121:
122: static WidgetData ScrolledWindowContextFromWindow(dpy, w)
123: Display *dpy;
124: Window w;
125: {
126: WidgetData data;
127: if (!XFindContext(dpy, w, scrolledWindowContext, (caddr_t *) &data))
128: return data;
129: return 0;
130: }
131:
132: static SetBar(dpy, w, fx, wd, tw)
133: Display *dpy;
134: Window w;
135: Position fx;
136: Dimension wd, tw;
137: {
138: float from, width;
139: from = (float) fx / tw;
140: width = (float) wd / tw;
141: XtScrollBarSetThumb(dpy, w, from, width);
142: }
143:
144: static RedrawThumbs(data)
145: WidgetData data;
146: {
147: if (data->horizinuse)
148: SetBar(data->dpy, data->horizinuse, -(data->innerbox.x), data->framebox.width,
149: data->innerbox.width);
150: if (data->vertinuse)
151: SetBar(data->dpy, data->vertinuse, -(data->innerbox.y), data->framebox.height,
152: data->innerbox.height);
153: }
154:
155:
156:
157: static MoveInner(data, nx, ny)
158: WidgetData data;
159: int nx, ny;
160: {
161: if (-nx + data->framebox.width > data->innerbox.width)
162: nx = -(data->innerbox.width - data->framebox.width);
163: if (-ny + data->framebox.height > data->innerbox.height)
164: ny = -(data->innerbox.height - data->framebox.height);
165: if (nx > 0) nx = 0;
166: if (ny > 0) ny = 0;
167: if (nx != data->innerbox.x || ny != data->innerbox.y) {
168: XMoveWindow(data->dpy,data->inner, nx, ny);
169: data->innerbox.x = nx;
170: data->innerbox.y = ny;
171: (void)XtSendConfigureNotify(data->dpy, data->inner, &(data->innerbox));
172: }
173: RedrawThumbs(data);
174: }
175:
176: static ResizeEverything(data)
177: WidgetData data;
178: {
179: int lw, lh;
180: Boolean needshoriz, needsvert;
181: int oldinnerwidth = data->innerbox.width;
182: int oldinnerheight = data->innerbox.height;
183:
184: data->thickness = XtScrollMgrGetThickness(data->dpy, data->outer);
185: if (data->forcebars) {
186: needshoriz = data->allowhoriz;
187: needsvert = data->allowvert;
188: data->framebox.width =
189: data->outerwidth - (needsvert ? data->thickness : 0);
190: data->framebox.height =
191: data->outerheight - (needshoriz ? data->thickness : 0);
192: if (!needshoriz)
193: data->innerbox.width = data->framebox.width;
194: if (!needsvert)
195: data->innerbox.height = data->framebox.height;
196: }
197: else {
198: data->framebox.width = data->outerwidth;
199: data->framebox.height = data->outerheight;
200: do {
201: lw = data->framebox.width;
202: lh = data->framebox.height;
203: needshoriz = (Boolean)(data->innerbox.width > data->framebox.width);
204: needsvert =
205: (Boolean)(data->innerbox.height > data->framebox.height);
206: if (!(data->allowhoriz)) {
207: data->innerbox.width = data->framebox.width;
208: needshoriz = FALSE;
209: }
210: if (!(data->allowvert)) {
211: data->innerbox.height = data->framebox.height;
212: needsvert = FALSE;
213: }
214: data->framebox.width = data->outerwidth -
215: (needsvert ? data->thickness : 0);
216: data->framebox.height = data->outerheight -
217: (needshoriz ? data->thickness : 0);
218: } while (lw != data->framebox.width || lh != data->framebox.height);
219: }
220: if (oldinnerwidth != data->innerbox.width ||
221: oldinnerheight != data->innerbox.height) {
222: XResizeWindow(data->dpy, data->inner,
223: data->innerbox.width, data->innerbox.height);
224: (void)XtSendConfigureNotify(data->dpy, data->inner, &(data->innerbox));
225: }
226:
227: if (needshoriz && data->horizinuse == 0) {
228: addBarArgs[0].value = (XtArgVal)XtorientHorizontal;
229: addBarArgs[1].value = (XtArgVal)(data->usebottom);
230: addBarArgs[2].value = (XtArgVal)(data->outer);
231: data->horizinuse =
232: XtScrollMgrAddBar(data->dpy, data->outer, addBarArgs, XtNumber(addBarArgs));
233: XMapWindow(data->dpy,data->horizinuse);
234: }
235: else
236: if (!needshoriz && data->horizinuse) {
237: XtDeleteScrollBar(data->dpy, data->outer, data->horizinuse);
238: data->horizinuse = 0;
239: }
240: if (needsvert && data->vertinuse == 0) {
241: addBarArgs[0].value = (XtArgVal)XtorientVertical;
242: addBarArgs[1].value = (XtArgVal)(data->useright);
243: addBarArgs[2].value = (XtArgVal)(data->outer);
244: data->vertinuse =
245: XtScrollMgrAddBar(data->dpy, data->outer, addBarArgs, XtNumber(addBarArgs));
246: XMapWindow(data->dpy,data->vertinuse);
247: }
248: else
249: if (!needsvert && data->vertinuse) {
250: XtDeleteScrollBar(data->dpy, data->outer, data->vertinuse);
251: data->vertinuse = 0;
252: }
253: data->framebox.width = data->outerwidth - (needsvert ? data->thickness : 0);
254: data->framebox.height = data->outerheight - (needshoriz ? data->thickness : 0);
255: RedrawThumbs(data);
256: }
257:
258:
259:
260: /* Semi-public routines */
261:
262:
263: static ScrollUpDownProc(dpy, swin, outer, pix)
264: Display *dpy;
265: Window swin, outer;
266: int pix;
267: {
268: WidgetData data;
269: int nx, ny;
270: data = ScrolledWindowContextFromWindow(dpy, outer);
271: if (!data) return;
272: nx = data->innerbox.x - ((swin == data->horizinuse) ? pix : 0);
273: ny = data->innerbox.y - ((swin == data->vertinuse) ? pix : 0);
274: MoveInner(data, nx, ny);
275: }
276:
277: static ThumbProc(dpy, swin, outer, percent)
278: Display *dpy;
279: Window swin, outer;
280: float percent;
281: {
282: WidgetData data;
283: int nx, ny;
284: data = ScrolledWindowContextFromWindow(dpy, outer);
285: if (!data) return;
286: nx = data->innerbox.x;
287: ny = data->innerbox.y;
288: if (swin == data->horizinuse)
289: nx = -(percent * data->innerbox.width);
290: if (swin == data->vertinuse)
291: ny = -(percent * data->innerbox.height);
292: MoveInner(data, nx, ny);
293: }
294:
295: static XtGeometryReturnCode
296: ScrolledWindowGeometryRequest(dpy, window, request, requestBox, replyBox)
297: Display *dpy;
298: Window window;
299: XtGeometryRequest request;
300: WindowBox *requestBox, *replyBox;
301: {
302: WidgetData data;
303: XtGeometryReturnCode reply;
304: WindowBox myrequest;
305: data = ScrolledWindowContextFromWindow(dpy, window);
306: if (!data || window != data->inner || request != XtgeometryResize)
307: return XtgeometryNo;
308: *replyBox = *requestBox;
309: reply = XtgeometryYes;
310: if ((!(data->allowhoriz) && requestBox->width != data->innerbox.width) ||
311: (!(data->allowvert) && requestBox->height != data->innerbox.height)) {
312: myrequest = *requestBox;
313: if (data->horizinuse) myrequest.height += data->thickness;
314: if (data->vertinuse) myrequest.width += data->thickness;
315: if (data->allowhoriz) myrequest.width = data->outerwidth;
316: if (data->allowvert) myrequest.height = data->outerheight;
317: reply = XtMakeGeometryRequest(data->dpy, data->outer, XtgeometryResize, &myrequest,
318: replyBox);
319: if (reply != XtgeometryYes) {
320: replyBox->width = data->innerbox.width;
321: replyBox->height = data->innerbox.height;
322: reply = XtgeometryNo;
323: if (data->allowhoriz) replyBox->width = requestBox->width;
324: if (data->allowvert) replyBox->height = requestBox->height;
325: if (data->innerbox.width != replyBox->width ||
326: data->innerbox.height != replyBox->height) {
327: reply = XtgeometryAlmost;
328: }
329: }
330: }
331: if (reply == XtgeometryYes) {
332: if (requestBox->width != data->innerbox.width ||
333: requestBox->height != data->innerbox.height) {
334: XResizeWindow(dpy, window,
335: requestBox->width, requestBox->height);
336: data->innerbox.width = requestBox->width;
337: data->innerbox.height = requestBox->height;
338: (void) XtSendConfigureNotify(dpy, window, &(data->innerbox));
339: ResizeEverything(data);
340: MoveInner(data, data->innerbox.x, data->innerbox.y);
341: /* Check inner location */
342: }
343: }
344: return reply;
345: }
346:
347:
348: static XtEventReturnCode HandleEvents(event)
349: XEvent *event;
350: {
351: WidgetData data;
352: data = ScrolledWindowContextFromWindow(event->xany.display, event->xany.window);
353: if (!data) return XteventNotHandled;
354: switch(event->type) {
355: case ConfigureNotify:
356: if (data->outerwidth != event->xconfigure.width ||
357: data->outerheight != event->xconfigure.height) {
358: data->outerwidth = event->xconfigure.width;
359: data->outerheight = event->xconfigure.height;
360: ResizeEverything(data);
361: MoveInner(data, data->innerbox.x, data->innerbox.y);
362: }
363: return XteventHandled;
364: case DestroyNotify:
365: (void)XDeleteContext(data->dpy,data->outer,scrolledWindowContext);
366: (void)XDeleteContext(data->dpy,data->frame,scrolledWindowContext);
367: (void) XtSendDestroyNotify(data->dpy, data->inner);
368: /* Let the scrollbarmgr send messages to the scrollbars. */
369: XtFree((char*)data);
370: return XteventHandled;
371: }
372: return XteventNotHandled;
373: }
374:
375:
376:
377: /* Public routines */
378:
379: /* Create a scrolled window in the given one. */
380:
381: Window XtScrolledWindowCreate(dpy, parent, args, argCount)
382: Display *dpy;
383: Window parent;
384: ArgList args;
385: int argCount;
386: {
387: WidgetData data;
388: Dimension bw;
389: unsigned int depth;
390: Drawable root;
391: XrmNameList names;
392: XrmClassList classes;
393:
394: if (!initialized) ScrolledWindowInitialize();
395: globaldata = globalinit;
396: globaldata.dpy = dpy;
397: XtGetResources(dpy, resources, XtNumber(resources), args, argCount, parent,
398: "scrolledWin", "ScrolledWin", &names, &classes);
399: data = (WidgetData) XtMalloc(sizeof(WidgetDataRec));
400: *data = globaldata;
401: data->outer = XtScrollMgrCreate(dpy, parent, args, argCount);
402: data->frame = XtScrollMgrGetChild(data->dpy, data->outer);
403:
404: XtSetNameAndClass(data->dpy, data->frame, names, classes);
405: XrmFreeNameList(names);
406: XrmFreeClassList(classes);
407:
408: if (data->inner != NULL) {
409: XWindowChanges wc;
410: unsigned int valuemask;
411: valuemask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
412: wc.x = data->innerbox.x; wc.y = data ->innerbox.y; wc.width = data ->innerbox.width;
413: wc.height=data->innerbox.height; wc.border_width = 1;
414: XConfigureWindow(data->dpy,data->inner,valuemask,&wc);
415: XReparentWindow(data->dpy,data->inner,parent,data->x,data->y);
416:
417: } else {
418: data->inner = XtCreateWindow(data->dpy, data->frame, 0, 0,
419: data->innerbox.width,
420: data->innerbox.height,
421: 0, (Pixel)0, (Pixel)0, NorthWestGravity);
422: }
423: (void) XSaveContext(data->dpy, data->outer, scrolledWindowContext, (caddr_t) data);
424: (void) XSaveContext(data->dpy, data->inner, scrolledWindowContext, (caddr_t) data);
425: (void) XtSetGeometryHandler(data->dpy, data->inner, ScrolledWindowGeometryRequest);
426: data->innerbox.x = data->innerbox.y = 0;
427: (void) XGetGeometry(data->dpy, data->outer, &root, &(data->x), &(data->y),
428: &(data->outerwidth), &(data->outerheight), &bw, &depth);
429: data->horizinuse = data->vertinuse = (Window) NULL;
430: ResizeEverything(data);
431: XMapWindow(data->dpy,data->inner);
432: XMapSubwindows(data->dpy,data->outer);
433: XtSetEventHandler(data->dpy, data->outer, HandleEvents, StructureNotifyMask,
434: (caddr_t) NULL);
435: return data->outer;
436: }
437:
438:
439: Window XtScrolledWindowGetChild(dpy, outer)
440: Display *dpy;
441: Window outer;
442: {
443: WidgetData data;
444: data = ScrolledWindowContextFromWindow(dpy, outer);
445: if (data) return data->inner;
446: else return NULL;
447: }
448:
449: void XtScrolledWindowSetChild(dpy, parent, child)
450: Display *dpy;
451: Window parent, child;
452: {
453: WidgetData data;
454: Dimension bw;
455: unsigned int depth;
456: Drawable root;
457: data = ScrolledWindowContextFromWindow(dpy, parent);
458: if (data) {
459: XUnmapWindow(data->dpy,data->inner);
460: (void) XDeleteContext(data->dpy, data->inner, scrolledWindowContext);
461: data->inner = child;
462: (void) XGetGeometry(data->dpy,data->inner,&root,&(data->innerbox.x),
463: &(data->innerbox.y), &(data->innerbox.width),
464: &(data->innerbox.height), &bw, &depth);
465: (void) XSaveContext(data->dpy, data->inner, scrolledWindowContext, (caddr_t) data);
466: (void) XtSetGeometryHandler(data->dpy, data->inner, ScrolledWindowGeometryRequest);
467: ResizeEverything(data);
468: XMapWindow(data->dpy, data->inner);
469: }
470: }
471:
472: Window XtScrolledWindowGetFrame(dpy, parent)
473: Display *dpy;
474: Window parent;
475: {
476: WidgetData data;
477: data = ScrolledWindowContextFromWindow(dpy, parent);
478: if (data) return data->frame;
479: else return NULL;
480: }
481:
482: /* Unlink everything that was done to make this a scrolled window. All the
483: windows are actually destroyed, except for the parent one. */
484:
485: Window XtUnmakeScrolledWindow(dpy, parent)
486: Display *dpy;
487: Window parent;
488: {
489: WidgetData data;
490: data = ScrolledWindowContextFromWindow(dpy, parent);
491: if (!data) return;
492: (void) XDeleteContext(data->dpy, data->inner, scrolledWindowContext);
493: (void) XDeleteContext(data->dpy, parent, scrolledWindowContext);
494: XDestroyWindow(data->dpy,data->inner);
495: XtScrollMgrDestroy(data->dpy, parent);
496: XtFree((caddr_t) data);
497: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.