|
|
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.