|
|
1.1 root 1: /* $Header: VPane.c,v 1.1 87/09/11 07:59:07 toddb Exp $ */
2: #ifndef lint
3: static char *sccsid = "@(#)VPane.c 1.10 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: /* VPane.c */
31:
32: #include "Xlib.h"
33: #include "cursorfont.h"
34: #include "Intrinsic.h"
35: #include "VPane.h"
36: #include "Atoms.h"
37:
38: /* Private definitions. */
39:
40:
41: #define BORDERWIDTH 1 /* Size of borders between panes. */
42: /* %%% Should not be a constant! */
43: #define DEFAULTKNOBWIDTH 9
44: #define DEFAULTKNOBHEIGHT 9
45: #define DEFAULTKNOBINDENT 16
46:
47: typedef struct {
48: Display *dpy; /* Display connection */
49: Window w; /* Subwindow */
50: Position y; /* Location in master window */
51: Position dy; /* Desired location. */
52: Position olddy; /* The last value of dy. */
53: Dimension min, max; /* Minimum and maximum height. */
54: short autochange; /* Whether we're allowed to change this */
55: /* subwindow's height without an */
56: /* explicite command from user. */
57: Dimension height; /* Current height. */
58: Dimension dheight; /* Desired height. */
59: Window knob; /* The knob for this subwindow. */
60: Boolean allowresize; /* Whether we should honor geometry requests */
61: /* from this window to change its height. */
62: } SubWindowInfo, *SubWindowPtr;
63:
64: typedef struct {
65: Display *dpy; /* display connection for paned window */
66: Window ourparent; /* Parent of the paned window. */
67: Window window; /* Window containing everything. */
68: Pixel foregroundpixel; /* Foreground pixmap. */
69: Pixel backgroundpixel; /* Background pixmap. */
70: Position x, y; /* Location of master window. */
71: Dimension width, height; /* Dimension of master window. */
72: Dimension borderWidth; /* Borderwidth of master window. */
73: Dimension borderpixel; /* Color of border of master window. */
74: Dimension knobwidth, knobheight; /* Dimension of knobs. */
75: Position knobindent; /* Location of knobs (offset from */
76: /* right margin.) */
77: Pixel knobpixel; /* Color of knobs. */
78: Dimension heightused; /* Total height used by subwindows. */
79: int numsubwindows; /* How many windows within it. */
80: SubWindowInfo *sub; /* Array of info about the sub windows. */
81: int whichtracking; /* Which knob we are tracking, if any */
82: Position starty; /* Starting y value. */
83: int whichdirection; /* Which direction to refigure things in. */
84: SubWindowPtr whichadd; /* Which subwindow to add changes to. */
85: SubWindowPtr whichsub; /* Which subwindow to sub changes from. */
86: Boolean refiguremode; /* Whether to refigure things right now. */
87: GC normgc; /* GC to use when redrawing borders. */
88: GC invgc; /* GC to use when erasing borders. */
89: GC flipgc; /* GC to use when animating borders. */
90: } WidgetDataRec, *WidgetData;
91:
92: static WidgetDataRec globaldata, globaldatainit;
93:
94: static Resource resources[] = {
95: {XtNwindow, XtCWindow, XrmRWindow, sizeof(Window),
96: (caddr_t)&globaldata.window, NULL},
97: {XtNforeground, XtCColor, XrmRPixel, sizeof(int),
98: (caddr_t)&globaldata.foregroundpixel, (caddr_t)&XtDefaultFGPixel},
99: {XtNbackground, XtCColor, XrmRPixel, sizeof(int),
100: (caddr_t)&globaldata.backgroundpixel, (caddr_t)&XtDefaultBGPixel},
101: {XtNx, XtCX, XrmRInt, sizeof(int),
102: (caddr_t)&globaldata.x, NULL},
103: {XtNy, XtCY, XrmRInt, sizeof(int),
104: (caddr_t)&globaldata.y, NULL},
105: {XtNwidth, XtCWidth, XrmRInt, sizeof(int),
106: (caddr_t)&globaldata.width, NULL},
107: {XtNheight, XtCHeight, XrmRInt, sizeof(int),
108: (caddr_t)&globaldata.height, NULL},
109: {XtNborderWidth, XtCBorderWidth, XrmRInt, sizeof(int),
110: (caddr_t)&globaldata.borderWidth, NULL},
111: {XtNborder, XtCColor, XrmRPixmap, sizeof(int),
112: (caddr_t)&globaldata.borderpixel, (caddr_t)&XtDefaultFGPixel},
113: {XtNknobWidth, XtCWidth, XrmRInt, sizeof(int),
114: (caddr_t)&globaldata.knobwidth, NULL},
115: {XtNknobHeight, XtCHeight, XrmRInt, sizeof(int),
116: (caddr_t)&globaldata.knobheight, NULL},
117: {XtNknobIndent, XtCKnobIndent, XrmRInt, sizeof(int),
118: (caddr_t)&globaldata.knobindent, NULL},
119: {XtNknobPixel, XtCKnobPixel, XrmRPixel, sizeof(int),
120: (caddr_t)&globaldata.knobpixel, (caddr_t)&globaldata.foregroundpixel},
121: };
122:
123: static XContext widgetContext;
124: static int CursorNums[4] = {0,
125: XC_sb_up_arrow,
126: XC_sb_v_double_arrow,
127: XC_sb_down_arrow};
128:
129: static WidgetData DataFromWindow(dpy, w)
130: Display *dpy;
131: Window w;
132: {
133: WidgetData data;
134: if (XFindContext(dpy, w, widgetContext, (caddr_t *) &data)) return 0;
135: return data;
136: }
137:
138: static void TryResize(data, newwidth, newheight)
139: WidgetData data;
140: Dimension newwidth, newheight;
141: {
142: WindowBox requestBox, replyBox;
143: XtGeometryReturnCode result;
144: requestBox.x = 0;
145: requestBox.y = 0;
146: if (newwidth < 1) newwidth = 1;
147: if (newheight < 1) newheight = 1;
148: requestBox.width = newwidth;
149: requestBox.height = newheight;
150: result = XtMakeGeometryRequest(data->dpy, data->window, XtgeometryResize,
151: &requestBox, &replyBox);
152: if (result == XtgeometryAlmost) {
153: requestBox = replyBox;
154: result = XtMakeGeometryRequest(data->dpy, data->window, XtgeometryResize,
155: &requestBox, &replyBox);
156: }
157: if (result == XtgeometryYes) {
158: data->width = replyBox.width;
159: data->height = replyBox.height;
160: }
161: }
162:
163:
164: static RefigureLocations(data, position, dir)
165: WidgetData data;
166: int position;
167: int dir; /* -1 = up, 1 = down, 0 = this border only */
168: {
169: SubWindowPtr sub, firstsub;
170: int i, old, y, cdir;
171: if (data->numsubwindows == 0 || !data->refiguremode)
172: return;
173: do {
174: data->heightused = 0;
175: for (i = 0, sub = data->sub; i < data->numsubwindows; i++, sub++) {
176: if (sub->dheight < sub->min)
177: sub->dheight = sub->min;
178: if (sub->dheight > sub->max)
179: sub->dheight = sub->max;
180: data->heightused += sub->dheight;
181: }
182: data->heightused += BORDERWIDTH * (data->numsubwindows - 1);
183: if (dir == 0 && data->heightused != data->height) {
184: for (i = 0, sub = data->sub; i < data->numsubwindows; i++, sub++)
185: if (sub->dheight != sub->height)
186: sub->dheight += data->height - data->heightused;
187: }
188: } while (dir == 0 && data->heightused != data->height);
189:
190: firstsub = data->sub + position;
191: sub = firstsub;
192: cdir = dir;
193: while (data->heightused != data->height) {
194: if (sub->autochange || cdir != dir) {
195: old = sub->dheight;
196: sub->dheight = data->height - data->heightused + old;
197: if (sub->dheight < sub->min)
198: sub->dheight = sub->min;
199: if (sub->dheight > sub->max)
200: sub->dheight = sub->max;
201: data->heightused += (sub->dheight - old);
202: }
203: sub += cdir;
204: while (sub < data->sub || sub - data->sub == data->numsubwindows) {
205: cdir = -cdir;
206: if (cdir == dir) goto doublebreak;
207: sub = firstsub + cdir;
208: }
209: }
210: doublebreak:
211: y = -BORDERWIDTH;
212: for (i = 0, sub = data->sub; i < data->numsubwindows; i++, sub++) {
213: sub->dy = y;
214: y += sub->dheight + BORDERWIDTH;
215: }
216: }
217:
218:
219: static CommitNewLocations(data)
220: WidgetData data;
221: {
222: int i, kx, ky;
223: SubWindowPtr sub;
224: if (data->heightused != data->height)
225: TryResize(data, data->width, data->height);
226: for (i = 0, sub = data->sub; i < data->numsubwindows; i++, sub++) {
227: if (sub->dy != sub->y || sub->dheight != sub->height) {
228: WindowBox box;
229: XMoveResizeWindow(data->dpy, sub->w,
230: box.x = -BORDERWIDTH,
231: box.y = sub->dy,
232: box.width = data->width,
233: box.height = sub->dheight);
234: sub->y = sub->dy;
235: sub->height = sub->dheight;
236: (void) XtSendConfigureNotify(data->dpy, sub->w, &box);
237: kx = data->width - data->knobindent;
238: ky = sub->y + sub->height - (data->knobheight/2)+1;
239: if (i == data->numsubwindows - 1)
240: ky = -99; /* Keep the last knob hidden. */
241: XMoveWindow(data->dpy, sub->knob, kx, ky);
242: XRaiseWindow(data->dpy,sub->knob);
243:
244: }
245: }
246: /* kx = data->width - data->knobindent;
247: for (i = 0, sub = data->sub; i < data->numsubwindows; i++, sub++) {
248: ky = sub->y + sub->height - (data->knobheight / 2) + 1;
249: if (i == data->numsubwindows - 1)
250: ky = -99;
251: XMoveWindow(data->dpy, sub->knob, kx, ky);
252: XRaiseWindow(data->dpy, sub->knob);
253: }*/
254: }
255:
256:
257: static RefigureLocationsAndCommit(data, position, dir)
258: WidgetData data;
259: int position, dir;
260: {
261: RefigureLocations(data, position, dir);
262: CommitNewLocations(data);
263: }
264:
265:
266: EraseInternalBorders(data)
267: WidgetData data;
268: {
269: int i;
270: for (i = 1; i < data->numsubwindows; i++)
271: XFillRectangle(data->dpy, data->window, data->invgc,
272: 0, data->sub[i].y, data->width, BORDERWIDTH);
273: }
274:
275:
276: DrawInternalBorders(data)
277: WidgetData data;
278: {
279: int i;
280: for (i = 1; i < data->numsubwindows; i++)
281: XFillRectangle(data->dpy, data->window, data->normgc,
282: 0, data->sub[i].y, data->width, BORDERWIDTH);
283: }
284:
285:
286: static DrawTrackLines(data)
287: WidgetData data;
288: {
289: int i;
290: SubWindowPtr sub;
291: for (i = 1, sub = data->sub + 1; i < data->numsubwindows; i++, sub++) {
292: if (sub->olddy != sub->dy) {
293: XDrawLine(data->dpy, data->window, data->flipgc,
294: 0, sub->olddy, (Position) data->width, sub->olddy);
295: XDrawLine(data->dpy, data->window, data->flipgc,
296: 0, sub->dy, (Position) data->width, sub->dy);
297: sub->olddy = sub->dy;
298: }
299: }
300: }
301:
302: static EraseTrackLines(data)
303: WidgetData data;
304: {
305: int i;
306: SubWindowPtr sub;
307: for (i = 1, sub = data->sub + 1; i < data->numsubwindows; i++, sub++)
308: XDrawLine(data->dpy, data->window, data->flipgc,
309: 0, sub->olddy, (Position) data->width, sub->olddy);
310: }
311:
312:
313: /* Semi-public routines. */
314:
315: static XtGeometryReturnCode PanedWindowGeometryRequest(
316: dpy, w, request, reqBox, replBox)
317: Display *dpy;
318: Window w;
319: XtGeometryRequest request;
320: WindowBox *reqBox, *replBox;
321: {
322: WidgetData data;
323: int i;
324: SubWindowPtr sub;
325:
326: data = DataFromWindow(dpy, w);
327: if (!data) return XtgeometryNo;
328: for (i=0 ; i<data->numsubwindows ; i++)
329: if (data->sub[i].w == w) break;
330: if (i >= data->numsubwindows) return XtgeometryNo;
331: sub = data->sub + i;
332: if (request == XtgeometryResize) {
333: if (!sub->allowresize) return XtgeometryNo;
334: if (data->width != reqBox->width) {
335: if (sub->height == reqBox->height)
336: return XtgeometryNo;
337: *replBox = *reqBox;
338: replBox->width = data->width;
339: return XtgeometryAlmost;
340: }
341: if (sub->min == sub->height || sub->min > reqBox->height)
342: sub->min = reqBox->height;
343: if (sub->max == sub->height || sub->max < reqBox->height)
344: sub->max = reqBox->height;
345: sub->dheight = reqBox->height;
346: RefigureLocationsAndCommit(data, i, 1);
347: return XtgeometryYes;
348: }
349: if (request == XtgeometryGetWindowBox) {
350: replBox->x = -BORDERWIDTH;
351: replBox->y = sub->y;
352: replBox->width = data->width;
353: replBox->height = sub->height;
354: replBox->borderWidth = BORDERWIDTH;
355: return XtgeometryYes;
356: }
357: return XtgeometryNo;
358: }
359:
360: static XtEventReturnCode HandleEvents(event)
361: XEvent *event;
362: {
363: WidgetData data;
364: WindowBox box;
365: int i;
366:
367: data = DataFromWindow(event->xany.display, event->xany.window);
368: if (!data) return XteventNotHandled;
369: switch (event->type) {
370: case ConfigureNotify:
371: if (data->width != event->xconfigure.width ||
372: data->height != event->xconfigure.height) {
373: if (data->width != event->xconfigure.width) {
374: box.x = -BORDERWIDTH;
375: box.width = event->xconfigure.width;
376: box.borderWidth = BORDERWIDTH;
377: for (i = 0; i < data->numsubwindows; i++) {
378: XResizeWindow(data->dpy, data->sub[i].w,
379: (Dimension) event->xconfigure.width,
380: (Dimension) data->sub[i].height);
381: box.y = data->sub[i].y;
382: box.height = data->sub[i].height;
383: (void) XtSendConfigureNotify(data->dpy, data->sub[i].w,
384: &box);
385: }
386: }
387: data->width = event->xconfigure.width;
388: data->height = event->xconfigure.height;
389: RefigureLocationsAndCommit(data, data->numsubwindows - 1, -1);
390: }
391: data->x = event->xconfigure.x;
392: data->y = event->xconfigure.y;
393: data->borderWidth = event->xconfigure.border_width;
394: return XteventHandled;
395: case DestroyNotify:
396: data->refiguremode = FALSE;
397: for (i = data->numsubwindows-1 ; i >= 0 ; i--)
398: (void) XtSendDestroyNotify(data->dpy, data->sub[i].w);
399: (void) XDeleteContext(data->dpy, data->window, widgetContext);
400: XtClearEventHandlers(data->dpy, data->window);
401: XtFree((char *)data->sub);
402: XtFree((char *)data);
403: return XteventHandled;
404: }
405: return XteventNotHandled;
406: }
407:
408: static XtEventReturnCode HandleSubwindow(event)
409: XEvent *event;
410: {
411: WidgetData data;
412: if (event->type == DestroyNotify) {
413: data = DataFromWindow(event->xdestroywindow.display, event->xdestroywindow.window);
414: if (data) {
415: XtVPanedWindowDeletePane(data->dpy, data->window,
416: event->xdestroywindow.window);
417: return XteventHandled;
418: }
419: }
420: return XteventNotHandled;
421: }
422:
423: static XtEventReturnCode HandleKnob(event)
424: XEvent *event;
425: {
426: WidgetData data;
427: int position, diff, y, i;
428:
429: data = DataFromWindow(event->xbutton.display, event->xbutton.window);
430: if (!data) return XteventNotHandled;
431: switch (event->type) {
432: case ButtonPress:
433: y = event->xbutton.y;
434: if (data->whichtracking != -1)
435: return XteventNotHandled;
436: for (position = 0; position < data->numsubwindows; position++)
437: if (data->sub[position].knob == event->xbutton.window)
438: break;
439: if (position >= data->numsubwindows)
440: return XteventNotHandled;
441:
442: (void) XGrabPointer(data->dpy, event->xbutton.window, FALSE,
443: (unsigned int)PointerMotionMask | ButtonReleaseMask,
444: GrabModeAsync, GrabModeAsync, None,
445: XtGetCursor(data->dpy,
446: CursorNums[event->xbutton.button]),
447: CurrentTime);
448: data->whichadd = data->whichsub = NULL;
449: data->whichdirection = 2 - event->xbutton.button;/* Hack! */
450: data->starty = y;
451: if (data->whichdirection >= 0) {
452: data->whichadd = data->sub + position;
453: while (data->whichadd->max == data->whichadd->min &&
454: data->whichadd > data->sub)
455: (data->whichadd)--;
456: }
457: if (data->whichdirection <= 0) {
458: data->whichsub = data->sub + position + 1;
459: while (data->whichsub->max == data->whichsub->min &&
460: data->whichsub < data->sub + data->numsubwindows - 1)
461: (data->whichsub)++;
462: }
463: data->whichtracking = position;
464: if (data->whichdirection == 1)
465: (data->whichtracking)++;
466: EraseInternalBorders(data);
467: for (i = 0; i < data->numsubwindows; i++)
468: data->sub[i].olddy = -99;
469: /* Fall through */
470:
471: case MotionNotify:
472: case ButtonRelease:
473: if (event->type == MotionNotify) y = event->xmotion.y;
474: else y = event->xbutton.y;
475: if (data->whichtracking == -1)
476: return XteventNotHandled;
477: for (i = 0; i < data->numsubwindows; i++)
478: data->sub[i].dheight = data->sub[i].height;
479: diff = y - data->starty;
480: if (data->whichadd)
481: data->whichadd->dheight = data->whichadd->height + diff;
482: if (data->whichsub)
483: data->whichsub->dheight = data->whichsub->height - diff;
484: RefigureLocations(data, data->whichtracking, data->whichdirection);
485:
486: if (event->type != ButtonRelease) {
487: DrawTrackLines(data);/* Draw new borders */
488: return XteventHandled;
489: }
490: XUngrabPointer(data->dpy, CurrentTime);
491: EraseTrackLines(data);
492: CommitNewLocations(data);
493: DrawInternalBorders(data);
494: data->whichtracking = -1;
495: return XteventHandled;
496: }
497: return XteventNotHandled;
498: }
499:
500:
501: /* Public routines. */
502:
503: static Boolean initialized = FALSE;
504:
505: extern void VPanedInitialize()
506: {
507: if (initialized)
508: return;
509: initialized = TRUE;
510:
511: widgetContext = XUniqueContext();
512: globaldatainit.window = NULL;
513: globaldatainit.x = globaldatainit.y = 0;
514: globaldatainit.width = globaldatainit.height = 10;
515: globaldatainit.borderWidth = 1;
516: globaldatainit.knobwidth = DEFAULTKNOBWIDTH;
517: globaldatainit.knobheight = DEFAULTKNOBHEIGHT;
518: globaldatainit.knobindent = DEFAULTKNOBINDENT;
519: }
520:
521:
522: Window XtVPanedWindowCreate(dpy, parent, args, argCount)
523: Display *dpy;
524: Window parent;
525: ArgList args;
526: int argCount;
527: {
528: WidgetData data;
529: XrmNameList names;
530: XrmClassList classes;
531: unsigned long valuemask;
532: XSetWindowAttributes wvals;
533: XGCValues values;
534:
535: if (!initialized) VPanedInitialize();
536:
537: data = (WidgetData) XtMalloc(sizeof(WidgetDataRec));
538: globaldata = globaldatainit;
539: globaldata.dpy = dpy;
540: XtGetResources(dpy, resources, XtNumber(resources), args, argCount, parent,
541: "vpane", "VPane", &names, &classes);
542: *data = globaldata;
543:
544: wvals.background_pixel = data->backgroundpixel;
545: wvals.border_pixel = data->borderpixel;
546: wvals.bit_gravity = NorthWestGravity;
547: valuemask = CWBackPixel | CWBorderPixel | CWBitGravity;
548:
549: if (data->window != NULL) {
550: Drawable root;
551: Position x, y;
552: unsigned int depth;
553: (void) XGetGeometry(data->dpy, data->window, &root, &x, &y,
554: &(data->width), &(data->height), &(data->borderWidth),
555: &depth);
556: XReparentWindow(data->dpy, data->window, parent, data->x, data->y);
557: XChangeWindowAttributes(data->dpy, data->window, valuemask, &wvals);
558: } else {
559: data->window = XCreateWindow(data->dpy, parent, data->x, data->y,
560: data->width, data->height, data->borderWidth,
561: (int) CopyFromParent, InputOutput,
562: (Visual *) CopyFromParent, valuemask, &wvals);
563: }
564:
565: values.foreground = data->foregroundpixel;
566: values.function = GXcopy;
567: values.plane_mask = ~0;
568: values.fill_style = FillSolid;
569: values.fill_rule = EvenOddRule;
570: values.subwindow_mode = IncludeInferiors;
571: valuemask = GCForeground | GCFunction | GCPlaneMask | GCFillStyle
572: | GCFillRule | GCSubwindowMode;
573: data->normgc = XtGetGC(dpy, widgetContext, data->window, valuemask, &values);
574: values.foreground = data->backgroundpixel;
575: data->invgc = XtGetGC(dpy, widgetContext, data->window, valuemask, &values);
576: values.function = GXinvert;
577: #if BORDERWIDTH == 1
578: values.line_width = 0; /* Take advantage of fast server lines. */
579: #else
580: values.line_width = BORDERWIDTH;
581: #endif
582: values.line_style = LineSolid;
583: valuemask |= GCLineWidth | GCLineStyle;
584: data->flipgc = XtGetGC(dpy, widgetContext, data->window, valuemask, &values);
585:
586: XtSetNameAndClass(data->dpy, data->window, names, classes);
587: XrmFreeNameList(names);
588: XrmFreeClassList(classes);
589: data->heightused = 0;
590: data->numsubwindows = 0;
591: data->sub = (SubWindowInfo *) XtMalloc(1);
592: data->whichtracking = -1;
593: data->refiguremode = TRUE;
594: (void) XSaveContext(data->dpy, data->window, widgetContext, (caddr_t) data);
595: (void) XtSetEventHandler(data->dpy, data->window, HandleEvents, StructureNotifyMask,
596: (caddr_t) NULL);
597: return data->window;
598: }
599:
600:
601: void XtVPanedWindowDelete(dpy, w)
602: Display *dpy;
603: Window w;
604: {
605: WidgetData data;
606: int i;
607: data = DataFromWindow(dpy, w);
608: XUnmapWindow(data->dpy, w);
609: for (i=data->numsubwindows-1 ; i>=0 ; i--)
610: XtVPanedWindowDeletePane(dpy, w, data->sub[i].w);
611: (void) XDeleteContext(dpy, w, widgetContext);
612: XtFree((char *) data->sub);
613: XtFree((char *) data);
614: }
615:
616:
617:
618: void XtVPanedWindowAddPane(
619: dpy, parent, paneWindow, position, min, max, autochange)
620: Display *dpy;
621: Window parent, paneWindow;
622: int position, min, max, autochange;
623: {
624: WidgetData data;
625: Drawable root;
626: int i;
627: Position x;
628: Dimension width, borderWidth, needed;
629: unsigned int depth;
630: SubWindowPtr sub;
631: data = DataFromWindow(dpy, parent);
632: if (!data) return;
633: if (position > 0 && position == data->numsubwindows)
634: data->sub[position - 1].y = -99; /* HACK to make knob reappear. */
635: data->numsubwindows++;
636: data->sub = (SubWindowPtr)
637: XtRealloc((char *) data->sub,
638: (unsigned) data->numsubwindows * sizeof(SubWindowInfo));
639: for (i = data->numsubwindows - 1; i > position; i--)
640: data->sub[i] = data->sub[i - 1];
641: sub = &(data->sub[position]);
642: sub->w = paneWindow;
643: (void) XGetGeometry(data->dpy, paneWindow, &root, &x, &(sub->y),
644: &width, &(sub->height), &borderWidth, &depth);
645: XReparentWindow(data->dpy, paneWindow, data->window, -BORDERWIDTH,
646: sub->y);
647: sub->dheight = sub->height;
648: if (width != data->width || borderWidth != BORDERWIDTH) {
649: XWindowChanges changes;
650: changes.width = data->width;
651: changes.border_width = BORDERWIDTH;
652: XConfigureWindow(data->dpy, paneWindow,
653: (unsigned int) CWWidth | CWBorderWidth, &changes);
654: }
655: sub->min = min;
656: sub->max = max;
657: sub->autochange = autochange;
658: needed = sub->height + BORDERWIDTH + data->heightused;
659: if (needed > data->height)
660: TryResize(data, data->width, needed);
661: (void) XtSetGeometryHandler(data->dpy, paneWindow, PanedWindowGeometryRequest);
662: sub->knob = XCreateSimpleWindow(data->dpy, data->window, -99, -99,
663: data->knobwidth, data->knobheight,
664: 0, (Pixel) 0, data->knobpixel);
665: (void) XSaveContext(dpy, sub->w, widgetContext, (caddr_t) data);
666: (void) XSaveContext(dpy, sub->knob, widgetContext, (caddr_t) data);
667: XDefineCursor(data->dpy, sub->knob, XtGetCursor(dpy, XC_double_arrow));
668: XMapWindow(data->dpy, sub->w);
669: XMapWindow(data->dpy, sub->knob);
670: (void) XtSetEventHandler(dpy, sub->w, HandleSubwindow, StructureNotifyMask,
671: (caddr_t) NULL);
672: (void) XtSetEventHandler(dpy, sub->knob, HandleKnob,
673: ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
674: (caddr_t) NULL);
675: RefigureLocationsAndCommit(data, position, 1);
676: for (i=0 ; i<data->numsubwindows; i++)
677: XRaiseWindow(data->dpy, data->sub[i].knob);
678: }
679:
680:
681: /* Change the min and max size of the given sub window. */
682:
683: void XtVPanedSetMinMax(dpy, w, paneWindow, min, max)
684: Display *dpy;
685: Window w, paneWindow;
686: int min, max;
687: {
688: WidgetData data;
689: int i;
690: data = DataFromWindow(dpy, w);
691: if (!data)
692: return;
693: for (i = 0; i < data->numsubwindows; i++) {
694: if (data->sub[i].w == paneWindow) {
695: data->sub[i].min = min;
696: data->sub[i].max = max;
697: RefigureLocationsAndCommit(data, i, 1);
698: return;
699: }
700: }
701: }
702:
703:
704: /* Get the min and max size of the given sub window. */
705:
706: void XtVPanedGetMinMax(dpy, w, paneWindow, min, max)
707: Display *dpy;
708: Window w, paneWindow;
709: int *min, *max;
710: {
711: WidgetData data;
712: int i;
713: data = DataFromWindow(dpy, w);
714: if (!data)
715: return;
716: for (i = 0; i < data->numsubwindows; i++) {
717: if (data->sub[i].w == paneWindow) {
718: *min = data->sub[i].min;
719: *max = data->sub[i].max;
720: return;
721: }
722: }
723: }
724:
725:
726:
727: /* Delete the given paneWindow from the given paned window. Doesn't actually
728: destroy the paneWindow. */
729:
730: void XtVPanedWindowDeletePane(dpy, w, paneWindow)
731: Display *dpy;
732: Window w, paneWindow;
733: {
734: WidgetData data;
735: int i;
736: Boolean j;
737:
738: data = DataFromWindow(dpy, w);
739: if (!data)
740: return;
741: j = FALSE;
742: for (i = 0; i < data->numsubwindows; i++) {
743: if (data->sub[i].w == paneWindow) {
744: j = TRUE;
745: (void) XDeleteContext(dpy, data->sub[i].w, widgetContext);
746: (void) XDeleteContext(dpy, data->sub[i].knob, widgetContext);
747: (void) XtSetEventHandler(dpy, data->sub[i].w, HandleSubwindow,
748: (unsigned long) NULL, (caddr_t) NULL);
749: XtClearEventHandlers(dpy, data->sub[i].knob);
750: XDestroyWindow(data->dpy, data->sub[i].knob);
751: TryResize(data, data->width,
752: data->height - data->sub[i].height - BORDERWIDTH);
753: }
754: if (j && i < data->numsubwindows - 1)
755: data->sub[i] = data->sub[i + 1];
756: }
757: if (!j)
758: return;
759: data->numsubwindows--;
760: if (data->numsubwindows > 0) {
761: data->sub = (SubWindowPtr)
762: XtRealloc((char *) data->sub,
763: (unsigned) data->numsubwindows * sizeof(SubWindowInfo));
764: }
765: RefigureLocationsAndCommit(data, data->numsubwindows - 1, -1);
766: }
767:
768:
769: void XtVPanedAllowResize(dpy, window, paneWindow, allowresize)
770: Display *dpy;
771: Window window, paneWindow;
772: Boolean allowresize;
773: {
774: WidgetData data;
775: int i;
776: data = DataFromWindow(dpy, window);
777: if (data)
778: for (i=0 ; i<data->numsubwindows ; i++)
779: if (data->sub[i].w == paneWindow)
780: data->sub[i].allowresize = allowresize;
781: }
782:
783:
784:
785: Boolean XtVPanedGetResize(dpy, window, paneWindow)
786: Display *dpy;
787: Window window, paneWindow;
788: {
789: WidgetData data;
790: int i;
791: data = DataFromWindow(dpy, window);
792: if (data)
793: for (i=0 ; i<data->numsubwindows ; i++)
794: if (data->sub[i].w == paneWindow)
795: return(data->sub[i].allowresize);
796: return (0);
797: }
798:
799:
800:
801: int XtVPanedGetNumSub(dpy, window)
802: Display *dpy;
803: Window window;
804: {
805: WidgetData data;
806: int i;
807: data = DataFromWindow(dpy, window);
808: if (data)
809: return(data->numsubwindows);
810: return (0);
811: }
812:
813:
814:
815:
816: void XtVPanedRefigureMode(dpy, window, mode)
817: Display *dpy;
818: Window window;
819: Boolean mode;
820: {
821: WidgetData data;
822: data = DataFromWindow(dpy, window);
823: if (data) {
824: data->refiguremode = mode;
825: if (mode)
826: RefigureLocationsAndCommit(data, data->numsubwindows - 1, -1);
827: }
828: }
829:
830: void XtVPaneGetValues(dpy, window, args, argCount)
831: Display *dpy;
832: Window window;
833: ArgList args;
834: int argCount;
835: {
836: WidgetData data;
837: data = DataFromWindow(dpy, window);
838: if (data == NULL) return;
839:
840: globaldata = *data;
841: XtGetValues(resources, XtNumber(resources), args, argCount);
842: }
843:
844: void XtVPaneSetValues(dpy, window, args, argCount)
845: Display *dpy;
846: Window window;
847: ArgList args;
848: int argCount;
849: {
850: WidgetData data;
851: data = DataFromWindow(dpy, window);
852: if (data == NULL) return;
853:
854: globaldata = *data;
855: XtSetValues(resources, XtNumber(resources), args, argCount);
856: *data = globaldata;
857: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.