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