Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtPrint / PsubDefProc.c
1 /* $XConsortium: PsubDefProc.c /main/14 1996/12/02 10:51:20 rswiston $ */
2 /*
3  * DtPrint/PsubDefProc.c
4  */
5 /*
6  * (c) Copyright 1996 Digital Equipment Corporation.
7  * (c) Copyright 1996 Hewlett-Packard Company.
8  * (c) Copyright 1996 International Business Machines Corp.
9  * (c) Copyright 1996 Sun Microsystems, Inc.
10  * (c) Copyright 1996 Novell, Inc. 
11  * (c) Copyright 1996 FUJITSU LIMITED.
12  * (c) Copyright 1996 Hitachi.
13  */
14 /*
15  * ------------------------------------------------------------------------
16  * Include Files
17  *
18  */
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22
23 #include <Xm/XmAll.h>
24
25 #include <Dt/HelpDialog.h>
26 #include <Dt/DtNlUtils.h>
27 #include <Dt/HourGlass.h>
28
29 /*
30  * PrintSetupBP.h is included only for access to the DtPrintDefProcData
31  * member of the widget instance structure.
32  */
33 #include <Dt/PrintSetupBP.h>
34
35 #include <Dt/PsubUtilI.h>
36
37 /*
38  * ------------------------------------------------------------------------
39  * Constant Definitions
40  *
41  */
42 #define HELP_VOLUME "LibDtPrint"
43 #define PRINTER_INFO_HELP_ID "PrinterInfo"
44 #define SELECT_PRINTER_HELP_ID "SelectPrinter"
45 #define SELECT_FILE_HELP_ID "SelectFile"
46
47 /*
48  * ------------------------------------------------------------------------
49  * Static Function Declarations
50  *
51  */
52 static XtEnum BuildPrinterLists(
53                                 Widget w,
54                                 DtPrintDefaultProcData* dpd,
55                                 int* item_count);
56 static XmStringTable BuildPrinterSelectionItems(
57                                                 Display* display,
58                                                 DtPrintDefaultProcData* dpd,
59                                                 int item_count,
60                                                 String initial_printer,
61                                                 XmStringTag tag);
62 static void CloseSelectPrinterInfoConnection(
63                                              DtPrintDefaultProcData* dpd);
64 static int CompareSelectPrinterRecs(const void*,
65                                     const void*);
66 static String CompoundTextToString(
67                                    Display* display,
68                                    unsigned char* compound_text);
69 static XtEnum CreateFileSelectionBox(
70                                      Widget parent,
71                                      Widget psub,
72                                      DtPrintDefaultProcData* dpd);
73 static XtEnum CreatePrinterInfoBox(
74                                    Widget parent,
75                                    Widget psub,
76                                    DtPrintDefaultProcData* dpd);
77 static XtEnum CreatePrinterSelectionBox(
78                                         Widget parent,
79                                         Widget psub,
80                                         DtPrintDefaultProcData* dpd);
81 static void DestroyWidgetCB(
82                             Widget w,
83                             XtPointer client_data,
84                             XtPointer call_data);
85 static void DtPrintDefProcDestroyCB(Widget w,
86                                     XtPointer client_data,
87                                     XtPointer call_data);
88 static void ErrorMessageDestroyCB(
89                                   Widget w,
90                                   XtPointer client_data,
91                                   XtPointer call_data);
92 static String FindSelectedPrinter(
93                                   Display* display,
94                                   DtPrintDefaultProcData* dpd);
95 static void FreeSelectPrinterData(
96                                   DtPrintDefaultProcData* dpd);
97 static Widget GetWMShellAncestor(
98                                  Widget w);
99 static void HelpDialogDestroyCB(
100                                 Widget w,
101                                 XtPointer client_data,
102                                 XtPointer call_data);
103 static void InfoBoxLayoutCB(
104                             Widget widget,
105                             XtPointer client_data,
106                             XtPointer call_data);
107 static void ParseFileNameSpec(
108                               const char* file_name,
109                               XmString* pattern,
110                               char** name_only);
111 static void PresentErrorDialog(
112                                Widget w,
113                                String title,
114                                String message,
115                                ...);
116 static void PresentHelp(
117                         Widget w,
118                         const char* help_volume,
119                         const char* location_id);
120 static void PresentVerifyError(
121                                Widget w,
122                                XtEnum status,
123                                String printer_spec);
124 static void PrinterInfoDestroyCB(
125                                  Widget w,
126                                  XtPointer client_data,
127                                  XtPointer call_data);
128 static void PrinterInfoHelpCB(
129                               Widget w,
130                               XtPointer client_data,
131                               XtPointer call_data);
132 static void SelectFileDestroyCB(
133                                 Widget w,
134                                 XtPointer client_data,
135                                 XtPointer call_data);
136 static void SelectFileHelpCB(
137                              Widget w,
138                              XtPointer client_data,
139                              XtPointer call_data);
140 static void SelectPrinterCB(
141                             Widget w,
142                             XtPointer client_data,
143                             XtPointer call_data);
144 static void SelectPrinterDestroyCB(
145                                    Widget w,
146                                    XtPointer client_data,
147                                    XtPointer call_data);
148 static void SelectPrinterHelpCB(
149                                 Widget w,
150                                 XtPointer client_data,
151                                 XtPointer call_data);
152 static void SelectPrinterInfoCB(
153                                 Widget w,
154                                 XtPointer client_data,
155                                 XtPointer call_data);
156 static void SelectPrinterItemCB(
157                                 Widget w,
158                                 XtPointer client_data,
159                                 XtPointer call_data);
160 static void SetListBoxSelection(
161                                 Widget list_box,
162                                 int position);
163 static void UpdateFileNameCB(
164                              Widget w,
165                              XtPointer client_data,
166                              XtPointer call_data);
167
168 /*
169  * ------------------------------------------------------------------------
170  * Name: BuildPrinterLists
171  *
172  * Description:
173  *
174  *     Retrieves lists of printers from the Xp server found in the
175  *     XpServerList resource or XPSERVERLIST env var.
176  *
177  * Return value:
178  *
179  *
180  *
181  */
182 static XtEnum
183 BuildPrinterLists(
184                   Widget w,
185                   DtPrintDefaultProcData* dpd,
186                   int* item_count)
187 {
188     String* server_list;
189     int server_count;
190     int i, j;
191     Display* display;
192     int error_base;
193     int event_base;
194     XPPrinterList xp_printer_list;
195     DtPrintSelectPrinterList printer_list;
196     /*
197      * clean up previous lists if needed
198      */
199     FreeSelectPrinterData(dpd);
200     /*
201      * get the list of servers
202      */
203     server_list = _DtPrintGetXpServerList(w);
204     if((String*)NULL == server_list)
205         return DtPRINT_FAILURE;
206     /*
207      * get the printer list for each valid Xp server
208      */
209     for(server_count = 0;
210         (String)NULL != server_list[server_count];
211         server_count++);
212     dpd->xp_server_list =
213         (String*)XtCalloc(server_count, sizeof(String));
214     dpd->printer_lists = (DtPrintSelectPrinterList*)
215         XtCalloc(server_count, sizeof(DtPrintSelectPrinterList));
216     dpd->printer_counts =
217         (int*)XtCalloc(server_count, sizeof(int));
218     for(i = 0, *item_count = 0; i < server_count; i++)
219     {
220         /*
221          * ensure the server is a valid Xp server
222          */
223         display = XOpenDisplay(server_list[i]);
224         if((Display*)NULL == display)
225             continue;
226         if(!XpQueryExtension(display, &event_base, &error_base))
227         {
228             XCloseDisplay(display);
229             continue;
230         }
231         /*
232          * add the server to the xp server list
233          */
234         dpd->xp_server_list[dpd->xp_server_count] =
235             XtNewString(server_list[i]);
236         /*
237          * get the printer list for the server
238          */
239         xp_printer_list =
240             XpGetPrinterList(display, (char*)NULL,
241                              &dpd->printer_counts[dpd->xp_server_count]);
242         /*
243          * save a copy of the compound text printer name and
244          * string versions of the name and description for
245          * eventual use in the printer selection list.
246          */
247         dpd->printer_lists[dpd->xp_server_count] = (DtPrintSelectPrinterList)
248             XtCalloc(dpd->printer_counts[dpd->xp_server_count],
249                      sizeof(DtPrintSelectPrinterRec));
250         printer_list = dpd->printer_lists[dpd->xp_server_count];
251         for(j = 0; j < dpd->printer_counts[dpd->xp_server_count]; j++)
252         {
253             printer_list[j].printer_name_ct =
254                 XtNewString(xp_printer_list[j].name);
255             printer_list[j].printer_name =
256                 CompoundTextToString(display,
257                                      (unsigned char*)xp_printer_list[j].name);
258             printer_list[j].description =
259                 CompoundTextToString(display,
260                                      (unsigned char*)xp_printer_list[j].desc);
261         }
262         XpFreePrinterList(xp_printer_list);
263         /*
264          * sort the printer list
265          */
266         if(0 < dpd->printer_counts[dpd->xp_server_count])
267             qsort((void*)printer_list,
268                   dpd->printer_counts[dpd->xp_server_count],
269                   sizeof(DtPrintSelectPrinterRec), CompareSelectPrinterRecs);
270
271         *item_count += dpd->printer_counts[dpd->xp_server_count];
272         ++dpd->xp_server_count;
273         XCloseDisplay(display);
274     }
275     _DtPrintFreeStringList(server_list);
276     if(0 == *item_count)
277     {
278         FreeSelectPrinterData(dpd);
279         return DtPRINT_FAILURE;
280     }
281     else
282         return DtPRINT_SUCCESS;
283 }
284
285 /*
286  * ------------------------------------------------------------------------
287  * Name: BuildPrinterSelectionItems
288  *
289  * Description:
290  *
291  *     Builds the list of XmString items (printer name + desc) to be set
292  *     in the printer selection list box.
293  *
294  * Return value:
295  *
296  *     None.
297  *
298  */
299 static XmStringTable
300 BuildPrinterSelectionItems(
301                            Display* display,
302                            DtPrintDefaultProcData* dpd,
303                            int item_count,
304                            String initial_printer,
305                            XmStringTag tag)
306 {
307     XmStringTable items;
308     int i, j;
309     char* buf = (char*)NULL;
310     Cardinal buf_size = 0;
311     Cardinal new_size;
312     int current_item;
313     String name, full_name, desc;
314     char* server_name;
315     int server_len;
316     
317     items = (XmStringTable)XtCalloc(item_count, sizeof(XmString));
318     for(i = 0, current_item = 0; i < dpd->xp_server_count; i++)
319     {
320         server_name = dpd->xp_server_list[i];
321         server_len = strlen(server_name);
322         
323         for(j = 0; j < dpd->printer_counts[i]; j++, current_item++)
324         {
325             /*
326              * build a fully qualified X printer specifier
327              */
328             name = (dpd->printer_lists[i])[j].printer_name;
329             (dpd->printer_lists[i])[j].printer_name = (String)NULL;
330             full_name =
331                 _DtPrintCreateXPrinterSpecifier(name, server_name,
332                                                 DtPRINT_NET_UNSPECIFIED,
333                                                 -1, -1);
334             XtFree(name);
335             /*
336              * check to see if this should be the initially selected printer
337              */
338             if(dpd->selected_printer == 0
339                && (String)NULL != initial_printer)
340                 if(strcmp(initial_printer, full_name) == 0)
341                     dpd->selected_printer = current_item + 1;
342             /*
343              * convert the printer description
344              */
345             desc = (dpd->printer_lists[i])[j].description;
346             (dpd->printer_lists[i])[j].description = (String)NULL;
347             if((String)NULL != desc && '\0' != *desc)
348             {
349                 /*
350                  * chop the description after the 1st line
351                  */
352                 char* ptr = Dt_strchr(desc, '\n');
353                 if((char*)NULL != ptr)
354                     *ptr = '\0';
355             }
356             /*
357              * ensure the format buffer is large enough to contain
358              * the formatted list item
359              */
360             new_size = 2;
361             new_size += full_name ? strlen(full_name) : 0;
362             new_size += desc ? strlen(desc) : 0;
363             if(new_size > buf_size)
364             {
365                 buf_size = new_size;
366                 buf = XtRealloc(buf, buf_size);
367             }
368             /*
369              * format the item, and add it to the item list
370              */
371             sprintf(buf, "%s\t%s",
372                     full_name ? full_name : "",
373                     desc ? desc : "");
374             XtFree(desc);
375             XtFree(full_name);
376             items[current_item] =
377                 XmStringGenerate((XtPointer)buf, (XmStringTag)NULL,
378                                  XmMULTIBYTE_TEXT, tag);
379         }
380     }
381     XtFree(buf);
382     return items;
383 }
384
385 /*
386  * ------------------------------------------------------------------------
387  * Name: CloseSelectPrinterInfoConnection
388  *
389  * Description:
390  *
391  *     Close the X printer connection maintained for the Select Printer
392  *     dialog's Printer Information dialog.
393  *
394  * Return value:
395  *
396  *     None.
397  *
398  */
399 static void
400 CloseSelectPrinterInfoConnection(
401                                  DtPrintDefaultProcData* dpd)
402 {
403     if((Display*)NULL != dpd->select_printer_info_display)
404     {
405         if((XPContext)None != dpd->select_printer_info_context)
406         {
407             XpDestroyContext(dpd->select_printer_info_display,
408                              dpd->select_printer_info_context);
409             dpd->select_printer_info_context = (XPContext)None;
410         }
411         XCloseDisplay(dpd->select_printer_info_display);
412         dpd->select_printer_info_display = (Display*)NULL;
413     }
414 }
415
416 /*
417  * ------------------------------------------------------------------------
418  * Name: CompareSelectPrinterRecs
419  *
420  * Description:
421  *
422  *     Compares the printer names in two DtPrintSelectPrinterRecs.
423  *
424  * Return value:
425  *
426  *     Returns an integer greater than, equal to, or less than zero,
427  *     according to whether the printer name in spr1 is greater
428  *     than, equal to, or less than the printer name in spr2.
429  *
430  */
431 static int
432 CompareSelectPrinterRecs(const void* spr1,
433                          const void* spr2)
434 {
435     return strcoll(((DtPrintSelectPrinterRec*)spr1)->printer_name,
436                    ((DtPrintSelectPrinterRec*)spr2)->printer_name);
437 }
438
439 /*
440  * ------------------------------------------------------------------------
441  * Name: CompoundTextToString
442  *
443  * Description:
444  *
445  *     
446  *
447  * Return value:
448  *
449  *     None.
450  *
451  */
452 static String
453 CompoundTextToString(
454                      Display* display,
455                      unsigned char* compound_text)
456 {
457     String str = (String)NULL;
458
459     if((unsigned char*)NULL != compound_text)
460     {
461         XTextProperty text_prop;
462         char** list;
463         int count;
464
465         text_prop.encoding = XInternAtom(display, "COMPOUND_TEXT", False);
466         text_prop.format = 8;
467         text_prop.value = compound_text;
468         text_prop.nitems = strlen((char*)text_prop.value);
469         if(Success ==
470            XmbTextPropertyToTextList(display, &text_prop, &list, &count))
471         {
472             if(count > 0)
473                 str = XtNewString(list[0]);
474             XFreeStringList(list);
475         }
476     }
477     return str;
478 }
479
480 /*
481  * ------------------------------------------------------------------------
482  * Name: CreateFileSelectionBox
483  *
484  * Description:
485  *
486  *     Creates the file selection dialog box.
487  *
488  * Return value:
489  *
490  *     None.
491  *
492  */
493 static XtEnum
494 CreateFileSelectionBox(
495                        Widget parent,
496                        Widget psub,
497                        DtPrintDefaultProcData* dpd)
498 {
499     Arg args[15];
500     Cardinal n;
501     XmString title_xmstr;
502
503     title_xmstr = XmStringCreateLocalized(SELECT_FILE_TITLE);
504     
505     n = 0;
506     /*
507      * dialog resources
508      */
509     XtSetArg(args[n], XmNdialogTitle, title_xmstr); n++;
510     XtSetArg(args[n], XmNdialogStyle,
511              XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
512     XtSetArg(args[n], XmNdeleteResponse, XmUNMAP); n++;
513     /*
514      * file selection box resources
515      */
516     XtSetArg(args[n], XmNautoUnmanage, True); n++;
517     /*
518      * create the file selection box dialog
519      */
520     dpd->file_selection_box =
521         XmCreateFileSelectionDialog(parent, "_PsubDefProcFileSelectionBox",
522                                     args, n);
523     XmStringFree(title_xmstr);
524     if(dpd->file_selection_box == (Widget)NULL)
525         return DtPRINT_FAILURE;
526     /*
527      * add callbacks
528      */
529     XtAddCallback(dpd->file_selection_box, XmNokCallback,
530                   UpdateFileNameCB, (XtPointer)psub);
531     XtAddCallback(dpd->file_selection_box, XmNhelpCallback,
532                   SelectFileHelpCB, (XtPointer)psub);
533     XtAddCallback(dpd->file_selection_box, XmNdestroyCallback,
534                   SelectFileDestroyCB, (XtPointer)psub);
535     /*
536      * return
537      */
538     return DtPRINT_SUCCESS;
539 }
540
541 /*
542  * ------------------------------------------------------------------------
543  * Name: CreatePrinterInfoBox
544  *
545  * Description:
546  *
547  *     Creates the printer information dialog box.
548  *
549  * Return value:
550  *
551  *     None.
552  *
553  */
554 static XtEnum
555 CreatePrinterInfoBox(
556                      Widget parent,
557                      Widget psub,
558                      DtPrintDefaultProcData* dpd)
559 {
560     Arg args[15];
561     Cardinal n;
562     XmString title_xmstr;
563     Widget manager;
564     Widget description_label, description;
565     Widget name_label, name;
566     Widget format_label, format;
567     Widget model_label, model;
568     XmString label;
569     
570     title_xmstr = XmStringCreateLocalized(PRINTER_INFO_TITLE);
571     
572     n = 0;
573     /*
574      * dialog resources
575      */
576     XtSetArg(args[n], XmNdialogTitle, title_xmstr); n++;
577     XtSetArg(args[n], XmNdialogStyle,
578              XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
579     XtSetArg(args[n], XmNdeleteResponse, XmUNMAP); n++;
580     /*
581      * printer info box resources
582      */
583     XtSetArg(args[n], XmNautoUnmanage, True); n++;
584     /*
585      * create the dialog
586      */
587     dpd->printer_info_box =
588         XmCreateInformationDialog(parent, "_PsubDefProcPrinterInfoBox",
589                                   args, n);
590     XmStringFree(title_xmstr);
591     if(dpd->printer_info_box == (Widget)NULL)
592         return DtPRINT_FAILURE;
593     /*
594      * add callbacks
595      */
596     XtAddCallback(dpd->printer_info_box, XmNhelpCallback,
597                   PrinterInfoHelpCB, (XtPointer)psub);
598     XtAddCallback(dpd->printer_info_box, XmNdestroyCallback,
599                   PrinterInfoDestroyCB, (XtPointer)psub);
600     XtAddCallback(dpd->printer_info_box, XmNmapCallback,
601                   InfoBoxLayoutCB, (XtPointer)dpd);
602     /*
603      * unmanage unwanted children
604      */
605     XtUnmanageChild(XtNameToWidget(dpd->printer_info_box, "Cancel"));
606     XtUnmanageChild(XtNameToWidget(dpd->printer_info_box, "Message"));
607     XtUnmanageChild(XtNameToWidget(dpd->printer_info_box, "Symbol"));
608     /*
609      * create the control manager
610      */
611     manager =
612         XtVaCreateManagedWidget("PrinterInfoForm", xmFormWidgetClass,
613                                 dpd->printer_info_box,
614                                 XmNallowOverlap, False,
615                                 NULL);
616     /*
617      * printer description
618      */
619     label = XmStringCreateLocalized(DESCRIPTION_LABEL);
620     description_label =
621         XtVaCreateManagedWidget("DescriptionLabel",
622                                 xmLabelWidgetClass,
623                                 manager,
624                                 XmNlabelString, label,
625                                 XmNleftAttachment,   XmATTACH_FORM,
626                                 XmNtopAttachment,    XmATTACH_FORM,
627                                 XmNtopOffset,        5,
628                                 NULL);
629     XmStringFree(label);
630     description = 
631         XtVaCreateManagedWidget("Description",
632                                 xmLabelWidgetClass,
633                                 manager,
634                                 XmNalignment,        XmALIGNMENT_BEGINNING,
635                                 XmNleftAttachment,   XmATTACH_WIDGET,
636                                 XmNleftWidget,       description_label,
637                                 XmNleftOffset,       10,
638                                 XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
639                                 XmNtopWidget,        description_label,
640                                 NULL);
641     /*
642      * printer name
643      */
644     label = XmStringCreateLocalized(PRINTER_NAME_LABEL);
645     name_label =
646         XtVaCreateManagedWidget("NameLabel",
647                                 xmLabelWidgetClass,
648                                 manager,
649                                 XmNlabelString, label,
650                                 XmNleftAttachment,   XmATTACH_FORM,
651                                 XmNtopAttachment,    XmATTACH_WIDGET,
652                                 XmNtopWidget,        description,
653                                 XmNtopOffset,        5,
654                                 NULL);
655     XmStringFree(label);
656     name = 
657         XtVaCreateManagedWidget("Name",
658                                 xmLabelWidgetClass,
659                                 manager,
660                                 XmNleftAttachment,   XmATTACH_WIDGET,
661                                 XmNleftWidget,       name_label,
662                                 XmNleftOffset,       10,
663                                 XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
664                                 XmNtopWidget,        name_label,
665                                 NULL);
666     /*
667      * printer format
668      */
669     label = XmStringCreateLocalized(FORMAT_LABEL);
670     format_label =
671         XtVaCreateManagedWidget("FormatLabel",
672                                 xmLabelWidgetClass,
673                                 manager,
674                                 XmNlabelString, label,
675                                 XmNleftAttachment,   XmATTACH_FORM,
676                                 XmNtopAttachment,    XmATTACH_WIDGET,
677                                 XmNtopWidget,        name_label,
678                                 XmNtopOffset,        5,
679                                 NULL);
680     XmStringFree(label);
681     format = 
682         XtVaCreateManagedWidget("Format",
683                                 xmLabelWidgetClass,
684                                 manager,
685                                 XmNleftAttachment,   XmATTACH_WIDGET,
686                                 XmNleftWidget,       format_label,
687                                 XmNleftOffset,       10,
688                                 XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
689                                 XmNtopWidget,        format_label,
690                                 NULL);
691     /*
692      * printer model
693      */
694     label = XmStringCreateLocalized(MODEL_LABEL);
695     model_label =
696         XtVaCreateManagedWidget("ModelLabel",
697                                 xmLabelWidgetClass,
698                                 manager,
699                                 XmNlabelString, label,
700                                 XmNleftAttachment,   XmATTACH_FORM,
701                                 XmNtopAttachment,    XmATTACH_WIDGET,
702                                 XmNtopWidget,        format_label,
703                                 XmNtopOffset,        5,
704                                 NULL);
705     XmStringFree(label);
706     model = 
707         XtVaCreateManagedWidget("Model",
708                                 xmLabelWidgetClass,
709                                 manager,
710                                 XmNalignment,        XmALIGNMENT_BEGINNING,
711                                 XmNleftAttachment,   XmATTACH_WIDGET,
712                                 XmNleftWidget,       model_label,
713                                 XmNleftOffset,       10,
714                                 XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
715                                 XmNtopWidget,        model_label,
716                                 NULL);
717     /*
718      * return
719      */
720     return DtPRINT_SUCCESS;
721 }
722
723 /*
724  * ------------------------------------------------------------------------
725  * Name: CreatePrinterSelectionBox
726  *
727  * Description:
728  *
729  *     Creates the printer selection dialog box.
730  *
731  * Return value:
732  *
733  *     None.
734  *
735  */
736 static XtEnum
737 CreatePrinterSelectionBox(
738                           Widget parent,
739                           Widget psub,
740                           DtPrintDefaultProcData* dpd)
741 {
742     Arg args[15];
743     Cardinal n;
744     Widget control;
745     XmString list_label;
746     XmString title_xmstr;
747     XmString info_label;
748
749     title_xmstr = XmStringCreateLocalized(MORE_PRINTERS_TITLE);
750     list_label = XmStringCreateLocalized(PRINTER_LIST_LABEL);
751     info_label = XmStringCreateLocalized(PRINTER_INFO_LABEL);
752     
753     n = 0;
754     /*
755      * dialog resources
756      */
757     XtSetArg(args[n], XmNdialogTitle, title_xmstr); n++;
758     XtSetArg(args[n], XmNdialogStyle,
759              XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
760     XtSetArg(args[n], XmNdeleteResponse, XmDESTROY); n++;
761     /*
762      * selection box resources
763      */
764     XtSetArg(args[n], XmNautoUnmanage, True); n++;
765     XtSetArg(args[n], XmNlistLabelString, list_label); n++;
766     XtSetArg(args[n], XmNapplyLabelString, info_label); n++;
767     /*
768      * create the dialog
769      */
770     dpd->printer_selection_box =
771         XmCreateSelectionDialog(parent, "_PsubDefProcPrinterSelectionBox",
772                                 args, n);
773     XmStringFree(list_label);
774     XmStringFree(info_label);
775     XmStringFree(title_xmstr);
776     if(dpd->printer_selection_box == (Widget)NULL)
777         return DtPRINT_FAILURE;
778     /*
779      * add callbacks
780      */
781     XtAddCallback(dpd->printer_selection_box, XmNokCallback,
782                   SelectPrinterCB, (XtPointer)psub);
783     XtAddCallback(dpd->printer_selection_box, XmNapplyCallback,
784                   SelectPrinterInfoCB, (XtPointer)psub);
785     XtAddCallback(dpd->printer_selection_box, XmNcancelCallback,
786                   SelectPrinterCB, (XtPointer)psub);
787     XtAddCallback(dpd->printer_selection_box, XmNhelpCallback,
788                   SelectPrinterHelpCB, (XtPointer)psub);
789     XtAddCallback(dpd->printer_selection_box, XmNdestroyCallback,
790                   SelectPrinterDestroyCB, (XtPointer)psub);
791     /*
792      * get the list box widget ID
793      */
794     dpd->printer_list_box =
795         XtNameToWidget(dpd->printer_selection_box, "*ItemsList");
796     XtAddCallback(dpd->printer_list_box, XmNbrowseSelectionCallback,
797                   SelectPrinterItemCB, (XtPointer)psub);
798     /*
799      * unmanaged unwanted children
800      */
801     control = XtNameToWidget(dpd->printer_selection_box, "*Selection");
802     if(control != (Widget)NULL)
803         XtUnmanageChild(control);
804     control = XtNameToWidget(dpd->printer_selection_box, "*Text");
805     if(control != (Widget)NULL)
806         XtUnmanageChild(control);
807     /*
808      * return
809      */
810     return DtPRINT_SUCCESS;
811 }
812
813 /*
814  * ------------------------------------------------------------------------
815  * Name: DestroyWidgetCB
816  *
817  * Description:
818  *
819  *     Destroys the Widget passed as client_data.
820  *
821  * Return value:
822  *
823  *     None.
824  *
825  */
826 static void 
827 DestroyWidgetCB(
828                 Widget w,
829                 XtPointer client_data,
830                 XtPointer call_data)
831 {
832     XtDestroyWidget((Widget)client_data);
833 }
834
835 /*
836  * ------------------------------------------------------------------------
837  * Name: DtPrintDefProcDestroyCB
838  *
839  * Description:
840  *
841  *     Free resources allocated for the default procedure data structure
842  *     in response to the destruction of the DtPrintSetupBox.
843  *
844  *     Calls destroy callbacks for dialogs *directly* because the dialogs
845  *     aren't children of the DtPrintSetupBox, but instead are more like
846  *     siblings or cousins of the PrintSetupBox whose common ancestor is
847  *     the shell parent of the PrintSetupBox. As such the dialogs may or
848  *     may not otherwise be destroyed when the PrintSetupBox is
849  *     destroyed. Furthermore the 2nd phase of the XtDestroyWidget calls
850  *     made in this routine isn't reached until after the PrintSetupBox
851  *     instance record has been destroyed (as part of the destroy phase
852  *     of which *this* call is a part).
853  *
854  *     The main reason this is a concern is because data associated with
855  *     these dialogs is stored in the PrintSetupBox widget instance
856  *     structure.
857  *
858  * Return value:
859  *
860  *     None.
861  *
862  */
863 static void
864 DtPrintDefProcDestroyCB(Widget w,
865                         XtPointer client_data,
866                         XtPointer call_data)
867 {
868     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
869
870     if(dpd->error_message_box)
871     {
872         XtRemoveCallback(dpd->error_message_box, XmNdestroyCallback,
873                          ErrorMessageDestroyCB, (XtPointer)w);
874         XtDestroyWidget(dpd->error_message_box);
875         ErrorMessageDestroyCB(dpd->error_message_box,
876                               (XtPointer)w, (XtPointer)NULL);
877     }
878     if(dpd->help_dialog)
879     {
880         XtRemoveCallback(dpd->help_dialog, XmNdestroyCallback,
881                          HelpDialogDestroyCB, (XtPointer)w);
882         XtDestroyWidget(dpd->help_dialog);
883         HelpDialogDestroyCB(dpd->help_dialog,
884                             (XtPointer)w, (XtPointer)NULL);
885     }
886     if(dpd->file_selection_box)
887     {
888         XtRemoveCallback(dpd->file_selection_box, XmNdestroyCallback,
889                          SelectFileDestroyCB, (XtPointer)w);
890         XtDestroyWidget(dpd->file_selection_box);
891         SelectFileDestroyCB(dpd->file_selection_box,
892                             (XtPointer)w, (XtPointer)NULL);
893     }
894     if(dpd->printer_selection_box)
895     {
896         XtRemoveCallback(dpd->printer_selection_box, XmNdestroyCallback,
897                          SelectPrinterDestroyCB, (XtPointer)w);
898         XtDestroyWidget(dpd->printer_selection_box);
899         SelectPrinterDestroyCB(dpd->printer_selection_box,
900                                (XtPointer)w, (XtPointer)NULL);
901     }
902     if(dpd->printer_info_box)
903     {
904         XtRemoveCallback(dpd->printer_info_box, XmNdestroyCallback,
905                          PrinterInfoDestroyCB, (XtPointer)w);
906         XtDestroyWidget(dpd->printer_info_box);
907         PrinterInfoDestroyCB(dpd->printer_info_box,
908                              (XtPointer)w, (XtPointer)NULL);
909     }
910     
911 }
912
913 /*
914  * ------------------------------------------------------------------------
915  * Name: ErrorMessageDestroyCB
916  *
917  * Description:
918  *
919  *     Reset the error message widget ID instance data when the message
920  *     box is destroyed.
921  *
922  *     This callback is considered part of the default resource
923  *     procedures and not part of the setup box widget proper.
924  *
925  * Return value:
926  *
927  *     None.
928  *
929  */
930 static void 
931 ErrorMessageDestroyCB(
932                       Widget w,
933                       XtPointer client_data,
934                       XtPointer call_data)
935 {
936     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(client_data);
937     
938     dpd->error_message_box = (Widget)NULL;
939 }
940
941 /*
942  * ------------------------------------------------------------------------
943  * Name: FindSelectedPrinter
944  *
945  * Description:
946  *
947  *     Build a full printer name by locating the currently selected
948  *     printer in the server list and printer list.
949  *
950  *
951  * Return value:
952  *
953  *     A newly allocated full printer name. It is the caller's
954  *     responsibility to free the returned String by calling XtFree.
955  *
956  */
957 static String
958 FindSelectedPrinter(
959                     Display* display,
960                     DtPrintDefaultProcData* dpd)
961 {
962     int printer_count;
963     int i;
964     int printer_index;
965
966     /*
967      * return if any of the structures are not in place
968      */
969     if(dpd->xp_server_list == (String*)NULL
970        ||
971        dpd->printer_counts == (int*)NULL
972        ||
973        dpd->printer_lists == (DtPrintSelectPrinterList*)NULL)
974     {
975         return (String)NULL;
976     }
977     /*
978      * find the printer list containing the selected printer
979      */
980     if(0 == dpd->selected_printer)
981         return (String)NULL;
982     else
983         printer_index = dpd->selected_printer - 1;
984     
985     for(i = 0, printer_count = 0; i < dpd->xp_server_count; i++)
986     {
987         if(printer_index < printer_count + (dpd->printer_counts)[i])
988             break;
989         else
990             printer_count += (dpd->printer_counts)[i];
991     }
992     if(i < dpd->xp_server_count)
993     {
994         /*
995          * build and return the printer name
996          */
997         DtPrintSelectPrinterList printer_list;
998         String printer_spec;
999         String printer_name;
1000         char* printer_name_ct;
1001         char* display_spec;
1002
1003         display_spec = (dpd->xp_server_list)[i];
1004         printer_list = (dpd->printer_lists)[i];
1005         printer_name_ct =
1006             printer_list[printer_index - printer_count].printer_name_ct;
1007         printer_name =
1008             CompoundTextToString(display, (unsigned char*)printer_name_ct);
1009         if((String)NULL != printer_name)
1010         {
1011             printer_spec =
1012                 _DtPrintCreateXPrinterSpecifier(printer_name,
1013                                                 display_spec,
1014                                                 DtPRINT_NET_UNSPECIFIED,
1015                                                 -1, -1);
1016             XtFree(printer_name);
1017             return printer_spec;
1018         }
1019     }
1020     return (String)NULL;
1021 }
1022
1023 /*
1024  * ------------------------------------------------------------------------
1025  * Name: FreeSelectPrinterData
1026  *
1027  * Description:
1028  *
1029  *     Deallocate and reset data items associated with the printer
1030  *     selection dialog.
1031  *
1032  * Return value:
1033  *
1034  *     None.
1035  */
1036 static void
1037 FreeSelectPrinterData(
1038                       DtPrintDefaultProcData* dpd)
1039 {
1040     int i, j;
1041     DtPrintSelectPrinterList printer_list;
1042     
1043     for(i = 0; i < dpd->xp_server_count; i++)
1044     {
1045         printer_list = dpd->printer_lists[i];
1046         for(j = 0; j < dpd->printer_counts[i]; j++)
1047         {
1048             XtFree(printer_list[j].printer_name_ct);
1049         }
1050         XtFree((char*)printer_list);
1051     }
1052     XtFree((char*)dpd->printer_lists);
1053     dpd->printer_lists = (DtPrintSelectPrinterList*)NULL;
1054     XtFree((char*)dpd->xp_server_list);
1055     dpd->xp_server_list = (String*)NULL;
1056     dpd->xp_server_count = 0;
1057     dpd->selected_printer = 0;
1058 }
1059
1060 /*
1061  * ------------------------------------------------------------------------
1062  * Name: GetWMShellAncestor
1063  *
1064  * Description:
1065  *
1066  *     Obtains the widget ID of the closest WMShell ancestor for
1067  *     the passed widget.
1068  *
1069  * Return value:
1070  *
1071  *     The widget ID of the closest WMShell ancestor.
1072  *
1073  */
1074 static Widget
1075 GetWMShellAncestor(Widget w)
1076 {
1077     Widget wmshell_ancestor = XtParent(w);
1078     while(wmshell_ancestor != (Widget)NULL)
1079     {
1080         if(XtIsWMShell(wmshell_ancestor))
1081             break;
1082         else
1083             wmshell_ancestor = XtParent(wmshell_ancestor);
1084     }
1085     return wmshell_ancestor;
1086 }
1087
1088 /*
1089  * ------------------------------------------------------------------------
1090  * Name: HelpDialogDestroyCB
1091  *
1092  * Description:
1093  *
1094  *     Reset the help dialog widget ID instance data when the widget
1095  *     is destroyed.
1096  *
1097  *     This callback is considered part of the default resource
1098  *     procedures and not part of the setup box widget proper.
1099  *
1100  * Return value:
1101  *
1102  *     None.
1103  *
1104  */
1105 static void 
1106 HelpDialogDestroyCB(
1107                     Widget w,
1108                     XtPointer client_data,
1109                     XtPointer call_data)
1110 {
1111     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(client_data);
1112     
1113     dpd->help_dialog = (Widget)NULL;
1114 }
1115
1116 /*
1117  * ------------------------------------------------------------------------
1118  * Name: InfoBoxLayoutCB
1119  *
1120  * Description:
1121  *
1122  *     Callback to right justify printer information dialog labels at
1123  *     mapping time.
1124  *
1125  * Return value:
1126  *
1127  *     None.
1128  *
1129  *
1130  */
1131 static void
1132 InfoBoxLayoutCB(
1133                 Widget widget,
1134                 XtPointer client_data,
1135                 XtPointer call_data)
1136 {
1137     DtPrintDefaultProcData* dpd = (DtPrintDefaultProcData*)client_data;
1138     Widget w[4];
1139     int i, widest;
1140     Dimension width, max_width;
1141     /*
1142      * only need to do this once after the widget is created
1143      */
1144     XtRemoveCallback(widget, XmNmapCallback, InfoBoxLayoutCB, client_data);
1145     /*
1146      * get the label widget ids
1147      */
1148     w[0] = XtNameToWidget(dpd->printer_info_box,
1149                           "PrinterInfoForm.DescriptionLabel");
1150     w[1] = XtNameToWidget(dpd->printer_info_box,
1151                           "PrinterInfoForm.NameLabel");
1152     w[2] = XtNameToWidget(dpd->printer_info_box,
1153                           "PrinterInfoForm.FormatLabel");
1154     w[3] = XtNameToWidget(dpd->printer_info_box,
1155                           "PrinterInfoForm.ModelLabel");
1156     /*
1157      * find the widest label
1158      */
1159     for(i = 0, widest = 0, max_width = 0; i < 4; i++)
1160     {
1161         XtVaGetValues(w[i], XmNwidth, &width, NULL);
1162         if(width > max_width)
1163         {
1164             widest = i;
1165             max_width = width;
1166         }
1167     }
1168     /*
1169      * sever the top attachment on the widest label in order to avoid
1170      * circular dependencies in form children; apparently one of the form
1171      * widget's many talents is the inability to manage the vertical and
1172      * horizontal attachments independently...
1173      */
1174     XtVaSetValues(w[widest], XmNtopAttachment, XmATTACH_SELF, NULL);
1175     /*
1176      * attach the right side of the smaller labels to the right side of
1177      * the widest label
1178      */
1179     for(i = 0; i < 4; i++)
1180         if(i != widest)
1181             XtVaSetValues(w[i],
1182                           XmNleftAttachment, XmATTACH_NONE,
1183                           XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
1184                           XmNrightWidget, w[widest],
1185                           NULL);
1186 }
1187
1188 /*
1189  * ------------------------------------------------------------------------
1190  * Name: ParseFileNameSpec
1191  *
1192  * Description:
1193  *
1194  *     Parse the passed file name to create a file selection box filter
1195  *     pattern and the name only portion of the full name spec.
1196  *
1197  *     It is the caller's responsibility to free the allocated memory
1198  *     returned in 'pattern' and 'name_only' using XmStringFree and
1199  *     XtFree respectively.
1200  *
1201  * Return value:
1202  *
1203  *     None.
1204  *
1205  *
1206  */
1207 static void
1208 ParseFileNameSpec(const char* file_name,
1209                   XmString* pattern_xmstr,
1210                   char** name_only)
1211 {
1212     String ptr;
1213     String pattern;
1214     /*
1215      * start off with a copy of the file name, ensuring there is
1216      * enough space for the added "*" and the string terminator.
1217      */
1218     pattern = XtMalloc(strlen(file_name)+2);
1219     strcpy(pattern, file_name);
1220     /*
1221      * find the last slash
1222      */
1223     ptr = DtStrrchr(pattern, '/');
1224     if(ptr != (String)NULL)
1225     {
1226         /*
1227          * grab the name portion of the file name
1228          */
1229         *name_only = XtNewString(ptr+1);
1230         /*
1231          * set the wildcard character immediately following the last
1232          * slash
1233          */
1234         strcpy(ptr+1, "*");
1235         *pattern_xmstr = XmStringCreateLocalized(pattern);
1236     }
1237     else
1238     {
1239         /*
1240          * no slash found; use the default pattern
1241          */
1242         *pattern_xmstr = (XmString)NULL;
1243         *name_only = XtNewString(file_name);
1244     }
1245     XtFree(pattern);
1246 }
1247
1248 /*
1249  * ------------------------------------------------------------------------
1250  * Name: PresentErrorDialog
1251  *
1252  * Description:
1253  *
1254  *     This is a utility function that will present an Error Dialog. It
1255  *     takes a title, a message, and a variable list of Strings to
1256  *     include in the message. The message parm is treated like a
1257  *     printf-style format string, except that only the "%s" directive is
1258  *     supported.
1259  *
1260  *     This function is to be used exclusively by the default
1261  *     resource procedures (e.g. _DtPrintSetupBoxVerifyXPrinterProc).
1262  *
1263  *     The variable list of String parms must be terminated by
1264  *     (String)NULL.
1265  *
1266  * Return Value:
1267  *
1268  *     None.
1269  *
1270  */
1271 static void
1272 PresentErrorDialog(
1273                    Widget w,
1274                    String title,
1275                    String message,
1276                    ...)
1277 {
1278     Arg args[15];
1279     Cardinal n;
1280     String expanded_message;
1281     String str_n;
1282     XmString message_xmstr;
1283     XmString title_xmstr;
1284     int message_len;
1285     va_list arg_marker;
1286     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
1287     Widget wmshell_ancestor;
1288     WidgetList wmshell_ancestors_children = (WidgetList)NULL;
1289     
1290     wmshell_ancestor = GetWMShellAncestor(w);
1291
1292     if (wmshell_ancestor)
1293     {
1294         n = 0;
1295         XtSetArg(args[n], XmNchildren, &wmshell_ancestors_children); n++;
1296         XtGetValues(wmshell_ancestor, args, n);
1297     }
1298
1299     if(dpd->error_message_box != (Widget)NULL)
1300     {
1301         /*
1302          * present only one message box
1303          */
1304         XtDestroyWidget(dpd->error_message_box);
1305     }
1306     
1307     title_xmstr = XmStringCreateLocalized(title);
1308     /*
1309      * determine length of expanded message
1310      */
1311     message_len = strlen(message);
1312     va_start(arg_marker, message);
1313     while((str_n = va_arg(arg_marker, String)) != (String)NULL)
1314     {
1315         message_len += strlen(str_n);
1316     }
1317     va_end(arg_marker);
1318     ++message_len;
1319     /*
1320      * expand the message
1321      */
1322     expanded_message = XtMalloc(message_len);
1323     va_start(arg_marker, message);
1324     vsprintf(expanded_message, message, arg_marker);
1325     va_end(arg_marker);
1326     /*
1327      * convert message to XmString
1328      */
1329     message_xmstr = XmStringCreateLocalized(expanded_message);
1330     XtFree(expanded_message);
1331     /*
1332      * create the error dialog
1333      */
1334     n = 0;
1335     XtSetArg(args[n], XmNdialogTitle, title_xmstr); n++;
1336     XtSetArg(args[n], XmNmessageString, message_xmstr); n++;
1337     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
1338     XtSetArg(args[n], XmNdeleteResponse, XmDESTROY); n++;
1339     dpd->error_message_box = 
1340         XmCreateErrorDialog(wmshell_ancestors_children ?
1341                             wmshell_ancestors_children[0] :
1342                             wmshell_ancestor,
1343                             "_PsubDefProcErrorMsg", args, n);
1344     XmStringFree(title_xmstr);
1345     XmStringFree(message_xmstr);
1346
1347     XtUnmanageChild(XtNameToWidget(dpd->error_message_box, "Cancel"));
1348     XtUnmanageChild(XtNameToWidget(dpd->error_message_box, "Help"));
1349
1350     XtAddCallback(dpd->error_message_box, XmNokCallback,
1351                   DestroyWidgetCB, (XtPointer)dpd->error_message_box);
1352     XtAddCallback(dpd->error_message_box, XmNcancelCallback,
1353                   DestroyWidgetCB, (XtPointer)dpd->error_message_box);
1354     XtAddCallback(dpd->error_message_box, XmNdestroyCallback,
1355                   ErrorMessageDestroyCB, (XtPointer)w);
1356     /*
1357      * manage the message box according to the hint
1358      */
1359     if(DtPRINT_HINT_MESSAGES_OK == dpd->messages_hint)
1360         XtManageChild(dpd->error_message_box);
1361
1362 #ifdef XXX_JUNGLE_REMOVE
1363     /*
1364      * manage the message box only if the psub is mapped
1365      * and the focus is not in the printer name field
1366      */
1367     {
1368         XWindowAttributes attr;
1369         Status status;
1370         Window window = XtWindow(w);
1371         if(window)
1372         {
1373             status = XGetWindowAttributes(XtDisplay(w), window, &attr);
1374             if(status == 0 || attr.map_state == IsViewable)
1375             {
1376                 Widget name_w = XtNameToWidget(w, "Name");
1377                 Widget child;
1378                 
1379                 for(child = XmGetFocusWidget(w);
1380                     child != wmshell_ancestor && child != name_w
1381                     && child != (Widget)NULL;
1382                     child = XtParent(child));
1383
1384                 if(child != name_w && child != (Widget)NULL)
1385                     XtManageChild(dpd->error_message_box);
1386             }
1387         }
1388     }
1389 #endif /* XXX_JUNGLE_REMOVE */
1390 }
1391
1392 /*
1393  * ------------------------------------------------------------------------
1394  * Name: PresentHelp
1395  *
1396  * Description:
1397  *
1398  *     Presents a help dialog whose widget instance may be shared between
1399  *     the default dialogs.
1400  *
1401  * Return value:
1402  *
1403  *     None.
1404  *
1405  */
1406 static void PresentHelp(
1407                         Widget w,
1408                         const char* help_volume,
1409                         const char* location_id)
1410 {
1411     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
1412     Widget wmshell_ancestor;
1413     Widget dialog_shell;
1414
1415     char* hv = 0;
1416     char* lid = 0;
1417     
1418     
1419     wmshell_ancestor = GetWMShellAncestor(w);
1420
1421     if((Widget)NULL == dpd->help_dialog)
1422     {
1423         Arg args[5];
1424         Cardinal n;
1425         XmString title;
1426         
1427         n = 0;
1428         title = XmStringCreateLocalized(HELP_DLG_TITLE);
1429         XtSetArg(args[n], XmNdialogTitle, title); n++;
1430         dpd->help_dialog =
1431             DtCreateHelpDialog(wmshell_ancestor, "_PsubDefProcHelpDialog",
1432                                args, n);
1433         XmStringFree(title);
1434         XtAddCallback(dpd->help_dialog, XmNdestroyCallback,
1435                       HelpDialogDestroyCB, (XtPointer)w);
1436     }
1437     /*
1438      * set the help volume and location
1439      */
1440     XtVaSetValues(dpd->help_dialog,
1441                   DtNhelpVolume, help_volume,
1442                   DtNlocationId, location_id,
1443                   DtNhelpType, DtHELP_TYPE_TOPIC,
1444                   NULL);
1445     /*
1446      * pop up the help dialog
1447      */
1448     XtManageChild(dpd->help_dialog);
1449     dialog_shell = XtParent(dpd->help_dialog);
1450     if(None != XtWindow(dialog_shell))
1451         XRaiseWindow(XtDisplay(dialog_shell), XtWindow(dialog_shell));
1452 }
1453
1454 /*
1455  * ------------------------------------------------------------------------
1456  * Name: PresentVerifyError
1457  *
1458  * Description:
1459  *
1460  *     Presents a error dialog appropriate for an error status returned
1461  *     by _DtPrintVerifyXPrinter.
1462  *
1463  * Return value:
1464  *
1465  *     None.
1466  *
1467  */
1468 static void
1469 PresentVerifyError(
1470                    Widget w,
1471                    XtEnum status,
1472                    String printer_spec)
1473 {
1474     String printer_name;
1475     String display_spec;
1476     
1477     _DtPrintParseXPrinterSpecifier(printer_spec,
1478                                    &printer_name,
1479                                    &display_spec);
1480     switch(status)
1481     {
1482     case DtPRINT_PRINTER_MISSING:
1483         PresentErrorDialog(w, INVALID_PRINTER_TITLE,
1484                            PRINTER_MISSING_MESSAGE,
1485                            printer_spec,
1486                            (String)NULL);
1487         break;
1488
1489     case DtPRINT_NO_DEFAULT:
1490         PresentErrorDialog(w, INVALID_PRINTER_TITLE,
1491                            NO_DEFAULT_MESSAGE,
1492                            (String)NULL);
1493         break;
1494
1495     case DtPRINT_NO_DEFAULT_DISPLAY:
1496         PresentErrorDialog(w, INVALID_PRINTER_TITLE,
1497                            NO_DEFAULT_DISPLAY_MESSAGE,
1498                            printer_name,
1499                            (String)NULL);
1500         break;
1501         
1502     case DtPRINT_NO_PRINTER:
1503         PresentErrorDialog(w, INVALID_PRINTER_TITLE,
1504                            INVALID_PRINTER_MESSAGE,
1505                            printer_name, display_spec,
1506                            (String)NULL);
1507         break;
1508
1509     case DtPRINT_NOT_XP_DISPLAY:
1510         PresentErrorDialog(w, INVALID_PRINTER_TITLE,
1511                            NOT_XP_DISPLAY_MESSAGE,
1512                            display_spec,
1513                            (String)NULL);
1514         break;
1515
1516     case DtPRINT_INVALID_DISPLAY:
1517         PresentErrorDialog(w, INVALID_PRINTER_TITLE,
1518                            INVALID_DISPLAY_MESSAGE,
1519                            display_spec,
1520                            (String)NULL);
1521         break;
1522     }
1523     XtFree(printer_name);
1524     XtFree(display_spec);
1525 }
1526
1527
1528 /*
1529  * ------------------------------------------------------------------------
1530  * Name: PrinterInfoDestroyCB
1531  *
1532  * Description:
1533  *
1534  *     Reset data items used in conjunction with the
1535  *     printer information selection dialog.
1536  *
1537  * Return value:
1538  *
1539  *     None.
1540  *
1541  */
1542 static void
1543 PrinterInfoDestroyCB(
1544                     Widget w,
1545                     XtPointer client_data,
1546                     XtPointer call_data)
1547 {
1548     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(client_data);
1549
1550     dpd->printer_info_box = (Widget)NULL;
1551 }
1552
1553 /*
1554  * ------------------------------------------------------------------------
1555  * Name: PrinterInfoHelpCB
1556  *
1557  * Description:
1558  *
1559  *     Display context sensitive help.
1560  *
1561  * Return value:
1562  *
1563  *     None.
1564  *
1565  */
1566 static void
1567 PrinterInfoHelpCB(
1568                   Widget w,
1569                   XtPointer client_data,
1570                   XtPointer call_data)
1571 {
1572     PresentHelp((Widget)client_data, HELP_VOLUME, PRINTER_INFO_HELP_ID);
1573 }
1574
1575 /*
1576  * ------------------------------------------------------------------------
1577  * Name: SelectFileDestroyCB
1578  *
1579  * Description:
1580  *
1581  *     Reset data items used in conjunction with the
1582  *     file selection dialog.
1583  *
1584  * Return value:
1585  *
1586  *     None.
1587  *
1588  */
1589 static void
1590 SelectFileDestroyCB(
1591                     Widget w,
1592                     XtPointer client_data,
1593                     XtPointer call_data)
1594 {
1595     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(client_data);
1596
1597     dpd->file_selection_box = (Widget)NULL;
1598 }
1599
1600 /*
1601  * ------------------------------------------------------------------------
1602  * Name: SelectFileHelpCB
1603  *
1604  * Description:
1605  *
1606  *     Display context sensitive help.
1607  *
1608  * Return value:
1609  *
1610  *     None.
1611  *
1612  */
1613 static void
1614 SelectFileHelpCB(
1615                  Widget w,
1616                  XtPointer client_data,
1617                  XtPointer call_data)
1618 {
1619     PresentHelp((Widget)client_data, HELP_VOLUME, SELECT_FILE_HELP_ID);
1620 }
1621
1622 /*
1623  * ------------------------------------------------------------------------
1624  * Name: SelectPrinterCB
1625  *
1626  * Description:
1627  *
1628  *     Callback to handle the printer selection box OK and Cancel
1629  *     buttons.
1630  *
1631  * Return value:
1632  *
1633  *     None.
1634  *
1635  */
1636 static void
1637 SelectPrinterCB(
1638                 Widget w,
1639                 XtPointer client_data,
1640                 XtPointer call_data)
1641 {
1642     XmSelectionBoxCallbackStruct* cbs =
1643         (XmSelectionBoxCallbackStruct*)call_data;
1644     Widget psub = (Widget)client_data;
1645     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(psub);
1646     int i;
1647     String printer_spec;
1648
1649     /*
1650      * close the info dialog display connection if it's been opened
1651      */
1652     CloseSelectPrinterInfoConnection(dpd);
1653
1654     switch(cbs->reason)
1655     {
1656     case XmCR_OK:
1657         /*
1658          * set the selected printer name in the PrintSetupBox
1659          */
1660         printer_spec = FindSelectedPrinter(XtDisplay(psub), dpd);
1661         if((String)NULL != printer_spec)
1662         {
1663             XtVaSetValues(psub, DtNprinterName, printer_spec, NULL);
1664             XtFree(printer_spec);
1665         }
1666         /*
1667          * no break
1668          */
1669
1670     case XmCR_CANCEL:
1671         /*
1672          * deallocate and reset the lists
1673          */
1674         FreeSelectPrinterData(dpd);
1675         if(dpd->printer_list_box != (Widget)NULL)
1676             XmListDeleteAllItems(dpd->printer_list_box);
1677         break;
1678     }
1679 }
1680
1681 /*
1682  * ------------------------------------------------------------------------
1683  * Name: SelectPrinterDestroyCB
1684  *
1685  * Description:
1686  *
1687  *     Deallocate and reset data items used in conjunction with the
1688  *     printer selection dialog.
1689  *
1690  * Return value:
1691  *
1692  *     None.
1693  *
1694  */
1695 static void
1696 SelectPrinterDestroyCB(
1697                        Widget w,
1698                        XtPointer client_data,
1699                        XtPointer call_data)
1700 {
1701     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(client_data);
1702
1703     dpd->printer_selection_box = (Widget)NULL;
1704     dpd->printer_list_box = (Widget)NULL;
1705     CloseSelectPrinterInfoConnection(dpd);
1706     FreeSelectPrinterData(dpd);
1707 }
1708
1709 /*
1710  * ------------------------------------------------------------------------
1711  * Name: SelectPrinterHelpCB
1712  *
1713  * Description:
1714  *
1715  *     Display context sensitive help.
1716  *
1717  * Return value:
1718  *
1719  *     None.
1720  *
1721  */
1722 static void
1723 SelectPrinterHelpCB(
1724                     Widget w,
1725                     XtPointer client_data,
1726                     XtPointer call_data)
1727 {
1728     PresentHelp((Widget)client_data, HELP_VOLUME, SELECT_PRINTER_HELP_ID);
1729 }
1730
1731 /*
1732  * ------------------------------------------------------------------------
1733  * Name: SelectPrinterInfoCB
1734  *
1735  * Description:
1736  *
1737  *     Callback attached to the printer selection box "Info..."
1738  *     button. The "Info..." button is intended to behave just like the
1739  *     PrintSetupBox "Info..." button, so it is implemented to call the
1740  *     procedure set for the PrintSetupBox DtNprinterInfoProc resource.
1741  *     As such, this function needs to open a new display connection to
1742  *     the print server indicated by the currently selected printer in
1743  *     the list. The connection is not closed until a selection is made
1744  *     in the list, or the printer selection dialog is dismissed. This is
1745  *     because no assumptions about the Printer Info dialog's widget
1746  *     heirarchy can be made.
1747  *
1748  * Return value:
1749  *
1750  *     None.
1751  *
1752  */
1753 static void
1754 SelectPrinterInfoCB(
1755                     Widget w,
1756                     XtPointer client_data,
1757                     XtPointer call_data)
1758 {
1759     Widget psub = (Widget)client_data;
1760     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(psub);
1761     DtPrintSetupProc info_proc;
1762
1763     CloseSelectPrinterInfoConnection(dpd);
1764     XtVaGetValues(psub, DtNprinterInfoProc, &info_proc, NULL);
1765     if((DtPrintSetupProc)NULL != info_proc)
1766     {
1767         String printer_spec;
1768         
1769         printer_spec = FindSelectedPrinter(XtDisplay(psub), dpd);
1770         if((String)NULL != printer_spec)
1771         {
1772             String new_printer_spec; /*
1773                                       * will always be set to NULL by
1774                                       * _DtPrintVerifyXPrinter when
1775                                       * called from within this routine
1776                                       */
1777             XtEnum status;
1778             
1779             /*
1780              * open a connection to the X printer
1781              */
1782             status =
1783                 _DtPrintVerifyXPrinter(psub,
1784                                        printer_spec,
1785                                        &new_printer_spec,
1786                                        &dpd->select_printer_info_display,
1787                                        &dpd->select_printer_info_context);
1788             if(status == DtPRINT_SUCCESS)
1789             {
1790                 DtPrintSetupData psd;
1791
1792                 memset(&psd, 0, sizeof(DtPrintSetupData));
1793                 psd.printer_name = printer_spec;
1794                 psd.print_display = dpd->select_printer_info_display;
1795                 psd.print_context = dpd->select_printer_info_context;
1796                 (*info_proc)(psub, &psd);
1797             }
1798             else
1799             {
1800                 /*
1801                  * this should only happen if, while a user is viewing
1802                  * the printer selection dialog, a server rehash is
1803                  * performed that deletes the currently selected printer
1804                  */
1805                 PresentVerifyError(w, status, printer_spec);
1806             }
1807             XtFree(printer_spec);
1808         }
1809     }
1810 }
1811
1812 /*
1813  * ------------------------------------------------------------------------
1814  * Name: SelectPrinterItemCB
1815  *
1816  * Description:
1817  *
1818  *     Callback to handle the a selection in the printer selection list
1819  *     box.
1820  *
1821  * Return value:
1822  *
1823  *     None.
1824  *
1825  */
1826 static void
1827 SelectPrinterItemCB(
1828                     Widget w,
1829                     XtPointer client_data,
1830                     XtPointer call_data)
1831 {
1832     XmListCallbackStruct* cbs =
1833         (XmListCallbackStruct*)call_data;
1834     Widget psub = (Widget)client_data;
1835     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(psub);
1836     Widget info_button;
1837
1838     if(dpd->selected_printer != cbs->item_position)
1839     {
1840         dpd->selected_printer = cbs->item_position;
1841         info_button = XtNameToWidget(dpd->printer_selection_box, "*Apply");
1842         if(0 == dpd->selected_printer)
1843             XtSetSensitive(info_button, False);
1844         else
1845             XtSetSensitive(info_button, True);
1846         /*
1847          * update the default printer info dialog if it is visible
1848          */
1849         if(dpd->printer_info_box && XtIsManaged(dpd->printer_info_box))
1850             SelectPrinterInfoCB(w, client_data, (XtPointer)NULL);
1851     }
1852 }
1853
1854 /*
1855  * ------------------------------------------------------------------------
1856  * Name: SetListBoxSelection
1857  *
1858  * Description:
1859  *
1860  *
1861  * Return value:
1862  *
1863  *     None.
1864  *
1865  */
1866 static void
1867 SetListBoxSelection(Widget list_box, int position)
1868 {
1869     int visible_item_count;
1870     int item_count;
1871     int middle_offset;
1872     int first_visible_pos;
1873     /*
1874      * Scroll the list, making the item at the indicated position
1875      * visible in the center of the list box, and make
1876      * it the initial selection.
1877      */
1878     XtVaGetValues(list_box,
1879                   XmNitemCount, &item_count,
1880                   XmNvisibleItemCount, &visible_item_count,
1881                   NULL);
1882
1883     if(item_count > visible_item_count)
1884     {
1885         middle_offset = (visible_item_count+1) / 2;
1886         if(position > middle_offset)
1887             if(position > item_count - middle_offset)
1888                 first_visible_pos = item_count - visible_item_count +1;
1889             else
1890                 first_visible_pos = position - middle_offset + 1;
1891         else
1892             first_visible_pos = 1;
1893         XmListSetPos(list_box, first_visible_pos);
1894     }
1895
1896     if(position > 0)
1897         XmListSelectPos(list_box, position, True);
1898     else
1899         XmListDeselectAllItems(list_box);
1900 }
1901
1902 /*
1903  * ------------------------------------------------------------------------
1904  * Name: UpdateFileNameCB
1905  *
1906  * Description:
1907  *
1908  *     Updates the PrintSetupBox fileName resource based on the selection
1909  *     make in the file selection box.
1910  *
1911  * Return value:
1912  *
1913  *     None.
1914  *
1915  */
1916 static void 
1917 UpdateFileNameCB(
1918                  Widget w,
1919                  XtPointer client_data,
1920                  XtPointer call_data)
1921 {
1922     Widget text_field;
1923     Widget psub = (Widget)client_data;
1924     String file_name;
1925     /*
1926      * get the file name from the file selection box text field
1927      */
1928     text_field = XtNameToWidget(w, "Text");
1929     if(text_field)
1930     {
1931         XtVaGetValues(text_field, XmNvalue, &file_name, NULL);
1932         if(file_name)
1933         {
1934             /*
1935              * set the file name in the print setup box
1936              */
1937             XtVaSetValues(psub, DtNfileName, file_name, NULL);
1938             /*
1939              * free the file name retrieved from the text field
1940              */
1941             XtFree(file_name);
1942         }
1943     }
1944 }
1945
1946 /*
1947  * ------------------------------------------------------------------------
1948  * Name: _DtPrintDefProcInitialize
1949  *
1950  * Description:
1951  *
1952  *     
1953  *
1954  * Return value:
1955  *
1956  *
1957  */
1958 void
1959 _DtPrintDefProcInitialize(Widget w)
1960 {
1961     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
1962     
1963     dpd->error_message_box = (Widget)NULL;
1964     dpd->messages_hint = DtPRINT_HINT_MESSAGES_OK;
1965     dpd->help_dialog = (Widget)NULL;
1966     dpd->file_selection_box = (Widget)NULL;
1967     dpd->printer_selection_box = (Widget)NULL;
1968     dpd->printer_list_box = (Widget)NULL;
1969     dpd->xp_server_list = (String*)NULL;
1970     dpd->xp_server_count = 0;
1971     dpd->printer_lists = (DtPrintSelectPrinterList*)NULL;
1972     dpd->selected_printer = 0;
1973     dpd->select_printer_info_display = (Display*)NULL;
1974     dpd->select_printer_info_context = (XPContext)None;
1975     dpd->printer_info_box = (Widget)NULL;
1976
1977     XtAddCallback(w, XmNdestroyCallback,
1978                   DtPrintDefProcDestroyCB, (XtPointer)NULL);
1979 }
1980
1981 /*
1982  * ------------------------------------------------------------------------
1983  * Name: _DtPrintDefProcManageErrorBox
1984  *
1985  * Description:
1986  *
1987  *     Manage the Error Message Box if it exists.
1988  *
1989  * Return value:
1990  *
1991  *
1992  */
1993 void
1994 _DtPrintDefProcManageErrorBox(
1995                               DtPrintDefaultProcData* dpd)
1996 {
1997     if(dpd->error_message_box != (Widget)NULL)
1998         XtManageChild(dpd->error_message_box);
1999 }
2000
2001 /*
2002  * ------------------------------------------------------------------------
2003  * Name: _DtPrintSetupBoxXPrinterInfoProc
2004  *
2005  * Description:
2006  *
2007  *     Default Xp mode function for the DtNprinterInfoProc resource.
2008  *
2009  * Return value:
2010  *
2011  *
2012  */
2013 XtEnum
2014 _DtPrintSetupBoxXPrinterInfoProc(
2015                                  Widget w,
2016                                  DtPrintSetupData* print_data)
2017 {
2018     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
2019     Widget wmshell_ancestor;
2020     Widget ctl;
2021     XmString label;
2022     char* attr_value_ct;
2023     String attr_value;
2024     XmString empty_label;
2025     Widget name_label_top;
2026     Position max_y, y;
2027     Dimension height;
2028     Widget manager = NULL;
2029     Widget dialog_shell;
2030     
2031     wmshell_ancestor = GetWMShellAncestor(w);
2032     _DtTurnOnHourGlass(wmshell_ancestor);
2033     empty_label = XmStringCreateLocalized("");
2034     /*
2035      * if needed, create the printer information dialog
2036      */
2037     if(dpd->printer_info_box == (Widget)NULL)
2038     {
2039         XtEnum status = CreatePrinterInfoBox(wmshell_ancestor, w, dpd);
2040         if(status != DtPRINT_SUCCESS)
2041         {
2042             _DtTurnOffHourGlass(wmshell_ancestor);
2043             return status;
2044         }
2045         dialog_shell = XtParent(dpd->printer_info_box);
2046     }
2047     else
2048     {
2049         /*
2050          * hide the widget during re-layout
2051          */
2052         manager = XtNameToWidget(dpd->printer_info_box, "*PrinterInfoForm");
2053         XtUnmapWidget(dpd->printer_info_box);
2054         dialog_shell = XtParent(dpd->printer_info_box);
2055         XtVaSetValues(dialog_shell, XmNallowShellResize, False, NULL);
2056         XtUnmanageChild(manager);
2057     }
2058     /*
2059      * description
2060      */
2061     ctl = XtNameToWidget(dpd->printer_info_box, "*Description");
2062     XtVaSetValues(ctl, XmNlabelString, empty_label, NULL);
2063     attr_value_ct = XpGetOneAttribute(print_data->print_display,
2064                                       print_data->print_context,
2065                                       XPPrinterAttr,
2066                                       "descriptor");
2067     if((char*)NULL != attr_value_ct)
2068     {
2069         attr_value =
2070             CompoundTextToString(XtDisplay(w), (unsigned char*)attr_value_ct);
2071         XFree(attr_value_ct);
2072         if((String)NULL != attr_value)
2073         {
2074             label = XmStringGenerate((XtPointer)attr_value, (XmStringTag)NULL,
2075                                      XmMULTIBYTE_TEXT, (XmStringTag)NULL);
2076             XtFree(attr_value);
2077             XtVaSetValues(ctl, XmNlabelString, label, NULL);
2078             XmStringFree(label);
2079         }
2080     }
2081     /*
2082      * set the top attachment for the name label
2083      */
2084     XtVaGetValues(ctl, XmNy, &y, XmNheight, &height, NULL);
2085     max_y = y + height;
2086     name_label_top = ctl;
2087     ctl = XtNameToWidget(dpd->printer_info_box, "*DescriptionLabel");
2088     XtVaGetValues(ctl, XmNy, &y, XmNheight, &height, NULL);
2089     if(y+height > max_y)
2090         name_label_top = ctl;
2091     ctl = XtNameToWidget(dpd->printer_info_box, "*NameLabel");
2092     XtVaSetValues(ctl, XmNtopWidget, name_label_top, NULL);
2093     /*
2094      * printer name
2095      */
2096     ctl = XtNameToWidget(dpd->printer_info_box, "*Name");
2097     label = XmStringCreateLocalized(print_data->printer_name);
2098     XtVaSetValues(ctl, XmNlabelString, label, NULL);
2099     XmStringFree(label);
2100     /*
2101      * document format
2102      */
2103     ctl = XtNameToWidget(dpd->printer_info_box, "*Format");
2104     XtVaSetValues(ctl, XmNlabelString, empty_label, NULL);
2105     attr_value = XpGetOneAttribute(print_data->print_display,
2106                                    print_data->print_context,
2107                                    XPDocAttr,
2108                                    "document-format");
2109     if((String)NULL != attr_value)
2110     {
2111         char* format_start;
2112         format_start = strchr(attr_value, '{');
2113         if((char*)NULL != format_start)
2114         {
2115             char* format_end;
2116             ++format_start;
2117             format_end = strchr(format_start, '}');
2118             if((char*)NULL != format_end)
2119             {
2120                 *format_end = '\0';
2121                 label = XmStringCreateLocalized(format_start);
2122                 XtVaSetValues(ctl, XmNlabelString, label, NULL);
2123                 XmStringFree(label);
2124             }
2125         }
2126         XFree(attr_value);
2127     }
2128     /*
2129      * printer model
2130      */
2131     ctl = XtNameToWidget(dpd->printer_info_box, "*Model");
2132     XtVaSetValues(ctl, XmNlabelString, empty_label, NULL);
2133     attr_value_ct = XpGetOneAttribute(print_data->print_display,
2134                                       print_data->print_context,
2135                                       XPPrinterAttr,
2136                                       "printer-model");
2137     if((char*)NULL != attr_value_ct)
2138     {
2139         attr_value =
2140             CompoundTextToString(XtDisplay(w), (unsigned char*)attr_value_ct);
2141         XFree(attr_value_ct);
2142         if((String)NULL != attr_value)
2143         {
2144             label = XmStringGenerate((XtPointer)attr_value, (XmStringTag)NULL,
2145                                      XmCHARSET_TEXT, (XmStringTag)NULL);
2146             XtFree(attr_value);
2147             XtVaSetValues(ctl, XmNlabelString, label, NULL);
2148             XmStringFree(label);
2149         }
2150     }
2151     /*
2152      * pop up the printer info dialog and return
2153      */
2154     XmStringFree(empty_label);
2155     if(manager)
2156     {
2157         XtVaSetValues(dialog_shell, XmNallowShellResize, True, NULL);
2158         XtManageChild(manager);
2159         XtMapWidget(dpd->printer_info_box);
2160     }
2161     XtManageChild(dpd->printer_info_box);
2162     if(None != XtWindow(dialog_shell))
2163         XRaiseWindow(XtDisplay(dialog_shell), XtWindow(dialog_shell));
2164     _DtTurnOffHourGlass(wmshell_ancestor);
2165     return DtPRINT_SUCCESS;
2166 }
2167
2168 /*
2169  * ------------------------------------------------------------------------
2170  * Name: _DtPrintSetupBoxSelectFileProc
2171  *
2172  * Description:
2173  *
2174  *     Default function for the DtNselectFileProc resource.
2175  *
2176  * Return value:
2177  *
2178  *
2179  */
2180 XtEnum
2181 _DtPrintSetupBoxSelectFileProc(
2182                                Widget w,
2183                                DtPrintSetupData* print_data)
2184 {
2185     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
2186     String name_only;
2187     String file_name;
2188     XmString pattern;
2189     Widget file_list;
2190     Widget text_field;
2191     Widget wmshell_ancestor;
2192     
2193     wmshell_ancestor = GetWMShellAncestor(w);
2194     _DtTurnOnHourGlass(wmshell_ancestor);
2195     /*
2196      * if needed, create the file selection dialog
2197      */
2198     if(dpd->file_selection_box == (Widget)NULL)
2199     {
2200         XtEnum status = CreateFileSelectionBox(wmshell_ancestor, w, dpd);
2201         if(status != DtPRINT_SUCCESS)
2202         {
2203             _DtTurnOffHourGlass(wmshell_ancestor);
2204             return status;
2205         }
2206     }
2207     /*
2208      * get the file name passed from the PrintSetupBox
2209      */
2210     file_name = print_data->dest_info;
2211     /*
2212      * parse the file name to create the filter pattern and the name only
2213      * portion of the full name spec
2214      */
2215     ParseFileNameSpec(file_name, &pattern, &name_only);
2216     /*
2217      * set the filter pattern in the file selection box
2218      */
2219     XtVaSetValues(dpd->file_selection_box, XmNpattern, pattern, NULL);
2220     if(pattern != (XmString)NULL)
2221         XmStringFree(pattern);
2222     /*
2223      * select the current file name in the file names list
2224      */
2225     file_list = XtNameToWidget(dpd->file_selection_box, "*ItemsList");
2226     if(file_list != (Widget)NULL)
2227     {
2228         XmString file_name_xmstr;
2229         int position;
2230
2231         text_field = XtNameToWidget(dpd->file_selection_box, "Text");
2232         if(text_field != (Widget)NULL)
2233         {
2234             String dir_spec;
2235             /*
2236              * recreate the file name from the name_only and the current
2237              * dir spec as determined by the file selection box
2238              *
2239              * Note: the char* value retrieved directly from the text
2240              * field is used, because forming the file name from a
2241              * concatenation of XmStrings causes XmListItemPos to fail
2242              * even though the file name is actually in the list.
2243              */
2244             XtVaGetValues(text_field, XmNvalue, &dir_spec, NULL);
2245             file_name = XtMalloc(strlen(dir_spec)+strlen(name_only)+1);
2246             strcpy(file_name, dir_spec);
2247             strcat(file_name, name_only);
2248             file_name_xmstr = XmStringCreateLocalized(file_name);
2249             XtFree(dir_spec);
2250             XtFree(file_name);
2251         }
2252         else
2253             file_name_xmstr = XmStringCreateLocalized(file_name);
2254         /*
2255          * find the position of the file name in the list
2256          */
2257         position = XmListItemPos(file_list, file_name_xmstr);
2258         SetListBoxSelection(file_list, position);
2259         if(position == 0)
2260         {
2261             /*
2262              * The file name is not in the list. Manually set in the
2263              * "Selection" text field.
2264              */
2265             XtVaSetValues(dpd->file_selection_box,
2266                           XmNdirSpec, file_name_xmstr,
2267                           NULL);
2268         }
2269         XmStringFree(file_name_xmstr);
2270     }
2271     XtFree(name_only);
2272     /*
2273      * pop up the file selection dialog and return
2274      */
2275     XtManageChild(dpd->file_selection_box);
2276     _DtTurnOffHourGlass(wmshell_ancestor);
2277     return DtPRINT_SUCCESS;
2278 }
2279
2280 /*
2281  * ------------------------------------------------------------------------
2282  * Name: _DtPrintSetupBoxSelectXPrinterProc
2283  *
2284  * Description:
2285  *
2286  *     Default Xp mode function for the DtNselectPrinterProc resource.
2287  *
2288  * Return value:
2289  *
2290  *
2291  */
2292 XtEnum
2293 _DtPrintSetupBoxSelectXPrinterProc(
2294                                    Widget w,
2295                                    DtPrintSetupData* print_data)
2296 {
2297     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
2298     Widget wmshell_ancestor;
2299     XmStringTable items;
2300     int item_count;
2301     int i;
2302     XmTabList tab_list;
2303     XmRenderTable render_table, new_render_table;
2304     int count;
2305     XmStringTag* tags;
2306     XmRendition rendition;
2307     Arg args[2];
2308     Cardinal n;
2309
2310     wmshell_ancestor = GetWMShellAncestor(w);
2311     _DtTurnOnHourGlass(wmshell_ancestor);
2312     /*
2313      * build the list of servers and printers
2314      */
2315     if(DtPRINT_SUCCESS != BuildPrinterLists(w, dpd, &item_count))
2316     {
2317         PresentErrorDialog(w, PRLIST_ERROR_TITLE,
2318                            NO_PRINTERS_MESSAGE,
2319                            (String)NULL);
2320         _DtTurnOffHourGlass(wmshell_ancestor);
2321         return DtPRINT_FAILURE;
2322     }
2323     /*
2324      * create the dialog if it doesn't exist
2325      */
2326     if(dpd->printer_selection_box == (Widget)NULL)
2327     {
2328         XtEnum status = CreatePrinterSelectionBox(wmshell_ancestor, w, dpd);
2329         if(status != DtPRINT_SUCCESS)
2330         {
2331             _DtTurnOffHourGlass(wmshell_ancestor);
2332             return status;
2333         }
2334     }
2335     /*
2336      * get a copy of the list widget's render table
2337      */
2338     XtVaGetValues(dpd->printer_list_box,
2339                   XmNrenderTable, &render_table,
2340                   NULL);
2341     render_table = XmRenderTableCopy(render_table, (XmStringTag*)NULL, 0);
2342     /*
2343      * build the item list for the list box
2344      */
2345     count = XmRenderTableGetTags(render_table, &tags);
2346     items = BuildPrinterSelectionItems(XtDisplay(w), dpd, item_count,
2347                                        print_data->printer_name, tags[0]);
2348     /*
2349      * generate a tab list for the items
2350      */
2351     tab_list = XmStringTableProposeTablist(items, item_count,
2352                                            dpd->printer_list_box,
2353                                            20, XmRELATIVE);
2354     /*
2355      * get a copy of the first rendition in the render table
2356      */
2357     rendition = XmRenderTableGetRendition(render_table, tags[0]);
2358     for(i = 0; i < count; i++)
2359         XtFree(tags[i]);
2360     XtFree((char*)tags);
2361     /*
2362      * update the copy with the new tab list
2363      */
2364     n = 0;
2365     XtSetArg(args[n], XmNtabList, tab_list); n++;
2366     XmRenditionUpdate(rendition, args, n);
2367     XmTabListFree(tab_list);
2368     /*
2369      * create a new render table replacing the first entry with the
2370      * updated rendition
2371      */
2372     new_render_table = XmRenderTableAddRenditions(render_table, &rendition,
2373                                                   1, XmMERGE_REPLACE);
2374     XmRenditionFree(rendition);
2375     /*
2376      * set the new render table and list items in the list box
2377      */
2378     XtVaSetValues(dpd->printer_list_box,
2379                   XmNrenderTable, new_render_table,
2380                   XmNitems, items,
2381                   XmNitemCount, item_count,
2382                   NULL);
2383     XmRenderTableFree(new_render_table);
2384     for(i = 0; i < item_count; i++)
2385         XmStringFree(items[i]);
2386     XtFree((char*)items);
2387     SetListBoxSelection(dpd->printer_list_box, dpd->selected_printer);
2388     /*
2389      * disable the info button if nothing is selected
2390      */
2391     if(0 == dpd->selected_printer)
2392         XtSetSensitive(XtNameToWidget(dpd->printer_selection_box, "*Apply"),
2393                        False);
2394     /*
2395      * manage the dialog and return
2396      */
2397     XtManageChild(dpd->printer_selection_box);
2398     _DtTurnOffHourGlass(wmshell_ancestor);
2399     return DtPRINT_SUCCESS;
2400 }
2401
2402 /*
2403  * ------------------------------------------------------------------------
2404  * Name: _DtPrintSetupBoxVerifyXPrinterProc
2405  *
2406  * Description:
2407  *
2408  *     Default function for the DtNverifyPrinterProc resource when the
2409  *     setup mode is XP.
2410  *
2411  *     (this rest of this description outlines the responsibilities of a
2412  *     DtNverifyPrinterProc in general)
2413  *
2414  *     This function verifies the printer name passed in the
2415  *     PrintSetupData structure.
2416  *
2417  *     If needed, the DtNprintSetupMode resource may be obtained via a
2418  *     GetValues call in order to determine the current setup mode.
2419  *
2420  *     It is the responsibility of this proc to return a valid print
2421  *     Display handle and print context by setting the print_display and
2422  *     print_context in the PrintSetupData. Conceptually, this is a
2423  *     side-effect of this proc, but since it will be necessary to open a
2424  *     display connection in order to properly verify the X printer,
2425  *     there's no point in doing it twice.
2426  *
2427  *     If the passed printer name is incomplete, this proc may attempt to
2428  *     determine a default or fully-qualified name (e.g. fill in a
2429  *     missing display spec for an X Printer Specifier). The new default
2430  *     or fully-qualified printer name should be set in the PrintSetupBox
2431  *     by updating the DtNprinterName resource via a SetValues call. If a
2432  *     fully-qualified name cannot be determined, this proc simply
2433  *     returns DtPRINT_FAILURE.
2434  *
2435  *     If the printer cannot be verified, it is the responsibiliy of this
2436  *     function to present an appropriate message to the user.
2437  *
2438  * Return value:
2439  *
2440  *     DtPRINT_SUCCESS
2441  *         if the printer name has been successfully verified.
2442  *     
2443  *     DtPRINT_FAILURE
2444  *         if the printer name is invalid.
2445  *
2446  *
2447  */
2448 XtEnum
2449 _DtPrintSetupBoxVerifyXPrinterProc(
2450                                    Widget w,
2451                                    DtPrintSetupData* psd)
2452 {
2453     DtPrintDefaultProcData* dpd = &PSUB_DefaultProcData(w);
2454     XtEnum status;
2455     String new_printer_spec;
2456     Display* new_display;
2457     XPContext new_context;
2458     Widget wmshell_ancestor;
2459     
2460     wmshell_ancestor = GetWMShellAncestor(w);
2461     _DtTurnOnHourGlass(wmshell_ancestor);
2462     /*
2463      * verify the printer
2464      */
2465     status = _DtPrintVerifyXPrinter(w,
2466                                     psd->printer_name,
2467                                     &new_printer_spec,
2468                                     &new_display,
2469                                     &new_context);
2470     if(status == DtPRINT_SUCCESS)
2471     {
2472         /*
2473          * update the passed print setup data with the new display and
2474          * context
2475          */
2476         psd->print_display = new_display;
2477         psd->print_context = new_context;
2478     }
2479     else
2480     {
2481         /*
2482          * unable to open the printer; present a message to the user
2483          * according to the hint set in the setup data
2484          */
2485         dpd->messages_hint = psd->messages_hint;
2486         PresentVerifyError(w, status,
2487                            new_printer_spec
2488                            ? new_printer_spec : psd->printer_name);
2489         /*
2490          * reset the hint since the error dialog is also used
2491          * by the other default procs
2492          */
2493         dpd->messages_hint = DtPRINT_HINT_MESSAGES_OK;
2494         /*
2495          * this function only indicates success or failure
2496          */
2497         status = DtPRINT_FAILURE;
2498     }
2499     if(new_printer_spec)
2500     {
2501         /*
2502          * set the new printer spec, even if the verify failed
2503          */
2504         XtVaSetValues(w,
2505                       DtNprinterName, new_printer_spec,
2506                       NULL);
2507         XtFree(new_printer_spec);
2508     }
2509     /*
2510      * return
2511      */
2512     _DtTurnOffHourGlass(wmshell_ancestor);
2513     return status;
2514 }