SetValues.c revision a3bd7f05
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
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
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1994, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in 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
80static void
81SetValues(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
108static Boolean
109CallSetValues(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
142static Boolean
143CallConstraintSetValues(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
180void
181XtSetSubvalues(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
194void
195XtSetValues(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