mirror of
https://github.com/NishiOwO/chimera.git
synced 2025-04-21 08:34:39 +00:00
363 lines
11 KiB
C
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);
|
|
}
|
|
}
|