SetValues.c revision fdf6a26f
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates.
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        if (class == NULL) {
155            XtAppErrorMsg(XtWidgetToApplicationContext(current),
156                          "invalidClass", "constraintSetValue",
157                          XtCXtToolkitError,
158                          "Subclass of Constraint required in CallConstraintSetValues",
159                          NULL, NULL);
160        }
161        else {
162            ConstraintWidgetClass superclass;
163
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    XtWidgetGeometry geoReq, geoReply;
205    WidgetClass wc;
206    ConstraintWidgetClass cwc = NULL;
207    Boolean hasConstraints;
208    XtAppContext app = XtWidgetToApplicationContext(w);
209    Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(w));
210
211    LOCK_APP(app);
212    wc = XtClass(w);
213    if ((args == NULL) && (num_args != 0)) {
214        XtAppErrorMsg(app,
215                      "invalidArgCount", "xtSetValues", XtCXtToolkitError,
216                      "Argument count > 0 on NULL argument list in XtSetValues",
217                      NULL, NULL);
218    }
219
220    /* Allocate and copy current widget into old widget */
221
222    LOCK_PROCESS;
223    widgetSize = wc->core_class.widget_size;
224    UNLOCK_PROCESS;
225    oldw = (Widget) XtStackAlloc(widgetSize, oldwCache);
226    reqw = (Widget) XtStackAlloc(widgetSize, reqwCache);
227    (void) memcpy(oldw, w, (size_t) widgetSize);
228
229    /* Set resource values */
230
231    LOCK_PROCESS;
232    SetValues((char *) w, (XrmResourceList *) wc->core_class.resources,
233              wc->core_class.num_resources, args, num_args);
234    UNLOCK_PROCESS;
235
236    (void) memcpy(reqw, w, (size_t) widgetSize);
237
238    hasConstraints = (XtParent(w) != NULL && !XtIsShell(w) &&
239                      XtIsConstraint(XtParent(w)));
240
241    /* Some widget sets apparently do ugly things by freeing the
242     * constraints on some children, thus the extra test here */
243    if (hasConstraints) {
244        cwc = (ConstraintWidgetClass) XtClass(w->core.parent);
245        if (w->core.constraints) {
246            LOCK_PROCESS;
247            constraintSize = cwc->constraint_class.constraint_size;
248            UNLOCK_PROCESS;
249        }
250        else
251            constraintSize = 0;
252    }
253    else
254        constraintSize = 0;
255
256    if (constraintSize) {
257        /* Allocate and copy current constraints into oldw */
258        oldw->core.constraints = XtStackAlloc(constraintSize, oldcCache);
259        reqw->core.constraints = XtStackAlloc(constraintSize, reqcCache);
260        (void) memcpy(oldw->core.constraints,
261                      w->core.constraints, (size_t) constraintSize);
262
263        /* Set constraint values */
264        LOCK_PROCESS;
265        SetValues((char *) w->core.constraints,
266                  (XrmResourceList *) (cwc->constraint_class.resources),
267                  cwc->constraint_class.num_resources, args, num_args);
268        UNLOCK_PROCESS;
269        (void) memcpy(reqw->core.constraints,
270                      w->core.constraints, (size_t) constraintSize);
271    }
272
273    /* Inform widget of changes, then inform parent of changes */
274    redisplay = CallSetValues(wc, oldw, reqw, w, args, num_args);
275    if (hasConstraints) {
276        redisplay |=
277            CallConstraintSetValues(cwc, oldw, reqw, w, args, num_args);
278    }
279
280    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
281        XtChangeHookDataRec call_data;
282        XtChangeHookSetValuesDataRec set_val;
283
284        set_val.old = oldw;
285        set_val.req = reqw;
286        set_val.args = args;
287        set_val.num_args = num_args;
288        call_data.type = XtHsetValues;
289        call_data.widget = w;
290        call_data.event_data = (XtPointer) &set_val;
291        XtCallCallbackList(hookobj,
292                           ((HookObject) hookobj)->hooks.changehook_callbacks,
293                           (XtPointer) &call_data);
294    }
295
296    if (XtIsRectObj(w)) {
297        /* Now perform geometry request if needed */
298        geoReq.request_mode = 0;
299        if (oldw->core.x != w->core.x) {
300            geoReq.x = w->core.x;
301            w->core.x = oldw->core.x;
302            geoReq.request_mode |= CWX;
303        }
304        if (oldw->core.y != w->core.y) {
305            geoReq.y = w->core.y;
306            w->core.y = oldw->core.y;
307            geoReq.request_mode |= CWY;
308        }
309        if (oldw->core.width != w->core.width) {
310            geoReq.width = w->core.width;
311            w->core.width = oldw->core.width;
312            geoReq.request_mode |= CWWidth;
313        }
314        if (oldw->core.height != w->core.height) {
315            geoReq.height = w->core.height;
316            w->core.height = oldw->core.height;
317            geoReq.request_mode |= CWHeight;
318        }
319        if (oldw->core.border_width != w->core.border_width) {
320            geoReq.border_width = w->core.border_width;
321            w->core.border_width = oldw->core.border_width;
322            geoReq.request_mode |= CWBorderWidth;
323        }
324
325        if (geoReq.request_mode != 0) {
326            XtGeometryResult result;
327
328            /* Pass on any requests for unchanged geometry values */
329            if (geoReq.request_mode !=
330                (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) {
331                for (; num_args != 0; num_args--, args++) {
332                    if (!(geoReq.request_mode & CWX) &&
333                        strcmp(XtNx, args->name) == 0) {
334                        geoReq.x = w->core.x;
335                        geoReq.request_mode |= CWX;
336                    }
337                    else if (!(geoReq.request_mode & CWY) &&
338                             strcmp(XtNy, args->name) == 0) {
339                        geoReq.y = w->core.y;
340                        geoReq.request_mode |= CWY;
341                    }
342                    else if (!(geoReq.request_mode & CWWidth) &&
343                             strcmp(XtNwidth, args->name) == 0) {
344                        geoReq.width = w->core.width;
345                        geoReq.request_mode |= CWWidth;
346                    }
347                    else if (!(geoReq.request_mode & CWHeight) &&
348                             strcmp(XtNheight, args->name) == 0) {
349                        geoReq.height = w->core.height;
350                        geoReq.request_mode |= CWHeight;
351                    }
352                    else if (!(geoReq.request_mode & CWBorderWidth) &&
353                             strcmp(XtNborderWidth, args->name) == 0) {
354                        geoReq.border_width = w->core.border_width;
355                        geoReq.request_mode |= CWBorderWidth;
356                    }
357                }
358            }
359            CALLGEOTAT(_XtGeoTrace(w,
360                                   "\nXtSetValues sees some geometry changes for \"%s\".\n",
361                                   XtName(w)));
362            CALLGEOTAT(_XtGeoTab(1));
363            do {
364                XtGeometryHookDataRec call_data;
365                XtAlmostProc set_values_almost;
366
367                if (XtHasCallbacks(hookobj, XtNgeometryHook) ==
368                    XtCallbackHasSome) {
369                    call_data.type = XtHpreGeometry;
370                    call_data.widget = w;
371                    call_data.request = &geoReq;
372                    XtCallCallbackList(hookobj,
373                                       ((HookObject) hookobj)->hooks.
374                                       geometryhook_callbacks,
375                                       (XtPointer) &call_data);
376                    call_data.result = result =
377                        _XtMakeGeometryRequest(w, &geoReq, &geoReply,
378                                               &cleared_rect_obj);
379                    call_data.type = XtHpostGeometry;
380                    call_data.reply = &geoReply;
381                    XtCallCallbackList(hookobj,
382                                       ((HookObject) hookobj)->hooks.
383                                       geometryhook_callbacks,
384                                       (XtPointer) &call_data);
385                }
386                else {
387                    result = _XtMakeGeometryRequest(w, &geoReq, &geoReply,
388                                                    &cleared_rect_obj);
389                }
390                if (result == XtGeometryYes || result == XtGeometryDone)
391                    break;
392
393                /* An Almost or No reply.  Call widget and let it munge
394                   request, reply */
395                LOCK_PROCESS;
396                set_values_almost = wc->core_class.set_values_almost;
397                UNLOCK_PROCESS;
398                if (set_values_almost == NULL) {
399                    XtAppWarningMsg(app,
400                                    "invalidProcedure", "set_values_almost",
401                                    XtCXtToolkitError,
402                                    "set_values_almost procedure shouldn't be NULL",
403                                    NULL, NULL);
404                    break;
405                }
406                if (result == XtGeometryNo)
407                    geoReply.request_mode = 0;
408                CALLGEOTAT(_XtGeoTrace(w, "calling SetValuesAlmost.\n"));
409                (*set_values_almost) (oldw, w, &geoReq, &geoReply);
410            } while (geoReq.request_mode != 0);
411            /* call resize proc if we changed size and parent
412             * didn't already invoke resize */
413            {
414                XtWidgetProc resize;
415
416                LOCK_PROCESS;
417                resize = wc->core_class.resize;
418                UNLOCK_PROCESS;
419                if ((w->core.width != oldw->core.width ||
420                     w->core.height != oldw->core.height)
421                    && result != XtGeometryDone
422                    && resize != (XtWidgetProc) NULL) {
423                    CALLGEOTAT(_XtGeoTrace(w,
424                                           "XtSetValues calls \"%s\"'s resize proc.\n",
425                                           XtName(w)));
426                    (*resize) (w);
427                }
428            }
429            CALLGEOTAT(_XtGeoTab(-1));
430        }
431        /* Redisplay if needed.  No point in clearing if the window is
432         * about to disappear, as the Expose event will just go straight
433         * to the bit bucket. */
434        if (XtIsWidget(w)) {
435            /* widgets can distinguish between redisplay and resize, since
436               the server will cause an expose on resize */
437            if (redisplay && XtIsRealized(w) && !w->core.being_destroyed) {
438                CALLGEOTAT(_XtGeoTrace(w,
439                                       "XtSetValues calls ClearArea on \"%s\".\n",
440                                       XtName(w)));
441                XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, TRUE);
442            }
443        }
444        else {                  /*non-window object */
445            if (redisplay && !cleared_rect_obj) {
446                Widget pw = _XtWindowedAncestor(w);
447
448                if (XtIsRealized(pw) && !pw->core.being_destroyed) {
449                    RectObj r = (RectObj) w;
450                    int bw2 = r->rectangle.border_width << 1;
451
452                    CALLGEOTAT(_XtGeoTrace(w,
453                                           "XtSetValues calls ClearArea on \"%s\"'s parent \"%s\".\n",
454                                           XtName(w), XtName(pw)));
455                    XClearArea(XtDisplay(pw), XtWindow(pw),
456                               r->rectangle.x, r->rectangle.y,
457                               (unsigned) (r->rectangle.width + bw2),
458                               (unsigned) (r->rectangle.height + bw2), TRUE);
459                }
460            }
461        }
462    }
463
464    /* Free dynamic storage */
465    if (constraintSize) {
466        XtStackFree(oldw->core.constraints, oldcCache);
467        XtStackFree(reqw->core.constraints, reqcCache);
468    }
469    XtStackFree((XtPointer) oldw, oldwCache);
470    XtStackFree((XtPointer) reqw, reqwCache);
471    UNLOCK_APP(app);
472}                               /* XtSetValues */
473