chimera/mxw/Porthole.c
2025-03-12 01:30:36 +09:00

363 lines
11 KiB
C

/*
* $XConsortium: Porthole.c,v 1.14 91/03/14 16:48:01 converse Exp $
*
* Copyright 1990 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, 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 M.I.T. not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. M.I.T. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
* 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.
*
* Author: Jim Fulton, MIT X Consortium
*
* This widget is a trivial clipping widget. It is typically used with a
* panner or scrollbar to navigate.
*/
#include <X11/IntrinsicP.h> /* get basic toolkit stuff */
#include <X11/StringDefs.h> /* get XtN and XtC defines */
#include <X11/Xaw/XawInit.h> /* get Xaw initialize stuff */
#include <X11/Xaw/PortholeP.h> /* get porthole structs */
#include <X11/Xmu/Misc.h> /* for MAX */
/*
* resources for the porthole
*/
static XtResource resources[] = {
#define poff(field) XtOffsetOf(PortholeRec, porthole.field)
{ XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
poff(report_callbacks), XtRCallback, (XtPointer) NULL },
#undef poff
};
/*
* widget class methods used below
*/
static void Realize(); /* set gravity and upcall */
static void Resize(); /* report new size */
static XtGeometryResult GeometryManager(); /* deal with child requests */
static void ChangeManaged(); /* somebody added a new widget */
static XtGeometryResult QueryGeometry(); /* say how big would like to be */
PortholeClassRec portholeClassRec = {
{ /* core fields */
/* superclass */ (WidgetClass) &compositeClassRec,
/* class_name */ "Porthole",
/* widget_size */ sizeof(PortholeRec),
/* class_initialize */ XawInitializeWidgetSet,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ NULL,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ NULL,
/* resize */ Resize,
/* expose */ NULL,
/* set_values */ NULL,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ NULL,
/* query_geometry */ QueryGeometry,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* composite fields */
/* geometry_manager */ GeometryManager,
/* change_managed */ ChangeManaged,
/* insert_child */ XtInheritInsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL
},
{ /* porthole fields */
/* ignore */ 0
}
};
WidgetClass portholeWidgetClass = (WidgetClass) &portholeClassRec;
/*****************************************************************************
* *
* utility routines *
* *
*****************************************************************************/
static Widget find_child (pw)
register PortholeWidget pw;
{
register Widget *children;
register int i;
/*
* Find the managed child on which we should operate. Ignore multiple
* managed children.
*/
for (i = 0, children = pw->composite.children;
i < pw->composite.num_children; i++, children++) {
if (XtIsManaged(*children)) return *children;
}
return (Widget) NULL;
}
static void SendReport (pw, changed)
PortholeWidget pw;
unsigned int changed;
{
Widget child = find_child (pw);
if (pw->porthole.report_callbacks && child) {
XawPannerReport prep;
prep.changed = changed;
prep.slider_x = -child->core.x; /* porthole is "inner" */
prep.slider_y = -child->core.y; /* child is outer since it is larger */
prep.slider_width = pw->core.width;
prep.slider_height = pw->core.height;
prep.canvas_width = child->core.width;
prep.canvas_height = child->core.height;
XtCallCallbackList ((Widget)pw, pw->porthole.report_callbacks,
(XtPointer) &prep);
}
}
static void layout_child (pw, child, geomp, xp, yp, widthp, heightp)
PortholeWidget pw;
Widget child;
XtWidgetGeometry *geomp;
Position *xp, *yp;
Dimension *widthp, *heightp;
{
Position minx, miny;
*xp = child->core.x; /* default to current values */
*yp = child->core.y;
*widthp = child->core.width;
*heightp = child->core.height;
if (geomp) { /* mix in any requested changes */
if (geomp->request_mode & CWX) *xp = geomp->x;
if (geomp->request_mode & CWY) *yp = geomp->y;
if (geomp->request_mode & CWWidth) *widthp = geomp->width;
if (geomp->request_mode & CWHeight) *heightp = geomp->height;
}
/*
* Make sure that the child is at least as large as the porthole; there
* is no maximum size.
*/
if (*widthp < pw->core.width) *widthp = pw->core.width;
if (*heightp < pw->core.height) *heightp = pw->core.height;
/*
* Make sure that the child is still on the screen. Note that this must
* be done *after* the size computation so that we know where to put it.
*/
minx = ((Position) pw->core.width) - ((Position) *widthp);
miny = ((Position) pw->core.height) - ((Position) *heightp);
if (*xp < minx) *xp = minx; /* keep at lower right corner */
if (*yp < miny) *yp = miny;
if (*xp > 0) *xp = 0; /* keep at upper left corner */
if (*yp > 0) *yp = 0;
}
/*****************************************************************************
* *
* Porthole Widget Class Methods *
* *
*****************************************************************************/
static void Realize (gw, valueMask, attributes)
register Widget gw;
Mask *valueMask;
XSetWindowAttributes *attributes;
{
attributes->bit_gravity = NorthWestGravity;
*valueMask |= CWBitGravity;
if (gw->core.width < 1) gw->core.width = 1;
if (gw->core.height < 1) gw->core.height = 1;
(*portholeWidgetClass->core_class.superclass->core_class.realize)
(gw, valueMask, attributes);
}
static void Resize (gw)
Widget gw;
{
PortholeWidget pw = (PortholeWidget) gw;
Widget child = find_child (pw);
/*
* If we have a child, we need to make sure that it is at least as big
* as we are and in the right place.
*/
if (child) {
Position x, y;
Dimension width, height;
layout_child (pw, child, NULL, &x, &y, &width, &height);
XtConfigureWidget (child, x, y, width, height, (Dimension) 0);
}
SendReport (pw, (unsigned int) (XawPRCanvasWidth | XawPRCanvasHeight));
}
static XtGeometryResult QueryGeometry (gw, intended, preferred)
Widget gw;
XtWidgetGeometry *intended, *preferred;
{
register PortholeWidget pw = (PortholeWidget) gw;
Widget child = find_child (pw);
if (child) {
#define SIZEONLY (CWWidth | CWHeight)
preferred->request_mode = SIZEONLY;
preferred->width = child->core.width;
preferred->height = child->core.height;
if (((intended->request_mode & SIZEONLY) == SIZEONLY) &&
intended->width == preferred->width &&
intended->height == preferred->height)
return XtGeometryYes;
else if (preferred->width == pw->core.width &&
preferred->height == pw->core.height)
return XtGeometryNo;
else
return XtGeometryAlmost;
#undef SIZEONLY
}
return XtGeometryNo;
}
static XtGeometryResult GeometryManager (w, req, reply)
Widget w;
XtWidgetGeometry *req, *reply;
{
PortholeWidget pw = (PortholeWidget) w->core.parent;
Widget child = find_child (pw);
Boolean okay = TRUE;
if (child != w) return XtGeometryNo; /* unknown child */
*reply = *req; /* assume we'll grant everything */
if ((req->request_mode & CWBorderWidth) && req->border_width != 0) {
reply->border_width = 0; /* require border width of 0 */
okay = FALSE;
}
layout_child (pw, child, req, &reply->x, &reply->y,
&reply->width, &reply->height);
if ((req->request_mode & CWX) && req->x != reply->x) okay = FALSE;
if ((req->request_mode & CWY) && req->x != reply->x) okay = FALSE;
if ((req->request_mode & CWWidth) && req->width != reply->width)
okay = FALSE;
if ((req->request_mode & CWHeight) && req->height != reply->height)
okay = FALSE;
/*
* If we failed on anything, simply return without touching widget
*/
if (!okay) return XtGeometryAlmost;
/*
* If not just doing a query, update widget and send report. Note that
* we will often set fields that weren't requested because we want to keep
* the child visible.
*/
if (!(req->request_mode & XtCWQueryOnly)) {
unsigned int changed = 0;
if (child->core.x != reply->x) {
changed |= XawPRSliderX;
child->core.x = reply->x;
}
if (child->core.y != reply->y) {
changed |= XawPRSliderY;
child->core.y = reply->y;
}
if (child->core.width != reply->width) {
changed |= XawPRSliderWidth;
child->core.width = reply->width;
}
if (child->core.height != reply->height) {
changed |= XawPRSliderHeight;
child->core.height = reply->height;
}
if (changed) SendReport (pw, changed);
}
return XtGeometryYes; /* success! */
}
static void ChangeManaged (gw)
Widget gw;
{
PortholeWidget pw = (PortholeWidget) gw;
Widget child = find_child (pw); /* ignore extra children */
if (child) {
if (!XtIsRealized (gw)) {
XtWidgetGeometry geom, retgeom;
geom.request_mode = 0;
if (pw->core.width == 0) {
geom.width = child->core.width;
geom.request_mode |= CWWidth;
}
if (pw->core.height == 0) {
geom.height = child->core.height;
geom.request_mode |= CWHeight;
}
if (geom.request_mode &&
XtMakeGeometryRequest (gw, &geom, &retgeom) ==
XtGeometryAlmost) {
(void) XtMakeGeometryRequest (gw, &retgeom, NULL);
}
}
XtResizeWidget (child, Max (child->core.width, pw->core.width),
Max (child->core.height, pw->core.height), 0);
SendReport (pw, (unsigned int) XawPRAll);
}
}