SetValues.c revision 249c3046
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
80
81static void SetValues(
82  char*			base,		/* Base address to write values to   */
83  XrmResourceList*	res,		/* The current resource values.      */
84  register Cardinal	num_resources,	/* number of items in resources      */
85  ArgList 		args,		/* The resource values to set        */
86  Cardinal		num_args)	/* number of items in arg list       */
87{
88    register ArgList		arg;
89    register Cardinal 	        i;
90    register XrmName		argName;
91    register XrmResourceList*   xrmres;
92
93    /* Resource lists are assumed to be in compiled form already via the
94       initial XtGetResources, XtGetSubresources calls */
95
96    for (arg = args ; num_args != 0; num_args--, arg++) {
97	argName = StringToName(arg->name);
98	for (xrmres = res, i = 0; i < num_resources; i++, xrmres++) {
99	    if (argName == (*xrmres)->xrm_name) {
100		_XtCopyFromArg(arg->value,
101		    base - (*xrmres)->xrm_offset - 1,
102		    (*xrmres)->xrm_size);
103		break;
104	    }
105	}
106    }
107} /* SetValues */
108
109static Boolean CallSetValues (
110    WidgetClass class,
111    Widget      current,
112    Widget      request,
113    Widget      new,
114    ArgList     args,
115    Cardinal    num_args)
116{
117    Boolean redisplay = FALSE;
118    WidgetClass superclass;
119    XtArgsFunc set_values_hook;
120    XtSetValuesFunc set_values;
121
122    LOCK_PROCESS;
123    superclass = class->core_class.superclass;
124    UNLOCK_PROCESS;
125    if (superclass)
126        redisplay =
127	    CallSetValues(superclass, current, request, new, args, num_args);
128
129    LOCK_PROCESS;
130    set_values = class->core_class.set_values;
131    UNLOCK_PROCESS;
132    if (set_values)
133        redisplay |= (*set_values) (current, request, new, args, &num_args);
134
135    LOCK_PROCESS;
136    set_values_hook = class->core_class.set_values_hook;
137    UNLOCK_PROCESS;
138    if (set_values_hook)
139	redisplay |= (*set_values_hook) (new, args, &num_args);
140    return (redisplay);
141}
142
143static Boolean
144CallConstraintSetValues (
145    ConstraintWidgetClass class,
146    Widget      current,
147    Widget      request,
148    Widget      new,
149    ArgList     args,
150    Cardinal    num_args)
151{
152    Boolean redisplay = FALSE;
153    XtSetValuesFunc set_values;
154    ConstraintWidgetClass superclass;
155
156    if ((WidgetClass)class != constraintWidgetClass) {
157	if (class == NULL)
158	    XtAppErrorMsg(XtWidgetToApplicationContext(current),
159		    "invalidClass","constraintSetValue",XtCXtToolkitError,
160                 "Subclass of Constraint required in CallConstraintSetValues",
161                  (String *)NULL, (Cardinal *)NULL);
162	LOCK_PROCESS;
163	superclass = (ConstraintWidgetClass) class->core_class.superclass;
164	UNLOCK_PROCESS;
165	redisplay =
166	   CallConstraintSetValues(superclass,
167				   current, request, new, args, num_args);
168    }
169    LOCK_PROCESS;
170    set_values = class->constraint_class.set_values;
171    UNLOCK_PROCESS;
172    if (set_values)
173        redisplay |= (*set_values) (current, request, new, args, &num_args);
174    return (redisplay);
175}
176
177void XtSetSubvalues(
178  XtPointer             base,           /* Base address to write values to   */
179  register XtResourceList resources,    /* The current resource values.      */
180  register Cardinal     num_resources,  /* number of items in resources      */
181  ArgList               args,           /* The resource values to set        */
182  Cardinal              num_args)       /* number of items in arg list       */
183{
184      register XrmResourceList*   xrmres;
185      xrmres = _XtCreateIndirectionTable (resources, num_resources);
186      SetValues((char*)base,xrmres,num_resources, args, num_args);
187      XtFree((char *)xrmres);
188}
189
190
191void XtSetValues(
192    register Widget   w,
193	     ArgList  args,
194	     Cardinal num_args)
195{
196    register Widget oldw, reqw;
197    /* need to use strictest alignment rules possible in next two decls. */
198    double	    oldwCache[100], reqwCache[100];
199    double	    oldcCache[20], reqcCache[20];
200    Cardinal	    widgetSize, constraintSize;
201    Boolean	    redisplay, cleared_rect_obj = False;
202    XtGeometryResult result;
203    XtWidgetGeometry geoReq, geoReply;
204    WidgetClass     wc;
205    ConstraintWidgetClass cwc = NULL;
206    Boolean	    hasConstraints;
207    XtAlmostProc set_values_almost;
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                 (String *)NULL, (Cardinal *)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) memmove((char *) oldw, (char *) w, (int) 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) memmove ((char *) reqw, (char *) w, (int) widgetSize);
237
238    hasConstraints = (XtParent(w) != NULL && !XtIsShell(w) && XtIsConstraint(XtParent(w)));
239
240    /* Some widget sets apparently do ugly things by freeing the
241     * constraints on some children, thus the extra test here */
242    if (hasConstraints) {
243	cwc = (ConstraintWidgetClass) XtClass(w->core.parent);
244	if (w->core.constraints) {
245	    LOCK_PROCESS;
246	    constraintSize = cwc->constraint_class.constraint_size;
247	    UNLOCK_PROCESS;
248	} else constraintSize = 0;
249    } else constraintSize = 0;
250
251    if (constraintSize) {
252	/* Allocate and copy current constraints into oldw */
253	oldw->core.constraints = XtStackAlloc(constraintSize, oldcCache);
254	reqw->core.constraints = XtStackAlloc(constraintSize, reqcCache);
255	(void) memmove((char *) oldw->core.constraints,
256		       (char *) w->core.constraints, (int) constraintSize);
257
258	/* Set constraint values */
259	LOCK_PROCESS;
260	SetValues((char*)w->core.constraints,
261	    (XrmResourceList *)(cwc->constraint_class.resources),
262	    cwc->constraint_class.num_resources, args, num_args);
263	UNLOCK_PROCESS;
264	(void) memmove((char *) reqw->core.constraints,
265		       (char *) w->core.constraints, (int) constraintSize);
266    }
267
268    /* Inform widget of changes, then inform parent of changes */
269    redisplay = CallSetValues (wc, oldw, reqw, w, args, num_args);
270    if (hasConstraints) {
271	redisplay |= CallConstraintSetValues(cwc, oldw, reqw, w, args, num_args);
272    }
273
274    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
275	XtChangeHookDataRec call_data;
276	XtChangeHookSetValuesDataRec set_val;
277
278	set_val.old = oldw;
279	set_val.req = reqw;
280	set_val.args = args;
281	set_val.num_args = num_args;
282	call_data.type = XtHsetValues;
283	call_data.widget = w;
284	call_data.event_data = (XtPointer) &set_val;
285	XtCallCallbackList(hookobj,
286		((HookObject)hookobj)->hooks.changehook_callbacks,
287		(XtPointer)&call_data);
288    }
289
290    if (XtIsRectObj(w)) {
291	/* Now perform geometry request if needed */
292	geoReq.request_mode = 0;
293	if (oldw->core.x	!= w->core.x) {
294	    geoReq.x		= w->core.x;
295	    w->core.x		= oldw->core.x;
296	    geoReq.request_mode |= CWX;
297	}
298	if (oldw->core.y	!= w->core.y) {
299	    geoReq.y		= w->core.y;
300	    w->core.y		= oldw->core.y;
301	    geoReq.request_mode |= CWY;
302	}
303	if (oldw->core.width	!= w->core.width) {
304	    geoReq.width	= w->core.width;
305	    w->core.width	= oldw->core.width;
306	    geoReq.request_mode |= CWWidth;
307	}
308	if (oldw->core.height	!= w->core.height) {
309	    geoReq.height	= w->core.height;
310	    w->core.height	= oldw->core.height;
311	    geoReq.request_mode |= CWHeight;
312	}
313	if (oldw->core.border_width != w->core.border_width) {
314	    geoReq.border_width	    = w->core.border_width;
315	    w->core.border_width    = oldw->core.border_width;
316	    geoReq.request_mode	    |= CWBorderWidth;
317	}
318
319	if (geoReq.request_mode != 0) {
320	    /* Pass on any requests for unchanged geometry values */
321	    if (geoReq.request_mode !=
322		(CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) {
323		for ( ; num_args != 0; num_args--, args++) {
324		    if (! (geoReq.request_mode & CWX) &&
325			strcmp(XtNx, args->name) == 0) {
326			geoReq.x = w->core.x;
327			geoReq.request_mode |= CWX;
328		    } else if (! (geoReq.request_mode & CWY) &&
329			       strcmp(XtNy, args->name) == 0) {
330			geoReq.y = w->core.y;
331			geoReq.request_mode |= CWY;
332		    } else if (! (geoReq.request_mode & CWWidth) &&
333			       strcmp(XtNwidth, args->name) == 0) {
334			geoReq.width = w->core.width;
335			geoReq.request_mode |= CWWidth;
336		    } else if (! (geoReq.request_mode & CWHeight) &&
337			       strcmp(XtNheight, args->name) == 0) {
338			geoReq.height = w->core.height;
339			geoReq.request_mode |= CWHeight;
340		    } else if (! (geoReq.request_mode & CWBorderWidth) &&
341			       strcmp(XtNborderWidth, args->name) == 0) {
342			geoReq.border_width = w->core.border_width;
343			geoReq.request_mode |= CWBorderWidth;
344		    }
345		}
346	    }
347	    CALLGEOTAT(_XtGeoTrace(w,
348		     "\nXtSetValues sees some geometry changes for \"%s\".\n",
349			   XtName(w)));
350	    CALLGEOTAT(_XtGeoTab(1));
351	    do {
352		XtGeometryHookDataRec call_data;
353
354		if (XtHasCallbacks(hookobj, XtNgeometryHook) == XtCallbackHasSome) {
355		    call_data.type = XtHpreGeometry;
356		    call_data.widget = w;
357		    call_data.request = &geoReq;
358		    XtCallCallbackList(hookobj,
359			((HookObject)hookobj)->hooks.geometryhook_callbacks,
360			(XtPointer)&call_data);
361		    call_data.result = result =
362			_XtMakeGeometryRequest(w, &geoReq, &geoReply,
363					       &cleared_rect_obj);
364		    call_data.type = XtHpostGeometry;
365		    call_data.reply = &geoReply;
366		    XtCallCallbackList(hookobj,
367			((HookObject)hookobj)->hooks.geometryhook_callbacks,
368			(XtPointer)&call_data);
369		} else {
370		    result = _XtMakeGeometryRequest(w, &geoReq, &geoReply,
371						    &cleared_rect_obj);
372		}
373		if (result == XtGeometryYes || result == XtGeometryDone)
374		    break;
375
376		/* An Almost or No reply.  Call widget and let it munge
377		   request, reply */
378		LOCK_PROCESS;
379		set_values_almost = wc->core_class.set_values_almost;
380		UNLOCK_PROCESS;
381		if (set_values_almost == NULL) {
382		    XtAppWarningMsg(app,
383			    "invalidProcedure","set_values_almost",
384			  XtCXtToolkitError,
385			  "set_values_almost procedure shouldn't be NULL",
386			  (String *)NULL, (Cardinal *)NULL);
387		    break;
388		}
389		if (result == XtGeometryNo) geoReply.request_mode = 0;
390		CALLGEOTAT(_XtGeoTrace(w,"calling SetValuesAlmost.\n"));
391		(*set_values_almost) (oldw, w, &geoReq, &geoReply);
392	    } while (geoReq.request_mode != 0);
393	    /* call resize proc if we changed size and parent
394	     * didn't already invoke resize */
395	    {
396	    XtWidgetProc resize;
397	    LOCK_PROCESS;
398	    resize = wc->core_class.resize;
399	    UNLOCK_PROCESS;
400	    if ((w->core.width != oldw->core.width ||
401		 w->core.height != oldw->core.height)
402		&& result != XtGeometryDone
403		&& resize != (XtWidgetProc) NULL) {
404		CALLGEOTAT(_XtGeoTrace(w,
405				 "XtSetValues calls \"%s\"'s resize proc.\n",
406			       XtName(w)));
407		(*resize)(w);
408	      }
409	    }
410	    CALLGEOTAT(_XtGeoTab(-1));
411	}
412	/* Redisplay if needed.  No point in clearing if the window is
413	 * about to disappear, as the Expose event will just go straight
414	 * to the bit bucket. */
415        if (XtIsWidget(w)) {
416            /* widgets can distinguish between redisplay and resize, since
417             the server will cause an expose on resize */
418            if (redisplay && XtIsRealized(w) && !w->core.being_destroyed) {
419                CALLGEOTAT(_XtGeoTrace(w,
420				 "XtSetValues calls ClearArea on \"%s\".\n",
421			       XtName(w)));
422		XClearArea (XtDisplay(w), XtWindow(w), 0, 0, 0, 0, TRUE);
423	    }
424        } else { /*non-window object */
425	  if (redisplay && ! cleared_rect_obj ) {
426	      Widget pw = _XtWindowedAncestor(w);
427	      if (XtIsRealized(pw) && !pw->core.being_destroyed) {
428		  RectObj r = (RectObj)w;
429		  int bw2 = r->rectangle.border_width << 1;
430		  CALLGEOTAT(_XtGeoTrace(w,
431		   "XtSetValues calls ClearArea on \"%s\"'s parent \"%s\".\n",
432				 XtName(w),XtName(pw)));
433		  XClearArea (XtDisplay (pw), XtWindow (pw),
434			      r->rectangle.x, r->rectangle.y,
435			      r->rectangle.width + bw2,
436			      r->rectangle.height + bw2,TRUE);
437	      }
438	  }
439        }
440    }
441
442
443    /* Free dynamic storage */
444    if (constraintSize) {
445        XtStackFree(oldw->core.constraints, oldcCache);
446        XtStackFree(reqw->core.constraints, reqcCache);
447    }
448    XtStackFree((XtPointer)oldw, oldwCache);
449    XtStackFree((XtPointer)reqw, reqwCache);
450    UNLOCK_APP(app);
451} /* XtSetValues */
452