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