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