home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute these examples for any
- purpose and without fee is hereby granted, provided that the above
- copyright notice appear in all copies and that both that copyright
- notice and this permission notice appear in supporting documentation,
- and that the name of Digital not be used in advertising or publicity
- pertaining to distribution of the software without specific, written
- prior permission.
-
- DIGITAL AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
- OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
- OR PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- #include <X11/IntrinsicP.h> /* Intrinsics header file */
- #include <X11/StringDefs.h> /* Resource string definitions */
- #include "MenuP.h" /* Menu private header file */
- #include "LabelGadge.h" /* To check LabelGadgets */
-
- static Cardinal InsertBefore();
-
- static XtResource resources[] = {
- {XtNinsertPosition, XtCInsertPosition,
- XtRFunction, sizeof(XtOrderProc),
- XtOffsetOf(MenuRec, composite.insert_position),
- XtRImmediate, (XtPointer) InsertBefore}
- };
-
- static Cardinal InsertBefore(w)
- Widget w;
- {
- MenuWidget menu = (MenuWidget) XtParent(w);
- MenuConstraint mc = (MenuConstraint) w->core.constraints;
- int i;
-
- if (mc->menu.insert_before == NULL) {
- return menu->composite.num_children;
- }
-
- for (i = 0; i < menu->composite.num_children; i++) {
- if (mc->menu.insert_before == menu->composite.children[i]) {
- return i;
- }
- }
-
- return menu->composite.num_children;
- }
-
- static XtResource constraintResources[] = {
- {XtNinsertBefore, XtCInsertBefore, XtRWidget, sizeof(Widget),
- XtOffsetOf(MenuConstraintRec, menu.insert_before),
- XtRImmediate, NULL},
- };
-
- /* Forward declarations */
-
- static void ClassInitialize(), ChangeManaged(), Initialize(),
- ConstraintInitialize(), Resize(), InsertChild(),
- Redisplay(), Destroy(), ConstraintGetValuesHook();
- static XtGeometryResult GeometryManager();
- static Boolean ConstraintSetValues();
-
- static CompositeClassExtensionRec compositeExtension = {
- /* next_extension */ NULL,
- /* record_type */ NULLQUARK,
- /* version */ XtCompositeExtensionVersion,
- /* record_size */ sizeof(CompositeClassExtensionRec),
- /* accepts_objects */ TRUE
- };
-
- static ConstraintClassExtensionRec constraintExtension = {
- /* next_extension */ NULL,
- /* record_type */ NULLQUARK,
- /* version */ XtConstraintExtensionVersion,
- /* record_size */ sizeof(ConstraintClassExtensionRec),
- /* get_values_hook */ ConstraintGetValuesHook
- };
-
- MenuClassRec menuClassRec = {
- /* Core class part */
- {
- /* superclass */ (WidgetClass) &constraintClassRec,
- /* class_name */ "Menu",
- /* widget_size */ sizeof(MenuRec),
- /* class_initialize */ ClassInitialize,
- /* class_part_initialize */ NULL,
- /* class_inited */ FALSE,
- /* initialize */ Initialize,
- /* initialize_hook */ NULL,
- /* realize */ XtInheritRealize,
- /* actions */ NULL,
- /* num_actions */ 0,
- /* resources */ resources,
- /* num_resources */ XtNumber(resources),
- /* xrm_class */ NULLQUARK,
- /* compress_motion */ TRUE,
- /* compress_exposure */ XtExposeCompressMultiple,
- /* compress_enterleave */ TRUE,
- /* visible_interest */ FALSE,
- /* destroy */ Destroy,
- /* resize */ Resize,
- /* expose */ Redisplay,
- /* set_values */ NULL,
- /* set_values_hook */ NULL,
- /* set_values_almost */ XtInheritSetValuesAlmost,
- /* get_values_hook */ NULL,
- /* accept_focus */ NULL,
- /* version */ XtVersion,
- /* callback offsets */ NULL,
- /* tm_table */ NULL,
- /* query_geometry */ XtInheritQueryGeometry,
- /* display_accelerator */ NULL,
- /* extension */ NULL,
- },
- /* Composite class part */
- {
- /* geometry_manager */ GeometryManager,
- /* change_managed */ ChangeManaged,
- /* insert_child */ InsertChild,
- /* delete_child */ XtInheritDeleteChild,
- /* extension */ (XtPointer) &compositeExtension,
- },
- /* Constraint class part */
- {
- /* resources */ constraintResources,
- /* num_resources */ XtNumber(constraintResources),
- /* constraint_size */ sizeof(MenuConstraintRec),
- /* initialize */ ConstraintInitialize,
- /* destroy */ NULL,
- /* set_values */ ConstraintSetValues,
- /* extension */ (XtPointer) &constraintExtension,
- },
- /* Menu class part */
- {
- /* extension */ NULL,
- }
- };
-
- WidgetClass menuWidgetClass = (WidgetClass) &menuClassRec;
-
- static void InsertChild(w)
- Widget w;
- {
- String params[2];
- Cardinal num_params;
- Widget parent = XtParent(w);
-
- if (!XtIsWidget(w) && !XtIsSubclass(w, labelGadgetClass)) {
- params[0] = XtClass(w)->core_class.class_name;
- params[1] = XtClass(parent)->core_class.class_name;
- num_params = 2;
- XtAppErrorMsg(XtWidgetToApplicationContext(w),
- "childError", "class", "WidgetError",
- "Children of class %s cannot be added to %n widgets",
- params, &num_params);
- }
-
- (*((CompositeWidgetClass)(menuWidgetClass->
- core_class.superclass))->composite_class.insert_child) (w);
- }
-
- static Boolean CvtStringToWidget(dpy, args, num_args, from, to, data)
- Display *dpy;
- XrmValuePtr args;
- Cardinal *num_args;
- XrmValuePtr from, to;
- XtPointer *data;
- {
- static Widget w;
- Widget parent;
- Boolean badConvert;
-
- if (*num_args != 1) {
- XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
- "wrongParameters", "cvtStringToWidget",
- "XtToolkitError",
- "StringToWidget conversion needs parent arg",
- (String *) NULL, (Cardinal *) NULL);
- }
-
- /* Convert first arg into parent */
-
- parent = *(Widget*) args[0].addr;
-
- w = XtNameToWidget(parent, (String) from->addr);
- badConvert = (w == NULL);
-
- if (badConvert) {
- XtDisplayStringConversionWarning(dpy, from->addr, "Widget");
- } else {
- if (to->addr == NULL) to->addr = (caddr_t) &w;
- else if (to->size < sizeof(Widget)) badConvert = TRUE;
- else *(Widget *) to->addr = w;
-
- to->size = sizeof(Widget);
- }
- return !badConvert;
- }
-
- static void ClassInitialize()
- {
- static XtConvertArgRec parentConvertArgs[] = {
- {XtBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.parent),
- sizeof(Widget)},
- };
-
-
- /* Register a converter for string to widget */
-
- XtSetTypeConverter(XtRString, XtRWidget, CvtStringToWidget,
- parentConvertArgs, XtNumber(parentConvertArgs),
- XtCacheNone, (XtDestructor) NULL);
- }
-
- static void HandleMenuButton(w, client_data, event,
- continue_to_dispatch)
- Widget w;
- XtPointer client_data;
- XEvent *event;
- Boolean *continue_to_dispatch;
- {
- switch (event->type) {
- case ButtonPress:
- /* The new grab does an implicit AllowEvents */
- (void) XtGrabPointer(w, True,
- EnterWindowMask | LeaveWindowMask |
- ButtonReleaseMask,
- GrabModeAsync, GrabModeAsync, None, None,
- event->xbutton.time);
- break;
-
- case ButtonRelease:
- /* Popping down also ungrabs the pointer */
- XtPopdown(w);
- break;
- }
- }
-
- static void Initialize(req, new)
- Widget req, new;
- {
- ((MenuWidget) new)->menu.save_border = -1;
-
- if (XtIsShell(XtParent(new))) {
- XtAddRawEventHandler(XtParent(new),
- ButtonPressMask | ButtonReleaseMask,
- FALSE, HandleMenuButton, NULL);
- }
- }
-
- static void ConstraintInitialize(req, new, args, num_args)
- Widget req, new;
- ArgList args;
- Cardinal *num_args;
- {
- MenuConstraint mc = (MenuConstraint) new->core.constraints;
-
- mc->menu.desired_height = new->core.height;
- mc->menu.desired_border_width = new->core.border_width;
- }
-
- static void Destroy(w)
- Widget w;
- {
- XtRemoveRawEventHandler(XtParent(w), XtAllEvents, TRUE,
- HandleMenuButton, NULL);
- }
-
- static void PositionChildren(menu, initiator)
- register MenuWidget menu;
- Widget initiator;
- {
- int i, y;
- register int last_border;
- register Widget child;
- MenuConstraint mc;
- Boolean first = TRUE;
-
- if (menu->composite.num_children == 0) return;
-
- for (i = 0; i < menu->composite.num_children; i++) {
- child = menu->composite.children[i];
- if (!XtIsManaged(child)) continue;
- mc = (MenuConstraint) child->core.constraints;
-
- if (first) {
- first = FALSE;
- last_border = mc->menu.desired_border_width;
- y = -last_border;
- }
-
- if (child == initiator) {
- if (last_border > child->core.border_width) {
- y += last_border - child->core.border_width;
- }
- last_border = child->core.border_width;
-
- child->core.x = -last_border;
- child->core.y = y;
- child->core.width = menu->core.width;
- } else {
- if (last_border > mc->menu.desired_border_width) {
- y += last_border - mc->menu.desired_border_width;
- }
- last_border = mc->menu.desired_border_width;
-
- XtConfigureWidget(child, -last_border, y,
- menu->core.width, mc->menu.desired_height,
- last_border);
- }
-
- y += (int) child->core.height + last_border;
- }
- }
-
- static void Resize(w)
- Widget w;
- {
- PositionChildren((MenuWidget) w, (Widget) NULL);
- }
-
- static int WidestDesiredSize(menu, initiator)
- MenuWidget menu;
- Widget initiator;
- {
- register int i, width = 0;
- register Widget child;
- XtWidgetGeometry desired;
-
- for (i = 0; i < menu->composite.num_children; i++) {
- child = menu->composite.children[i];
- if (!XtIsManaged(child)) continue;
-
- if (child == initiator) {
- if (child->core.width > width) {
- width = child->core.width;
- }
- } else {
- (void) XtQueryGeometry(child, NULL, &desired);
- if (desired.width > width) width = desired.width;
- }
- }
-
- if (width <= 0) return 1;
- else return width;
- }
-
- static void CalculateDesiredSizes(menu, width, initiator)
- MenuWidget menu;
- Dimension width;
- Widget initiator;
- {
- XtWidgetGeometry proposed, desired;
- register Widget child;
- MenuConstraint mc;
- register int i;
-
- for (i = 0; i < menu->composite.num_children; i++) {
- child = menu->composite.children[i];
- if (!XtIsManaged(child)) continue;
- mc = (MenuConstraint) child->core.constraints;
-
- if (child == initiator) {
- mc->menu.desired_height = child->core.height;
- mc->menu.desired_border_width =
- child->core.border_width;
- } else {
- proposed.width = width;
- proposed.request_mode = CWWidth;
- (void) XtQueryGeometry(child, &proposed, &desired);
-
- mc->menu.desired_height = desired.height;
- mc->menu.desired_border_width = desired.border_width;
- }
- }
- }
-
- static void CalculateNewSize(menu, width, height, initiator)
- register MenuWidget menu;
- Dimension *width, *height;
- Widget initiator;
- {
- register int i;
- register int last_border;
- register Widget child;
- int y;
- MenuConstraint mc;
- Boolean first = TRUE;
-
- if (menu->composite.num_children == 0) {
- *width = *height = 10; /* Arbitrary */
- return;
- }
-
- *width = WidestDesiredSize(menu, initiator);
-
- CalculateDesiredSizes(menu, *width, initiator);
-
- for (i = 0; i < menu->composite.num_children; i++) {
- child = menu->composite.children[i];
- if (!XtIsManaged(child)) continue;
- mc = (MenuConstraint) child->core.constraints;
-
- if (first) {
- first = FALSE;
- last_border = mc->menu.desired_border_width;
- y = -last_border;
- }
-
- if (last_border > mc->menu.desired_border_width) {
- y += last_border - (int) mc->menu.desired_border_width;
- }
- last_border = mc->menu.desired_border_width;
- y += (int) mc->menu.desired_height + last_border;
- }
-
- if (y <= 0) y = 1;
- *height = y;
- }
-
- static void ChangeManaged(w)
- Widget w;
- {
- MenuWidget menu = (MenuWidget) w;
- XtWidgetGeometry request;
- XtGeometryResult result;
-
- CalculateNewSize(menu, &request.width, &request.height,
- (Widget) NULL);
-
- if (request.width != menu->core.width ||
- request.height != menu->core.height) {
- request.request_mode = CWWidth | CWHeight;
- do {
- result = XtMakeGeometryRequest(w, &request, &request);
- } while (result == XtGeometryAlmost);
- }
-
- PositionChildren(menu, (Widget) NULL);
- }
-
- static XtGeometryResult GeometryManager(w, desired, allowed)
- Widget w;
- XtWidgetGeometry *desired, *allowed;
- {
- MenuWidget menu = (MenuWidget) XtParent(w);
- XtWidgetGeometry request;
- XtGeometryResult result;
- Dimension save_width, save_height, save_border_width;
-
- #define Wants(flag) (desired->request_mode & flag)
- #define RestoreGeometry(w) { \
- w->core.width = save_width; \
- w->core.height = save_height; \
- w->core.border_width = save_border_width; }
-
- if (menu->menu.save_border != -1) {
- /* This was caused by a child set-values */
- w->core.border_width = menu->menu.save_border;
- menu->menu.save_border = -1;
- desired->border_width -= 1000;
- }
-
- if (Wants(CWX) || Wants(CWY)) {
- return XtGeometryNo;
- }
-
- /* If only requesting a stack mode change, allow it */
-
- if (!Wants(CWWidth) && !Wants(CWHeight) && !Wants(CWBorderWidth)) {
- return XtGeometryYes;
- }
-
- /* Figure out how big we would be with this change */
-
- save_width = w->core.width;
- save_height = w->core.height;
- save_border_width = w->core.border_width;
- if (Wants(CWWidth)) w->core.width = desired->width;
- if (Wants(CWHeight)) w->core.height = desired->height;
- if (Wants(CWBorderWidth)) {
- w->core.border_width = desired->border_width;
- }
-
- CalculateNewSize(menu, &request.width, &request.height, w);
-
- /* If the new width is the same as the old and the child requested
- a width change, CalculateNewSize was not able to accommodate
- the width change, so refuse the geometry request. */
-
- if (request.width == menu->core.width && Wants(CWWidth)) {
- RestoreGeometry(w);
- return XtGeometryNo;
- }
-
- /* If new width is equal to child's width, we are going to try
- to accommodate the child. Make a geometry request. This also
- covers cases where the child requested no width
- change since that wouldn't cause the menu to change width. */
-
- if (request.width == w->core.width) {
- request.request_mode = CWWidth | CWHeight;
- if (Wants(XtCWQueryOnly)) {
- request.request_mode |= XtCWQueryOnly;
- }
- result = XtMakeGeometryRequest((Widget) menu, &request, NULL);
-
- /* Almost isn't good enough here; must be allowed */
-
- if (result == XtGeometryAlmost) result = XtGeometryNo;
- if (result == XtGeometryNo || Wants(XtCWQueryOnly)) {
- RestoreGeometry(w);
- } else PositionChildren(menu, w);
- return result;
- }
-
- /* New width is different from child's width, so we want to return
- XtGeometryAlmost. See if this is allowed. */
-
- RestoreGeometry(w);
-
- request.request_mode = CWWidth | CWHeight | XtCWQueryOnly;
- result = XtMakeGeometryRequest((Widget) menu, &request, NULL);
-
- /* Almost isn't good enough here; must be allowed */
-
- if (result != XtGeometryYes) return XtGeometryNo;
-
- /* It would be allowed, so return suggested geometry */
-
- *allowed = *desired;
- allowed->width = request.width;
- return XtGeometryAlmost;
- #undef Wants
- #undef RestoreGeometry
- }
-
- static Boolean ConstraintSetValues(old, req, new, args, num_args)
- Widget old, req, new;
- ArgList args;
- Cardinal *num_args;
- {
- MenuConstraint newmc = (MenuConstraint) new->core.constraints;
- MenuConstraint oldmc = (MenuConstraint) old->core.constraints;
- register MenuWidget menu;
- register int i, j;
-
- if (newmc->menu.insert_before != oldmc->menu.insert_before) {
- menu = (MenuWidget) XtParent(new);
-
- /* Remove child from current position */
-
- for (i = 0; i < menu->composite.num_children &&
- menu->composite.children[i] != new; i++) {}
-
- for (; i < menu->composite.num_children - 1; i++) {
- menu->composite.children[i] =
- menu->composite.children[i+1];
- }
-
- /* Find new widget to insert before */
-
- for (i = 0; i < menu->composite.num_children - 1 &&
- menu->composite.children[i] !=
- newmc->menu.insert_before;
- i++) {}
-
- /* Move the rest of them up */
-
- for (j = menu->composite.num_children - 1; j > i; j--) {
- menu->composite.children[j] =
- menu->composite.children[j-1];
- }
-
- menu->composite.children[i] = new;
-
- /* Cause a geometry request */
-
- menu->menu.save_border = new->core.border_width;
- new->core.border_width += 1000;
- }
-
- return FALSE;
- }
-
- static void Redisplay(w, event, region)
- Widget w;
- XEvent *event;
- Region region;
- {
- CompositeWidget comp = (CompositeWidget) w;
- int i;
- Widget c; /* child */
-
- for (i = 0; i < comp->composite.num_children; i++) {
- c = comp->composite.children[i];
- if (XtIsManaged(c) && XtIsSubclass(c, labelGadgetClass) &&
- XRectInRegion(region, c->core.x, c->core.y,
- c->core.width + 2*c->core.border_width,
- c->core.height + 2*c->core.border_width)
- != RectangleOut) {
- (*(XtClass(c)->core_class.expose))(c, event, region);
- }
- }
- }
-
- static void ConstraintGetValuesHook(w, args, num_args)
- Widget w;
- ArgList args;
- Cardinal *num_args;
- {
- register int i, j;
-
- for (i = 0; i < *num_args; i++) {
- if (strcmp(args[i].name, XtNinsertBefore) == 0) {
- MenuConstraint mc = (MenuConstraint) w->core.constraints;
- MenuWidget menu = (MenuWidget) XtParent(w);
-
- for (j = 0; j < menu->composite.num_children; j++) {
- if (menu->composite.children[j] == w) {
- if (j == menu->composite.num_children - 1) {
- args[i].value = NULL;
- } else {
- *(Widget *) (args[i].value) =
- menu->composite.children[j+1];
- }
- break;
- }
- } /* End of for loop checking children */
- }
- }
- }
-