Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  *
      3 Copyright 1990, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24  *
     25  * Author:  Jim Fulton, MIT X Consortium
     26  *
     27  * This widget is a trivial clipping widget.  It is typically used with a
     28  * panner or scrollbar to navigate.
     29  */
     30 
     31 #ifdef HAVE_CONFIG_H
     32 #include <config.h>
     33 #endif
     34 #include <X11/IntrinsicP.h>
     35 #include <X11/StringDefs.h>
     36 #include <X11/Xmu/Misc.h>
     37 #include <X11/Xaw/PortholeP.h>
     38 #include <X11/Xaw/XawInit.h>
     39 #include "Private.h"
     40 
     41 /*
     42  * Class Methods
     43  */
     44 static void XawPortholeChangeManaged(Widget);
     45 static XtGeometryResult XawPortholeGeometryManager(Widget, XtWidgetGeometry*,
     46 						   XtWidgetGeometry*);
     47 static XtGeometryResult XawPortholeQueryGeometry(Widget, XtWidgetGeometry*,
     48 						 XtWidgetGeometry*);
     49 static void XawPortholeRealize(Widget, Mask*, XSetWindowAttributes*);
     50 static void XawPortholeResize(Widget);
     51 
     52 /*
     53  * Prototypes
     54  */
     55 static Widget find_child(PortholeWidget);
     56 static void layout_child(PortholeWidget, Widget, XtWidgetGeometry*,
     57 			 Position*, Position*, Dimension*, Dimension*);
     58 static void SendReport(PortholeWidget, unsigned int);
     59 
     60 /*
     61  * Initialization
     62  */
     63 #define offset(field)	XtOffsetOf(PortholeRec, porthole.field)
     64 static XtResource resources[] = {
     65   {
     66     XtNreportCallback,
     67     XtCReportCallback,
     68     XtRCallback,
     69     sizeof(XtPointer),
     70     offset(report_callbacks),
     71     XtRCallback,
     72     NULL
     73   },
     74 };
     75 #undef offset
     76 
     77 #define Superclass	(&compositeClassRec)
     78 PortholeClassRec portholeClassRec = {
     79   /* core */
     80   {
     81     (WidgetClass)Superclass,		/* superclass */
     82     "Porthole",				/* class_name */
     83     sizeof(PortholeRec),		/* widget_size */
     84     XawInitializeWidgetSet,		/* class_initialize */
     85     NULL,				/* class_part_initialize */
     86     False,				/* class_inited */
     87     NULL,				/* initialize */
     88     NULL,				/* initialize_hook */
     89     XawPortholeRealize,			/* realize */
     90     NULL,				/* actions */
     91     0,					/* num_actions */
     92     resources,				/* resources */
     93     XtNumber(resources),		/* num_resources */
     94     NULLQUARK,				/* xrm_class */
     95     True,				/* compress_motion */
     96     True,				/* compress_exposure */
     97     True,				/* compress_enterleave */
     98     False,				/* visible_interest */
     99     NULL,				/* destroy */
    100     XawPortholeResize,			/* resize */
    101     NULL,				/* expose */
    102     NULL,				/* set_values */
    103     NULL,				/* set_values_hook */
    104     XtInheritSetValuesAlmost,		/* set_values_almost */
    105     NULL,				/* get_values_hook */
    106     NULL,				/* accept_focus */
    107     XtVersion,				/* version */
    108     NULL,				/* callback_private */
    109     NULL,				/* tm_table */
    110     XawPortholeQueryGeometry,		/* query_geometry */
    111     XtInheritDisplayAccelerator,	/* display_accelerator */
    112     NULL,				/* extension */
    113   },
    114   /* composite */
    115   {
    116     XawPortholeGeometryManager,		/* geometry_manager */
    117     XawPortholeChangeManaged,		/* change_managed */
    118     XtInheritInsertChild,		/* insert_child */
    119     XtInheritDeleteChild,		/* delete_child */
    120     NULL,				/* extension */
    121   },
    122   { /* porthole */
    123     NULL,				/* extension */
    124   },
    125 };
    126 
    127 WidgetClass portholeWidgetClass = (WidgetClass)&portholeClassRec;
    128 
    129 /*
    130  * Implementation
    131  */
    132 static Widget
    133 find_child(PortholeWidget pw)
    134 {
    135     Widget *children;
    136     unsigned int i;
    137 
    138     /*
    139      * Find the managed child on which we should operate.  Ignore multiple
    140      * managed children
    141      */
    142     for (i = 0, children = pw->composite.children;
    143 	 i < pw->composite.num_children; i++, children++)
    144 	if (XtIsManaged(*children))
    145 	    return (*children);
    146 
    147     return (NULL);
    148 }
    149 
    150 static void
    151 SendReport(PortholeWidget pw, unsigned int changed)
    152 {
    153     Widget child = find_child(pw);
    154 
    155     if (pw->porthole.report_callbacks && child) {
    156 	XawPannerReport prep = {
    157 	    .changed = changed,
    158 	    .slider_x = (Position)(-XtX(child)), /* porthole is "inner" */
    159 	    .slider_y = (Position)(-XtY(child)), /* child is outer since it is larger */
    160 	    .slider_width = XtWidth(pw),
    161 	    .slider_height = XtHeight(pw),
    162 	    .canvas_width = XtWidth(child),
    163 	    .canvas_height = XtHeight(child)
    164 	};
    165 	XtCallCallbackList((Widget)pw, pw->porthole.report_callbacks,
    166 			   (XtPointer)&prep);
    167     }
    168 }
    169 
    170 static void
    171 layout_child(PortholeWidget pw, Widget child, XtWidgetGeometry *geomp,
    172 	     Position *xp, Position *yp, Dimension *widthp, Dimension *heightp)
    173 {
    174     Position minx, miny;
    175 
    176     *xp = XtX(child);			/* default to current values */
    177     *yp = XtY(child);
    178     *widthp = XtWidth(child);
    179     *heightp = XtHeight(child);
    180     if (geomp) {			/* mix in any requested changes */
    181 	if (geomp->request_mode & CWX)
    182 	    *xp = geomp->x;
    183 	if (geomp->request_mode & CWY)
    184 	    *yp = geomp->y;
    185 	if (geomp->request_mode & CWWidth)
    186 	    *widthp = geomp->width;
    187 	if (geomp->request_mode & CWHeight)
    188 	    *heightp = geomp->height;
    189     }
    190 
    191     /*
    192      * Make sure that the child is at least as large as the porthole; there
    193      * is no maximum size
    194      */
    195     if (*widthp < XtWidth(pw)) *widthp = XtWidth(pw);
    196     if (*heightp < XtHeight(pw)) *heightp = XtHeight(pw);
    197 
    198     /*
    199      * Make sure that the child is still on the screen.  Note that this must
    200      * be done *after* the size computation so that we know where to put it
    201      */
    202     minx = (Position)(XtWidth(pw) - *widthp);
    203     miny = (Position)(XtHeight(pw) - *heightp);
    204 
    205     if (*xp < minx)
    206 	*xp = minx;
    207     if (*yp < miny)
    208 	*yp = miny;
    209 
    210     if (*xp > 0)
    211 	*xp = 0;
    212     if (*yp > 0)
    213 	*yp = 0;
    214 }
    215 
    216 static void
    217 XawPortholeRealize(Widget gw, Mask *valueMask, XSetWindowAttributes *attr)
    218 {
    219     attr->bit_gravity = NorthWestGravity;
    220     *valueMask |= CWBitGravity;
    221 
    222     if (XtWidth(gw) < 1)
    223 	XtWidth(gw) = 1;
    224     if (XtHeight(gw) < 1)
    225 	XtHeight(gw) = 1;
    226     (*portholeWidgetClass->core_class.superclass->core_class.realize)
    227 	(gw, valueMask, attr);
    228 }
    229 
    230 static void
    231 XawPortholeResize(Widget gw)
    232 {
    233     PortholeWidget pw = (PortholeWidget)gw;
    234     Widget child = find_child(pw);
    235 
    236     /*
    237      * If we have a child, we need to make sure that it is at least as big
    238      * as we are and in the right place
    239      */
    240     if (child) {
    241 	Position x, y;
    242 	Dimension width, height;
    243 
    244 	layout_child(pw, child, NULL, &x, &y, &width, &height);
    245 	XtConfigureWidget(child, x, y, width, height, 0);
    246     }
    247 
    248     SendReport(pw, XawPRCanvasWidth | XawPRCanvasHeight);
    249 }
    250 
    251 static XtGeometryResult
    252 XawPortholeQueryGeometry(Widget gw, XtWidgetGeometry *intended,
    253 			 XtWidgetGeometry *preferred)
    254 {
    255     PortholeWidget pw = (PortholeWidget)gw;
    256     Widget child = find_child(pw);
    257 
    258     if (child) {
    259 #define SIZEONLY (CWWidth | CWHeight)
    260 	preferred->request_mode = SIZEONLY;
    261 	preferred->width = XtWidth(child);
    262 	preferred->height = XtHeight(child);
    263 
    264 	if ((intended->request_mode & SIZEONLY) == SIZEONLY &&
    265 	    intended->width == preferred->width &&
    266 	    intended->height == preferred->height)
    267 	    return (XtGeometryYes);
    268 	else if (preferred->width == XtWidth(pw) &&
    269 		 preferred->height == XtHeight(pw))
    270 	    return (XtGeometryNo);
    271 
    272 	return (XtGeometryAlmost);
    273 #undef SIZEONLY
    274     }
    275 
    276     return (XtGeometryNo);
    277 }
    278 
    279 static XtGeometryResult
    280 XawPortholeGeometryManager(Widget w, XtWidgetGeometry *req,
    281 			   XtWidgetGeometry *reply)
    282 {
    283     PortholeWidget pw = (PortholeWidget) w->core.parent;
    284     Widget child = find_child(pw);
    285     Bool okay = True;
    286 
    287     if (child != w)
    288 	return (XtGeometryNo);
    289 
    290     *reply = *req;			/* assume we'll grant everything */
    291 
    292     if ((req->request_mode & CWBorderWidth) && req->border_width != 0) {
    293 	reply->border_width = 0;
    294 	okay = False;
    295     }
    296 
    297     layout_child(pw, child, req, &reply->x, &reply->y,
    298 		 &reply->width, &reply->height);
    299 
    300     if ((req->request_mode & CWX) && req->x != reply->x)
    301 	okay = False;
    302     if ((req->request_mode & CWY) && req->x != reply->x)
    303 	okay = False;
    304     if ((req->request_mode & CWWidth) && req->width != reply->width)
    305 	okay = False;
    306     if ((req->request_mode & CWHeight) && req->height != reply->height)
    307 	okay = False;
    308 
    309     /*
    310      * If we failed on anything, simply return without touching widget
    311      */
    312     if (!okay)
    313 	return (XtGeometryAlmost);
    314 
    315     /*
    316      * If not just doing a query, update widget and send report.  Note that
    317      * we will often set fields that weren't requested because we want to keep
    318      * the child visible
    319      */
    320     if (!(req->request_mode & XtCWQueryOnly)) {
    321 	unsigned int changed = 0;
    322 
    323 	if (XtX(child) != reply->x) {
    324 	    changed |= XawPRSliderX;
    325 	    XtX(child) = reply->x;
    326 	}
    327 	if (XtY(child) != reply->y) {
    328 	    changed |= XawPRSliderY;
    329 	    XtY(child) = reply->y;
    330 	}
    331 	if (XtWidth(child) != reply->width) {
    332 	    changed |= XawPRSliderWidth;
    333 	    XtWidth(child) = reply->width;
    334 	}
    335 	if (XtHeight(child) != reply->height) {
    336 	    changed |= XawPRSliderHeight;
    337 	    XtHeight(child) = reply->height;
    338 	}
    339 	if (changed)
    340 	    SendReport(pw, changed);
    341     }
    342 
    343     return (XtGeometryYes);		/* success! */
    344 }
    345 
    346 static void
    347 XawPortholeChangeManaged(Widget gw)
    348 {
    349     PortholeWidget pw = (PortholeWidget)gw;
    350     Widget child = find_child (pw);	/* ignore extra children */
    351 
    352     if (child) {
    353 	if (!XtIsRealized (gw)) {
    354 	    XtWidgetGeometry geom = { .request_mode = 0 }, retgeom;
    355 
    356 	    if (XtWidth(pw) == 0) {
    357 		geom.width = XtWidth(child);
    358 		geom.request_mode |= CWWidth;
    359 	    }
    360 	    if (XtHeight(pw) == 0) {
    361 		geom.height = XtHeight(child);
    362 		geom.request_mode |= CWHeight;
    363 	    }
    364 	    if (geom.request_mode &&
    365 		XtMakeGeometryRequest (gw, &geom, &retgeom)
    366 		== XtGeometryAlmost)
    367 		(void)XtMakeGeometryRequest(gw, &retgeom, NULL);
    368 	}
    369 
    370 	XtResizeWidget(child, Max(XtWidth(child), XtWidth(pw)),
    371 		       Max(XtHeight(child), XtHeight(pw)), 0);
    372 
    373 	SendReport(pw, XawPRAll);
    374     }
    375 }
    376