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