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