1 /***********************************************************
2 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3 
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice (including the next
12 paragraph) shall be included in all copies or substantial portions of the
13 Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
22 
23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24 
25                         All Rights Reserved
26 
27 Permission to use, copy, modify, and distribute this software and its
28 documentation for any purpose and without fee is hereby granted,
29 provided that the above copyright notice appear in all copies and that
30 both that copyright notice and this permission notice appear in
31 supporting documentation, and that the name of Digital not be
32 used in advertising or publicity pertaining to distribution of the
33 software without specific, written prior permission.
34 
35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41 SOFTWARE.
42 
43 ******************************************************************/
44 
45 /*
46 
47 Copyright 1987, 1988, 1994, 1998  The Open Group
48 
49 Permission to use, copy, modify, distribute, and sell this software and its
50 documentation for any purpose is hereby granted without fee, provided that
51 the above copyright notice appear in all copies and that both that
52 copyright notice and this permission notice appear in supporting
53 documentation.
54 
55 The above copyright notice and this permission notice shall be included in
56 all copies or substantial portions of the Software.
57 
58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64 
65 Except as contained in this notice, the name of The Open Group shall not be
66 used in advertising or otherwise to promote the sale, use or other dealings
67 in this Software without prior written authorization from The Open Group.
68 
69 */
70 
71 #ifdef HAVE_CONFIG_H
72 #include <config.h>
73 #endif
74 #include "IntrinsicI.h"
75 
76 /*
77  *      XtSetValues(), XtSetSubvalues()
78  */
79 
80 static void
SetValues(char * base,XrmResourceList * res,register Cardinal num_resources,ArgList args,Cardinal num_args)81 SetValues(char *base,                           /* Base address to write values to */
82           XrmResourceList *res,                 /* The current resource values. */
83           register Cardinal num_resources,      /* number of items in resources      */
84           ArgList args,                         /* The resource values to set */
85           Cardinal num_args)                    /* number of items in arg list       */
86 {
87     register ArgList arg;
88     register Cardinal i;
89     register XrmName argName;
90     register XrmResourceList *xrmres;
91 
92     /* Resource lists are assumed to be in compiled form already via the
93        initial XtGetResources, XtGetSubresources calls */
94 
95     for (arg = args; num_args != 0; num_args--, arg++) {
96         argName = StringToName(arg->name);
97         for (xrmres = res, i = 0; i < num_resources; i++, xrmres++) {
98             if (argName == (*xrmres)->xrm_name) {
99                 _XtCopyFromArg(arg->value,
100                                base - (*xrmres)->xrm_offset - 1,
101                                (*xrmres)->xrm_size);
102                 break;
103             }
104         }
105     }
106 }                               /* SetValues */
107 
108 static Boolean
CallSetValues(WidgetClass class,Widget current,Widget request,Widget new,ArgList args,Cardinal num_args)109 CallSetValues(WidgetClass class,
110               Widget current,
111               Widget request,
112               Widget new,
113               ArgList args,
114               Cardinal num_args)
115 {
116     Boolean redisplay = FALSE;
117     WidgetClass superclass;
118     XtArgsFunc set_values_hook;
119     XtSetValuesFunc set_values;
120 
121     LOCK_PROCESS;
122     superclass = class->core_class.superclass;
123     UNLOCK_PROCESS;
124     if (superclass)
125         redisplay =
126             CallSetValues(superclass, current, request, new, args, num_args);
127 
128     LOCK_PROCESS;
129     set_values = class->core_class.set_values;
130     UNLOCK_PROCESS;
131     if (set_values)
132         redisplay |= (*set_values) (current, request, new, args, &num_args);
133 
134     LOCK_PROCESS;
135     set_values_hook = class->core_class.set_values_hook;
136     UNLOCK_PROCESS;
137     if (set_values_hook)
138         redisplay |= (*set_values_hook) (new, args, &num_args);
139     return (redisplay);
140 }
141 
142 static Boolean
CallConstraintSetValues(ConstraintWidgetClass class,Widget current,Widget request,Widget new,ArgList args,Cardinal num_args)143 CallConstraintSetValues(ConstraintWidgetClass class,
144                         Widget current,
145                         Widget request,
146                         Widget new,
147                         ArgList args,
148                         Cardinal num_args)
149 {
150     Boolean redisplay = FALSE;
151     XtSetValuesFunc set_values;
152 
153     if ((WidgetClass) class != constraintWidgetClass) {
154         ConstraintWidgetClass superclass;
155 
156         if (class == NULL) {
157             XtAppErrorMsg(XtWidgetToApplicationContext(current),
158                           "invalidClass", "constraintSetValue",
159                           XtCXtToolkitError,
160                           "Subclass of Constraint required in CallConstraintSetValues",
161                           NULL, NULL);
162         }
163         else {
164             LOCK_PROCESS;
165             superclass = (ConstraintWidgetClass) class->core_class.superclass;
166             UNLOCK_PROCESS;
167             redisplay =
168                 CallConstraintSetValues(superclass,
169                                         current, request, new, args, num_args);
170         }
171     }
172     LOCK_PROCESS;
173     set_values = class ? class->constraint_class.set_values : NULL;
174     UNLOCK_PROCESS;
175     if (set_values)
176         redisplay |= (*set_values) (current, request, new, args, &num_args);
177     return (redisplay);
178 }
179 
180 void
XtSetSubvalues(XtPointer base,register XtResourceList resources,register Cardinal num_resources,ArgList args,Cardinal num_args)181 XtSetSubvalues(XtPointer base,                  /* Base address to write values to */
182                register XtResourceList resources,       /* The current resource values.      */
183                register Cardinal num_resources, /* number of items in resources      */
184                ArgList args,                    /* The resource values to set */
185                Cardinal num_args)               /* number of items in arg list       */
186 {
187     register XrmResourceList *xrmres;
188 
189     xrmres = _XtCreateIndirectionTable(resources, num_resources);
190     SetValues((char *) base, xrmres, num_resources, args, num_args);
191     XtFree((char *) xrmres);
192 }
193 
194 void
XtSetValues(register Widget w,ArgList args,Cardinal num_args)195 XtSetValues(register Widget w, ArgList args, Cardinal num_args)
196 {
197     register Widget oldw, reqw;
198 
199     /* need to use strictest alignment rules possible in next two decls. */
200     double oldwCache[100], reqwCache[100];
201     double oldcCache[20], reqcCache[20];
202     Cardinal widgetSize, constraintSize;
203     Boolean redisplay, cleared_rect_obj = False;
204     XtGeometryResult result;
205     XtWidgetGeometry geoReq, geoReply;
206     WidgetClass wc;
207     ConstraintWidgetClass cwc = NULL;
208     Boolean hasConstraints;
209     XtAppContext app = XtWidgetToApplicationContext(w);
210     Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(w));
211 
212     LOCK_APP(app);
213     wc = XtClass(w);
214     if ((args == NULL) && (num_args != 0)) {
215         XtAppErrorMsg(app,
216                       "invalidArgCount", "xtSetValues", XtCXtToolkitError,
217                       "Argument count > 0 on NULL argument list in XtSetValues",
218                       NULL, NULL);
219     }
220 
221     /* Allocate and copy current widget into old widget */
222 
223     LOCK_PROCESS;
224     widgetSize = wc->core_class.widget_size;
225     UNLOCK_PROCESS;
226     oldw = (Widget) XtStackAlloc(widgetSize, oldwCache);
227     reqw = (Widget) XtStackAlloc(widgetSize, reqwCache);
228     (void) memmove((char *) oldw, (char *) w, (size_t) widgetSize);
229 
230     /* Set resource values */
231 
232     LOCK_PROCESS;
233     SetValues((char *) w, (XrmResourceList *) wc->core_class.resources,
234               wc->core_class.num_resources, args, num_args);
235     UNLOCK_PROCESS;
236 
237     (void) memmove((char *) reqw, (char *) w, (size_t) widgetSize);
238 
239     hasConstraints = (XtParent(w) != NULL && !XtIsShell(w) &&
240                       XtIsConstraint(XtParent(w)));
241 
242     /* Some widget sets apparently do ugly things by freeing the
243      * constraints on some children, thus the extra test here */
244     if (hasConstraints) {
245         cwc = (ConstraintWidgetClass) XtClass(w->core.parent);
246         if (w->core.constraints) {
247             LOCK_PROCESS;
248             constraintSize = cwc->constraint_class.constraint_size;
249             UNLOCK_PROCESS;
250         }
251         else
252             constraintSize = 0;
253     }
254     else
255         constraintSize = 0;
256 
257     if (constraintSize) {
258         /* Allocate and copy current constraints into oldw */
259         oldw->core.constraints = XtStackAlloc(constraintSize, oldcCache);
260         reqw->core.constraints = XtStackAlloc(constraintSize, reqcCache);
261         (void) memmove((char *) oldw->core.constraints,
262                        (char *) w->core.constraints, (size_t) constraintSize);
263 
264         /* Set constraint values */
265         LOCK_PROCESS;
266         SetValues((char *) w->core.constraints,
267                   (XrmResourceList *) (cwc->constraint_class.resources),
268                   cwc->constraint_class.num_resources, args, num_args);
269         UNLOCK_PROCESS;
270         (void) memmove((char *) reqw->core.constraints,
271                        (char *) w->core.constraints, (size_t) constraintSize);
272     }
273 
274     /* Inform widget of changes, then inform parent of changes */
275     redisplay = CallSetValues(wc, oldw, reqw, w, args, num_args);
276     if (hasConstraints) {
277         redisplay |=
278             CallConstraintSetValues(cwc, oldw, reqw, w, args, num_args);
279     }
280 
281     if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
282         XtChangeHookDataRec call_data;
283         XtChangeHookSetValuesDataRec set_val;
284 
285         set_val.old = oldw;
286         set_val.req = reqw;
287         set_val.args = args;
288         set_val.num_args = num_args;
289         call_data.type = XtHsetValues;
290         call_data.widget = w;
291         call_data.event_data = (XtPointer) &set_val;
292         XtCallCallbackList(hookobj,
293                            ((HookObject) hookobj)->hooks.changehook_callbacks,
294                            (XtPointer) &call_data);
295     }
296 
297     if (XtIsRectObj(w)) {
298         /* Now perform geometry request if needed */
299         geoReq.request_mode = 0;
300         if (oldw->core.x != w->core.x) {
301             geoReq.x = w->core.x;
302             w->core.x = oldw->core.x;
303             geoReq.request_mode |= CWX;
304         }
305         if (oldw->core.y != w->core.y) {
306             geoReq.y = w->core.y;
307             w->core.y = oldw->core.y;
308             geoReq.request_mode |= CWY;
309         }
310         if (oldw->core.width != w->core.width) {
311             geoReq.width = w->core.width;
312             w->core.width = oldw->core.width;
313             geoReq.request_mode |= CWWidth;
314         }
315         if (oldw->core.height != w->core.height) {
316             geoReq.height = w->core.height;
317             w->core.height = oldw->core.height;
318             geoReq.request_mode |= CWHeight;
319         }
320         if (oldw->core.border_width != w->core.border_width) {
321             geoReq.border_width = w->core.border_width;
322             w->core.border_width = oldw->core.border_width;
323             geoReq.request_mode |= CWBorderWidth;
324         }
325 
326         if (geoReq.request_mode != 0) {
327             /* Pass on any requests for unchanged geometry values */
328             if (geoReq.request_mode !=
329                 (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) {
330                 for (; num_args != 0; num_args--, args++) {
331                     if (!(geoReq.request_mode & CWX) &&
332                         strcmp(XtNx, args->name) == 0) {
333                         geoReq.x = w->core.x;
334                         geoReq.request_mode |= CWX;
335                     }
336                     else if (!(geoReq.request_mode & CWY) &&
337                              strcmp(XtNy, args->name) == 0) {
338                         geoReq.y = w->core.y;
339                         geoReq.request_mode |= CWY;
340                     }
341                     else if (!(geoReq.request_mode & CWWidth) &&
342                              strcmp(XtNwidth, args->name) == 0) {
343                         geoReq.width = w->core.width;
344                         geoReq.request_mode |= CWWidth;
345                     }
346                     else if (!(geoReq.request_mode & CWHeight) &&
347                              strcmp(XtNheight, args->name) == 0) {
348                         geoReq.height = w->core.height;
349                         geoReq.request_mode |= CWHeight;
350                     }
351                     else if (!(geoReq.request_mode & CWBorderWidth) &&
352                              strcmp(XtNborderWidth, args->name) == 0) {
353                         geoReq.border_width = w->core.border_width;
354                         geoReq.request_mode |= CWBorderWidth;
355                     }
356                 }
357             }
358             CALLGEOTAT(_XtGeoTrace(w,
359                                    "\nXtSetValues sees some geometry changes for \"%s\".\n",
360                                    XtName(w)));
361             CALLGEOTAT(_XtGeoTab(1));
362             do {
363                 XtGeometryHookDataRec call_data;
364                 XtAlmostProc set_values_almost;
365 
366                 if (XtHasCallbacks(hookobj, XtNgeometryHook) ==
367                     XtCallbackHasSome) {
368                     call_data.type = XtHpreGeometry;
369                     call_data.widget = w;
370                     call_data.request = &geoReq;
371                     XtCallCallbackList(hookobj,
372                                        ((HookObject) hookobj)->hooks.
373                                        geometryhook_callbacks,
374                                        (XtPointer) &call_data);
375                     call_data.result = result =
376                         _XtMakeGeometryRequest(w, &geoReq, &geoReply,
377                                                &cleared_rect_obj);
378                     call_data.type = XtHpostGeometry;
379                     call_data.reply = &geoReply;
380                     XtCallCallbackList(hookobj,
381                                        ((HookObject) hookobj)->hooks.
382                                        geometryhook_callbacks,
383                                        (XtPointer) &call_data);
384                 }
385                 else {
386                     result = _XtMakeGeometryRequest(w, &geoReq, &geoReply,
387                                                     &cleared_rect_obj);
388                 }
389                 if (result == XtGeometryYes || result == XtGeometryDone)
390                     break;
391 
392                 /* An Almost or No reply.  Call widget and let it munge
393                    request, reply */
394                 LOCK_PROCESS;
395                 set_values_almost = wc->core_class.set_values_almost;
396                 UNLOCK_PROCESS;
397                 if (set_values_almost == NULL) {
398                     XtAppWarningMsg(app,
399                                     "invalidProcedure", "set_values_almost",
400                                     XtCXtToolkitError,
401                                     "set_values_almost procedure shouldn't be NULL",
402                                     NULL, NULL);
403                     break;
404                 }
405                 if (result == XtGeometryNo)
406                     geoReply.request_mode = 0;
407                 CALLGEOTAT(_XtGeoTrace(w, "calling SetValuesAlmost.\n"));
408                 (*set_values_almost) (oldw, w, &geoReq, &geoReply);
409             } while (geoReq.request_mode != 0);
410             /* call resize proc if we changed size and parent
411              * didn't already invoke resize */
412             {
413                 XtWidgetProc resize;
414 
415                 LOCK_PROCESS;
416                 resize = wc->core_class.resize;
417                 UNLOCK_PROCESS;
418                 if ((w->core.width != oldw->core.width ||
419                      w->core.height != oldw->core.height)
420                     && result != XtGeometryDone
421                     && resize != (XtWidgetProc) NULL) {
422                     CALLGEOTAT(_XtGeoTrace(w,
423                                            "XtSetValues calls \"%s\"'s resize proc.\n",
424                                            XtName(w)));
425                     (*resize) (w);
426                 }
427             }
428             CALLGEOTAT(_XtGeoTab(-1));
429         }
430         /* Redisplay if needed.  No point in clearing if the window is
431          * about to disappear, as the Expose event will just go straight
432          * to the bit bucket. */
433         if (XtIsWidget(w)) {
434             /* widgets can distinguish between redisplay and resize, since
435                the server will cause an expose on resize */
436             if (redisplay && XtIsRealized(w) && !w->core.being_destroyed) {
437                 CALLGEOTAT(_XtGeoTrace(w,
438                                        "XtSetValues calls ClearArea on \"%s\".\n",
439                                        XtName(w)));
440                 XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, TRUE);
441             }
442         }
443         else {                  /*non-window object */
444             if (redisplay && !cleared_rect_obj) {
445                 Widget pw = _XtWindowedAncestor(w);
446 
447                 if (XtIsRealized(pw) && !pw->core.being_destroyed) {
448                     RectObj r = (RectObj) w;
449                     int bw2 = r->rectangle.border_width << 1;
450 
451                     CALLGEOTAT(_XtGeoTrace(w,
452                                            "XtSetValues calls ClearArea on \"%s\"'s parent \"%s\".\n",
453                                            XtName(w), XtName(pw)));
454                     XClearArea(XtDisplay(pw), XtWindow(pw),
455                                r->rectangle.x, r->rectangle.y,
456                                (unsigned) (r->rectangle.width + bw2),
457                                (unsigned) (r->rectangle.height + bw2), TRUE);
458                 }
459             }
460         }
461     }
462 
463     /* Free dynamic storage */
464     if (constraintSize) {
465         XtStackFree(oldw->core.constraints, oldcCache);
466         XtStackFree(reqw->core.constraints, reqcCache);
467     }
468     XtStackFree((XtPointer) oldw, oldwCache);
469     XtStackFree((XtPointer) reqw, reqwCache);
470     UNLOCK_APP(app);
471 }                               /* XtSetValues */
472