utils.c revision 33c89af1
1/*
2 * $Xorg: utils.c,v 1.4 2001/02/09 02:05:30 xorgcvs Exp $
3 *
4Copyright 1989, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
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 THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25 */
26/* $XFree86: xc/programs/editres/utils.c,v 1.5 2001/04/01 14:00:17 tsi Exp $ */
27
28#include <X11/Intrinsic.h>
29#include <X11/Xutil.h>
30#include <X11/Xos.h>
31#include <X11/Shell.h>
32#include <X11/StringDefs.h>
33
34#include <X11/Xaw/Cardinals.h>
35#include <X11/Xaw/Dialog.h>
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <X11/Xmu/Error.h>
40
41#include "editresP.h"
42
43static WNode * FindWidgetFromWindowGivenNode ( WNode * node, Window win );
44static WidgetResources * ParseResources ( GetResourcesInfo * info,
45					  char **error );
46static int CompareResourceEntries ( const void *e1,
47				    const void *e2 );
48static void AddResource ( ResourceInfo * res_info,
49			  WidgetResourceInfo * resource );
50static void FreeResources ( WidgetResources * resources );
51
52
53/*	Function Name: SetMessage(w, str)
54 *	Description: shows the message to the user.
55 *	Arguments: w - a label widget to show the message in.
56 *                 str - the string to show.
57 *	Returns: none.
58 */
59
60void
61SetMessage(w, str)
62Widget w;
63char * str;
64{
65    Arg args[1];
66
67    XtSetArg(args[0], XtNlabel, str);
68    XtSetValues(w, args, ONE);
69}
70
71/*	Function Name: GetAllStrings
72 *	Description: Returns a list of strings that have been borken up by
73 *                   the character specified.
74 *	Arguments: in - the string to parse.
75 *                 sep - the separator character.
76 *                 out - the strings to send out.
77 *                 num - the number of strings in out.
78 *	Returns: none
79 */
80
81void
82GetAllStrings(char *in, char sep, char ***out, int *num)
83{
84    int size, i;
85    char * ptr;
86
87    if (*in == sep)		/* jump over first char if it is the sep. */
88	in++;
89
90    /*
91     * count the number of strings.
92     */
93
94    for (*num = 1, ptr = in; (ptr = strchr(ptr, sep)) != NULL; (*num)++)
95	ptr++;
96
97/*
98 * Create Enough space for pointers and string.
99 */
100
101    size = (sizeof(char *) * *num) + (sizeof(char) * (strlen(in) + 1));
102    *out = (char **) XtMalloc( (Cardinal) size);
103
104    ptr = (char *) (*out + *num);
105    strcpy(ptr, in);
106
107/*
108 * Change all `sep' characters to '\0' and stuff the pointer into
109 * the next pointer slot.
110 */
111
112    i = 1;
113    (*out)[0] = ptr;
114    while (TRUE) {
115	if ((ptr = strchr(ptr, sep)) == NULL)
116	    break;
117
118	*ptr++ = '\0';
119	(*out)[i++] = ptr;
120    }
121
122/*
123 * If last string is empty then strip it off.
124 */
125
126    if ( *((*out)[i - 1]) == '\0' )
127	(*num)--;
128}
129
130/*	Function Name: AddString
131 *	Description: Mallocs and strcats the string onto the end of
132 *                   the given string.
133 *	Arguments: str - string to add on to.
134 *                 add - string to add.
135 *	Returns: none.
136 */
137
138void
139AddString(str, add)
140char ** str, *add;
141{
142    int len_str, len_add;
143    char * ptr;
144
145    len_str = ((*str) ? strlen(*str) : 0);
146    len_add = strlen(add);
147
148    *str = XtRealloc(*str, sizeof(char) * (len_str + len_add + 1));
149    ptr = *str + len_str;
150    strcpy(ptr, add);
151}
152
153/*	Function Name: FindNode
154 *	Description: Finds a node give the top node, and a node id number.
155 *	Arguments: top_node - the top node.
156 *                 id - the node id.
157 *	Returns: node.
158 */
159
160WNode *
161FindNode(top_node, ids, number)
162WNode *top_node;
163unsigned long * ids;
164Cardinal number;
165{
166    int i, j;
167    WNode *node;
168
169    if (top_node == NULL)
170	return(NULL);
171
172    if (ids[0] != top_node->id)
173	return(NULL);
174
175    for (node = top_node, i = 1 ; i < number; i++) {
176	Boolean found_it = FALSE;
177
178	for (j = 0; j < node->num_children; j++) {
179	    if (node->children[j]->id == ids[i]) {
180		node = node->children[j];
181		found_it = TRUE;
182		break;
183	    }
184	}
185	if (!found_it)
186	    return(NULL);
187    }
188    return(node);
189}
190
191/*	Function Name: FindWidgetFromWindow
192 *	Description: finds a widget in the current tree given its window id.
193 *	Arguments: tree_info - information about this tree.
194 *                 win - window to search for.
195 *	Returns: node - the node corrosponding to this widget.
196 */
197
198WNode *
199FindWidgetFromWindow(tree_info, win)
200TreeInfo * tree_info;
201Window win;
202{
203    if (tree_info == NULL)
204	return(NULL);
205
206    return(FindWidgetFromWindowGivenNode(tree_info->top_node, win));
207}
208
209/*	Function Name: FindWidgetFromWindowGivenNode
210 *	Description: finds a widget in the current tree given its window id.
211 *	Arguments: node - current node.
212 *                 win - window to search for.
213 *	Returns: node - the node corrosponding to this widget.
214 */
215
216static WNode *
217FindWidgetFromWindowGivenNode(node, win)
218WNode * node;
219Window win;
220{
221    int i;
222    WNode * ret_node;
223
224    if (node->window == win)
225	return(node);
226
227    for (i = 0; i < node->num_children; i++) {
228	ret_node = FindWidgetFromWindowGivenNode(node->children[i], win);
229	if (ret_node != NULL)
230	    return(ret_node);
231    }
232    return(NULL);
233}
234
235/*	Function Name: HandleXErrors
236 *	Description: Handles error codes from the server.
237 *	Arguments: display - the display.
238 *                 error - error information.
239 *	Returns: none.
240 */
241
242/* ARGSUSED */
243int
244HandleXErrors(display, error)
245Display * display;
246XErrorEvent * error;
247{
248    if (error->serial != global_serial_num) {
249	(*global_old_error_handler) (display, error);
250	return(0);
251    }
252
253    if (error->error_code == BadWindow)
254	global_error_code = NO_WINDOW;
255    else {
256	if (XmuPrintDefaultErrorMessage(display, error, stderr) != 0)
257	    exit(1);
258    }
259    return(0);
260}
261
262/*	Function Name: _DumpTreeToFile
263 *	Description: Dumps the widget tree to a file
264 *	Arguments: w - a random widget in the application on the
265 *                     currently active display
266 *                 tree_ptr - pointer to the widget tree info.
267 *                 filename - name of the file.
268 *	Returns: none.
269 */
270
271/* ARGSUSED */
272
273void
274_DumpTreeToFile(w, tree_ptr, filename)
275Widget w;
276XtPointer tree_ptr;
277XtPointer filename;
278{
279    TreeInfo * tree_info = (TreeInfo *) tree_ptr;
280    FILE * fp;
281
282    if (tree_info == NULL) {
283	SetMessage(global_screen_data.info_label,
284		   res_labels[17]);
285	return;
286    }
287
288    if ( (fp = fopen((char *)filename, "w")) == NULL ) {
289	char buf[BUFSIZ];
290
291	sprintf(buf, res_labels[24], (char *)filename);
292	SetMessage(global_screen_data.info_label, buf);
293	return;
294    }
295
296    PerformTreeToFileDump(tree_info->top_node, 0, fp);
297    fclose(fp);
298}
299
300/************************************************************
301 *
302 * The file dialog boxes are handled with this code.
303 *
304 * It automatically calls the function specified when the
305 * user selects okay, or hits <CR>.
306 *
307 * A translation is required in the app-defaults file.
308 *
309 ************************************************************/
310
311/*	Function Name: _PopupFileDialog
312 *	Description: Puts up a dialog box to get the filename.
313 *	Arguments: str - message.
314 *                 default_value - the default value of the filename;
315 *                 func - function to call when filename has been entered.
316 *                 data - generic data to pass to func.
317 *	Returns: none
318 */
319
320static XContext file_dialog_context = None;
321
322typedef struct _FileDialogInfo {
323    XtCallbackProc func;
324    XtPointer data;
325} FileDialogInfo;
326
327void
328_PopupFileDialog(w, str, default_value, func, data)
329Widget w;
330String str, default_value;
331XtCallbackProc func;
332XtPointer data;
333{
334    FileDialogInfo * file_info;
335    Widget shell, dialog;
336    Arg args[2];
337    Cardinal num_args;
338
339    if (file_dialog_context == None)
340	file_dialog_context = XUniqueContext();
341
342    shell = XtCreatePopupShell("fileDialog", transientShellWidgetClass, w,
343			       NULL, ZERO);
344
345    num_args = 0;
346    XtSetArg(args[num_args], XtNlabel, str); num_args++;
347    XtSetArg(args[num_args], XtNvalue, default_value); num_args++;
348    dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
349				   shell, args, num_args);
350
351    file_info = XtNew(FileDialogInfo);
352
353    file_info->func = func;
354    file_info->data = data;
355
356    if  (XSaveContext(XtDisplay(dialog), (Window) dialog, file_dialog_context,
357		      (XPointer) file_info) != 0) {
358	SetMessage(global_screen_data.info_label,
359	    "Error while trying to save Context\nAborting file dialog popup.");
360	XtDestroyWidget(shell);
361	return;
362    }
363
364    XawDialogAddButton(dialog, "okay", _PopdownFileDialog, (XtPointer) TRUE);
365    XawDialogAddButton(dialog, "cancel", _PopdownFileDialog,(XtPointer) FALSE);
366
367    PopupCentered(NULL, shell, XtGrabNone);
368}
369
370/*	Function Name: PopupCentered
371 *	Description: Pops up the window specified under the location passed
372 *                   in the event, or under the cursor.
373 *	Arguments: event - the event that we should use.
374 *                 w - widget to popup.
375 *                 mode - mode to pop it up in.
376 *	Returns: none
377 */
378
379void
380PopupCentered(event, w, mode)
381XEvent * event;
382Widget w;
383XtGrabKind mode;
384{
385    Boolean get_from_cursor = FALSE;
386    Arg args[3];
387    Cardinal num_args;
388    Dimension width, height, b_width;
389    int x, y, max_x, max_y;
390
391    XtRealizeWidget(w);
392
393    if (event == NULL)
394	get_from_cursor = TRUE;
395    else {
396	switch (event->type) {
397	case ButtonPress:
398	case ButtonRelease:
399	    x = event->xbutton.x_root;
400	    y = event->xbutton.y_root;
401	    break;
402	case KeyPress:
403	case KeyRelease:
404	    x = event->xkey.x_root;
405	    y = event->xkey.y_root;
406	    break;
407	default:
408	    get_from_cursor = TRUE;
409	    break;
410	}
411    }
412
413    if (get_from_cursor) {
414	Window root, child;
415	int win_x, win_y;
416	unsigned int mask;
417
418	XQueryPointer(XtDisplay(w), XtWindow(w),
419		      &root, &child, &x, &y, &win_x, &win_y, &mask);
420    }
421
422    num_args = 0;
423    XtSetArg(args[num_args], XtNwidth, &width); num_args++;
424    XtSetArg(args[num_args], XtNheight, &height); num_args++;
425    XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
426    XtGetValues(w, args, num_args);
427
428    width += 2 * b_width;
429    height += 2 * b_width;
430
431    x -= ((int) width/2);
432    if (x < 0)
433	x = 0;
434    if ( x > (max_x = (int) (XtScreen(w)->width - width)) )
435	x = max_x;
436
437    y -= ( (Position) height/2 );
438    if (y < 0)
439	y = 0;
440    if ( y > (max_y = (int) (XtScreen(w)->height - height)) )
441	y = max_y;
442
443    num_args = 0;
444    XtSetArg(args[num_args], XtNx, x); num_args++;
445    XtSetArg(args[num_args], XtNy, y); num_args++;
446    XtSetValues(w, args, num_args);
447
448    XtPopup(w, mode);
449}
450
451/*	Function Name: _PopdownFileDialog
452 *	Description: Destroys the file dialog, and calls the correct function.
453 *	Arguments:  w - a child of the dialog widget.
454 *                  client_data - TRUE if command was sucessful.
455 *                  junk - ** UNUSED **.
456 *	Returns: none.
457 */
458
459/* ARGSUSED */
460
461void
462_PopdownFileDialog(w, client_data, junk)
463Widget w;
464XtPointer client_data, junk;
465{
466    Widget dialog = XtParent(w);
467    XPointer file_info_ptr;
468    FileDialogInfo * file_info;
469
470    if (XFindContext(XtDisplay(dialog), (Window) dialog, file_dialog_context,
471		     &file_info_ptr) == XCNOENT) {
472	SetMessage(global_screen_data.info_label,
473		   "Error while trying to find Context\nAborting...");
474    }
475
476    (void) XDeleteContext(XtDisplay(dialog), (Window)dialog,
477			  file_dialog_context);
478
479    file_info = (FileDialogInfo *) file_info_ptr;
480
481    if ( ((Boolean)(long) client_data) == TRUE ) {
482	String filename = XawDialogGetValueString(dialog);
483
484	(*file_info->func)(w, file_info->data, filename); /* call handler */
485    }
486
487    XtFree( (XtPointer) file_info); /* Free data. */
488
489    XtPopdown(XtParent(dialog));
490    XtDestroyWidget(XtParent(dialog)); /* Remove file dialog. */
491}
492
493/************************************************************
494 *
495 * Functions for dealing with the Resource Box.
496 *
497 ************************************************************/
498
499/*    Function Name: GetNamesAndClasses
500 *    Description: Gets a list of names and classes for this widget.
501 *    Arguments: node - this widget's node.
502 *                 names, classes - list of names and classes. ** RETURNED **
503 *    Returns: none.
504 */
505
506void
507GetNamesAndClasses(node, names, classes)
508WNode * node;
509char *** names, ***classes;
510{
511    int i, total_widgets;
512    WNode * temp = node;
513
514    for (total_widgets = 1 ; temp->parent != NULL ;
515       total_widgets++, temp = temp->parent) {}
516
517    *names = (char **) XtMalloc(sizeof(char *) * (total_widgets + 1));
518    *classes = (char **) XtMalloc(sizeof(char *) * (total_widgets + 1));
519
520    (*names)[total_widgets] = (*classes)[total_widgets] = NULL;
521
522    for ( i = (total_widgets - 1); i >= 0 ; node = node->parent, i--) {
523      (*names)[i] = node->name;
524      (*classes)[i] = node->class;
525    }
526}
527
528/*	Function Name: HandleGetResources
529 *	Description: Gets the resources.
530 *	Arguments: event - the information from the client.
531 *	Returns: an error message to display.
532 */
533
534char *
535HandleGetResources(event)
536Event * event;
537{
538    GetResourcesEvent * get_event = (GetResourcesEvent *) event;
539    char buf[BUFSIZ], * errors = NULL;
540    int i;
541    WNode * node;
542
543    for (i = 0; i < (int)get_event->num_entries; i++) {
544	node = FindNode(global_tree_info->top_node,
545			get_event->info[i].widgets.ids,
546			get_event->info[i].widgets.num_widgets);
547
548	if (node == NULL) {
549	    sprintf(buf, res_labels[16]);
550	    AddString(&errors, buf);
551	    continue;
552	}
553
554	if (node->resources != NULL)
555	    FreeResources(node->resources);
556
557	if (!get_event->info[i].error) {
558	    node->resources = ParseResources(get_event->info + i, &errors);
559	    CreateResourceBox(node, &errors);
560	}
561	else {
562	    AddString(&errors, get_event->info[i].message);
563	    AddString(&errors, "\n");
564	}
565    }
566
567    return(errors);
568}
569
570/*	Function Name: CreateResourceBox
571 *	Description: Creates a resource box for the widget specified.
572 *	Arguments: node - the node of the widget in question.
573 *                 errors - an error string.
574 *	Returns: none.
575 */
576
577void
578CreateResourceBox(node, errors)
579WNode * node;
580char ** errors;
581{
582    WidgetResources * resources = node->resources;
583    char ** names, ** cons_names;
584    int i;
585
586    if (global_resource_box_up) {
587	AddString(errors, res_labels[34]);
588	return;
589    }
590    else
591	global_resource_box_up = TRUE;
592
593    if (resources->num_normal > 0) {
594	names = (char **) XtMalloc(sizeof(char *) *
595				   (resources->num_normal + 1));
596	for (i = 0 ; i < resources->num_normal ; i++)
597	    names[i] = resources->normal[i].name;
598	names[i] = NULL;
599    }
600    else
601	names = NULL;
602
603    if (resources->num_constraint > 0) {
604	cons_names = (char **) XtMalloc(sizeof(char *) *
605					(resources->num_constraint + 1));
606
607	for (i = 0 ; i < resources->num_constraint ; i++)
608	    cons_names[i] = resources->constraint[i].name;
609	cons_names[i] = NULL;
610    }
611    else
612	cons_names = NULL;
613
614    CreateResourceBoxWidgets(node, names, cons_names);
615}
616
617/*	Function Name: ParseResources
618 *	Description: Parses the resource values returned from the client
619 *                   into a resources structure.
620 *	Arguments: info - info about a widget's resources.
621 *                 error - where to place error info.
622 *	Returns: The resource information.
623 */
624
625static WidgetResources *
626ParseResources(info, error)
627GetResourcesInfo * info;
628char **error;
629{
630    WidgetResources * resources;
631    WidgetResourceInfo * normal;
632    int i;
633
634    resources = (WidgetResources *) XtMalloc(sizeof(WidgetResources));
635
636    /*
637     * Allocate enough space for both the normal and constraint resources,
638     * then add the normal resources from the top, and the constraint resources
639     * from the bottom.  This assures that enough memory is allocated, and
640     * that there is no overlap.
641     */
642
643    resources->normal = (WidgetResourceInfo *)
644	            XtMalloc(sizeof(WidgetResourceInfo) * info->num_resources);
645
646    normal = resources->normal;
647    resources->constraint = resources->normal + info->num_resources - 1;
648
649    resources->num_constraint = resources->num_normal = 0;
650
651    for (i = 0; i < (int)info->num_resources; i++) {
652	switch((int) info->res_info[i].res_type) {
653	case NormalResource:
654	    resources->num_normal++;
655	    AddResource(info->res_info + i, normal++);
656	    break;
657	case ConstraintResource:
658	    resources->num_constraint++;
659	    AddResource(info->res_info + i, resources->constraint--);
660	    break;
661	default:
662	    {
663		char buf[BUFSIZ];
664		sprintf(buf, "Unknown resource type %d\n",
665			info->res_info[i].res_type);
666		AddString(error, buf);
667	    }
668	    break;
669	}
670    }
671
672    /*
673     * Sort the resources alphabetically.
674     */
675
676    qsort(resources->normal, resources->num_normal,
677	  sizeof(WidgetResourceInfo), CompareResourceEntries);
678
679    if (resources->num_constraint > 0) {
680	resources->constraint++;
681	qsort(resources->constraint, resources->num_constraint,
682	      sizeof(WidgetResourceInfo), CompareResourceEntries);
683    }
684    else
685	resources->constraint = NULL;
686
687    return(resources);
688}
689
690/*	Function Name: CompareResourceEntries
691 *	Description: Compares two resource entries.
692 *	Arguments: e1, e2 - the entries to compare.
693 *	Returns: an integer >, < or = 0.
694 */
695
696static int
697CompareResourceEntries(e1, e2)
698const void *e1, *e2;
699{
700    return (strcmp(((WidgetResourceInfo *)e1)->name,
701		   ((WidgetResourceInfo *)e2)->name));
702}
703
704/*	Function Name: AddResource
705 *	Description: Parses the resource string a stuffs in individual
706 *                   parts into the resource info struct.
707 *	Arguments: res_info - the resource info from the event.
708 *                 resource - location to stuff the resource into.
709 *	Returns: none.
710 */
711
712static void
713AddResource(res_info, resource)
714ResourceInfo * res_info;
715WidgetResourceInfo * resource;
716{
717    resource->name = res_info->name;
718    res_info->name = NULL;	/* Keeps it from being deallocated. */
719    resource->class = res_info->class;
720    res_info->class = NULL;	/* Keeps it from being deallocated. */
721    resource->type = res_info->type;
722    res_info->type = NULL;	/* Keeps it from being deallocated. */
723}
724
725
726/*	Function Name: FreeResources
727 *	Description: frees the resource inforation.
728 *	Arguments: resources.
729 *	Returns: none.
730 */
731
732static void
733FreeResources(resources)
734WidgetResources * resources;
735{
736    int i;
737
738    if (resources->num_normal > 0) {
739	for (i = 0; i < resources->num_normal; i++) {
740	    XtFree(resources->normal[i].name);
741	    XtFree(resources->normal[i].class);
742	    XtFree(resources->normal[i].type);
743	}
744	XFree((char *)resources->normal);
745    }
746
747    if (resources->num_constraint > 0) {
748	for (i = 0; i < resources->num_constraint; i++) {
749	    XtFree(resources->constraint[i].name);
750	    XtFree(resources->constraint[i].class);
751	    XtFree(resources->constraint[i].type);
752	}
753	XFree((char *)resources->constraint);
754    }
755
756    XFree((char *)resources);
757}
758
759
760/*	Function Name: CheckDatabase
761 *	Description: Checks to see if the node is in the database.
762 *	Arguments: db - the db to check
763 *                 names, clases - names and clases, represented as quarks.
764 *	Returns: True if this entry is found.
765 */
766
767Boolean
768CheckDatabase(db, names, classes)
769XrmDatabase db;
770XrmQuarkList names, classes;
771{
772    XrmRepresentation junk;
773    XrmValue garbage;
774
775    return(XrmQGetResource(db, names, classes, &junk, &garbage));
776}
777
778/*	Function Name: Quarkify
779 *	Description: Quarkifies the string list specifed.
780 *	Arguments: list - list of strings to quarkify
781 *                 ptr - an additional string to quarkify.
782 *	Returns: none.
783 */
784
785XrmQuarkList
786Quarkify(list, ptr)
787char ** list;
788char * ptr;
789{
790    int i;
791    char ** tlist;
792    XrmQuarkList quarks, tquarks;
793
794    for (i = 0, tlist = list; *tlist != NULL; tlist++, i++) {}
795    if (ptr != NULL)
796	i++;
797    i++;			/* leave space for NULLQUARK */
798
799    quarks = (XrmQuarkList) XtMalloc(sizeof(XrmQuark) * i);
800
801    for (tlist = list, tquarks = quarks; *tlist != NULL; tlist++, tquarks++)
802	*tquarks = XrmStringToQuark(*tlist);
803
804    if (ptr != NULL)
805	*tquarks++ = XrmStringToQuark(ptr);
806
807    *tquarks = NULLQUARK;
808    return(quarks);
809}
810
811/*	Function Name: ExecuteOverAllNodes
812 *	Description: Executes the given function over all nodes.
813 *	Arguments: top_node - top node of the tree.
814 *                 func - the function to execute.
815 *                 data - a data pointer to pass to the function.
816 *	Returns: none
817 */
818
819void
820ExecuteOverAllNodes(top_node, func, data)
821WNode * top_node;
822void (*func)(WNode *, XtPointer);
823XtPointer data;
824{
825    int i;
826
827    (*func)(top_node, data);
828
829    for (i = 0; i < top_node->num_children; i++)
830	ExecuteOverAllNodes(top_node->children[i], func, data);
831}
832
833/*	Function Name: InsertWidgetFromNode
834 *	Description: Inserts the widget info for this widget represented
835 *                   by this node.
836 *	Arguments: stream - the stream to insert it info into.
837 *                 none - the widget node to insert.
838 *	Returns: none
839 */
840
841void
842InsertWidgetFromNode(stream, node)
843ProtocolStream * stream;
844WNode * node;
845{
846    WNode *temp;
847    unsigned long * widget_list;
848    register int i, num_widgets;
849
850    for (temp = node, i = 0; temp != 0; temp = temp->parent, i++) {}
851
852    num_widgets = i;
853    widget_list = (unsigned long *)
854	          XtMalloc(sizeof(unsigned long) * num_widgets);
855
856    /*
857     * Put the widgets into the list.
858     * Make sure that they are inserted in the list from parent -> child.
859     */
860
861    for (i--, temp = node; temp != 0; temp = temp->parent, i--)
862	widget_list[i] = temp->id;
863
864    _XEditResPut16(stream, num_widgets);	/* insert number of widgets. */
865    for (i = 0; i < num_widgets; i++) 	/* insert Widgets themselves. */
866	_XEditResPut32(stream, widget_list[i]);
867
868    XtFree((char *)widget_list);
869}
870
871/*	Function Name: GetFailureMesssage
872 *	Description: returns the message returned from a failed request.
873 *	Arguments: stream - the protocol stream containing the message.
874 *	Returns: message to show.
875 */
876
877char *
878GetFailureMessage(stream)
879ProtocolStream * stream;
880{
881    char * return_str;
882
883    if (_XEditResGetString8(stream, &return_str))
884	return(return_str);
885
886    return(XtNewString(res_labels[35]));
887}
888
889/*	Function Name: ProtocolFailure
890 *	Description: Gets the version of the protocol the client is
891 *                   willing to speak.
892 *	Arguments: stream - the protocol stream containing the message.
893 *	Returns: message to show.
894 */
895
896char *
897ProtocolFailure(stream)
898ProtocolStream * stream;
899{
900    char buf[BUFSIZ];
901    unsigned char version;
902    char* old_version_string;
903
904    if (!_XEditResGet8(stream, &version))
905	return(XtNewString(res_labels[35]));
906
907    switch ((int)version) {
908    case PROTOCOL_VERSION_ONE_POINT_ZERO: old_version_string = "1.0"; break;
909    default: old_version_string = "1.0";
910    }
911
912    sprintf(buf, res_labels[36],
913	    CURRENT_PROTOCOL_VERSION_STRING, old_version_string);
914    return(XtNewString(buf));
915}
916
917