749N/A/*
749N/A * $XConsortium: Porthole.c,v 1.16 94/04/17 20:12:34 kaleb Exp $
749N/A *
749N/ACopyright (c) 1990, 1994 X Consortium
749N/A
749N/APermission is hereby granted, free of charge, to any person obtaining a copy
749N/Aof this software and associated documentation files (the "Software"), to deal
749N/Ain the Software without restriction, including without limitation the rights
749N/Ato use, copy, modify, merge, publish, distribute, sublicense, and/or sell
749N/Acopies of the Software, and to permit persons to whom the Software is
749N/Afurnished to do so, subject to the following conditions:
749N/A
749N/AThe above copyright notice and this permission notice shall be included in
749N/Aall copies or substantial portions of the Software.
749N/A
749N/ATHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
749N/AIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
749N/AFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
749N/AX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
749N/AAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
749N/ACONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
749N/A
749N/AExcept as contained in this notice, the name of the X Consortium shall not be
749N/Aused in advertising or otherwise to promote the sale, use or other dealings
749N/Ain this Software without prior written authorization from the X Consortium.
749N/A *
749N/A * Author: Jim Fulton, MIT X Consortium
749N/A *
749N/A * This widget is a trivial clipping widget. It is typically used with a
749N/A * panner or scrollbar to navigate.
749N/A */
749N/A
749N/A#include <X11/IntrinsicP.h>
749N/A#include <X11/StringDefs.h> /* get XtN and XtC defines */
749N/A#include <X11/Xaw/XawInit.h> /* get Xaw initialize stuff */
749N/A#include <X11/Xaw/PortholeP.h> /* get porthole structs */
749N/A#include <X11/Xmu/Misc.h> /* for MAX */
749N/A
749N/A
749N/A/*
749N/A * resources for the porthole
749N/A */
749N/Astatic XtResource resources[] = {
749N/A#define poff(field) XtOffsetOf(PortholeRec, porthole.field)
749N/A { XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
749N/A poff(report_callbacks), XtRCallback, (XtPointer) NULL },
749N/A#undef poff
749N/A};
749N/A
749N/A
749N/A/*
749N/A * widget class methods used below
749N/A */
749N/Astatic void Realize(); /* set gravity and upcall */
749N/Astatic void Resize(); /* report new size */
749N/Astatic XtGeometryResult GeometryManager(); /* deal with child requests */
749N/Astatic void ChangeManaged(); /* somebody added a new widget */
749N/Astatic XtGeometryResult QueryGeometry(); /* say how big would like to be */
749N/A
749N/APortholeClassRec portholeClassRec = {
749N/A { /* core fields */
749N/A /* superclass */ (WidgetClass) &compositeClassRec,
749N/A /* class_name */ "Porthole",
749N/A /* widget_size */ sizeof(PortholeRec),
749N/A /* class_initialize */ XawInitializeWidgetSet,
749N/A /* class_part_initialize */ NULL,
749N/A /* class_inited */ FALSE,
749N/A /* initialize */ NULL,
749N/A /* initialize_hook */ NULL,
749N/A /* realize */ Realize,
749N/A /* actions */ NULL,
749N/A /* num_actions */ 0,
749N/A /* resources */ resources,
749N/A /* num_resources */ XtNumber(resources),
749N/A /* xrm_class */ NULLQUARK,
749N/A /* compress_motion */ TRUE,
749N/A /* compress_exposure */ TRUE,
749N/A /* compress_enterleave */ TRUE,
749N/A /* visible_interest */ FALSE,
749N/A /* destroy */ NULL,
749N/A /* resize */ Resize,
749N/A /* expose */ NULL,
749N/A /* set_values */ NULL,
749N/A /* set_values_hook */ NULL,
749N/A /* set_values_almost */ XtInheritSetValuesAlmost,
749N/A /* get_values_hook */ NULL,
749N/A /* accept_focus */ NULL,
749N/A /* version */ XtVersion,
749N/A /* callback_private */ NULL,
749N/A /* tm_table */ NULL,
749N/A /* query_geometry */ QueryGeometry,
749N/A /* display_accelerator */ XtInheritDisplayAccelerator,
749N/A /* extension */ NULL
749N/A },
749N/A { /* composite fields */
749N/A /* geometry_manager */ GeometryManager,
749N/A /* change_managed */ ChangeManaged,
749N/A /* insert_child */ XtInheritInsertChild,
749N/A /* delete_child */ XtInheritDeleteChild,
749N/A /* extension */ NULL
749N/A },
749N/A { /* porthole fields */
749N/A /* ignore */ 0
749N/A }
749N/A};
749N/A
749N/AWidgetClass portholeWidgetClass = (WidgetClass) &portholeClassRec;
749N/A
749N/A
749N/A/*****************************************************************************
749N/A * *
749N/A * utility routines *
749N/A * *
749N/A *****************************************************************************/
749N/A
749N/Astatic Widget find_child (pw)
749N/A PortholeWidget pw;
749N/A{
749N/A Widget *children;
749N/A int i;
749N/A
749N/A /*
749N/A * Find the managed child on which we should operate. Ignore multiple
749N/A * managed children.
749N/A */
749N/A for (i = 0, children = pw->composite.children;
749N/A i < pw->composite.num_children; i++, children++) {
749N/A if (XtIsManaged(*children)) return *children;
749N/A }
749N/A
749N/A return (Widget) NULL;
749N/A}
749N/A
749N/Astatic void SendReport (pw, changed)
749N/A PortholeWidget pw;
749N/A unsigned int changed;
749N/A{
749N/A Widget child = find_child (pw);
749N/A
749N/A if (pw->porthole.report_callbacks && child) {
749N/A XawPannerReport prep;
749N/A
749N/A prep.changed = changed;
749N/A prep.slider_x = -child->core.x; /* porthole is "inner" */
749N/A prep.slider_y = -child->core.y; /* child is outer since it is larger */
749N/A prep.slider_width = pw->core.width;
749N/A prep.slider_height = pw->core.height;
749N/A prep.canvas_width = child->core.width;
749N/A prep.canvas_height = child->core.height;
749N/A XtCallCallbackList ((Widget)pw, pw->porthole.report_callbacks,
749N/A (XtPointer) &prep);
749N/A }
749N/A}
749N/A
749N/A
749N/Astatic void layout_child (pw, child, geomp, xp, yp, widthp, heightp)
749N/A PortholeWidget pw;
749N/A Widget child;
749N/A XtWidgetGeometry *geomp;
749N/A Position *xp, *yp;
749N/A Dimension *widthp, *heightp;
749N/A{
749N/A Position minx, miny;
749N/A
749N/A *xp = child->core.x; /* default to current values */
749N/A *yp = child->core.y;
749N/A *widthp = child->core.width;
749N/A *heightp = child->core.height;
749N/A if (geomp) { /* mix in any requested changes */
749N/A if (geomp->request_mode & CWX) *xp = geomp->x;
749N/A if (geomp->request_mode & CWY) *yp = geomp->y;
749N/A if (geomp->request_mode & CWWidth) *widthp = geomp->width;
749N/A if (geomp->request_mode & CWHeight) *heightp = geomp->height;
749N/A }
749N/A
749N/A /*
749N/A * Make sure that the child is at least as large as the porthole; there
749N/A * is no maximum size.
749N/A */
749N/A if (*widthp < pw->core.width) *widthp = pw->core.width;
749N/A if (*heightp < pw->core.height) *heightp = pw->core.height;
749N/A
749N/A /*
749N/A * Make sure that the child is still on the screen. Note that this must
749N/A * be done *after* the size computation so that we know where to put it.
749N/A */
749N/A minx = ((Position) pw->core.width) - ((Position) *widthp);
749N/A miny = ((Position) pw->core.height) - ((Position) *heightp);
749N/A
749N/A if (*xp < minx) *xp = minx; /* keep at lower right corner */
749N/A if (*yp < miny) *yp = miny;
749N/A
749N/A if (*xp > 0) *xp = 0; /* keep at upper left corner */
749N/A if (*yp > 0) *yp = 0;
749N/A}
749N/A
749N/A
749N/A
749N/A/*****************************************************************************
749N/A * *
749N/A * Porthole Widget Class Methods *
749N/A * *
749N/A *****************************************************************************/
749N/A
749N/A
749N/Astatic void Realize (gw, valueMask, attributes)
749N/A Widget gw;
749N/A Mask *valueMask;
749N/A XSetWindowAttributes *attributes;
749N/A{
749N/A attributes->bit_gravity = NorthWestGravity;
749N/A *valueMask |= CWBitGravity;
749N/A
749N/A if (gw->core.width < 1) gw->core.width = 1;
749N/A if (gw->core.height < 1) gw->core.height = 1;
749N/A (*portholeWidgetClass->core_class.superclass->core_class.realize)
749N/A (gw, valueMask, attributes);
749N/A}
749N/A
749N/A
749N/Astatic void Resize (gw)
749N/A Widget gw;
749N/A{
749N/A PortholeWidget pw = (PortholeWidget) gw;
749N/A Widget child = find_child (pw);
749N/A
749N/A /*
749N/A * If we have a child, we need to make sure that it is at least as big
749N/A * as we are and in the right place.
749N/A */
749N/A if (child) {
749N/A Position x, y;
749N/A Dimension width, height;
749N/A
749N/A layout_child (pw, child, (XtWidgetGeometry *)NULL,
749N/A &x, &y, &width, &height);
749N/A XtConfigureWidget (child, x, y, width, height, (Dimension) 0);
749N/A }
749N/A
749N/A SendReport (pw, (unsigned int) (XawPRCanvasWidth | XawPRCanvasHeight));
749N/A}
749N/A
749N/A
749N/Astatic XtGeometryResult QueryGeometry (gw, intended, preferred)
749N/A Widget gw;
749N/A XtWidgetGeometry *intended, *preferred;
749N/A{
749N/A PortholeWidget pw = (PortholeWidget) gw;
749N/A Widget child = find_child (pw);
749N/A
749N/A if (child) {
749N/A#define SIZEONLY (CWWidth | CWHeight)
749N/A preferred->request_mode = SIZEONLY;
749N/A preferred->width = child->core.width;
749N/A preferred->height = child->core.height;
749N/A
749N/A if (((intended->request_mode & SIZEONLY) == SIZEONLY) &&
749N/A intended->width == preferred->width &&
749N/A intended->height == preferred->height)
749N/A return XtGeometryYes;
749N/A else if (preferred->width == pw->core.width &&
749N/A preferred->height == pw->core.height)
749N/A return XtGeometryNo;
749N/A else
749N/A return XtGeometryAlmost;
749N/A#undef SIZEONLY
749N/A }
749N/A return XtGeometryNo;
749N/A}
749N/A
749N/A
749N/Astatic XtGeometryResult GeometryManager (w, req, reply)
749N/A Widget w;
749N/A XtWidgetGeometry *req, *reply;
749N/A{
749N/A PortholeWidget pw = (PortholeWidget) w->core.parent;
749N/A Widget child = find_child (pw);
749N/A Boolean okay = TRUE;
749N/A
749N/A if (child != w) return XtGeometryNo; /* unknown child */
749N/A
749N/A *reply = *req; /* assume we'll grant everything */
749N/A
749N/A if ((req->request_mode & CWBorderWidth) && req->border_width != 0) {
749N/A reply->border_width = 0; /* require border width of 0 */
749N/A okay = FALSE;
749N/A }
749N/A
749N/A layout_child (pw, child, req, &reply->x, &reply->y,
749N/A &reply->width, &reply->height);
749N/A
749N/A if ((req->request_mode & CWX) && req->x != reply->x) okay = FALSE;
749N/A if ((req->request_mode & CWY) && req->x != reply->x) okay = FALSE;
749N/A if ((req->request_mode & CWWidth) && req->width != reply->width)
749N/A okay = FALSE;
749N/A if ((req->request_mode & CWHeight) && req->height != reply->height)
749N/A okay = FALSE;
749N/A
749N/A
749N/A /*
749N/A * If we failed on anything, simply return without touching widget
749N/A */
749N/A if (!okay) return XtGeometryAlmost;
749N/A
749N/A /*
749N/A * If not just doing a query, update widget and send report. Note that
749N/A * we will often set fields that weren't requested because we want to keep
749N/A * the child visible.
749N/A */
749N/A if (!(req->request_mode & XtCWQueryOnly)) {
749N/A unsigned int changed = 0;
749N/A
749N/A if (child->core.x != reply->x) {
749N/A changed |= XawPRSliderX;
749N/A child->core.x = reply->x;
749N/A }
749N/A if (child->core.y != reply->y) {
749N/A changed |= XawPRSliderY;
749N/A child->core.y = reply->y;
749N/A }
749N/A if (child->core.width != reply->width) {
749N/A changed |= XawPRSliderWidth;
749N/A child->core.width = reply->width;
749N/A }
749N/A if (child->core.height != reply->height) {
749N/A changed |= XawPRSliderHeight;
749N/A child->core.height = reply->height;
749N/A }
749N/A if (changed) SendReport (pw, changed);
749N/A }
749N/A
749N/A return XtGeometryYes; /* success! */
749N/A}
749N/A
749N/A
749N/Astatic void ChangeManaged (gw)
749N/A Widget gw;
749N/A{
749N/A PortholeWidget pw = (PortholeWidget) gw;
749N/A Widget child = find_child (pw); /* ignore extra children */
749N/A
749N/A if (child) {
749N/A if (!XtIsRealized (gw)) {
749N/A XtWidgetGeometry geom, retgeom;
749N/A
749N/A geom.request_mode = 0;
749N/A if (pw->core.width == 0) {
749N/A geom.width = child->core.width;
749N/A geom.request_mode |= CWWidth;
749N/A }
749N/A if (pw->core.height == 0) {
749N/A geom.height = child->core.height;
749N/A geom.request_mode |= CWHeight;
749N/A }
749N/A if (geom.request_mode &&
749N/A XtMakeGeometryRequest (gw, &geom, &retgeom) == XtGeometryAlmost) {
749N/A (void) XtMakeGeometryRequest (gw, &retgeom, (XtWidgetGeometry *)NULL);
749N/A }
749N/A }
749N/A
749N/A XtResizeWidget (child, Max (child->core.width, pw->core.width),
749N/A Max (child->core.height, pw->core.height), 0);
749N/A
749N/A SendReport (pw, (unsigned int) XawPRAll);
749N/A }
749N/A}