Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtPrint / PrintSetupB.c
1 /* $TOG: PrintSetupB.c /main/27 1998/08/06 17:28:56 mgreess $ */
2 /*
3  * DtPrint/PrintSetupB.c
4  */
5 /* (c) Copyright 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC.
6  *     ALL RIGHTS RESERVED
7  * (c) Copyright 1989, 1996 DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
8  * (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1995, 1996,
9  *     HEWLETT-PACKARD COMPANY
10  * (c) Copyright 1996 International Business Machines Corp.
11  * (c) Copyright 1996 Sun Microsystems, Inc.
12  * (c) Copyright 1996 Novell, Inc. 
13  * (c) Copyright 1996 FUJITSU LIMITED.
14  * (c) Copyright 1996 Hitachi.
15  */
16 /*
17  * ------------------------------------------------------------------------
18  * Include Files
19  *
20  */
21 #include <Dt/DtNlUtils.h>
22 #ifdef MAXINT
23 #undef MAXINT
24 #endif
25
26 #include <stdlib.h>
27 #include <values.h>
28 #include <stdio.h>
29
30 #include <Xm/XmAll.h>
31 #include <Xm/ActivatableT.h>
32 #include <Xm/RowColumnP.h>
33 #include <Xm/TraitP.h>
34 #include <Xm/TakesDefT.h>
35
36 #include <Dt/PrintSetupBP.h>
37 #include <Dt/PsubDefProcI.h>
38 #include <Dt/PsubUtilI.h>
39 #include <Dt/PrintI.h>
40
41 /*
42  * ------------------------------------------------------------------------
43  * Constant Definitions
44  *
45  */
46 #define IsButton(w) \
47 (((XtPointer) XmeTraitGet((XtPointer) XtClass((w)), XmQTactivatable) != NULL))
48
49 #define IsAutoButton(psub, w) ( \
50                               w == PSUB_PrinterInfoButton(psub) || \
51                               w == PSUB_SelectPrinterButton(psub) || \
52                               w == PSUB_SelectFileButton(psub) || \
53                               w == PSUB_PrintButton(psub) || \
54                               w == PSUB_SetupButton(psub) || \
55                               w == PSUB_CancelButton(psub) || \
56                               w == PSUB_HelpButton(psub))
57
58 /*
59  * value to indicate initially unspecified resources
60  */
61 #define DtUNSPECIFIED (~0)
62
63 /*
64  * limits
65  */
66 #define MAX_COPIES MAXINT
67
68 /*
69  * defaults
70  */
71 #define WORK_AREA_DEFAULT DtWORK_AREA_BOTTOM
72 #define SETUP_MODE_DEFAULT DtPRINT_SETUP_XP
73
74 #define DESCRIPTION_COLUMNS 35
75 #define FILE_NAME_COLUMNS 27
76 #define PRINTER_NAME_COLUMNS 25
77
78 /*
79  * Xp Attributes
80  */
81 #define XpATTR_DESCRIPTOR "descriptor"
82 #define XpATTR_DOC_ATTRS_SUPPORTED "document-attributes-supported"
83 #define XpATTR_COPY_COUNT "copy-count"
84 #define XpATTR_SETUP_PROVISO "xp-setup-proviso"
85 #define XpATTR_SETUP_STATE "xp-setup-state"
86
87 /*
88  * ------------------------------------------------------------------------
89  * Type Definitions
90  *
91  */
92 typedef enum {
93     DtPRINT_NULL_CHILD,
94     DtPRINT_CANCEL_BUTTON,
95     DtPRINT_FILES_BUTTON,
96     DtPRINT_HELP_BUTTON,
97     DtPRINT_INFO_BUTTON,
98     DtPRINT_PRINT_BUTTON,
99     DtPRINT_PRINTERS_BUTTON,
100     DtPRINT_SETUP_BUTTON
101 } DtPrintSetupBoxChild;
102
103 /*
104  * column oriented geometry definitions
105  */
106 #define PSUB_GEO_COL_COUNT 3
107 #define PSUB_GEO_MAX_ROW 4
108
109 typedef enum {
110     PSUB_GEO_ALIGN_LEFT = 0, /* default */
111     PSUB_GEO_ALIGN_RIGHT,
112     PSUB_GEO_ALIGN_EXPAND
113 } PSUB_GeoBoxAlignment;
114
115 typedef struct
116 {
117     XmKidGeometry geo;
118     PSUB_GeoBoxAlignment align;
119     Dimension orig_width;
120 } PSUB_GeoBoxRec, *PSUB_GeoBox;
121
122 typedef struct
123 {
124     int row_count;
125     PSUB_GeoBoxRec pbox[PSUB_GEO_MAX_ROW][PSUB_GEO_COL_COUNT];
126     XmGeoRowLayout layout_ptr[PSUB_GEO_MAX_ROW];
127     Dimension col_width[PSUB_GEO_COL_COUNT];
128 } PSUB_GeoExtensionRec, *PSUB_GeoExtension ;
129
130 /*
131  * ------------------------------------------------------------------------
132  * External Function Declarations
133  *
134  */
135 /*
136  * Geometry management functions defined in Xm/GeoUtils
137  */
138 extern XmGeoMatrix _XmGeoMatrixAlloc(
139                                      unsigned int numRows,
140                                      unsigned int numBoxes,
141                                      unsigned int extSize);
142 extern Boolean _XmGeoSetupKid(
143                               XmKidGeometry geo,
144                               Widget kidWid);
145 /*
146  * ------------------------------------------------------------------------
147  * Static Function Declarations
148  *
149  */
150 static void ClassInitialize(
151                             void);
152 static void ClassPartInitialize(
153                                 WidgetClass w_class);
154 static void ClosePrintConnection(
155                                  DtPrintSetupBoxWidget psub,
156                                  String old_printer_name,
157                                  Boolean update_gui);
158 static void ClosePrintConnectionCallback(Widget w,
159                                          XtPointer client_data,
160                                          XtPointer call_data);
161 static void ColumnGeoFixUp(
162                            XmGeoMatrix geoSpec,
163                            int action,
164                            XmGeoMajorLayout layoutPtr,
165                            XmKidGeometry rowPtr);
166 static void ColumnGeoPreSet(
167                             PSUB_GeoExtension ext,
168                             int row);
169 static void ColumnGeoRestoreWidths(
170                                    PSUB_GeoExtension ext,
171                                    int row);
172 static void ColumnGeoSaveWidths(
173                                 PSUB_GeoExtension ext,
174                                 int row);
175 static void ColumnGeoSetPreferredWidths(
176                                         PSUB_GeoExtension ext,
177                                         int row);
178 static Boolean ConvertStringToEnum(
179                                    Display *dpy,
180                                    XrmValuePtr args,
181                                    Cardinal *num_args,
182                                    XrmValuePtr from,
183                                    XrmValuePtr to,
184                                    XtPointer *data);
185 static void CopiesTextValueChangedCallback(
186                                        Widget w,
187                                        XtPointer client_data,
188                                        XtPointer call_data);
189 static Widget CreateButton(Widget parent,
190                            String label,
191                            String name,
192                            XmNavigationType nav_type);
193 static Widget CreateButtonGadget(
194                                  Widget parent,
195                                  String label,
196                                  String name,
197                                  XmNavigationType nav_type);
198 static Widget CreateLabelGadget(
199                                 Widget parent,
200                                 String label,
201                                 String name);
202 static String CreateModalPrinterSpec(
203                                      XtEnum name_mode,
204                                      const String full_printer_name);
205 static void DeleteChild(
206                         Widget child);
207 static void DestinationChangedCallback(
208                                        Widget w,
209                                        XtPointer client_data,
210                                        XtPointer call_data);
211 static void Destroy(
212                     Widget w);
213 static XtEnum EstablishPrinter(
214                                DtPrintSetupBoxWidget psub,
215                                DtPrintSetupData* psd);
216 static void GetPrintAttributes(
217                                DtPrintSetupBoxWidget psub);
218 static void Initialize(
219                        Widget rw,
220                        Widget nw,
221                        ArgList args,
222                        Cardinal *num_args);
223 static void InsertChild(
224                         Widget child);
225 static Boolean IsSetupRequired(
226                                DtPrintSetupBoxWidget psub);
227 static void MenuBarFixUp(
228                          XmGeoMatrix geoSpec,
229                          int action,
230                          XmGeoMajorLayout layoutPtr,
231                          XmKidGeometry rowPtr);
232 static void PrintSetupBoxCallback(
233                                   Widget w,
234                                   XtPointer client_data,
235                                   XtPointer call_data);
236 static void SeparatorFixUp(
237                            XmGeoMatrix geoSpec,
238                            int action,
239                            XmGeoMajorLayout layoutPtr,
240                            XmKidGeometry rowPtr);
241 static void SetNewPrinterName(
242                               DtPrintSetupBoxWidget psub,
243                               String new_printer_name,
244                               String old_printer_name);
245 static void SetPrintAttributes(
246                                DtPrintSetupBoxWidget psub);
247 static void SetPSDDestination(
248                               DtPrintSetupBoxWidget psub,
249                               DtPrintSetupData* psd);
250 static XmImportOperator SetSyntheticResForChild(
251                                                 Widget widget,
252                                                 int offset,
253                                                 XtArgVal *value);
254 static Boolean SetValues(
255                          Widget cw,
256                          Widget rw,
257                          Widget nw,
258                          ArgList args,
259                          Cardinal *num_args) ;
260 static int SpanNonWhitespace(
261                              const char* string);
262 static int SpanWhitespace(
263                           const char* string);
264 static void SynthGetFileName(
265                              DtPrintSetupBoxWidget psub);
266 static void SynthGetPrinterName(
267                                 DtPrintSetupBoxWidget psub);
268 static void SynthSetCopies(
269                            DtPrintSetupBoxWidget new_w,
270                            DtPrintSetupBoxWidget current);
271 static void SynthSetFileName(
272                              DtPrintSetupBoxWidget new_w,
273                              DtPrintSetupBoxWidget current);
274 static void SynthSetPrintDestination(
275                                      DtPrintSetupBoxWidget new_w,
276                                      DtPrintSetupBoxWidget current);
277 static void SynthSetPrinterName(
278                                 DtPrintSetupBoxWidget psub,
279                                 String new_printer_name,
280                                 String old_printer_name);
281 static void UpdatePrinterNameCallback(
282                                       Widget w,
283                                       XtPointer client_data,
284                                       XtPointer call_data);
285 static void UpdatePrinterNameTimeoutProc(XtPointer client_data,
286                                          XtIntervalId* id);
287 static void UpdateString(
288                          Widget w,
289                          XmString string,
290                          XmStringDirection direction) ;
291 static void ValidatePrintSetupMode(
292                                    DtPrintSetupBoxWidget new_w,
293                                    DtPrintSetupBoxWidget current);
294 static void ValidateWorkAreaLocation(
295                                      DtPrintSetupBoxWidget new_w,
296                                      DtPrintSetupBoxWidget current);
297 /*
298  * ------------------------------------------------------------------------
299  * Static Global Variable Definitions
300  *
301  */
302
303 /*  
304  * Synthetic Resource Definitions
305  */
306 static XmSyntheticResource syn_resources[] = 
307 {
308     {
309         DtNcopies,
310         sizeof(int), 
311         XtOffsetOf(DtPrintSetupBoxRec,
312                    print_setup_box.copies), 
313         _DtPrintSetupBoxGetCopies,
314         SetSyntheticResForChild
315     },
316     {
317         DtNdescription,
318         sizeof(XmString), 
319         XtOffsetOf(DtPrintSetupBoxRec,
320                    print_setup_box.description_string), 
321         _DtPrintSetupBoxGetDescription,
322         SetSyntheticResForChild
323     },
324     {
325         DtNfileName,
326         sizeof(String), 
327         XtOffsetOf(DtPrintSetupBoxRec,
328                    print_setup_box.file_name), 
329         _DtPrintSetupBoxGetFileName,
330         SetSyntheticResForChild
331     },
332     {
333         DtNprinterName,
334         sizeof(String), 
335         XtOffsetOf(DtPrintSetupBoxRec,
336                    print_setup_box.printer_name), 
337         _DtPrintSetupBoxGetPrinterName,
338         SetSyntheticResForChild
339     }
340 };
341
342 /*
343  * Resource Definitions
344  */
345 static XtResource resources[] = 
346 {
347     {
348         XmNnoResize, XmNnoResize,
349         XmRBoolean, sizeof(Boolean),
350         XtOffsetOf(XmBulletinBoardRec, bulletin_board.no_resize),
351         XmRImmediate, (XtPointer) True
352     },
353     {
354         DtNcancelCallback, DtCCancelCallback,
355         XmRCallback, sizeof(XtCallbackList), 
356         XtOffsetOf(DtPrintSetupBoxRec,
357                    print_setup_box.cancel_callback), 
358         XmRImmediate, (XtPointer) NULL
359     },
360     {
361         DtNclosePrintDisplayCallback, DtCClosePrintDisplayCallback,
362         XmRCallback, sizeof(XtCallbackList), 
363         XtOffsetOf(DtPrintSetupBoxRec,
364                    print_setup_box.close_display_callback), 
365         XmRImmediate, (XtPointer) NULL
366     },
367     {
368         DtNcopies, DtCCopies,
369         XmRInt, sizeof(int),
370         XtOffsetOf(DtPrintSetupBoxRec,
371                    print_setup_box.copies),
372         XmRImmediate, (XtPointer) 1
373     },
374     {
375         DtNdescription, DtCDescription,
376         XmRXmString, sizeof(XmString), 
377         XtOffsetOf(DtPrintSetupBoxRec,
378                    print_setup_box.description_string), 
379         XmRString, (XtPointer) NULL
380     },
381     {
382         DtNfileName, DtCFileName,
383         XmRString, sizeof(String), 
384         XtOffsetOf(DtPrintSetupBoxRec,
385                    print_setup_box.file_name), 
386         XmRString, (XtPointer) NULL
387     },
388     {
389         DtNminimizeButtons, DtCMinimizeButtons,
390         XmRBoolean, sizeof(Boolean), 
391         XtOffsetOf(DtPrintSetupBoxRec,
392                    print_setup_box.minimize_buttons), 
393         XmRImmediate, (XtPointer) False
394     },
395     {
396         DtNprintCallback, DtCPrintCallback,
397         XmRCallback, sizeof(XtCallbackList), 
398         XtOffsetOf(DtPrintSetupBoxRec,
399                    print_setup_box.print_callback), 
400         XmRImmediate, (XtPointer) NULL
401     },
402     {
403         DtNoptionCount, DtCOptionCount,
404         XmRCardinal, sizeof(Cardinal),
405         XtOffsetOf(DtPrintSetupBoxRec,
406                    print_setup_box.option_count),
407         XmRImmediate, (XtPointer) 0
408     },
409     {
410         DtNoptions, DtCOptions,
411         XmRPointer, sizeof(XtPointer), 
412         XtOffsetOf(DtPrintSetupBoxRec,
413                    print_setup_box.options),
414         XmRImmediate, (XtPointer) NULL
415     },
416     {
417         DtNprintDestination, DtCPrintDestination,
418         XmREnum, sizeof(XtEnum), 
419         XtOffsetOf(DtPrintSetupBoxRec,
420                    print_setup_box.print_destination), 
421         XmRImmediate, (XtPointer) DtPRINT_TO_PRINTER,
422     },
423     {
424         DtNprinterInfoProc, DtCPrinterInfoProc,
425         DtRPrintSetupProc, sizeof(DtPrintSetupProc), 
426         XtOffsetOf(DtPrintSetupBoxRec,
427                    print_setup_box.printer_info_proc), 
428         XmRImmediate, (XtPointer)DtUNSPECIFIED
429     },
430     {
431         DtNprinterName, DtCPrinterName,
432         XmRString, sizeof(String), 
433         XtOffsetOf(DtPrintSetupBoxRec,
434                    print_setup_box.printer_name), 
435         XmRString, (XtPointer) NULL
436     },
437     {
438         DtNprintSetupMode, DtCPrintSetupMode,
439         XmREnum, sizeof(XtEnum), 
440         XtOffsetOf(DtPrintSetupBoxRec,
441                    print_setup_box.print_setup_mode),
442         XmRImmediate, (XtPointer)SETUP_MODE_DEFAULT,
443     },
444     {
445         DtNselectFileProc, DtCSelectFileProc,
446         DtRPrintSetupProc, sizeof(DtPrintSetupProc), 
447         XtOffsetOf(DtPrintSetupBoxRec,
448                    print_setup_box.select_file_proc), 
449         XmRImmediate, (XtPointer) _DtPrintSetupBoxSelectFileProc
450     },
451     {
452         DtNselectPrinterProc, DtCSelectPrinterProc,
453         DtRPrintSetupProc, sizeof(DtPrintSetupProc), 
454         XtOffsetOf(DtPrintSetupBoxRec,
455                    print_setup_box.select_printer_proc), 
456         XmRImmediate, (XtPointer)DtUNSPECIFIED
457     },
458     {
459         DtNsetupCallback, DtCSetupCallback,
460         XmRCallback, sizeof(XtCallbackList), 
461         XtOffsetOf(DtPrintSetupBoxRec,
462                    print_setup_box.setup_callback), 
463         XmRImmediate, (XtPointer) NULL
464     },
465     {
466         DtNverifyPrinterProc, DtCVerifyPrinterProc,
467         DtRPrintSetupProc, sizeof(DtPrintSetupProc), 
468         XtOffsetOf(DtPrintSetupBoxRec,
469                    print_setup_box.verify_printer_proc), 
470         XmRImmediate, (XtPointer)DtUNSPECIFIED
471     },
472     {
473         DtNworkAreaLocation, DtCWorkAreaLocation,
474         XmREnum, sizeof(XtEnum), 
475         XtOffsetOf(DtPrintSetupBoxRec,
476                    print_setup_box.work_area_location), 
477         XmRImmediate, (XtPointer)WORK_AREA_DEFAULT,
478     },
479 };
480
481
482 externaldef(dtprintsetupboxclassrec) DtPrintSetupBoxClassRec
483 dtPrintSetupBoxClassRec =
484 {
485     {
486         /* superclass         */        (WidgetClass)&xmBulletinBoardClassRec, 
487         /* class_name         */        "DtPrintSetupBox", 
488         /* widget_size        */        sizeof(DtPrintSetupBoxRec), 
489         /* class_initialize   */        ClassInitialize, 
490         /* chained class init */        ClassPartInitialize, 
491         /* class_inited       */        FALSE, 
492         /* initialize         */        Initialize, 
493         /* initialize hook    */        NULL, 
494         /* realize            */        XtInheritRealize, 
495         /* actions            */        NULL, 
496         /* num_actions        */        0, 
497         /* resources          */        resources, 
498         /* num_resources      */        XtNumber(resources), 
499         /* xrm_class          */        NULLQUARK, 
500         /* compress_motion    */        TRUE, 
501         /* compress_exposure  */        XtExposeCompressMaximal,
502         /* compress enter/exit*/        TRUE, 
503         /* visible_interest   */        FALSE, 
504         /* destroy            */        Destroy, 
505         /* resize             */        XtInheritResize,
506         /* expose             */        XtInheritExpose, 
507         /* set_values         */        SetValues, 
508         /* set_values_hook    */        NULL,                    
509         /* set_values_almost  */        XtInheritSetValuesAlmost,
510         /* get_values_hook    */        NULL, 
511         /* accept_focus       */        NULL, 
512         /* version            */        XtVersion, 
513         /* callback_offsets   */        NULL, 
514         /* tm_table           */        XtInheritTranslations, 
515         /* query_geometry     */        XtInheritGeometryManager,
516         /* display_accelerator*/        NULL, 
517         /* extension          */        NULL, 
518     }, 
519
520     {   /* composite class record */    
521
522         /* childrens geo mgr proc   */  XtInheritGeometryManager,
523         /* set changed proc         */  XtInheritChangeManaged,
524         /* insert_child             */  InsertChild, 
525         /* delete_child             */  DeleteChild, 
526         /* extension                */  NULL, 
527     }, 
528
529     {   /* constraint class record */
530
531         /* no additional resources  */  NULL, 
532         /* num additional resources */  0, 
533         /* size of constraint rec   */  0, 
534         /* constraint_initialize    */  NULL, 
535         /* constraint_destroy       */  NULL, 
536         /* constraint_setvalue      */  NULL, 
537         /* extension                */  NULL, 
538     }, 
539
540     {   /* manager class record */
541       XmInheritTranslations,                    /* default translations   */
542       syn_resources,                            /* syn_resources          */
543       XtNumber (syn_resources),                 /* num_syn_resources      */
544       NULL,                                     /* syn_cont_resources     */
545       0,                                        /* num_syn_cont_resources */
546       XmInheritParentProcess,                   /* parent_process         */
547       NULL,                                     /* extension              */
548     }, 
549
550     {   /* bulletin board class record */     
551         TRUE,                                   /*always_install_accelerators*/
552         _DtPrintSetupBoxGeoMatrixCreate,         /* geo_matrix_create */
553         XmInheritFocusMovedProc,                /* focus_moved_proc */
554         NULL,                                   /* extension */
555     },  
556
557     {   /* print setup box class record */
558         NULL,                                   /* extension  */
559     }, 
560 };
561
562 externaldef(dtprintsetupboxwidgetclass) WidgetClass dtPrintSetupBoxWidgetClass = (WidgetClass) &dtPrintSetupBoxClassRec ;
563
564 /*
565  * ------------------------------------------------------------------------
566  * Name: ClassInitialize - Core class method
567  *
568  * Description:
569  *
570  * Return value:
571  *
572  *     None.
573  *
574  */
575 static void 
576 ClassInitialize(void)
577 {   
578     /*
579      * Register a type converter for String to Enum
580      */
581     XtSetTypeConverter("String", "Enum", ConvertStringToEnum,
582                        NULL, 0, XtCacheAll, NULL);
583 }
584
585 /*
586  * ------------------------------------------------------------------------
587  * Name: ClassPartInitialize - Core class method
588  *
589  * Description:
590  *
591  * Return value:
592  *
593  *     None.
594  *
595  */
596 static void 
597 ClassPartInitialize(WidgetClass w_class)
598 {   
599     DtPrintSetupBoxWidgetClass wc = (DtPrintSetupBoxWidgetClass) w_class;
600     DtPrintSetupBoxWidgetClass super =
601         (DtPrintSetupBoxWidgetClass) wc->core_class.superclass;
602
603     if (wc->print_setup_box_class.list_callback == XmInheritCallbackProc)
604         wc->print_setup_box_class.list_callback =
605             super->print_setup_box_class.list_callback;
606 }
607
608             
609 /*
610  * ------------------------------------------------------------------------
611  * Name: ClosePrintConnection
612  *
613  * Description:
614  *
615  *     Call the DtNclosePrintDisplayCallback list, and destroy the print
616  *     context and X print display connection managed by the widget.
617  *
618  * Return value:
619  *
620  *     None.
621  *
622  */
623 static void
624 ClosePrintConnection(
625                      DtPrintSetupBoxWidget psub,
626                      String old_printer_name,
627                      Boolean update_gui)
628 {
629     DtPrintSetupCallbackStruct cbs;
630     DtPrintSetupData psd;
631     XmString empty_label;
632     
633     memset(&cbs, 0, sizeof(DtPrintSetupCallbackStruct));
634     memset(&psd, 0, sizeof(DtPrintSetupData));
635     cbs.print_data = &psd;
636     /*
637      * call DtNclosePrintDisplayCallback before closing the
638      * current print display
639      */
640     cbs.reason = DtPRINT_CR_CLOSE_PRINT_DISPLAY;
641     psd.printer_name = old_printer_name;
642     psd.print_display = PSUB_Display(psub);
643     psd.print_context = PSUB_Context(psub);
644     XtCallCallbackList((Widget)psub,
645                        PSUB_CloseDisplayCallback(psub),
646                        (XtPointer)&cbs);
647     /*
648      * unset the printer description
649      */
650     if(update_gui)
651     {
652         empty_label = XmStringGenerate((XtPointer)"", (XmStringTag)NULL,
653                                        XmMULTIBYTE_TEXT, (XmStringTag)NULL);
654         UpdateString(PSUB_Description((Widget)psub), 
655                      empty_label, PSUB_StringDirection((Widget)psub));
656         XmStringFree(empty_label);
657     }
658     /*
659      * reset copy_count_supported flag
660      */
661     if(!PSUB_CopyCountSupported(psub))
662     {
663         PSUB_CopyCountSupported(psub) = True;
664         if(PSUB_PrintDestination(psub) == DtPRINT_TO_PRINTER && update_gui)
665         {
666             if(PSUB_CopiesSpinBox(psub))
667                 XtSetSensitive(PSUB_CopiesSpinBox(psub), True);
668             if(PSUB_CopiesControl(psub))
669             {
670                 Widget copies_label =
671                     XtNameToWidget(PSUB_CopiesControl(psub), "CopiesLabel");
672                 XtSetSensitive(copies_label, True);
673             }
674         }
675     }
676     /*
677      * destroy the print context
678      */
679     XpDestroyContext(PSUB_Display(psub), PSUB_Context(psub));
680     PSUB_Context(psub) = (XPContext)NULL;
681     /*
682      * close the print display
683      */
684     XtCloseDisplay(PSUB_Display(psub));
685     PSUB_Display(psub) = (Display*)NULL;
686 }
687
688 /*
689  * ------------------------------------------------------------------------
690  * Name: ClosePrintConnectionCallback
691  *
692  * Description:
693  *
694  *     Calls ClosePrintConnection if there is an existing connection.
695  *
696  * Return value:
697  *
698  *     None.
699  *
700  */
701 static void
702 ClosePrintConnectionCallback(Widget w,
703                              XtPointer client_data,
704                              XtPointer call_data)
705 {
706     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)client_data;
707     /*
708      * close the Xp connection if open
709      */
710     if(PSUB_Display(psub) != (Display*)NULL)
711     {
712         ClosePrintConnection(psub, PSUB_PrinterName(psub), True);
713     }
714 }
715
716 /*
717  * ------------------------------------------------------------------------
718  * Name: ColumnGeoFixUp
719  *
720  * Description:
721  *
722  *     This routine is a fixup routine which can be used for groups of
723  *     rows containing entries that can be organized into columns.
724  *
725  * Return value:
726  *
727  *     None.
728  *
729  */
730 static void 
731 ColumnGeoFixUp(
732                XmGeoMatrix geo_spec,
733                int action,
734                XmGeoMajorLayout layout_ptr,
735                XmKidGeometry row_ptr)
736 {
737     PSUB_GeoExtension ext = geo_spec->extension;
738     int row;
739     /*
740      * determine which row we're on
741      */
742     for(row = 0; row < ext->row_count; row++)
743         if((ext->layout_ptr)[row] == &(layout_ptr->row))
744             break;
745     if(row == ext->row_count)
746         /*
747          * shouldn't happen
748          */
749         return;
750
751     switch(action)
752     {
753     case XmGET_PREFERRED_SIZE:
754         ColumnGeoSaveWidths(ext, row);
755         ColumnGeoSetPreferredWidths(ext, row);
756         break;
757         
758     case XmGEO_PRE_SET:
759         ColumnGeoPreSet(ext, row);
760         break;
761
762     case XmGEO_POST_SET:
763         ColumnGeoRestoreWidths(ext, row);
764         break;
765     }
766 }
767
768 /*
769  * ------------------------------------------------------------------------
770  * Name: ColumnGeoPreSet
771  *
772  * Description:
773  *
774  *     Update origins and widths based on alignment.
775  *
776  * Return value:
777  *
778  *     None.
779  *
780  */
781 static void
782 ColumnGeoPreSet(
783                 PSUB_GeoExtension ext,
784                 int row)
785 {
786     Dimension delta = 0;
787     Dimension slack = 0;
788     int col;
789     
790     for(col = 0; col < PSUB_GEO_COL_COUNT; col++)
791     {
792         PSUB_GeoBox pbox = &(ext->pbox)[row][col];
793         if(pbox->geo)
794         {
795             pbox->geo->box.x += slack;
796             
797             switch(pbox->align)
798             {
799             case PSUB_GEO_ALIGN_RIGHT:
800                 delta += (ext->col_width)[col] - pbox->geo->box.width;
801                 pbox->geo->box.x += (ext->col_width)[col] - pbox->orig_width;
802                 pbox->geo->box.width = pbox->orig_width;
803                 break;
804                 
805             case PSUB_GEO_ALIGN_LEFT:
806                 pbox->geo->box.x += delta;
807                 delta += (ext->col_width)[col] - pbox->geo->box.width;
808                 pbox->geo->box.width = pbox->orig_width;
809                 break;
810                 
811             case PSUB_GEO_ALIGN_EXPAND:
812                 pbox->geo->box.x += delta;
813                 pbox->geo->box.width = (ext->col_width)[col];
814                 break;
815             }
816         }
817         else
818             slack += (ext->col_width)[col];
819     }
820 }
821
822 /*
823  * ------------------------------------------------------------------------
824  * Name: ColumnGeoRestoreWidths
825  *
826  * Description:
827  *
828  *     Restore the original widths for items in the current row.
829  *
830  * Return value:
831  *
832  *     None.
833  *
834  */
835 static void
836 ColumnGeoRestoreWidths(
837                        PSUB_GeoExtension ext,
838                        int row)
839 {
840     int col;
841     
842     for(col = 0; col < PSUB_GEO_COL_COUNT; col++)
843     {
844         PSUB_GeoBox pbox = &(ext->pbox)[row][col];
845         if(pbox->geo)
846         {
847             /*
848              * restore the original box width
849              */
850             pbox->geo->box.width = pbox->orig_width;
851         }
852     }
853 }
854
855 /*
856  * ------------------------------------------------------------------------
857  * Name: ColumnGeoSaveWidths
858  *
859  * Description:
860  *
861  *     Save the original widths for items in the current row, and
862  *     increase a given column width if an item in a corresponding column
863  *     in this row is wider.
864  *
865  * Return value:
866  *
867  *     None.
868  *
869  */
870 static void
871 ColumnGeoSaveWidths(
872                     PSUB_GeoExtension ext,
873                     int row)
874 {
875     int col;
876     
877     for(col = 0; col < PSUB_GEO_COL_COUNT; col++)
878     {
879         PSUB_GeoBox pbox = &(ext->pbox)[row][col];
880         if(pbox->geo)
881         {
882             /*
883              * save the original box width
884              */
885             pbox->orig_width = pbox->geo->box.width;
886             /*
887              * update the overall column width
888              */
889             if(pbox->geo->box.width > (ext->col_width)[col])
890                 (ext->col_width)[col] = pbox->geo->box.width;
891         }
892     }
893 }
894
895 /*
896  * ------------------------------------------------------------------------
897  * Name: ColumnGeoSetPreferredWidths
898  *
899  * Description:
900  *
901  *     Ensure the overall width of the current row is equal to the
902  *     overall width of all of the columns.
903  *
904  *     Assumes at least one box is defined in the row.
905  *
906  * Return value:
907  *
908  *     None.
909  *
910  */
911 static void
912 ColumnGeoSetPreferredWidths(
913                             PSUB_GeoExtension ext,
914                             int row)
915 {
916     Dimension slack = 0;
917     int last_non_empty_col;
918     int col;
919     
920     for(col = 0; col < PSUB_GEO_COL_COUNT; col++)
921     {
922         PSUB_GeoBox pbox = &(ext->pbox)[row][col];
923         if(pbox->geo)
924         {
925             pbox->geo->box.width = (ext->col_width)[col] + slack;
926             slack = 0;
927             last_non_empty_col = col;
928         }
929         else
930         {
931             slack += (ext->col_width)[col];
932         }
933     }
934     if(slack)
935         (ext->pbox)[row][last_non_empty_col].geo->box.width += slack;
936 }
937
938 /*
939  * ------------------------------------------------------------------------
940  * Name: ConvertStringToEnum
941  *
942  * Description:
943  *
944  *     This type converter converts from type String to Enum.  It is
945  *     used for the DtNprintDestination, DtNworkAreaLocation, and
946  *     DtNprintSetupMode resources.
947  *
948  */
949 static Boolean
950 ConvertStringToEnum(
951                     Display *dpy,
952                     XrmValuePtr args,
953                     Cardinal *num_args,
954                     XrmValuePtr from, 
955                     XrmValuePtr to,
956                     XtPointer *data)
957 {
958     char *from_str;
959     static unsigned char to_value;
960
961     if(*num_args !=0 )
962     {
963         XtError(WARN_CONVERSION_ARGS);
964     }
965
966     from_str = (char *)from->addr;
967     if(strcmp(from_str, "PRINT_TO_FILE")==0 ||
968        strcmp(from_str, "DtPRINT_TO_FILE")==0)
969         to_value = DtPRINT_TO_FILE;
970     else if(strcmp(from_str, "PRINT_TO_PRINTER")==0 ||
971             strcmp(from_str, "DtPRINT_TO_PRINTER")==0)
972         to_value = DtPRINT_TO_PRINTER;
973     else if(strcmp(from_str, "PRINT_SETUP_PLAIN")==0 ||
974             strcmp(from_str, "DtPRINT_SETUP_PLAIN")==0)
975         to_value = DtPRINT_SETUP_PLAIN;
976     else if(strcmp(from_str, "PRINT_SETUP_XP")==0 ||
977             strcmp(from_str, "DtPRINT_SETUP_XP")==0)
978         to_value = DtPRINT_SETUP_XP;
979     else if(strcmp(from_str, "WORK_AREA_BOTTOM")==0 ||
980             strcmp(from_str, "DtWORK_AREA_BOTTOM")==0)
981         to_value = DtWORK_AREA_BOTTOM;
982     else if(strcmp(from_str, "WORK_AREA_TOP")==0 ||
983             strcmp(from_str, "DtWORK_AREA_TOP")==0)
984         to_value = DtWORK_AREA_TOP;
985     else if(strcmp(from_str, "WORK_AREA_TOP_AND_BOTTOM")==0 ||
986             strcmp(from_str, "DtWORK_AREA_TOP_AND_BOTTOM")==0)
987         to_value = DtWORK_AREA_TOP_AND_BOTTOM;
988     else if(strcmp(from_str, "SHORT_NAME")==0 ||
989             strcmp(from_str, "DtSHORT_NAME")==0)
990         to_value = DtSHORT_NAME;
991     else if(strcmp(from_str, "MEDIUM_NAME")==0 ||
992             strcmp(from_str, "DtMEDIUM_NAME")==0)
993         to_value = DtMEDIUM_NAME;
994     else if(strcmp(from_str, "LONG_NAME")==0 ||
995             strcmp(from_str, "DtLONG_NAME")==0)
996         to_value = DtLONG_NAME;
997     else
998     {
999         XtDisplayStringConversionWarning(dpy, from->addr, "Enum");
1000         return False;
1001     }
1002
1003     if(to->addr == NULL)
1004         to->addr = (caddr_t) &to_value;
1005     else if(to->size <sizeof(unsigned char))
1006     {
1007         XtDisplayStringConversionWarning(dpy, from->addr, "Enum");
1008         return False;
1009     }
1010     else
1011         *(unsigned char *) to->addr = to_value;
1012
1013     to->size = sizeof(unsigned char);
1014
1015     return True;
1016 }
1017
1018 /*
1019  * ------------------------------------------------------------------------
1020  * Name: CopiesTextValueChangedCallback
1021  *
1022  * Description:
1023  *
1024  *     Process a change in the textfield of the copies simple spin box.
1025  *
1026  * Return value:
1027  *
1028  *     None.
1029  *
1030  */
1031 static void 
1032 CopiesTextValueChangedCallback(
1033                            Widget w,
1034                            XtPointer client_data,
1035                            XtPointer call_data)
1036 {
1037     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)client_data;
1038     XmAnyCallbackStruct* cbs = (XmAnyCallbackStruct*)call_data;
1039
1040     if (NULL == psub || NULL == cbs) return;
1041
1042     if(XmCR_VALUE_CHANGED == cbs->reason)
1043     {
1044         char *value = NULL;
1045         int value_int = 0;
1046         
1047         XtVaGetValues(w, XmNvalue, &value, NULL);
1048         if (value) value_int = strtol(value, (char**)NULL, 10);
1049
1050         if (1 <= value_int || value_int <= MAX_COPIES)
1051         {
1052             PSUB_Copies(psub) = value_int;
1053             XtVaSetValues(
1054                         PSUB_CopiesSpinBox(psub),
1055                         XmNposition, value_int,
1056                         NULL);
1057         }
1058         else
1059         {
1060             XmeWarning((Widget)w, WARN_COPY_COUNT);
1061             XtVaGetValues(
1062                         PSUB_CopiesSpinBox(psub),
1063                         XmNposition, &value_int,
1064                         NULL);
1065
1066             value = (char*) XtMalloc(64); 
1067             if (value)
1068             {
1069                 sprintf(value, "%d", value_int);
1070                 XtVaSetValues(w, XmNvalue, value, NULL);
1071                 XtFree(value);
1072             }
1073         }
1074
1075         if (value) XtVaSetValues(w, XmNcursorPosition, strlen(value), NULL);
1076     }
1077 }
1078
1079 /*
1080  * ------------------------------------------------------------------------
1081  * Name: CreateButton
1082  *
1083  * Description:
1084  *
1085  * Return value:
1086  *
1087  *     Widget ID of the new button widget.
1088  *
1089  */
1090 static Widget 
1091 CreateButton(Widget parent,
1092              String label,
1093              String name,
1094              XmNavigationType nav_type)
1095 {
1096     XmString label_string;
1097     Widget w;
1098     XmTakesDefaultTrait trait_default ;
1099     
1100     label_string = XmStringGenerate((XtPointer)label, (XmStringTag)NULL,
1101                                     XmMULTIBYTE_TEXT, (XmStringTag)NULL);
1102     w = XtVaCreateWidget(name,
1103                          xmPushButtonWidgetClass,
1104                          parent,
1105                          XmNlabelString, label_string,
1106                          XmNnavigationType, nav_type,
1107                          NULL);
1108
1109     if(label_string) XmStringFree(label_string);
1110
1111     trait_default = (XmTakesDefaultTrait)
1112         XmeTraitGet((XtPointer)XtClass(w), XmQTtakesDefault) ;
1113     if(trait_default) 
1114         trait_default->showAsDefault(w, XmDEFAULT_READY);
1115
1116     return w;
1117 }
1118
1119 /*
1120  * ------------------------------------------------------------------------
1121  * Name: CreateButtonGadget
1122  *
1123  * Description:
1124  *
1125  * Return value:
1126  *
1127  *     Widget ID of the new button gadget.
1128  *
1129  */
1130 static Widget 
1131 CreateButtonGadget(Widget parent,
1132                    String label,
1133                    String name,
1134                    XmNavigationType nav_type)
1135 {
1136     XmString label_string;
1137     Widget w;
1138     XmTakesDefaultTrait trait_default ;
1139     
1140     label_string = XmStringGenerate((XtPointer)label, (XmStringTag)NULL,
1141                                     XmMULTIBYTE_TEXT, (XmStringTag)NULL);
1142     w = XtVaCreateWidget(name,
1143                          xmPushButtonGadgetClass,
1144                          parent,
1145                          XmNlabelString, label_string,
1146                          XmNnavigationType, nav_type,
1147                          NULL);
1148
1149     if(label_string) XmStringFree(label_string);
1150
1151     trait_default = (XmTakesDefaultTrait)
1152         XmeTraitGet((XtPointer)XtClass(w), XmQTtakesDefault) ;
1153     if(trait_default) 
1154         trait_default->showAsDefault(w, XmDEFAULT_READY);
1155
1156     return w;
1157 }
1158
1159 /*
1160  * ------------------------------------------------------------------------
1161  * Name: CreateLabelGadget
1162  *
1163  * Description:
1164  *
1165  * Return value:
1166  *
1167  *     Widget ID of the new label gadget.
1168  *
1169  */
1170 static Widget 
1171 CreateLabelGadget(
1172                   Widget parent,
1173                   String label,
1174                   String name)
1175 {
1176     XmString label_string;
1177     Widget w;
1178     
1179     label_string = XmStringGenerate((XtPointer)label, (XmStringTag)NULL,
1180                                     XmMULTIBYTE_TEXT, (XmStringTag)NULL);
1181     w = XtVaCreateWidget(name,
1182                          xmLabelGadgetClass,
1183                          parent,
1184                          XmNlabelString, label_string,
1185                          NULL);
1186
1187     if(label_string) XmStringFree(label_string);
1188
1189     return w;
1190 }
1191
1192 /*
1193  * ------------------------------------------------------------------------
1194  * Name: CreateModalPrinterSpec
1195  *
1196  * Arguments:
1197  *
1198  *     name_mode
1199  *         A valid X Printer Specifier Display Mode (see the
1200  *         XpPrinterNameMode resource definition).
1201  *
1202  *     full_printer_name
1203  *         The fully qualified printer name
1204  *
1205  * Description:
1206  *
1207  *     Creates an X Printer Specifier appropriate to an X Printer
1208  *     Specifier Display Mode, given a full printer name
1209  *
1210  * Return value:
1211  *
1212  *     A newly allocated string containing the resulting X Printer
1213  *     specifier. It is the resposibility of the caller to free the
1214  *     memory using XtFree(1).
1215  *
1216  *     NULL is returned if:
1217  *      * the passed printer_name is NULL
1218  *      * if memory allocation fails.
1219  *
1220  */
1221 static String
1222 CreateModalPrinterSpec(
1223                        XtEnum name_mode,
1224                        const String full_printer_name)
1225 {
1226     String modal_printer_spec;
1227     String printer_name;
1228     String display_spec;
1229     /*
1230      * check for NULL passed parms
1231      */
1232     if(full_printer_name == (String)NULL)
1233     {
1234         return (String)NULL;
1235     }
1236     /*
1237      * break the fully qualified printer name into printer and display
1238      * name components
1239      */
1240     _DtPrintParseXPrinterSpecifier(full_printer_name,
1241                                    &printer_name, &display_spec);
1242     /*
1243      * if display mode is SHORT, just the printer name will do
1244      */
1245     if(name_mode == DtSHORT_NAME)
1246     {
1247         modal_printer_spec = XtNewString(printer_name);
1248     }
1249     else
1250     {
1251         String host_name;
1252         DtPrintSpecNet spec_net;
1253         int display_num;
1254         int screen_num;
1255         /*
1256          * break up the display specifier
1257          */
1258         _DtPrintParseXDisplaySpecifier(display_spec, &host_name,
1259                                        &spec_net, &display_num, &screen_num);
1260         /*
1261          * create the modal specifier
1262          */
1263         switch(name_mode)
1264         {
1265         case DtMEDIUM_NAME:
1266             modal_printer_spec =
1267                 _DtPrintCreateXPrinterSpecifier(printer_name, host_name,
1268                                                 DtPRINT_NET_UNSPECIFIED,
1269                                                 -1, -1);
1270             break;
1271
1272         case DtLONG_NAME:
1273             modal_printer_spec =
1274                 _DtPrintCreateXPrinterSpecifier(printer_name, host_name,
1275                                                 spec_net,
1276                                                 display_num, screen_num);
1277             break;
1278             
1279         default:
1280             /*
1281              * invalid name mode; default to short name
1282              */
1283             modal_printer_spec = XtNewString(printer_name);
1284             break;
1285         }
1286         XtFree(host_name);
1287     }
1288     /*
1289      * clean up and return
1290      */
1291     XtFree(printer_name);
1292     XtFree(display_spec);
1293     return modal_printer_spec;
1294 }
1295
1296 /*
1297  * ------------------------------------------------------------------------
1298  * Name: DeleteChild - Composite class method
1299  *
1300  * Description:
1301  *
1302  *     Remove child from setup box widget
1303  *
1304  * Return value:
1305  *
1306  *     None.
1307  *
1308  */
1309 static void 
1310 DeleteChild(
1311             Widget child)
1312 {   
1313     DtPrintSetupBoxWidget psub ;
1314     XtWidgetProc delete_child;
1315
1316     if(XtIsRectObj(child))
1317     {   
1318         psub = (DtPrintSetupBoxWidget) XtParent(child);
1319         /*
1320          * Clear widget fields (BulletinBoard does default and cancel).
1321          */
1322         if(child == PSUB_BottomSeparator(psub))
1323         {
1324             PSUB_BottomSeparator(psub) = NULL;
1325         } 
1326         else if(child == PSUB_ButtonSeparator(psub))
1327         {
1328             PSUB_ButtonSeparator(psub) = NULL;
1329         } 
1330         else if(child == PSUB_DescriptionLabel(psub))
1331         {
1332             PSUB_DescriptionLabel(psub) = NULL;
1333         } 
1334         else if(child == PSUB_Description(psub))
1335         {
1336             PSUB_Description(psub) = NULL;
1337         } 
1338         else if(child == PSUB_PrinterNameLabel(psub))
1339         {
1340             PSUB_PrinterNameLabel(psub) = NULL;
1341         } 
1342         else if(child == PSUB_CopiesControl(psub))
1343         {
1344             PSUB_CopiesControl(psub) = NULL;
1345             PSUB_CopiesSpinBox(psub) = NULL;
1346         } 
1347         else if(child == PSUB_TopWorkArea(psub))
1348         {
1349             PSUB_TopWorkArea(psub) = NULL;
1350         } 
1351         else if(child == PSUB_BottomWorkArea(psub))
1352         {
1353             PSUB_BottomWorkArea(psub) = NULL;
1354         } 
1355         else if(child == PSUB_PrintButton(psub))
1356         {
1357             PSUB_PrintButton(psub) = NULL;
1358         } 
1359         else if(child == PSUB_PrinterInfoButton(psub))
1360         {
1361             PSUB_PrinterInfoButton(psub) = NULL;
1362         }
1363         else if(child == PSUB_PrinterNameCombo(psub))
1364         {
1365             PSUB_PrinterNameCombo(psub) = NULL;
1366             PSUB_PrinterNameText(psub) = NULL;
1367         }
1368         else if(child == PSUB_SetupButton(psub))
1369         {
1370             PSUB_SetupButton(psub) = NULL;
1371         } 
1372         else if(child == PSUB_HelpButton(psub))
1373         {
1374             PSUB_HelpButton(psub) = NULL;
1375         }
1376         else if(child == PSUB_TopSeparator(psub))
1377         {
1378             PSUB_TopSeparator(psub) = NULL;
1379         }
1380         else if(child == PSUB_DestinationRadioBox(psub))
1381         {
1382             PSUB_DestinationRadioBox(psub) = NULL;
1383         }
1384         else if(child == PSUB_FileNameLabel(psub))
1385         {
1386             PSUB_FileNameLabel(psub) = NULL;
1387         }
1388         else if(child == PSUB_FileNameText(psub))
1389         {
1390             PSUB_FileNameText(psub) = NULL;
1391         }
1392         else if(child == PSUB_SelectFileButton(psub))
1393         {
1394             PSUB_SelectFileButton(psub) = NULL;
1395         }
1396         else if(child == PSUB_SelectPrinterButton(psub))
1397         {
1398             PSUB_SelectPrinterButton(psub) = NULL;
1399         }
1400     }
1401     _DtPrintProcessLock();
1402     delete_child = ((XmBulletinBoardWidgetClass)xmBulletinBoardWidgetClass)
1403       ->composite_class.delete_child;
1404     _DtPrintProcessUnlock();
1405     (*delete_child)(child) ;
1406 }
1407
1408 /*
1409  * ------------------------------------------------------------------------
1410  * Name: DestinationChangedCallback
1411  *
1412  * Description:
1413  *
1414  *     Process a change in the print destination generated by the GUI user.
1415  *
1416  * Return value:
1417  *
1418  *     None.
1419  *
1420  */
1421 static void 
1422 DestinationChangedCallback(
1423                            Widget w,
1424                            XtPointer client_data,
1425                            XtPointer call_data)
1426 {
1427     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)client_data;
1428     XmToggleButtonCallbackStruct* cbs =
1429         (XmToggleButtonCallbackStruct*)call_data;
1430
1431     if(cbs->set)
1432     {
1433         XtPointer user_data;
1434         /*
1435          * set the print destination according to the selected radio
1436          * button
1437          */
1438         XtVaGetValues(w, XmNuserData, &user_data, NULL);
1439         PSUB_PrintDestination(psub) = (XtEnum)user_data;
1440         /*
1441          * Update the print setup box controls sensitivity accordingly
1442          */
1443         if(PSUB_SelectFileButton(psub))
1444             XtSetSensitive(PSUB_SelectFileButton(psub),
1445                            PSUB_PrintDestination(psub) == DtPRINT_TO_FILE);
1446         if(PSUB_FileNameLabel(psub))
1447             XtSetSensitive(PSUB_FileNameLabel(psub),
1448                            PSUB_PrintDestination(psub) == DtPRINT_TO_FILE);
1449         if(PSUB_FileNameText(psub))
1450             XtSetSensitive(PSUB_FileNameText(psub),
1451                            PSUB_PrintDestination(psub) == DtPRINT_TO_FILE);
1452         if(PSUB_CopyCountSupported(psub))
1453         {
1454             if(PSUB_CopiesSpinBox(psub))
1455                 XtSetSensitive(PSUB_CopiesSpinBox(psub),
1456                                PSUB_PrintDestination(psub) == DtPRINT_TO_PRINTER);
1457             if(PSUB_CopiesControl(psub))
1458             {
1459                 Widget copies_label =
1460                     XtNameToWidget(PSUB_CopiesControl(psub), "CopiesLabel");
1461                 XtSetSensitive(copies_label,
1462                                PSUB_PrintDestination(psub) == DtPRINT_TO_PRINTER);
1463             }
1464         }
1465     }
1466 }
1467
1468 /*
1469  * ------------------------------------------------------------------------
1470  * Name: Destroy - Core class method
1471  *
1472  * Description:
1473  *
1474  *     Clean up resources allocated by the PrintSetupBox widget.
1475  *
1476  * Return Value:
1477  *
1478  *     None.
1479  */
1480 static void
1481 Destroy(
1482         Widget w)
1483 {
1484     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)w;
1485     /*
1486      * close the Xp connection
1487      */
1488     if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP
1489        &&
1490        PSUB_Display(psub) != (Display*)NULL)
1491     {
1492         ClosePrintConnection(psub, PSUB_PrinterName(psub), False);
1493     }
1494     /*
1495      * synthetic resources
1496      */
1497     XtFree(PSUB_FileName(psub));
1498     XtFree(PSUB_PrinterName(psub));
1499     /*
1500      * internal data
1501      */
1502     XtFree(PSUB_ModalPrinterSpec(psub));
1503 }
1504
1505 /*
1506  * ------------------------------------------------------------------------
1507  * Name: EstablishPrinter
1508  *
1509  * Description:
1510  *
1511  *
1512  * Return Value:
1513  *
1514  *     DtPRINT_SUCCESS
1515  *         if a valid printer has been established
1516  *         (i.e. for Xp, a connection has been set up)
1517  *
1518  *     DtPRINT_FAILURE
1519  *         if the printer could not be established
1520  *
1521  *     DtPRINT_BAD_PARM
1522  *         if any passed parameter is invalid
1523  *
1524  */
1525 static XtEnum
1526 EstablishPrinter(
1527                  DtPrintSetupBoxWidget psub,
1528                  DtPrintSetupData* psd)
1529 {
1530     switch(PSUB_VerifyPrinterState(psub))
1531     {
1532     case DtPRINT_NOT_VERIFIED:
1533         /*
1534          * if there's a printer connection timer waiting, remove it
1535          * to avoid conflict
1536          */
1537         if(PSUB_TimeoutId(psub) != (XtIntervalId)NULL)
1538         {
1539             XtRemoveTimeOut(PSUB_TimeoutId(psub));
1540             PSUB_TimeoutId(psub) = (XtIntervalId)NULL;
1541         }
1542         /*
1543          * call the verify printer proc for the new printer
1544          */
1545         if(PSUB_VerifyPrinterProc(psub) != NULL)
1546         {
1547             int status;
1548             
1549             psd->printer_name = PSUB_PrinterName(psub);
1550             PSUB_VerifyPrinterState(psub) = DtPRINT_IN_VERIFY;
1551             status = (*PSUB_VerifyPrinterProc(psub))((Widget)psub, psd);
1552             if(status != DtPRINT_SUCCESS)
1553             {
1554                 /*
1555                  * the printer isn't valid - set the verify printer state
1556                  * back to "not verified" and return
1557                  */
1558                 PSUB_VerifyPrinterState(psub) = DtPRINT_NOT_VERIFIED;
1559                 return status;
1560             }
1561             PSUB_VerifyPrinterState(psub) = DtPRINT_VERIFIED;
1562             if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP)
1563             {
1564                 /*
1565                  * set the new display and context in the widget
1566                  */
1567                 PSUB_Display(psub) = psd->print_display;
1568                 PSUB_Context(psub) = psd->print_context;
1569                 /*
1570                  * initialize the display for use with Xt
1571                  */
1572                 {
1573                     String *argv = NULL, *argv_copy;
1574                     int argc = 0, i;
1575                     String video_name, video_class;
1576                     Widget video_widget = (Widget)psub;
1577                     XtAppContext app_context;
1578                     /*
1579                      * get to the video app root shell 
1580                      */
1581                     while((Widget)NULL != video_widget)
1582                     {
1583                         if(XtIsApplicationShell(video_widget))
1584                             break;
1585                         else
1586                             video_widget = XtParent(video_widget);
1587                     }
1588                     if((Widget)NULL == video_widget)
1589                         video_widget = (Widget)psub;
1590                     /*
1591                      * if not an applicationShell, argc/argv will stay
1592                      * NULL in the GetValues call, no need to check
1593                      * explicitly
1594                      */
1595                     XtVaGetValues(video_widget,
1596                                   XmNargc, &argc, XmNargv, &argv,
1597                                   NULL);
1598
1599                     /* copy argv, modified by XtDisplayInitialize below */
1600                     argv_copy =
1601                         (String *) XtMalloc(sizeof(String) * (argc + 1));
1602                     for (i = 0; i < argc; i++) {
1603                         argv_copy[i] = argv[i];
1604                     }                   
1605                     argv_copy[argc] = NULL;
1606
1607                     /*
1608                      * now add the print display in our app context, so
1609                      * that event dispatching works
1610                      */
1611                     XtGetApplicationNameAndClass(XtDisplay(video_widget),
1612                                                  &video_name, &video_class);
1613                     app_context = XtWidgetToApplicationContext(video_widget);
1614                     XtDisplayInitialize(app_context,
1615                                         PSUB_Display(psub),
1616                                         video_name, video_class,
1617                                         PSUB_Options(psub),
1618                                         PSUB_OptionCount(psub),
1619                                         &argc, argv_copy);
1620
1621                     XtFree((char *) argv_copy);
1622                 }
1623                 /*
1624                  * pick up attributes for the new printer
1625                  */
1626                 GetPrintAttributes(psub);
1627             }
1628         }
1629         else
1630         {
1631             PSUB_VerifyPrinterState(psub) = DtPRINT_VERIFIED;
1632         }
1633         /*
1634          * no break
1635          */
1636         
1637     case DtPRINT_VERIFIED:
1638         /*
1639          * fill out current printer info in setup data
1640          */
1641         psd->printer_name = PSUB_PrinterName(psub);
1642         if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP)
1643         {
1644             psd->print_display = PSUB_Display(psub);
1645             psd->print_context = PSUB_Context(psub);
1646         }
1647         break;
1648
1649     case DtPRINT_IN_VERIFY:
1650         /*
1651          * EstablishPrinter should not be called recursively
1652          */
1653         return DtPRINT_BAD_PARM;
1654         break;
1655     }
1656     
1657     return DtPRINT_SUCCESS;
1658 }
1659
1660 /*
1661  * ------------------------------------------------------------------------
1662  * Name: GetPrintAttributes
1663  *
1664  * Description:
1665  *
1666  *     Get printing attributes relevant to the PrintSetupBox from the
1667  *     current print context.
1668  *
1669  * Return value:
1670  *
1671  *     None.
1672  *
1673  */
1674 static void
1675 GetPrintAttributes(
1676                    DtPrintSetupBoxWidget psub)
1677 {
1678     char* attr_value;
1679     XTextProperty text_prop;
1680     char** list;
1681     int count;
1682     XmString description = (XmString)NULL;
1683     char* ptr;
1684     /*
1685      * get the printer description, and set the description field
1686      */
1687     attr_value = XpGetOneAttribute(PSUB_Display(psub),
1688                                    PSUB_Context(psub),
1689                                    XPPrinterAttr,
1690                                    XpATTR_DESCRIPTOR);
1691     if(attr_value != (char*)NULL)
1692     {
1693         /*
1694          * convert the description from COMPOUND_TEXT into the
1695          * codeset of the current locale
1696          */
1697         text_prop.value = (unsigned char*)attr_value;
1698         text_prop.encoding =
1699             XInternAtom(XtDisplay((Widget)psub), "COMPOUND_TEXT", False);
1700         text_prop.format = 8;
1701         text_prop.nitems = strlen((char*)text_prop.value);
1702         if(Success ==
1703            XmbTextPropertyToTextList(XtDisplay((Widget)psub),
1704                                      &text_prop, &list, &count))
1705         {
1706             if(count > 0)
1707             {
1708                 if((String)NULL != list[0] && '\0' != *(list[0]))
1709                 {
1710                     /*
1711                      * chop the description after the 1st line
1712                      */
1713                     char* ptr = Dt_strchr(list[0], '\n');
1714                     if((char*)NULL != ptr)
1715                         *ptr = '\0';
1716                 }
1717                 description =
1718                     XmStringGenerate((XtPointer)list[0], (XmStringTag)NULL,
1719                                      XmMULTIBYTE_TEXT, (XmStringTag)NULL);
1720             }
1721             XFreeStringList(list);    
1722         }
1723         else
1724         {
1725             XmeWarning((Widget)psub, WARN_CT_CONVERSION);
1726         }
1727         XFree(attr_value);
1728     }
1729     /*
1730      * update the printer description
1731      */
1732     if((XmString)NULL == description)
1733         description = XmStringGenerate((XtPointer)"", (XmStringTag)NULL,
1734                                        XmMULTIBYTE_TEXT, (XmStringTag)NULL);
1735     UpdateString(PSUB_Description(psub), 
1736                  description,
1737                  PSUB_StringDirection(psub));
1738     XmStringFree(description);
1739     /*
1740      * determine if copy-count is supported
1741      */
1742     PSUB_CopyCountSupported(psub) = False;
1743     attr_value = XpGetOneAttribute(PSUB_Display(psub), PSUB_Context(psub),
1744                                    XPPrinterAttr, XpATTR_DOC_ATTRS_SUPPORTED);
1745     if(attr_value != (char*)NULL)
1746     {
1747         int token_len;
1748         for(ptr = attr_value + SpanWhitespace(attr_value);
1749             *ptr != '\0';
1750             ptr += SpanWhitespace(ptr+=token_len))
1751         {
1752             token_len = SpanNonWhitespace(ptr);
1753             if(0 == strncmp(ptr, XpATTR_COPY_COUNT, token_len))
1754             {
1755                 PSUB_CopyCountSupported(psub) = True;
1756                 break;
1757             }
1758         }
1759         XFree(attr_value);
1760     }
1761     if(!PSUB_CopyCountSupported(psub))
1762     {
1763         /*
1764          * copy-count not supported; disable the copies control
1765          */
1766         if(PSUB_CopiesSpinBox(psub))
1767             XtSetSensitive(PSUB_CopiesSpinBox(psub), False);
1768         if(PSUB_CopiesControl(psub))
1769         {
1770             Widget copies_label =
1771                 XtNameToWidget(PSUB_CopiesControl(psub), "CopiesLabel");
1772             XtSetSensitive(copies_label, False);
1773         }
1774     }
1775 }
1776
1777 /*
1778  * ------------------------------------------------------------------------
1779  * Name: Initialize - Core class method
1780  *
1781  * Description:
1782  *
1783  *     Create a PrintSetupBox widget instance.
1784  *
1785  * Return value:
1786  *
1787  *     None.
1788  *
1789  */
1790 static void 
1791 Initialize(
1792            Widget rw,
1793            Widget nw,
1794            ArgList args,
1795            Cardinal *num_args)
1796 {
1797     DtPrintSetupBoxWidget new_w = (DtPrintSetupBoxWidget) nw ;
1798     int i;
1799     /*
1800      * Validate the Print Setup Mode
1801      */
1802     ValidatePrintSetupMode(new_w, (DtPrintSetupBoxWidget)NULL);
1803     /*
1804      * set the Xp-mode default resource procedure if the resource is
1805      * unspecified
1806      */
1807     if(PSUB_PrintSetupMode(new_w) == DtPRINT_SETUP_XP)
1808     {
1809         if(PSUB_PrinterInfoProc(new_w) == (DtPrintSetupProc)DtUNSPECIFIED)
1810             PSUB_PrinterInfoProc(new_w) = _DtPrintSetupBoxXPrinterInfoProc;
1811         if(PSUB_SelectPrinterProc(new_w) == (DtPrintSetupProc)DtUNSPECIFIED)
1812             PSUB_SelectPrinterProc(new_w) = _DtPrintSetupBoxSelectXPrinterProc;
1813         if(PSUB_VerifyPrinterProc(new_w) == (DtPrintSetupProc)DtUNSPECIFIED)
1814             PSUB_VerifyPrinterProc(new_w) = _DtPrintSetupBoxVerifyXPrinterProc;
1815     }
1816     else
1817     {
1818         /*
1819          * for the plain setup mode, unspecified procedure resources
1820          * default to NULL
1821          */
1822         if(PSUB_PrinterInfoProc(new_w) == (DtPrintSetupProc)DtUNSPECIFIED)
1823             PSUB_PrinterInfoProc(new_w) = (DtPrintSetupProc)NULL;
1824         if(PSUB_SelectPrinterProc(new_w) == (DtPrintSetupProc)DtUNSPECIFIED)
1825             PSUB_SelectPrinterProc(new_w) = (DtPrintSetupProc)NULL;
1826         if(PSUB_VerifyPrinterProc(new_w) == (DtPrintSetupProc)DtUNSPECIFIED)
1827             PSUB_VerifyPrinterProc(new_w) = (DtPrintSetupProc)NULL;
1828     }
1829     /*
1830      * initialize internal flags
1831      */
1832     PSUB_VerifyPrinterState(new_w) = DtPRINT_NOT_VERIFIED;
1833     PSUB_CopyCountSupported(new_w) = True;
1834     /*
1835      * initialize internal data
1836      */
1837     PSUB_ModalPrinterSpec(new_w) = (String)NULL;
1838     PSUB_Display(new_w) = (Display*)NULL;
1839     PSUB_Context(new_w) = (XPContext)NULL;
1840     PSUB_TimeoutId(new_w) = (XtIntervalId)NULL;
1841     /*
1842      * retrieve the XpPrinterNameMode application resource for this
1843      * widget
1844      */
1845     {
1846         XtResource res_struct;
1847         res_struct.resource_name = "xpPrinterNameMode";
1848         res_struct.resource_class = "XpPrinterNameMode";
1849         res_struct.resource_type =  XmREnum;
1850         res_struct.resource_size = sizeof(XtEnum);
1851         res_struct.resource_offset = 0;
1852         res_struct.default_type = XmRImmediate;
1853         res_struct.default_addr = (XtPointer)DtSHORT_NAME;
1854         XtGetApplicationResources(nw,
1855                                   (XtPointer)&PSUB_XpPrinterNameMode(new_w),
1856                                   &res_struct, 1, (ArgList)NULL, 0);
1857     }
1858     /*
1859      * Initialize work area children variables
1860      */
1861     PSUB_TopWorkArea(new_w) = (Widget)NULL;
1862     PSUB_BottomWorkArea(new_w) = (Widget)NULL;
1863     ValidateWorkAreaLocation(new_w, (DtPrintSetupBoxWidget)NULL);
1864     /*
1865      * Initialize default resource procedures private data
1866      */
1867     _DtPrintDefProcInitialize((Widget)new_w);
1868     /*
1869      * Create child widgets.
1870      */
1871     PSUB_AddingSelWidgets(new_w) = True;
1872
1873     _DtPrintSetupBoxCreateTopSeparator(new_w);
1874
1875     _DtPrintSetupBoxCreateDescriptionLabel(new_w);
1876     _DtPrintSetupBoxCreateDescription(new_w);
1877     _DtPrintSetupBoxCreatePrinterInfoButton (new_w);
1878     
1879     _DtPrintSetupBoxCreatePrinterNameLabel(new_w);
1880     _DtPrintSetupBoxCreatePrinterNameCombo(new_w);
1881     _DtPrintSetupBoxCreateSelectPrinterButton(new_w);
1882
1883     _DtPrintSetupBoxCreateFileNameLabel(new_w);
1884     _DtPrintSetupBoxCreateFileNameText(new_w);
1885     _DtPrintSetupBoxCreateSelectFileButton(new_w);
1886
1887     _DtPrintSetupBoxCreateDestinationRadioBox(new_w);
1888     _DtPrintSetupBoxCreateCopiesControl(new_w);
1889
1890     _DtPrintSetupBoxCreateBottomSeparator(new_w);
1891
1892     _DtPrintSetupBoxCreateButtonSeparator (new_w);
1893     _DtPrintSetupBoxCreatePrintButton (new_w);
1894     _DtPrintSetupBoxCreateSetupButton (new_w);
1895     _DtPrintSetupBoxCreateCancelButton (new_w);
1896     _DtPrintSetupBoxCreateHelpButton (new_w);
1897     /*
1898      * Validate/update copies spin box
1899      */
1900     SynthSetCopies(new_w, (DtPrintSetupBoxWidget)NULL);
1901     /*
1902      * Update Printer Description
1903      */
1904     if((XmString)NULL != PSUB_DescriptionString(new_w))
1905     {
1906         UpdateString(PSUB_Description(new_w), 
1907                      PSUB_DescriptionString(new_w),
1908                      PSUB_StringDirection(new_w));
1909         PSUB_DescriptionString(new_w) = NULL ;
1910     }
1911     /*
1912      * Initialize printer information
1913      */
1914     SynthSetPrinterName(new_w,
1915                         XtNewString(PSUB_PrinterName(new_w)),
1916                         (String)NULL);
1917     /*
1918      * Validate print destination / update print to file checkbox
1919      */
1920     SynthSetPrintDestination(new_w, (DtPrintSetupBoxWidget)NULL);
1921     /*
1922      * Update the file name text box
1923      */
1924     SynthSetFileName(new_w, (DtPrintSetupBoxWidget)NULL);
1925     /*
1926      * specify the Print button as the default button
1927      */
1928     BB_DefaultButton(new_w) = PSUB_PrintButton(new_w) ;
1929     _XmBulletinBoardSetDynDefaultButton((Widget) new_w,
1930                                         BB_DefaultButton(new_w)) ;
1931
1932     PSUB_AddingSelWidgets(new_w) = False;
1933
1934     XtManageChildren (new_w->composite.children, 
1935                       new_w->composite.num_children) ;
1936
1937 }
1938
1939 /*
1940  * ------------------------------------------------------------------------
1941  * Name: InsertChild - Composite class method
1942  *
1943  * Description:
1944  *
1945  *     The Print Setup widget supports up to TWO work area children. This
1946  *     routine handles adding a child to the Print Setup widget.
1947  *
1948  * Return value:
1949  *
1950  *     None.
1951  *
1952  */
1953 static void 
1954 InsertChild(
1955             Widget child)
1956 {   
1957     DtPrintSetupBoxWidget psub ;
1958     XtWidgetProc insert_child;
1959     /*
1960      * Use the dialog class insert proc to do all the dirty work
1961      */
1962     _DtPrintProcessLock();
1963     insert_child = ((XmBulletinBoardWidgetClass)xmBulletinBoardWidgetClass)
1964       ->composite_class.insert_child;
1965     _DtPrintProcessUnlock();
1966     (*insert_child)(child) ;
1967
1968     if(!XtIsRectObj(child))
1969     {
1970         return ;
1971     } 
1972     psub = (DtPrintSetupBoxWidget) XtParent(child) ;
1973     /*
1974      * check if this child is to be the one of the work areas
1975      */
1976     if(!PSUB_AddingSelWidgets(psub)
1977        && !(XmIsRowColumn(child)
1978             && ((XmRowColumnWidget)child)->row_column.type == XmMENU_BAR
1979             )
1980        && !XtIsShell(child)
1981        && !IsButton(child))
1982     {
1983         if(PSUB_TopWorkArea(psub) == (Widget)NULL
1984            &&
1985            (PSUB_WorkAreaLocation(psub) == DtWORK_AREA_TOP
1986             ||
1987             PSUB_WorkAreaLocation(psub) == DtWORK_AREA_TOP_AND_BOTTOM)
1988            )
1989         {
1990             PSUB_TopWorkArea(psub) = child;
1991         }
1992         else if(PSUB_BottomWorkArea(psub) == (Widget)NULL
1993                 &&
1994                 (PSUB_WorkAreaLocation(psub) == DtWORK_AREA_BOTTOM
1995                  ||
1996                  PSUB_WorkAreaLocation(psub) == DtWORK_AREA_TOP_AND_BOTTOM)
1997                 )
1998         {
1999             PSUB_BottomWorkArea(psub) = child;
2000         }
2001     } 
2002 }
2003
2004 static Boolean
2005 IsSetupRequired(
2006                 DtPrintSetupBoxWidget psub)
2007 {
2008     char* setup_proviso;
2009     Boolean required = False;
2010
2011     setup_proviso = XpGetOneAttribute(PSUB_Display(psub),
2012                                       PSUB_Context(psub),
2013                                       XPPrinterAttr,
2014                                       XpATTR_SETUP_PROVISO);
2015     if((char*)NULL != setup_proviso)
2016     {
2017         char* ptr;
2018         int token_len;
2019
2020         ptr = setup_proviso + SpanWhitespace(setup_proviso);
2021         token_len = SpanNonWhitespace(ptr);
2022         if(token_len && 0 == strncmp(ptr, "xp-setup-mandatory", token_len))
2023         {
2024             char* setup_state;
2025             /*
2026              * setup is mandatory; check to see if it has been performed
2027              */
2028             setup_state = XpGetOneAttribute(PSUB_Display(psub),
2029                                             PSUB_Context(psub),
2030                                             XPJobAttr,
2031                                             XpATTR_SETUP_STATE);
2032             if((char*)NULL == setup_state)
2033                 required = True;
2034             else
2035             {
2036                 ptr = setup_state + SpanWhitespace(setup_state);
2037                 token_len = SpanNonWhitespace(ptr);
2038                 if(token_len)
2039                 {
2040                     /*
2041                      * if the value of the setup state attribute is
2042                      * xp-setup-ok then setup is not required
2043                      */
2044                     if(0 != strncmp(ptr, "xp-setup-ok", token_len))
2045                         required = True;
2046                 }
2047                 else
2048                     required = True;
2049                 XFree(setup_state);
2050             }
2051         }
2052         XFree(setup_proviso);
2053     }
2054     return required;
2055 }
2056
2057 /*
2058  * ------------------------------------------------------------------------
2059  * Name: MenuBarFixUp
2060  *
2061  * Description:
2062  *
2063  *     This routine is a fixup routine which can be used for rows which
2064  *     consist of a single MenuBar RowColumn.  The effect of this routine
2065  *     is to have the RowColumn ignore the margin width and height.
2066  *
2067  * Return value:
2068  *
2069  *     None.
2070  *
2071  */
2072 static void
2073 MenuBarFixUp(
2074              XmGeoMatrix geoSpec,
2075              int action,
2076              XmGeoMajorLayout layoutPtr,
2077              XmKidGeometry rowPtr)
2078 {
2079     register Dimension       marginW ;
2080     register Dimension       marginH ;
2081     register Dimension       twoMarginW ;
2082
2083     marginW = geoSpec->margin_w ;
2084     twoMarginW = (marginW << 1) ;
2085     marginH = geoSpec->margin_h ;
2086
2087     switch(    action    )
2088     {
2089         case XmGEO_PRE_SET:
2090         {
2091             rowPtr->box.x -= marginW ;
2092             rowPtr->box.width += twoMarginW ;
2093             rowPtr->box.y -= marginH ;
2094             break ;
2095         }
2096         default:
2097         {
2098             if(    rowPtr->box.width > twoMarginW    )
2099             {
2100                 /*
2101                  * Avoid subtracting a margin from box width which would
2102                  * result in underflow.
2103                  */
2104                 rowPtr->box.x += marginW ;
2105                 rowPtr->box.width -= twoMarginW ;
2106             }
2107             if(    action == XmGET_PREFERRED_SIZE    )
2108             {
2109                 /*
2110                  * Set width to some small value so it does not effect
2111                  * total width of matrix.
2112                  */
2113                 rowPtr->box.width = 1 ;
2114             }
2115             break ;
2116         }
2117     }
2118
2119
2120 /*
2121  * ------------------------------------------------------------------------
2122  * Name: PrintSetupBoxCallback
2123  *
2124  * Description:
2125  *
2126  *     Call the callbacks for a PrintSetupBox button.
2127  *
2128  * Return value:
2129  *
2130  *     None.
2131  *
2132  */
2133 static void 
2134 PrintSetupBoxCallback(
2135                       Widget w,
2136                       XtPointer client_data,
2137                       XtPointer call_data)
2138 {
2139     DtPrintSetupBoxChild which_button = (DtPrintSetupBoxChild)client_data;
2140     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)XtParent(w);
2141     XmAnyCallbackStruct* callback = (XmAnyCallbackStruct*)call_data;
2142     DtPrintSetupCallbackStruct cbs;
2143     DtPrintSetupData psd;
2144
2145     memset(&cbs, 0, sizeof(DtPrintSetupCallbackStruct));
2146     memset(&psd, 0, sizeof(DtPrintSetupData));
2147     cbs.print_data = &psd;
2148     cbs.event = callback->event;
2149
2150     /*
2151      * we want to see any error messages that may pop up when
2152      * establishing the printer connection
2153      */
2154     psd.messages_hint = DtPRINT_HINT_MESSAGES_OK;
2155     
2156     switch(which_button)
2157     {
2158     case DtPRINT_CANCEL_BUTTON:
2159         cbs.reason = DtPRINT_CR_CANCEL;
2160         XtCallCallbackList((Widget)psub,
2161                            PSUB_CancelCallback(psub),
2162                            (XtPointer)&cbs);
2163         break;
2164
2165     case DtPRINT_FILES_BUTTON:
2166         if(PSUB_SelectFileProc(psub))
2167         {
2168             /*
2169              * setup the destination info
2170              */
2171             SetPSDDestination(psub, &psd);
2172             /*
2173              * call select file proc
2174              */
2175             (*PSUB_SelectFileProc(psub))((Widget)psub, &psd);
2176         }
2177         break;
2178
2179     case DtPRINT_HELP_BUTTON:
2180         /*
2181          * Invoke the help system. 
2182          */
2183         _XmManagerHelp((Widget)psub, callback->event, NULL, NULL) ;
2184         break;
2185
2186     case DtPRINT_INFO_BUTTON:
2187         if(PSUB_PrinterInfoProc(psub))
2188         {
2189             /*
2190              * pick up the printer name from the widget's Printer Name text
2191              * field
2192              */
2193             SynthGetPrinterName(psub);
2194             /*
2195              * establish a connection to the X printer
2196              */
2197             if(EstablishPrinter(psub, &psd) == DtPRINT_SUCCESS)
2198             {
2199                 /*
2200                  * For X printing, set printing attributes
2201                  */
2202                 if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP)
2203                 {
2204                     SetPrintAttributes(psub);
2205                 }
2206                 /*
2207                  * call printer info proc
2208                  */
2209                 (*PSUB_PrinterInfoProc(psub))((Widget)psub, &psd);
2210             }
2211         }
2212         break;
2213         
2214     case DtPRINT_PRINT_BUTTON:
2215         /*
2216          * pick up the printer name from the widget's Printer Name text
2217          * field
2218          */
2219         SynthGetPrinterName(psub);
2220         /*
2221          * establish a connection to the X printer
2222          */
2223         if(EstablishPrinter(psub, &psd) == DtPRINT_SUCCESS)
2224         {
2225             /*
2226              * For X printing, set printing attributes
2227              */
2228             if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP)
2229             {
2230                 SetPrintAttributes(psub);
2231             }
2232             /*
2233              * setup the destination info
2234              */
2235             SetPSDDestination(psub, &psd);
2236
2237             if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP
2238                &&
2239                IsSetupRequired(psub))
2240             {
2241                 /*
2242                  * setup is needed; call the setup callback instead
2243                  */
2244                 cbs.reason = DtPRINT_CR_SETUP;
2245                 XtCallCallbackList((Widget)psub,
2246                                    PSUB_SetupCallback(psub),
2247                                    (XtPointer)&cbs);
2248             }
2249             else
2250             {
2251                 /*
2252                  * The printer name is OK. Go ahead and unmanage the print
2253                  * setup box if the auto-unmanage resource is set.
2254                  */
2255                 if(PSUB_AutoUnmanage(psub) && PSUB_Shell(psub))
2256                     XtUnmanageChild((Widget)psub);
2257                 /*
2258                  * call the Print callback list
2259                  */
2260                 cbs.reason = DtPRINT_CR_PRINT;
2261                 XtCallCallbackList((Widget)psub,
2262                                    PSUB_PrintCallback(psub),
2263                                    (XtPointer)&cbs);
2264             }
2265         }
2266         break;
2267
2268     case DtPRINT_PRINTERS_BUTTON:
2269         if(PSUB_SelectPrinterProc(psub))
2270         {
2271             /*
2272              * call the printer selection proc
2273              */
2274             psd.printer_name = PSUB_PrinterName(psub);
2275             (*PSUB_SelectPrinterProc(psub))((Widget)psub, &psd);
2276         }
2277         break;
2278
2279     case DtPRINT_SETUP_BUTTON:
2280         /*
2281          * pick up the printer name from the widget's Printer Name text
2282          * field
2283          */
2284         SynthGetPrinterName(psub);
2285         /*
2286          * establish a connection to the X printer
2287          */
2288         if(EstablishPrinter(psub, &psd) == DtPRINT_SUCCESS)
2289         {
2290             /*
2291              * For X printing, set printing attributes
2292              */
2293             if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP)
2294             {
2295                 SetPrintAttributes(psub);
2296             }
2297             /*
2298              * setup the destination info
2299              */
2300             SetPSDDestination(psub, &psd);
2301             /*
2302              * Call setup callback
2303              */
2304             cbs.reason = DtPRINT_CR_SETUP;
2305             XtCallCallbackList((Widget)psub,
2306                                PSUB_SetupCallback(psub),
2307                                (XtPointer)&cbs);
2308         }
2309         break;
2310     }
2311 }
2312
2313 /*
2314  * ------------------------------------------------------------------------
2315  * Name: SeparatorFixUp
2316  *
2317  * Description:
2318  *
2319  *     This routine is a fixup routine which can be used for rows which
2320  *     consist of a single separator widget.  The effect of this routine
2321  *     is to have the separator ignore the margin width.
2322  *
2323  * Return value:
2324  *
2325  *     None.
2326  *
2327  */
2328 static void 
2329 SeparatorFixUp(
2330              XmGeoMatrix geoSpec,
2331              int action,
2332              XmGeoMajorLayout layoutPtr,
2333              XmKidGeometry rowPtr )
2334 {
2335     register Dimension       marginW ;
2336     register Dimension       twoMarginW ;
2337
2338     marginW = geoSpec->margin_w ;
2339     twoMarginW = (marginW << 1) ;
2340
2341     switch(    action    )
2342     {   
2343         case XmGEO_PRE_SET:
2344         {
2345             rowPtr->box.x -= marginW ;
2346             rowPtr->box.width += twoMarginW ;
2347             break ;
2348         } 
2349         default:
2350         {
2351             if(    rowPtr->box.width > twoMarginW    )
2352             {   
2353                 /*
2354                  * Avoid subtracting a margin from box width which would
2355                  * result in underflow.
2356                  */
2357                 rowPtr->box.x += marginW ;
2358                 rowPtr->box.width -= twoMarginW ;
2359             } 
2360             if(    action == XmGET_PREFERRED_SIZE    )
2361             {   
2362                 /*
2363                  * Set width to some small value so it does not 
2364                  * effect total width of matrix.
2365                  */
2366                 rowPtr->box.width = 1 ;
2367             } 
2368             break ;
2369         } 
2370     } 
2371 }
2372
2373 /*
2374  * ------------------------------------------------------------------------
2375  * Name: SetNewPrinterName
2376  *
2377  * Description:
2378  *
2379  *     For Xp, if there is an existing open Xp connection, the
2380  *     connection is closed, and the DtNclosePrintDisplayCallback list is
2381  *     called using old_printer_name.
2382  *
2383  *     old_printer_name is then freed using XtFree.
2384  *
2385  *     The printer_name instance variable is set to new_printer_name
2386  *     which must point to memory previously allocated using one of the
2387  *     Xt memory allocation functions.
2388  *
2389  *     This function unsets the printer name verified flag.
2390  *
2391  * Return value:
2392  *
2393  *     None.
2394  *
2395  */
2396 static void
2397 SetNewPrinterName(
2398                   DtPrintSetupBoxWidget psub,
2399                   String new_printer_name,
2400                   String old_printer_name)
2401 {
2402     /*
2403      * close the existing Xp connection
2404      */
2405     if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP
2406        &&
2407        PSUB_Display(psub) != (Display*)NULL)
2408     {
2409         ClosePrintConnection(psub, old_printer_name, True);
2410     }
2411     /*
2412      * free the old printer name
2413      */
2414     XtFree(old_printer_name);
2415     /*
2416      * update the printer name instance data
2417      */
2418     PSUB_PrinterName(psub) = new_printer_name;
2419     /*
2420      * ensure the new printer name will be verified
2421      */
2422     if(PSUB_VerifyPrinterState(psub) == DtPRINT_VERIFIED)
2423         PSUB_VerifyPrinterState(psub) = DtPRINT_NOT_VERIFIED;
2424 }
2425
2426 /*
2427  * ------------------------------------------------------------------------
2428  * Name: SetPrintAttributes
2429  *
2430  * Description:
2431  *
2432  *     Set printing attributes relevant to the PrintSetupBox into the
2433  *     current print context.
2434  *
2435  * Return value:
2436  *
2437  *     None.
2438  *
2439  */
2440 static void
2441 SetPrintAttributes(
2442                    DtPrintSetupBoxWidget psub)
2443 {
2444     /*
2445      * Set the copy-count document attribute in the current context
2446      */
2447     if((Widget)NULL != PSUB_CopiesSpinBox(psub))
2448     {
2449         char str[48];
2450         
2451         XtVaGetValues(PSUB_CopiesSpinBox(psub),
2452                       XmNposition, &PSUB_Copies(psub),
2453                       NULL);
2454         sprintf(str, "*%s: %d\n", XpATTR_COPY_COUNT, PSUB_Copies(psub));
2455         XpSetAttributes(PSUB_Display(psub), PSUB_Context(psub),
2456                         XPDocAttr, str, XPAttrMerge);
2457     }
2458 }
2459
2460 /*
2461  * ------------------------------------------------------------------------
2462  * Name: SetPSDDestination
2463  *
2464  * Description:
2465  *
2466  *     Set print destination information in the passed setup data
2467  *     struct for use in callbacks.
2468  *
2469  * Return value:
2470  *
2471  *     None.
2472  *
2473  */
2474 static void SetPSDDestination(
2475                               DtPrintSetupBoxWidget psub,
2476                               DtPrintSetupData* psd)
2477 {
2478     psd->destination = PSUB_PrintDestination(psub);
2479     switch(PSUB_PrintDestination(psub))
2480     {
2481     case DtPRINT_TO_PRINTER:
2482         psd->dest_info = PSUB_ModalPrinterSpec(psub);
2483         break;
2484                 
2485     case DtPRINT_TO_FILE:
2486         SynthGetFileName(psub);
2487         psd->dest_info = PSUB_FileName(psub);
2488         break;
2489     }
2490 }
2491
2492 /*
2493  * ------------------------------------------------------------------------
2494  * Name: SetSyntheticResForChild
2495  *
2496  * Description:
2497  *
2498  *     Indicate to the synthetic resource mechanism that it should copy
2499  *     the resource value.
2500  *
2501  * Return value:
2502  *
2503  *     Always XmSYNTHETIC_LOAD.
2504  *
2505  */
2506 static XmImportOperator
2507 SetSyntheticResForChild(
2508                         Widget widget,
2509                         int offset,
2510                         XtArgVal *value)
2511
2512     return XmSYNTHETIC_LOAD;
2513 }
2514
2515 /*
2516  * ------------------------------------------------------------------------
2517  * Name: SetValues - Core class method
2518  *
2519  * Description:
2520  *
2521  *     Update widget when values change.
2522  *
2523  * Return value:
2524  *
2525  *     Always False, because this widget will redraw itself.
2526  *
2527  */
2528 static Boolean 
2529 SetValues(
2530           Widget cw,
2531           Widget rw,
2532           Widget nw,
2533           ArgList args,
2534           Cardinal *num_args)
2535 {
2536     DtPrintSetupBoxWidget current = (DtPrintSetupBoxWidget) cw ;
2537     DtPrintSetupBoxWidget request = (DtPrintSetupBoxWidget) rw ;
2538     DtPrintSetupBoxWidget new_w = (DtPrintSetupBoxWidget) nw ;
2539     Boolean need_layout = False;
2540
2541     BB_InSetValues(new_w) = True;
2542     /*
2543      * Validate the Print Setup Mode
2544      */
2545     if(PSUB_PrintSetupMode(new_w) != PSUB_PrintSetupMode(current))
2546         ValidatePrintSetupMode(new_w, current);
2547     /*
2548      * Validate work area location
2549      */
2550     if(PSUB_WorkAreaLocation(new_w) != PSUB_WorkAreaLocation(current))
2551         ValidateWorkAreaLocation(new_w, current);
2552     /*
2553      * Update Printer Description
2554      */
2555     if(PSUB_DescriptionString(new_w) != PSUB_DescriptionString(current))
2556     {
2557         UpdateString(PSUB_Description(new_w), 
2558                      PSUB_DescriptionString(new_w),
2559                      PSUB_StringDirection(new_w));
2560         PSUB_DescriptionString(new_w) = NULL ;
2561     }
2562     /*
2563      * Validate print destination / update print to file checkbox
2564      */
2565     if(PSUB_PrintDestination(new_w) != PSUB_PrintDestination(current))
2566         SynthSetPrintDestination(new_w, current);
2567     /*
2568      * Update the file name
2569      */
2570     if(PSUB_FileName(new_w) != PSUB_FileName(current))
2571         SynthSetFileName(new_w, current);
2572     /*
2573      * Validate/update copies spin box
2574      */
2575     if(PSUB_Copies(new_w) != PSUB_Copies(current))
2576         SynthSetCopies(new_w, current);
2577     /*
2578      * Update the Printer Name text field
2579      */
2580     if(PSUB_PrinterName(new_w) != PSUB_PrinterName(current))
2581     {
2582         if((PSUB_PrinterName(new_w) == NULL
2583             ||
2584             PSUB_PrinterName(current) == NULL)
2585            ? True
2586            : strcmp(PSUB_PrinterName(new_w), PSUB_PrinterName(current)) != 0)
2587         {
2588             /*
2589              * the printer names are different; set the new printer name
2590              * into the instance structure and the printer name text
2591              * field
2592              */
2593             SynthSetPrinterName(new_w,
2594                                 XtNewString(PSUB_PrinterName(new_w)),
2595                                 PSUB_PrinterName(current));
2596         }
2597         else
2598         {
2599             /*
2600              * printer names are identical; keep current
2601              */
2602             PSUB_PrinterName(new_w) = PSUB_PrinterName(current);
2603         }
2604     }
2605     if(PSUB_MinimizeButtons(new_w) != PSUB_MinimizeButtons(current))
2606     {
2607         need_layout = True;
2608     }
2609     /*
2610      * finished setting values
2611      */
2612     BB_InSetValues (new_w) = False;
2613     /*
2614      * If this is the instantiated class then do layout.
2615      */
2616     if(need_layout && XtClass(new_w) == dtPrintSetupBoxWidgetClass)
2617     {
2618         _XmBulletinBoardSizeUpdate((Widget) new_w) ;
2619     }
2620     return False;
2621 }
2622
2623 /*
2624  * ------------------------------------------------------------------------
2625  * Name: SpanNonWhitespace
2626  *
2627  * Description:
2628  *
2629  *     Returns the length of the initial segment of the passed string
2630  *     that consists entirely of non-whitespace characters.
2631  *
2632  *
2633  */
2634 static int
2635 SpanNonWhitespace(const char* string)
2636 {
2637     const char* ptr;
2638     for(ptr = string;
2639         *ptr != '\0' && !DtIsspace((char*)ptr);
2640         ptr = DtNextChar((char*)ptr));
2641     return ptr - string;
2642 }
2643
2644 /*
2645  * ------------------------------------------------------------------------
2646  * Name: SpanWhitespace
2647  *
2648  * Description:
2649  *
2650  *     Returns the length of the initial segment of the passed string
2651  *     that consists entirely of whitespace characters.
2652  *
2653  *
2654  */
2655 static int
2656 SpanWhitespace(const char* string)
2657 {
2658     const char* ptr;
2659     for(ptr = string;
2660         *ptr != '\0' && DtIsspace((char*)ptr);
2661         ptr = DtNextChar((char*)ptr));
2662     return ptr - string;
2663 }
2664
2665 /*
2666  * ------------------------------------------------------------------------
2667  * Name: SynthGetFileName
2668  *
2669  * Description:
2670  *
2671  *     Updates the file_name element of the PrintSetupBox instance
2672  *     structure based on the current state of the File Name text field.
2673  *
2674  * Return Value:
2675  *
2676  *     None.
2677  *
2678  */
2679 static void SynthGetFileName(
2680                              DtPrintSetupBoxWidget psub)
2681 {
2682     /*
2683      * free the existing file name
2684      */
2685     XtFree(PSUB_FileName(psub));
2686     /*
2687      * set the file name widget instance value based on the File Name
2688      * text field value
2689      */
2690     if(PSUB_FileNameText(psub) != (Widget)NULL)
2691         XtVaGetValues((Widget)PSUB_FileNameText(psub),
2692                       XmNvalue, &PSUB_FileName(psub),
2693                       NULL);
2694     else
2695         PSUB_FileName(psub) = (String)NULL;
2696 }
2697
2698 /*
2699  * ------------------------------------------------------------------------
2700  * Name: SynthGetPrinterName
2701  *
2702  * Description:
2703  *
2704  *     Updates the modal_printer_spec and the printer_name elements of
2705  *     the PrintSetupBox instance structure based on the current state of
2706  *     the Printer Name text field. The verify printer state will be set
2707  *     to "not verified" if the printer_name is updated.
2708  *
2709  * Return Value:
2710  *
2711  *     None.
2712  *
2713  */
2714 static void
2715 SynthGetPrinterName(
2716                     DtPrintSetupBoxWidget psub)
2717 {
2718     Boolean printer_spec_changed = False;
2719     String previous_modal_spec;
2720     
2721     if(PSUB_PrinterNameText(psub) != (Widget)NULL)
2722     {   
2723         /*
2724          * get the modal Printer Specifier from the Printer Name text
2725          * field
2726          */
2727         previous_modal_spec = PSUB_ModalPrinterSpec(psub);
2728         XtVaGetValues((Widget)PSUB_PrinterNameText(psub),
2729                       XmNvalue, &PSUB_ModalPrinterSpec(psub),
2730                       NULL);
2731         /*
2732          * determine if we have a new printer name
2733          */
2734         switch(PSUB_PrintSetupMode(psub))
2735         {
2736         case DtPRINT_SETUP_PLAIN:
2737             if((PSUB_ModalPrinterSpec(psub) == (String)NULL
2738                 ||
2739                 PSUB_PrinterName(psub) == (String)NULL))
2740             {
2741                 printer_spec_changed = True;
2742             }
2743             else if(strcmp(PSUB_ModalPrinterSpec(psub), PSUB_PrinterName(psub))
2744                     != 0)
2745             {
2746                 printer_spec_changed = True;
2747             }
2748             break;
2749
2750         case DtPRINT_SETUP_XP:
2751             if(PSUB_PrinterName(psub) == (String)NULL
2752                ||
2753                PSUB_ModalPrinterSpec(psub) == (String)NULL
2754                ||
2755                (Display*)NULL == PSUB_Display(psub)
2756                ||
2757                strcmp(previous_modal_spec, PSUB_ModalPrinterSpec(psub)) != 0)
2758             {
2759                 printer_spec_changed = True;
2760             }
2761             break;
2762         }
2763         XtFree(previous_modal_spec);
2764     }
2765     if(printer_spec_changed)
2766     {
2767         SetNewPrinterName(psub,
2768                           XtNewString(PSUB_ModalPrinterSpec(psub)),/*new name*/
2769                           PSUB_PrinterName(psub));               /* old name */
2770     }
2771 }
2772
2773 /*
2774  * ------------------------------------------------------------------------
2775  * Name: SynthSetCopies
2776  *
2777  * Description:
2778  *
2779  *     Validate the DtNcopies resource, and use it to update the Copies
2780  *     spin box.
2781  *
2782  * Return value:
2783  *
2784  *     None.
2785  *
2786  */
2787 static void
2788 SynthSetCopies(
2789                DtPrintSetupBoxWidget new_w,
2790                DtPrintSetupBoxWidget current)
2791 {
2792     if(PSUB_Copies(new_w) < 1 || PSUB_Copies(new_w) > MAX_COPIES)
2793     {
2794         XmeWarning((Widget)new_w, WARN_COPY_COUNT);
2795         if(current == (DtPrintSetupBoxWidget)NULL)
2796             PSUB_Copies(new_w) = 1;
2797         else
2798             PSUB_Copies(new_w) = PSUB_Copies(current);
2799     }
2800     if(PSUB_CopiesSpinBox(new_w) != (Widget)NULL)
2801         XtVaSetValues(PSUB_CopiesSpinBox(new_w),
2802                       XmNposition, PSUB_Copies(new_w),
2803                       NULL);
2804 }
2805
2806 /*
2807  * ------------------------------------------------------------------------
2808  * Name: SynthSetFileName
2809  *
2810  * Description:
2811  *
2812  *     Update the file name text field.
2813  *
2814  * Return value:
2815  *
2816  *     None.
2817  *
2818  */
2819 static void
2820 SynthSetFileName(
2821                  DtPrintSetupBoxWidget new_w,
2822                  DtPrintSetupBoxWidget current)
2823 {
2824     /*
2825      * free the old file name
2826      */
2827     if(current != (DtPrintSetupBoxWidget)NULL)
2828     {
2829         XtFree(PSUB_FileName(current));
2830     }
2831     /*
2832      * make a copy of the new file name
2833      */
2834     PSUB_FileName(new_w) = XtNewString(PSUB_FileName(new_w));
2835     /*
2836      * update the file name text box
2837      */
2838     if(PSUB_FileNameText(new_w) != (Widget)NULL)
2839     {
2840         XmTextPosition last_position;
2841         XmTextFieldSetString(PSUB_FileNameText(new_w), PSUB_FileName(new_w));
2842         last_position = XmTextFieldGetLastPosition(PSUB_FileNameText(new_w));
2843         XmTextFieldSetInsertionPosition(PSUB_FileNameText(new_w),
2844                                         last_position);
2845     }
2846 }
2847
2848 /*
2849  * ------------------------------------------------------------------------
2850  * Name: SynthSetPrintDestination
2851  *
2852  * Description:
2853  *
2854  *     Validate the DtNprintDestination resource, and use it to update
2855  *     the print destination radio buttons.
2856  *
2857  * Return value:
2858  *
2859  *     None.
2860  *
2861  */
2862 static void
2863 SynthSetPrintDestination(
2864                          DtPrintSetupBoxWidget new_w,
2865                          DtPrintSetupBoxWidget current)
2866 {
2867     if(PSUB_PrintDestination(new_w) != DtPRINT_TO_PRINTER
2868        &&
2869        PSUB_PrintDestination(new_w) != DtPRINT_TO_FILE)
2870     {
2871         XmeWarning((Widget)new_w, WARN_PRINT_DESTINATION);
2872         if(current == (DtPrintSetupBoxWidget)NULL)
2873             PSUB_PrintDestination(new_w) = DtPRINT_TO_PRINTER;
2874         else
2875             PSUB_PrintDestination(new_w) = PSUB_PrintDestination(current);
2876     }
2877     if((Widget)NULL != PSUB_DestinationRadioBox(new_w))
2878     {
2879         Widget button;
2880         
2881         switch(PSUB_PrintDestination(new_w))
2882         {
2883         case DtPRINT_TO_PRINTER:
2884             button =
2885                 XtNameToWidget(PSUB_DestinationRadioBox(new_w), "button_0");
2886             XmToggleButtonSetState(button, True, True);
2887             break;
2888             
2889         case DtPRINT_TO_FILE:
2890             button =
2891                 XtNameToWidget(PSUB_DestinationRadioBox(new_w), "button_1");
2892             XmToggleButtonSetState(button, True, True);
2893             break;
2894         }
2895     }
2896 }
2897
2898 /*
2899  * ------------------------------------------------------------------------
2900  * Name: SynthSetPrinterName
2901  *
2902  * Description:
2903  *
2904  *     Set the passed new_printer_name into the print setup box by
2905  *     updating the Printer Name text field and the modal_printer_name
2906  *     and printer_name instance variables. The verify printer state will
2907  *     be set to DtPRINT_NOT_VERIFIED if the printer_name was updated.
2908  *
2909  *     new_printer_name must have been previously allocated using one of
2910  *     the Xt memory allocation functions. If the passed new_printer_name
2911  *     is NULL, a default printer name will be used.
2912  *
2913  *     The old_printer_name is passed to the DtNclosePrintDisplayCallback
2914  *     list, if it is called. The old_printer_name is freed using XtFree.
2915  *
2916  * Return value:
2917  *
2918  *     None.
2919  *
2920  */
2921 static void
2922 SynthSetPrinterName(
2923                     DtPrintSetupBoxWidget psub,
2924                     String new_printer_name,
2925                     String old_printer_name)
2926 {
2927     /*
2928      * update the printer name in the widget instance structure
2929      */
2930     SetNewPrinterName(psub, new_printer_name, old_printer_name);
2931     /*
2932      * create a new modal printer name
2933      */
2934     XtFree(PSUB_ModalPrinterSpec(psub));
2935     switch(PSUB_PrintSetupMode(psub))
2936     {
2937     case DtPRINT_SETUP_PLAIN:
2938         /*
2939          * Ignore the name mode
2940          */
2941         PSUB_ModalPrinterSpec(psub) = XtNewString(PSUB_PrinterName(psub));
2942         break;
2943
2944     case DtPRINT_SETUP_XP:
2945         /*
2946          * Create a modal X Printer Specifier
2947          */
2948         PSUB_ModalPrinterSpec(psub) =
2949             CreateModalPrinterSpec(PSUB_XpPrinterNameMode(psub),
2950                                    PSUB_PrinterName(psub));
2951         break;
2952     }
2953     /*
2954      * Set the modal printer specifier in the Printer Name text field
2955      */
2956     if(PSUB_PrinterNameText(psub))
2957     {
2958         XtVaSetValues(PSUB_PrinterNameText(psub),
2959                       XmNvalue, PSUB_ModalPrinterSpec(psub),
2960                       NULL);
2961         XmComboBoxUpdate(PSUB_PrinterNameCombo(psub));
2962     }
2963     /*
2964      * verify the printer; get intial attributes for a new X printer
2965      * connection
2966      */
2967     if(PSUB_VerifyPrinterState(psub) == DtPRINT_NOT_VERIFIED)
2968     {
2969         DtPrintSetupData psd;
2970         Window window;
2971         
2972         memset(&psd, 0, sizeof(DtPrintSetupData));
2973         /*
2974          * don't show any messages if this widget isn't mapped
2975          */
2976         psd.messages_hint = DtPRINT_HINT_NO_MESSAGES;
2977         window = XtWindow((Widget)psub);
2978         if(window)
2979         {
2980             XWindowAttributes attr;
2981             Status status = XGetWindowAttributes(XtDisplay((Widget)psub),
2982                                                  window, &attr);
2983             if(status != 0 && attr.map_state == IsViewable)
2984                 psd.messages_hint = DtPRINT_HINT_MESSAGES_OK;
2985         }
2986         /*
2987          * establish a connection to the X printer
2988          */
2989         EstablishPrinter(psub, &psd);
2990     }
2991 }
2992
2993 /*
2994  * ------------------------------------------------------------------------
2995  * Name: UpdatePrinterNameCallback
2996  *
2997  * Description:
2998  *
2999  *     Kick off a timer proc to establish the selected printer in the
3000  *     widget. This allows the hourglass to be visible while the
3001  *     connection is being established. The hourglass can't be set inside
3002  *     the callback because the combo box list is still popped up with
3003  *     the pointer grabbed... Of course if the user is traversing through
3004  *     the list with the cursor keys, ie. without popping it down,
3005  *     there's nothing we can do to change the cursor...
3006  *
3007  * Return value:
3008  *
3009  *     None.
3010  *
3011  */
3012 static void
3013 UpdatePrinterNameCallback(
3014                           Widget w,
3015                           XtPointer client_data,
3016                           XtPointer call_data)
3017 {
3018     XmComboBoxCallbackStruct* callback = (XmComboBoxCallbackStruct*)call_data;
3019     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)client_data;
3020
3021     if(PSUB_TimeoutId(psub) != (XtIntervalId)NULL)
3022         XtRemoveTimeOut(PSUB_TimeoutId(psub));
3023
3024     PSUB_TimeoutId(psub) =
3025         XtAppAddTimeOut(XtWidgetToApplicationContext(w),
3026                         (unsigned long)0,
3027                         UpdatePrinterNameTimeoutProc,
3028                         (XtPointer)psub);
3029 }
3030
3031 /*
3032  * ------------------------------------------------------------------------
3033  * Name: UpdatePrinterNameCallback
3034  *
3035  * Description:
3036  *
3037  *     Timeout proc that establishes a printer connection in response to
3038  *     a user selection in the printer name combo box.
3039  *
3040  * Return value:
3041  *
3042  *     None.
3043  *
3044  */
3045 static void
3046 UpdatePrinterNameTimeoutProc(XtPointer client_data,
3047                              XtIntervalId* id)
3048 {
3049     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)client_data;
3050     DtPrintSetupData psd;
3051     /*
3052      * the timeout seems to happen before expose events from the
3053      * popdown
3054      */
3055     XmUpdateDisplay((Widget)psub);
3056     /*
3057      * the timeout proc is only called once per XtAppAddTimeOut
3058      */
3059     PSUB_TimeoutId(psub) = (XtIntervalId)NULL;
3060     /*
3061      * check to see if the printer name has changed (if so,
3062      * SynthGetPrinterName will close an existing print connection)
3063      */
3064     SynthGetPrinterName(psub);
3065     /*
3066      * try to establish a connection to a new printer name
3067      * (the message hint is set so that we don't see error messages from
3068      * here)
3069      */
3070     memset(&psd, 0, sizeof(DtPrintSetupData));
3071     psd.messages_hint = DtPRINT_HINT_NO_MESSAGES;
3072     EstablishPrinter(psub, &psd);
3073 }
3074
3075 /*
3076  * ------------------------------------------------------------------------
3077  * Name: UpdateString
3078  *
3079  * Description:
3080  *
3081  *     Set the label string of a label or button
3082  *
3083  * Return value:
3084  *
3085  *     None.
3086  *
3087  */
3088 static void 
3089 UpdateString(
3090              Widget w,
3091              XmString string,
3092              XmStringDirection direction)
3093 {
3094     Arg         al[3];
3095     register int        ac = 0;
3096
3097     if (w)
3098     {
3099         XtSetArg (al[ac], XmNstringDirection, direction);  ac++;
3100         XtSetArg (al[ac], XmNlabelString, string);  ac++;
3101         XtSetValues (w, al, ac);
3102     }
3103 }
3104
3105 /*
3106  * ------------------------------------------------------------------------
3107  * Name: ValidatePrintSetupMode
3108  *
3109  * Description:
3110  *
3111  *     Validate the DtNprintSetupMode resource.
3112  *
3113  * Return value:
3114  *
3115  *     None.
3116  *
3117  */
3118 static void
3119 ValidatePrintSetupMode(
3120                        DtPrintSetupBoxWidget new_w,
3121                        DtPrintSetupBoxWidget current)
3122 {
3123     if(current == (DtPrintSetupBoxWidget)NULL)
3124     {
3125         switch(PSUB_PrintSetupMode(new_w))
3126         {
3127         case DtPRINT_SETUP_PLAIN:
3128         case DtPRINT_SETUP_XP:
3129             break;
3130         default:
3131             PSUB_PrintSetupMode(new_w) = SETUP_MODE_DEFAULT;
3132             XmeWarning((Widget)new_w, WARN_SETUP_MODE);
3133             break;
3134         }
3135     }
3136     else
3137     {
3138         /*
3139          * prevent changes to the mode
3140          */
3141         PSUB_PrintSetupMode(new_w) = PSUB_PrintSetupMode(current);
3142         XmeWarning((Widget)new_w, WARN_SETUP_MODE_CHANGE);
3143     }
3144 }
3145
3146 /*
3147  * ------------------------------------------------------------------------
3148  * Name: ValidateWorkAreaLocation
3149  *
3150  * Description:
3151  *
3152  *     Validate the DtNworkAreaLocation resource.
3153  *
3154  * Return value:
3155  *
3156  *     None.
3157  *
3158  */
3159 static void
3160 ValidateWorkAreaLocation(
3161                          DtPrintSetupBoxWidget new_w,
3162                          DtPrintSetupBoxWidget current)
3163 {
3164     switch(PSUB_WorkAreaLocation(new_w))
3165     {
3166     case DtWORK_AREA_NONE:
3167     case DtWORK_AREA_TOP:
3168     case DtWORK_AREA_TOP_AND_BOTTOM:
3169     case DtWORK_AREA_BOTTOM:
3170         break;
3171         
3172     default:
3173         XmeWarning((Widget)new_w, WARN_WORK_AREA_LOCATION);
3174         if(current == (DtPrintSetupBoxWidget)NULL)
3175             PSUB_WorkAreaLocation(new_w) = WORK_AREA_DEFAULT;
3176         else
3177             PSUB_WorkAreaLocation(new_w) = PSUB_WorkAreaLocation(current);
3178         break;
3179     }
3180 }
3181
3182 /*
3183  * ------------------------------------------------------------------------
3184  * Name: _DtPrintSetupBoxCreateBottomSeparator
3185  *
3186  * Description:
3187  *
3188  *     Create the Separator displayed above the bottom work area
3189  *
3190  * Return value:
3191  *
3192  *     None.
3193  *
3194  */
3195 void 
3196 _DtPrintSetupBoxCreateBottomSeparator(DtPrintSetupBoxWidget psub)
3197 {
3198     Arg al[10];
3199     register int ac = 0;
3200
3201     XtSetArg(al[ac], XmNhighlightThickness, 0);  ac++;
3202     PSUB_BottomSeparator(psub) =
3203         XmCreateSeparatorGadget((Widget) psub,
3204                                 "BottomWorkAreaSeparator",
3205                                 al, ac);
3206 }
3207
3208 /*
3209  * ------------------------------------------------------------------------
3210  * Name: _DtPrintSetupBoxCreateButtonSeparator
3211  *
3212  * Description:
3213  *
3214  *     Create the Separator displayed above the buttons.
3215  *
3216  * Return value:
3217  *
3218  *     None.
3219  *
3220  */
3221 void 
3222 _DtPrintSetupBoxCreateButtonSeparator(DtPrintSetupBoxWidget sel)
3223 {
3224     Arg al[10];
3225     register int ac = 0;
3226
3227     XtSetArg(al[ac], XmNhighlightThickness, 0);  ac++;
3228     PSUB_ButtonSeparator(sel) =
3229         XmCreateSeparatorGadget((Widget) sel, "ButtonSeparator", al, ac);
3230 }
3231
3232 /*
3233  * ------------------------------------------------------------------------
3234  * Name: _DtPrintSetupBoxCreateCancelButton
3235  *
3236  * Description:
3237  *
3238  *     Create the "Cancel" PushButton.
3239  *
3240  * Return value:
3241  *
3242  *     None.
3243  *
3244  */
3245 void 
3246 _DtPrintSetupBoxCreateCancelButton(
3247                                    DtPrintSetupBoxWidget psub)
3248 {
3249     PSUB_CancelButton(psub) =
3250         CreateButtonGadget((Widget)psub, CANCEL_LABEL, "Cancel", XmNONE);
3251
3252     XtAddCallback(PSUB_CancelButton(psub), XmNactivateCallback, 
3253                   PrintSetupBoxCallback, (XtPointer) DtPRINT_CANCEL_BUTTON) ;
3254 }
3255
3256 /*
3257  * ------------------------------------------------------------------------
3258  * Name: _DtPrintSetupBoxCreateCopiesControl
3259  *
3260  * Description:
3261  *
3262  *     Create the copy count label and spin box.
3263  *
3264  * Return value:
3265  *
3266  *     None.
3267  *
3268  */
3269 void 
3270 _DtPrintSetupBoxCreateCopiesControl(DtPrintSetupBoxWidget psub)
3271 {
3272     Widget copies_label;
3273     Widget copies_text;
3274     Boolean copies_text_editable;
3275
3276     /*
3277      * create a row column to contain the copy count label and spin box
3278      */
3279     PSUB_CopiesControl(psub) =
3280         XtVaCreateWidget("CopiesControl",
3281                          xmRowColumnWidgetClass,
3282                          (Widget)psub,
3283                          XmNorientation, XmHORIZONTAL,
3284                          NULL);
3285     /*
3286      * create the label
3287      */
3288     copies_label = CreateLabelGadget(PSUB_CopiesControl(psub),
3289                                      COPIES_LABEL, "CopiesLabel");
3290     XtManageChild(copies_label);
3291     /*
3292      * spin box
3293      */
3294     PSUB_CopiesSpinBox(psub) =
3295         XtVaCreateManagedWidget("Copies", 
3296                                 xmSimpleSpinBoxWidgetClass,
3297                                 PSUB_CopiesControl(psub) ,
3298                                 XmNspinBoxChildType, XmNUMERIC,
3299                                 XmNminimumValue, 1,
3300                                 XmNmaximumValue, MAX_COPIES,
3301                                 XmNposition, 1,
3302                                 XmNpositionType, XmPOSITION_VALUE,
3303                                 XmNcolumns, 5,
3304                                 XmNwrap, False,
3305                                 NULL);
3306
3307     copies_text = NULL;
3308     copies_text_editable = FALSE;
3309     XtVaGetValues(
3310                 PSUB_CopiesSpinBox(psub),
3311                 XmNtextField, &copies_text,
3312                 XmNeditable, &copies_text_editable,
3313                 NULL);
3314
3315     if (copies_text && copies_text_editable)
3316       XtAddCallback(
3317                 copies_text, XmNvalueChangedCallback,
3318                 CopiesTextValueChangedCallback, (XtPointer) psub);
3319 }
3320
3321 /*
3322  * ------------------------------------------------------------------------
3323  * Name: _DtPrintSetupBoxCreateDescription
3324  *
3325  * Description:
3326  *
3327  *     Create the printer description.
3328  *
3329  * Return value:
3330  *
3331  *     None.
3332  *
3333  */
3334 void 
3335 _DtPrintSetupBoxCreateDescription(
3336                                   DtPrintSetupBoxWidget psub)
3337 {
3338     XmRenderTable render_table;
3339     XFontStruct* font;
3340     unsigned long char_width;
3341     XmString empty_label;
3342     /*
3343      * create the description label gadget
3344      */
3345     empty_label = XmStringCreateLocalized(" ");
3346     PSUB_Description(psub) =
3347         XtVaCreateWidget("Description",
3348                          xmLabelWidgetClass,
3349                          (Widget)psub,
3350                          XmNalignment, XmALIGNMENT_BEGINNING,
3351                          XmNlabelString, empty_label,
3352                          NULL);
3353     XmStringFree(empty_label);
3354     /*
3355      * get the maximum character width for the default font of the gadget
3356      */
3357     XtVaGetValues(PSUB_Description(psub), XmNrenderTable, &render_table, NULL);
3358     if(XmeRenderTableGetDefaultFont(render_table, &font))
3359     {
3360         Bool success;
3361
3362         success = XGetFontProperty(font, XA_QUAD_WIDTH, &char_width);
3363         if(!success || char_width == 0)
3364         {
3365             if(font->per_char
3366                && font->min_char_or_byte2 <= '0'
3367                && font->max_char_or_byte2 >= '0'
3368                )
3369                 char_width =
3370                     font->per_char['0' - font->min_char_or_byte2].width;
3371             else
3372                 char_width = font->max_bounds.width;
3373         }
3374         /*
3375          * set and lock the width of description gadget
3376          */
3377         XtVaSetValues(PSUB_Description(psub),
3378                       XmNwidth, (Dimension)(DESCRIPTION_COLUMNS*char_width),
3379                       XmNrecomputeSize, False,
3380                       NULL);
3381     }
3382 }
3383
3384 /*
3385  * ------------------------------------------------------------------------
3386  * Name: _DtPrintSetupBoxCreateDescriptionLabel
3387  *
3388  * Description:
3389  *
3390  *     Create the Label for the printer description.
3391  *
3392  * Return value:
3393  *
3394  *     None.
3395  *
3396  */
3397 void 
3398 _DtPrintSetupBoxCreateDescriptionLabel(DtPrintSetupBoxWidget psub)
3399 {
3400     PSUB_DescriptionLabel(psub) =
3401         CreateLabelGadget((Widget) psub,
3402                           DESCRIPTION_LABEL,
3403                           "DescriptionLabel") ;
3404 }
3405
3406 /*
3407  * ------------------------------------------------------------------------
3408  * Name: _DtPrintSetupBoxCreateDestinationRadioBox
3409  *
3410  * Description:
3411  *
3412  *     Create the "Print to Printer" and "Print to File" radio buttons.
3413  *
3414  * Return value:
3415  *
3416  *     None.
3417  *
3418  */
3419 void
3420 _DtPrintSetupBoxCreateDestinationRadioBox(DtPrintSetupBoxWidget psub)
3421 {
3422     Widget button;
3423     XmString label;
3424     
3425     PSUB_DestinationRadioBox(psub) =
3426         XtVaCreateWidget(
3427                          "DestRadioBox",
3428                          xmRowColumnWidgetClass,
3429                          (Widget)psub,
3430                          XmNradioBehavior, True,
3431                          XmNorientation, XmHORIZONTAL,
3432                          XmNpacking, XmPACK_TIGHT,
3433                          NULL);
3434
3435     label =
3436         XmStringGenerate((XtPointer)PRINT_TO_PRINTER_LABEL, (XmStringTag)NULL,
3437                          XmMULTIBYTE_TEXT, (XmStringTag)NULL);
3438     button =
3439         XtVaCreateManagedWidget("button_0",
3440                                 xmToggleButtonWidgetClass,
3441                                 PSUB_DestinationRadioBox(psub),
3442                                 XmNlabelString, label,
3443                                 XmNuserData, (XtPointer)DtPRINT_TO_PRINTER,
3444                                 NULL);
3445     XmStringFree(label);
3446     XtAddCallback(button, XmNvalueChangedCallback,
3447                   DestinationChangedCallback, (XtPointer)psub);
3448
3449     label = XmStringGenerate((XtPointer)PRINT_TO_FILE_LABEL, (XmStringTag)NULL,
3450                              XmMULTIBYTE_TEXT, (XmStringTag)NULL);
3451     button =
3452         XtVaCreateManagedWidget("button_1",
3453                                 xmToggleButtonWidgetClass,
3454                                 PSUB_DestinationRadioBox(psub),
3455                                 XmNlabelString, label,
3456                                 XmNuserData, (XtPointer)DtPRINT_TO_FILE,
3457                                 NULL);
3458     XmStringFree(label);
3459     XtAddCallback(button, XmNvalueChangedCallback,
3460                   DestinationChangedCallback, (XtPointer)psub);
3461 }
3462
3463 /*
3464  * ------------------------------------------------------------------------
3465  * Name: _DtPrintSetupBoxCreateFileNameLabel
3466  *
3467  * Description:
3468  *
3469  *     Create the "Print to File" check box.
3470  *
3471  * Return value:
3472  *
3473  *     None.
3474  *
3475  */
3476 void 
3477 _DtPrintSetupBoxCreateFileNameLabel(DtPrintSetupBoxWidget psub)
3478 {
3479     PSUB_FileNameLabel(psub) =
3480         CreateLabelGadget((Widget)psub, FILE_NAME_LABEL, "FileNameLabel") ;
3481 }
3482
3483 /*
3484  * ------------------------------------------------------------------------
3485  * Name: _DtPrintSetupBoxCreateFileNameText
3486  *
3487  * Description:
3488  *
3489  *     Create the print to file name text field.
3490  *
3491  * Return value:
3492  *
3493  *     None.
3494  *
3495  */
3496 void 
3497 _DtPrintSetupBoxCreateFileNameText(DtPrintSetupBoxWidget psub)
3498 {
3499     PSUB_FileNameText(psub) =
3500         XtVaCreateWidget("FileName", 
3501                          xmTextFieldWidgetClass,
3502                          (Widget)psub,
3503                          XmNcolumns, FILE_NAME_COLUMNS,
3504                          NULL);
3505 }
3506
3507 /*
3508  * ------------------------------------------------------------------------
3509  * Name: _DtPrintSetupBoxCreateHelpButton
3510  *
3511  * Description:
3512  *     Create the "Help" PushButton.
3513  *
3514  * Return value:
3515  *
3516  *     None.
3517  *
3518  */
3519 void 
3520 _DtPrintSetupBoxCreateHelpButton(DtPrintSetupBoxWidget psub)
3521 {
3522     PSUB_HelpButton(psub) =
3523         CreateButtonGadget((Widget)psub, HELP_LABEL, "Help", XmNONE) ;
3524     /*
3525      * Remove BulletinBoard Unmanage callback
3526      */
3527     XtRemoveAllCallbacks(PSUB_HelpButton(psub), XmNactivateCallback) ;
3528
3529     XtAddCallback(PSUB_HelpButton (psub), XmNactivateCallback, 
3530                   PrintSetupBoxCallback, (XtPointer)DtPRINT_HELP_BUTTON) ;
3531 }
3532
3533 /*
3534  * ------------------------------------------------------------------------
3535  * Name: _DtPrintSetupBoxCreatePrintButton
3536  *
3537  * Description:
3538  *     Create the "Print" PushButton.
3539  *
3540  * Return value:
3541  *
3542  *     None.
3543  *
3544  */
3545 void 
3546 _DtPrintSetupBoxCreatePrintButton(DtPrintSetupBoxWidget psub)
3547 {
3548     PSUB_PrintButton(psub) =
3549         CreateButton((Widget)psub, PRINT_LABEL, "Print", XmNONE) ;
3550     /*
3551      * Remove the BulletinBoard unmanage callback. The
3552      * PrintSetupBoxCallback routine will unmanage the widget if the
3553      * AutoUnmanage resource is set, but only if the printer name is
3554      * successfully verified.
3555      */
3556     XtRemoveAllCallbacks(PSUB_PrintButton(psub), XmNactivateCallback);
3557     XtAddCallback(PSUB_PrintButton(psub), XmNactivateCallback, 
3558                   PrintSetupBoxCallback, (XtPointer)DtPRINT_PRINT_BUTTON) ;
3559 }
3560
3561 /*
3562  * ------------------------------------------------------------------------
3563  * Name: _DtPrintSetupBoxCreatePrinterInfoButton
3564  *
3565  * Description:
3566  *
3567  *     Create the "Info..." PushButton
3568  *
3569  * Return value:
3570  *
3571  *     None.
3572  *
3573  */
3574 void 
3575 _DtPrintSetupBoxCreatePrinterInfoButton(DtPrintSetupBoxWidget psub)
3576 {
3577     PSUB_PrinterInfoButton(psub) =
3578         CreateButton((Widget)psub, PRINTER_INFO_LABEL, "Info", XmTAB_GROUP);
3579
3580     XtRemoveAllCallbacks(PSUB_PrinterInfoButton(psub), XmNactivateCallback);
3581     XtAddCallback(PSUB_PrinterInfoButton(psub), XmNactivateCallback, 
3582                   PrintSetupBoxCallback, (XtPointer) DtPRINT_INFO_BUTTON) ;
3583 }
3584
3585 /*
3586  * ------------------------------------------------------------------------
3587  * Name: _DtPrintSetupBoxCreatePrinterNameCombo
3588  *
3589  * Description:
3590  *
3591  *     Create the combo box containing the printer name text field and
3592  *     the short printer list.
3593  *
3594  * Return value:
3595  *
3596  *     None.
3597  *
3598  */
3599 void 
3600 _DtPrintSetupBoxCreatePrinterNameCombo(DtPrintSetupBoxWidget psub)
3601 {
3602     PSUB_PrinterNameCombo(psub) =
3603         XtVaCreateWidget("Name", xmComboBoxWidgetClass, (Widget)psub,
3604                          XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX,
3605                          XmNcolumns, PRINTER_NAME_COLUMNS,
3606                          XmNpositionMode, XmZERO_BASED,
3607                          NULL);
3608     PSUB_PrinterNameText(psub) =
3609         XtNameToWidget(PSUB_PrinterNameCombo(psub), "*Text");
3610     /*
3611      * add a selection callback to the combo box that will cause the
3612      * selected printer to be set in the PSUB (verified, etc).
3613      */
3614     XtAddCallback(PSUB_PrinterNameCombo(psub), XmNselectionCallback,
3615                   UpdatePrinterNameCallback, (XtPointer)psub);
3616     /*
3617      * Xp Setup Mode specific initialization
3618      */
3619     if(PSUB_PrintSetupMode(psub) == DtPRINT_SETUP_XP)
3620     {
3621         String* printer_list;
3622         Boolean hide_arrow = True;
3623         /*
3624          * add a callback to close an existing connection whenever the
3625          * user modifies the text field.
3626          */
3627         XtAddCallback(PSUB_PrinterNameText(psub), XmNvalueChangedCallback,
3628                       ClosePrintConnectionCallback, (XtPointer)psub);
3629         /*
3630          * initialize the combo box list
3631          */
3632         printer_list = _DtPrintGetXpPrinterList((Widget)psub);
3633         if(printer_list != (String*)NULL)
3634         {
3635             int count;
3636             /*
3637              * count the number of printer names in the returned list,
3638              */
3639             for(count = 0; printer_list[count] != (String)NULL; count++);
3640             if(count > 0)
3641             {
3642                 XmString* printer_xmstr_list;
3643                 int i;
3644                 Widget combo_list;
3645                 /*
3646                  * build a XmString version of the printer list
3647                  */
3648                 printer_xmstr_list =
3649                     (XmString*)XtCalloc(count, sizeof(XmString));
3650                 for(i = 0; i < count; i++)
3651                     printer_xmstr_list[i] =
3652                         XmStringGenerate((XtPointer)printer_list[i],
3653                                          (XmStringTag)NULL,
3654                                          XmMULTIBYTE_TEXT, (XmStringTag)NULL);
3655                 /*
3656                  * get the widget ID of the combo box list
3657                  */
3658                 combo_list =
3659                     XtNameToWidget(PSUB_PrinterNameCombo(psub), "*List");
3660                 if(combo_list)
3661                 {
3662                     int visible_item_count;
3663                     /*
3664                      * get the initial visible item count
3665                      */
3666                     XtVaGetValues(combo_list,
3667                                   XmNvisibleItemCount, &visible_item_count,
3668                                   NULL);
3669                     /*
3670                      * reduce the visible item count if needed
3671                      */
3672                     if(count < visible_item_count)
3673                         visible_item_count = count;
3674                     /*
3675                      * set the XmString printer list in the combo box list
3676                      */
3677                     XtVaSetValues(combo_list,
3678                                   XmNitemCount, count,
3679                                   XmNitems, printer_xmstr_list,
3680                                   XmNvisibleItemCount, visible_item_count,
3681                                   NULL);
3682                     hide_arrow = False;
3683                 }
3684                 for(i = 0; i < count; i++)
3685                     XmStringFree(printer_xmstr_list[i]);
3686                 XtFree((char*)printer_xmstr_list);
3687             }
3688             _DtPrintFreeStringList(printer_list);
3689         }
3690         if(hide_arrow)
3691         {
3692             Dimension text_shadow_thickness;
3693             XtVaGetValues(PSUB_PrinterNameText(psub),
3694                           XmNshadowThickness, &text_shadow_thickness,
3695                           NULL);
3696             XtVaSetValues(PSUB_PrinterNameCombo(psub),
3697                           XmNarrowSize, 0,
3698                           XmNarrowSpacing, 0,
3699                           XmNmarginWidth, 0,
3700                           XmNmarginHeight, 0,
3701                           XmNshadowThickness, 0,
3702                           NULL);
3703             XtVaSetValues(PSUB_PrinterNameText(psub),
3704                           XmNshadowThickness, text_shadow_thickness,
3705                           NULL);
3706         }
3707
3708     }
3709 }
3710
3711 /*
3712  * ------------------------------------------------------------------------
3713  * Name: _DtPrintSetupBoxCreatePrinterNameLabel
3714  *
3715  * Description:
3716  *
3717  *     Create the Label for the printer name.
3718  *
3719  * Return value:
3720  *
3721  *     None.
3722  *
3723  */
3724 void 
3725 _DtPrintSetupBoxCreatePrinterNameLabel(DtPrintSetupBoxWidget psub)
3726 {
3727     PSUB_PrinterNameLabel(psub) =
3728         CreateLabelGadget((Widget) psub,
3729                           PRINTER_NAME_LABEL,
3730                           "NameLabel") ;
3731 }
3732
3733 /*
3734  * ------------------------------------------------------------------------
3735  * Name: _DtPrintSetupBoxCreateSelectFileButton
3736  *
3737  * Description:
3738  *
3739  *     Create the "Select File..." PushButton
3740  *
3741  * Return value:
3742  *
3743  *     None.
3744  *
3745  */
3746 void 
3747 _DtPrintSetupBoxCreateSelectFileButton(DtPrintSetupBoxWidget psub)
3748 {
3749     PSUB_SelectFileButton(psub) =
3750         CreateButtonGadget((Widget)psub, SELECT_FILE_LABEL,
3751                            "SelectFile", XmTAB_GROUP);
3752
3753     XtRemoveAllCallbacks(PSUB_SelectFileButton(psub), XmNactivateCallback) ;
3754     XtAddCallback(PSUB_SelectFileButton(psub), XmNactivateCallback, 
3755                   PrintSetupBoxCallback, (XtPointer) DtPRINT_FILES_BUTTON) ;
3756 }
3757
3758 /*
3759  * ------------------------------------------------------------------------
3760  * Name: _DtPrintSetupBoxCreateSelectPrinterButton
3761  *
3762  * Description:
3763  *
3764  *     Create the "Select Printer..." PushButton
3765  *
3766  * Return value:
3767  *
3768  *     None.
3769  *
3770  */
3771 void 
3772 _DtPrintSetupBoxCreateSelectPrinterButton(DtPrintSetupBoxWidget psub)
3773 {
3774     PSUB_SelectPrinterButton(psub) =
3775         CreateButtonGadget((Widget)psub, SELECT_PRINTER_LABEL,
3776                            "SelectPrinter", XmTAB_GROUP);
3777
3778     XtRemoveAllCallbacks(PSUB_SelectPrinterButton(psub), XmNactivateCallback);
3779     XtAddCallback(PSUB_SelectPrinterButton(psub), XmNactivateCallback, 
3780                   PrintSetupBoxCallback, (XtPointer) DtPRINT_PRINTERS_BUTTON) ;
3781 }
3782
3783 /*
3784  * ------------------------------------------------------------------------
3785  * Name: _DtPrintSetupBoxCreateSetupButton
3786  *
3787  * Description:
3788  *
3789  *     Create the "Setup" PushButton.
3790  *
3791  * Return value:
3792  *
3793  *     None.
3794  *
3795  */
3796 void 
3797 _DtPrintSetupBoxCreateSetupButton(DtPrintSetupBoxWidget psub)
3798 {
3799     PSUB_SetupButton(psub) =
3800         CreateButton((Widget) psub, SETUP_LABEL, "Setup", XmNONE);
3801     /*
3802      * Remove BulletinBoard Unmanage callback from Setup button
3803      */
3804     XtRemoveAllCallbacks(PSUB_SetupButton(psub), XmNactivateCallback) ;
3805
3806     XtAddCallback(PSUB_SetupButton (psub), XmNactivateCallback, 
3807                   PrintSetupBoxCallback, (XtPointer) DtPRINT_SETUP_BUTTON) ;
3808 }
3809
3810 /*
3811  * ------------------------------------------------------------------------
3812  * Name: _DtPrintSetupBoxCreateTopSeparator
3813  *
3814  * Description:
3815  *
3816  *     Create the Separator displayed below the top work area
3817  *
3818  * Return value:
3819  *
3820  *     None.
3821  *
3822  */
3823 void 
3824 _DtPrintSetupBoxCreateTopSeparator(DtPrintSetupBoxWidget psub)
3825 {
3826     Arg al[10];
3827     register int ac = 0;
3828
3829     XtSetArg(al[ac], XmNhighlightThickness, 0);  ac++;
3830     PSUB_TopSeparator(psub) =
3831         XmCreateSeparatorGadget((Widget) psub,
3832                                 "TopWorkAreaSeparator",
3833                                 al, ac);
3834 }
3835
3836 /*
3837  * ------------------------------------------------------------------------
3838  * Name: _DtPrintSetupBoxGeoMatrixCreate - BulletinBoard class method
3839  *
3840  * Description:
3841  *
3842  * Return value:
3843  *
3844  */
3845 XmGeoMatrix 
3846 _DtPrintSetupBoxGeoMatrixCreate(
3847                                 Widget wid,
3848                                 Widget instigator,
3849                                 XtWidgetGeometry *desired)
3850 {
3851     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget) wid ;
3852     XmGeoMatrix     geoSpec ;
3853     register XmGeoRowLayout  layoutPtr ;
3854     register XmKidGeometry   boxPtr ;
3855     XmKidGeometry   firstButtonBox ;
3856     XmKidGeometry   boxMark;
3857     Dimension       vspace = BB_MarginHeight(psub);
3858     int             i;
3859     PSUB_GeoExtension ext;
3860     int psub_geo_fill = XmGEO_PACK;
3861     int psub_geo_fit = XmGEO_PROPORTIONAL;
3862     /*
3863      * Layout PrintSetupBox XmGeoMatrix.
3864      * Each row is terminated by leaving an empty XmKidGeometry and
3865      * moving to the next XmGeoRowLayout.
3866      */
3867     geoSpec = _XmGeoMatrixAlloc(DtPSUB_MAX_WIDGETS_VERT,
3868                                 psub->composite.num_children,
3869                                 sizeof(PSUB_GeoExtensionRec));
3870     ext = geoSpec->extension;
3871
3872     geoSpec->composite = (Widget) psub ;
3873     geoSpec->instigator = (Widget) instigator ;
3874     if(desired)
3875     {
3876         geoSpec->instig_request = *desired ;
3877     } 
3878     geoSpec->margin_w = BB_MarginWidth(psub) + psub->manager.shadow_thickness;
3879     geoSpec->margin_h = BB_MarginHeight(psub) + psub->manager.shadow_thickness;
3880     geoSpec->no_geo_request = _DtPrintSetupBoxNoGeoRequest ;
3881
3882     layoutPtr = &(geoSpec->layouts->row) ;
3883     boxPtr = geoSpec->boxes ;
3884     /*
3885      * menu bar 
3886      */
3887     for (i = 0; i < psub->composite.num_children; i++)
3888     {
3889         Widget w = psub->composite.children[i];
3890
3891         if(XmIsRowColumn(w)
3892             && ((XmRowColumnWidget)w)->row_column.type == XmMENU_BAR
3893             && w != PSUB_TopWorkArea(psub)
3894             && w != PSUB_BottomWorkArea(psub)
3895             && _XmGeoSetupKid(boxPtr, w))
3896         {
3897             layoutPtr->fix_up = MenuBarFixUp;
3898             boxPtr += 2;
3899             ++layoutPtr;
3900             vspace = 0;         /* fixup space_above of next row. */
3901             break;
3902         }
3903     }
3904     /*
3905      * top work area + separator
3906      */
3907     if(PSUB_TopWorkArea(psub) != (Widget)NULL)
3908     {
3909         if(_XmGeoSetupKid(boxPtr, PSUB_TopWorkArea(psub)))
3910         {
3911             layoutPtr->space_above = vspace;
3912             vspace = BB_MarginHeight(psub);
3913             boxPtr += 2;
3914             ++layoutPtr;
3915         }
3916         if(_XmGeoSetupKid(boxPtr, PSUB_TopSeparator(psub)))
3917         {
3918             layoutPtr->fix_up = SeparatorFixUp;
3919             layoutPtr->space_above = vspace;
3920             vspace = BB_MarginHeight(psub);
3921             boxPtr += 2 ;
3922             ++layoutPtr ;
3923         } 
3924     }
3925     /*
3926      * printer description label, printer description and printer info
3927      * button
3928      */
3929     boxMark = boxPtr;
3930     if(_XmGeoSetupKid(boxPtr, PSUB_DescriptionLabel(psub)))
3931     {   
3932         (ext->pbox)[ext->row_count][0].geo = boxPtr;
3933         (ext->pbox)[ext->row_count][0].align = PSUB_GEO_ALIGN_RIGHT;
3934         ++boxPtr;
3935     } 
3936     if(_XmGeoSetupKid(boxPtr, PSUB_Description(psub)))
3937     {   
3938         (ext->pbox)[ext->row_count][1].geo = boxPtr;
3939         (ext->pbox)[ext->row_count][1].align = PSUB_GEO_ALIGN_LEFT;
3940         ++boxPtr;
3941     }
3942     if(_XmGeoSetupKid(boxPtr, PSUB_PrinterInfoButton(psub)))
3943     {   
3944         (ext->pbox)[ext->row_count][2].geo = boxPtr;
3945         (ext->pbox)[ext->row_count][2].align = PSUB_GEO_ALIGN_EXPAND;
3946         ++boxPtr;
3947     }
3948     if(boxPtr != boxMark)
3949     {
3950         (ext->layout_ptr)[ext->row_count++] = layoutPtr;
3951         layoutPtr->fix_up = ColumnGeoFixUp;
3952         layoutPtr->even_width = 0;
3953         layoutPtr->even_height = 0;
3954         layoutPtr->fill_mode = psub_geo_fill ;
3955         layoutPtr->fit_mode = psub_geo_fit ;
3956         layoutPtr->space_above = vspace;
3957         vspace = BB_MarginHeight(psub);
3958         ++boxPtr;
3959         ++layoutPtr ;
3960     }
3961     /*
3962      * printer name label, printer name, select printer button
3963      */
3964     boxMark = boxPtr;
3965     if(_XmGeoSetupKid(boxPtr, PSUB_PrinterNameLabel(psub)))
3966     {   
3967         (ext->pbox)[ext->row_count][0].geo = boxPtr;
3968         (ext->pbox)[ext->row_count][0].align = PSUB_GEO_ALIGN_RIGHT;
3969         ++boxPtr;
3970     } 
3971     if(_XmGeoSetupKid(boxPtr, PSUB_PrinterNameCombo(psub)))
3972     {   
3973         (ext->pbox)[ext->row_count][1].geo = boxPtr;
3974         (ext->pbox)[ext->row_count][1].align = PSUB_GEO_ALIGN_LEFT;
3975         ++boxPtr;
3976     }
3977     if(_XmGeoSetupKid(boxPtr, PSUB_SelectPrinterButton(psub)))
3978     {   
3979         (ext->pbox)[ext->row_count][2].geo = boxPtr;
3980         (ext->pbox)[ext->row_count][2].align = PSUB_GEO_ALIGN_EXPAND;
3981         ++boxPtr;
3982     }
3983     if(boxPtr != boxMark)
3984     {
3985         (ext->layout_ptr)[ext->row_count++] = layoutPtr;
3986         layoutPtr->fix_up = ColumnGeoFixUp;
3987         layoutPtr->even_width = 0;
3988         layoutPtr->even_height = 0;
3989         layoutPtr->fill_mode = psub_geo_fill ;
3990         layoutPtr->fit_mode = psub_geo_fit ;
3991         layoutPtr->space_above = vspace;
3992         vspace = BB_MarginHeight(psub);
3993         ++boxPtr;
3994         ++layoutPtr ;
3995     }
3996     /*
3997      * file name label, file name text, select file button
3998      */
3999     boxMark = boxPtr;
4000     if(_XmGeoSetupKid(boxPtr, PSUB_FileNameLabel(psub)))
4001     {   
4002         (ext->pbox)[ext->row_count][0].geo = boxPtr;
4003         (ext->pbox)[ext->row_count][0].align = PSUB_GEO_ALIGN_RIGHT;
4004         ++boxPtr;
4005     } 
4006     if(_XmGeoSetupKid(boxPtr, PSUB_FileNameText(psub)))
4007     {   
4008         (ext->pbox)[ext->row_count][1].geo = boxPtr;
4009         (ext->pbox)[ext->row_count][1].align = PSUB_GEO_ALIGN_LEFT;
4010         ++boxPtr;
4011     } 
4012     if(_XmGeoSetupKid(boxPtr, PSUB_SelectFileButton(psub)))
4013     {   
4014         (ext->pbox)[ext->row_count][2].geo = boxPtr;
4015         (ext->pbox)[ext->row_count][2].align = PSUB_GEO_ALIGN_EXPAND;
4016         ++boxPtr;
4017     } 
4018     if(boxPtr != boxMark)
4019     {
4020         (ext->layout_ptr)[ext->row_count++] = layoutPtr;
4021         layoutPtr->fix_up = ColumnGeoFixUp;
4022         layoutPtr->even_width = 0;
4023         layoutPtr->even_height = 0;
4024         layoutPtr->fill_mode = psub_geo_fill ;
4025         layoutPtr->fit_mode = psub_geo_fit ;
4026         layoutPtr->space_above = vspace;
4027         vspace = BB_MarginHeight(psub);
4028         ++boxPtr;
4029         ++layoutPtr ;
4030     }
4031     /*
4032      * copies label and copies field
4033      */
4034     boxMark = boxPtr;
4035     if(_XmGeoSetupKid(boxPtr, PSUB_DestinationRadioBox(psub)))
4036     {   
4037         ++boxPtr;
4038     } 
4039     if(_XmGeoSetupKid(boxPtr, PSUB_CopiesControl(psub)))
4040     {   
4041         ++boxPtr;
4042     } 
4043     if(boxPtr != boxMark)
4044     {
4045         layoutPtr->fill_mode = XmGEO_CENTER ;
4046         layoutPtr->fit_mode = XmGEO_WRAP ;
4047         layoutPtr->even_width = 0;
4048         layoutPtr->even_height = 0;
4049         layoutPtr->space_between = 10;
4050         layoutPtr->space_above = vspace;
4051         vspace = BB_MarginHeight(psub);
4052         ++boxPtr;
4053         ++layoutPtr ;
4054     }
4055     /*
4056      * bottom work area + separator
4057      */
4058     if(PSUB_BottomWorkArea(psub) != (Widget)NULL)
4059     {
4060         if(_XmGeoSetupKid(boxPtr, PSUB_BottomSeparator(psub)))
4061         {
4062             layoutPtr->fix_up = SeparatorFixUp;
4063             layoutPtr->space_above = vspace;
4064             vspace = BB_MarginHeight(psub);
4065             boxPtr += 2 ;
4066             ++layoutPtr ;
4067         } 
4068         if(_XmGeoSetupKid(boxPtr, PSUB_BottomWorkArea(psub)))
4069         {
4070             layoutPtr->space_above = vspace;
4071             vspace = BB_MarginHeight(psub);
4072             boxPtr += 2;
4073             ++layoutPtr;
4074         }
4075     }
4076     /*
4077      * button separator 
4078      */
4079     if(_XmGeoSetupKid(boxPtr, PSUB_ButtonSeparator(psub)))
4080     {
4081         layoutPtr->fix_up = SeparatorFixUp;
4082         layoutPtr->space_above = vspace;
4083         vspace = BB_MarginHeight(psub);
4084         boxPtr += 2 ;
4085         ++layoutPtr ;
4086     } 
4087     /*
4088      * button row 
4089      */
4090     firstButtonBox = boxPtr ;
4091     if(_XmGeoSetupKid(boxPtr, PSUB_PrintButton(psub)))
4092     {
4093         ++boxPtr ;
4094     } 
4095     for(i = 0; i < psub->composite.num_children; i++)
4096     {
4097         Widget w = psub->composite.children[i];
4098         if(IsButton(w)
4099            &&
4100            !IsAutoButton(psub,w)
4101            &&
4102            w != PSUB_TopWorkArea(psub)
4103            &&
4104            w != PSUB_BottomWorkArea(psub)
4105            )
4106         {
4107             if(_XmGeoSetupKid(boxPtr, w))
4108             {
4109                 ++boxPtr ;
4110             } 
4111         }
4112     }
4113     if(_XmGeoSetupKid(boxPtr, PSUB_SetupButton(psub)))
4114     {
4115         ++boxPtr ;
4116     } 
4117     if(_XmGeoSetupKid(boxPtr, PSUB_CancelButton(psub)))
4118     {
4119         ++boxPtr ;
4120     } 
4121     if(_XmGeoSetupKid(boxPtr, PSUB_HelpButton(psub)))
4122     {
4123         ++boxPtr ;
4124     } 
4125     if(boxPtr != firstButtonBox)
4126     {
4127         layoutPtr->fill_mode = XmGEO_CENTER ;
4128         layoutPtr->fit_mode = XmGEO_WRAP ;
4129         layoutPtr->space_above = vspace;
4130         vspace = BB_MarginHeight(psub);
4131         if(!(psub->print_setup_box.minimize_buttons))
4132         {
4133             layoutPtr->even_width = 1 ;
4134         } 
4135         layoutPtr->even_height = 1 ;
4136         ++layoutPtr ;
4137     }
4138     /*
4139      * the end. 
4140      */
4141     layoutPtr->space_above = vspace;
4142     layoutPtr->end = TRUE ;
4143     return(geoSpec) ;
4144 }
4145
4146 /*
4147  * ------------------------------------------------------------------------
4148  * Name: _DtPrintSetupBoxNoGeoRequest
4149  *
4150  * Description:
4151  *
4152  * Return value:
4153  *
4154  */
4155 Boolean 
4156 _DtPrintSetupBoxNoGeoRequest(
4157                              XmGeoMatrix geoSpec)
4158 {
4159     if(BB_InSetValues(geoSpec->composite)
4160        && (XtClass(geoSpec->composite) == dtPrintSetupBoxWidgetClass))
4161     {   
4162         return(TRUE) ;
4163     } 
4164     return(FALSE) ;
4165 }
4166
4167 /*
4168  * ------------------------------------------------------------------------
4169  * Name: _DtPrintSetupBoxGetCopies
4170  *
4171  * Description:
4172  *
4173  *     Update the location pointed to by "value" with the current value
4174  *     of the Copies spin box.
4175  *
4176  * Return value:
4177  *
4178  *     None.
4179  *
4180  */
4181 void 
4182 _DtPrintSetupBoxGetCopies(
4183                           Widget wid,
4184                           int resource_offset,
4185                           XtArgVal *value)
4186 {
4187     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget) wid ;
4188     int copies;
4189
4190     if(PSUB_CopiesSpinBox(psub) != (Widget)NULL)
4191     {   
4192         XtVaGetValues(PSUB_CopiesSpinBox(psub),
4193                       XmNposition, &copies,
4194                       NULL);
4195         *value = (XtArgVal)copies;
4196     }
4197     else
4198     {
4199         *value = (XtArgVal)PSUB_Copies(psub);
4200     } 
4201 }
4202
4203 /*
4204  * ------------------------------------------------------------------------
4205  * Name: _DtPrintSetupBoxGetDescription
4206  *
4207  * Description:
4208  *
4209  *     Update the description instance variable based on the current
4210  *     value of the Printer Description label gadget.
4211  *
4212  * Return value:
4213  *
4214  *     None.
4215  *
4216  */
4217 void 
4218 _DtPrintSetupBoxGetDescription(
4219                                Widget wid,
4220                                int resource_offset,
4221                                XtArgVal *value)
4222 {
4223     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget) wid ;
4224     XmString data ;
4225
4226     if(PSUB_Description(psub) != (Widget)NULL)
4227     {   
4228         XtVaGetValues((Widget)PSUB_Description(psub),
4229                       XmNlabelString, &data,
4230                       NULL);
4231         *value = (XtArgVal)data;
4232     }
4233     else
4234     {
4235         *value = (XtArgVal)NULL;
4236     } 
4237 }
4238
4239 /*
4240  * ------------------------------------------------------------------------
4241  * Name: _DtPrintSetupBoxGetFileName
4242  *
4243  * Description:
4244  *
4245  * Return value:
4246  *
4247  *     None.
4248  *
4249  */
4250 void 
4251 _DtPrintSetupBoxGetFileName(
4252                             Widget w,
4253                             int resource_offset,
4254                             XtArgVal *value)
4255 {
4256     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)w;
4257
4258     SynthGetFileName(psub);
4259     *value = (XtArgVal)PSUB_FileName(psub);
4260 }
4261
4262 /*
4263  * ------------------------------------------------------------------------
4264  * Name: _DtPrintSetupBoxGetPrinterName
4265  *
4266  * Description:
4267  *
4268  * Return value:
4269  *
4270  *     None.
4271  *
4272  */
4273 void 
4274 _DtPrintSetupBoxGetPrinterName(
4275                                Widget w,
4276                                int resource_offset,
4277                                XtArgVal *value)
4278 {
4279     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)w;
4280
4281     SynthGetPrinterName(psub);
4282     *value = (XtArgVal)PSUB_PrinterName(psub);
4283 }
4284
4285 /*
4286  * ------------------------------------------------------------------------
4287  * Name: DtCreatePrintSetupBox
4288  *
4289  * Description:
4290  *
4291  *     DtCreatePrintSetupBox is a convenience function that creates an
4292  *     unmanaged instance of a DtPrintSetupBox widget, and returns its
4293  *     widget ID.
4294  *
4295  * Arguments:
4296  *
4297  *     parent
4298  *         Specifies the parent widget ID.
4299  *
4300  *     name
4301  *         Specifies the name of the created widget.
4302  *
4303  *     args
4304  *         Specifies the argument list.
4305  *
4306  *     n
4307  *         Specifies the number of attribute/value pairs in arglist.
4308  *
4309  * Return value:
4310  *
4311  *     Returns the DtPrintSetupBox widget ID.
4312  *
4313  */
4314 Widget 
4315 DtCreatePrintSetupBox(
4316                       Widget p,
4317                       String name,
4318                       ArgList args,
4319                       Cardinal n)
4320 {
4321     return XtCreateWidget(name, dtPrintSetupBoxWidgetClass, p, args, n);
4322 }
4323
4324 /*
4325  * ------------------------------------------------------------------------
4326  * Name: DtCreatePrintSetupDialog
4327  *
4328  * Description:
4329  *
4330  *     DtCreatePrintSetupDialog is a convenience function that creates an
4331  *     instance of a dialog containing a DtPrintSetupBox widget, and
4332  *     returns the DtPrintSetupBox widget ID.
4333  *
4334  * Arguments:
4335  *
4336  *     parent
4337  *         Specifies the parent widget ID.
4338  *
4339  *     name
4340  *         Specifies the name of the created widget.
4341  *
4342  *     args
4343  *         Specifies the argument list.
4344  *
4345  *     n
4346  *         Specifies the number of attribute/value pairs in arglist.
4347  *
4348  * Return value:
4349  *
4350  *     Returns the DtPrintSetupBox widget ID.
4351  *
4352  */
4353 Widget 
4354 DtCreatePrintSetupDialog(
4355                          Widget parent,
4356                          String name,
4357                          ArgList args,
4358                          Cardinal n)
4359 {
4360     return XmeCreateClassDialog(dtPrintSetupBoxWidgetClass,
4361                                 parent, name, args, n);
4362 }
4363
4364 /*
4365  * ------------------------------------------------------------------------
4366  * Name: DtPrintCopySetupData
4367  *
4368  * Description:
4369  *
4370  *     DtPrintCopySetupData is used to copy the DtPrintSetupData
4371  *     structure pointed to by 'source' to the DtPrintSetupData structure
4372  *     pointed to by 'target'. Elements in 'target' are updated only if
4373  *     different than the corresponding element in 'source'. For elements
4374  *     that point to allocated memory, DtPrintCopySetupData allocates new
4375  *     memory for those elements updated in 'target'. Existing elements
4376  *     in 'target' are freed using XtFree. All elements in a
4377  *     DtPrintSetupData structure can be freed by calling
4378  *     DtPrintFreeSetupData.
4379  *
4380  *     If 'source' or 'target' is NULL the copy will not be performed.
4381  *
4382  * Arguments:
4383  *
4384  *     target
4385  *         A pointer to the DtPrintSetupData structure to copy to.
4386  *
4387  *     source
4388  *         A pointer to the DtPrintSetupData structure to copy from.
4389  *
4390  * Return value:
4391  *
4392  *     The target pointer.
4393  *
4394  */
4395 DtPrintSetupData*
4396 DtPrintCopySetupData(
4397                      DtPrintSetupData* target,
4398                      const DtPrintSetupData* source)
4399 {
4400     if(source != (DtPrintSetupData*)NULL
4401        &&
4402        target != (DtPrintSetupData*)NULL)
4403     {
4404         if((source->printer_name == (String)NULL
4405             ||
4406             target->printer_name == (String)NULL)
4407            ? True
4408            : strcmp(source->printer_name, target->printer_name) != 0)
4409         {
4410             XtFree(target->printer_name);
4411             target->printer_name = XtNewString(source->printer_name);
4412         }
4413
4414         target->print_display = source->print_display;
4415         target->print_context = source->print_context;
4416         target->destination = source->destination;
4417         target->messages_hint = source->messages_hint;
4418
4419         if((source->dest_info == (String)NULL
4420             ||
4421             target->dest_info == (String)NULL)
4422            ? True
4423            : strcmp(source->dest_info, target->dest_info) != 0)
4424         {
4425             XtFree(target->dest_info);
4426             target->dest_info = XtNewString(source->dest_info);
4427         }
4428     }
4429     return target;
4430 }
4431
4432 /*
4433  * ------------------------------------------------------------------------
4434  * Name: DtPrintFillSetupData
4435  *
4436  * Description:
4437  *
4438  *     DtPrintFillSetupData is used to obtain an X printer connection in
4439  *     order to initiate an X printing job in situations other than
4440  *     direct interaction with a DtPrintSetupBox (e.g. a "quick print"
4441  *     button on a toolbar). This printer connection information can be
4442  *     obtained from an existing DtPrintSetupBox widget instance, or if a
4443  *     DtPrintSetupBox widget instance is unavailable,
4444  *     DtPrintFillSetupData will provide a new X printer connection.
4445  *
4446  * Arguments:
4447  *
4448  *     psub
4449  *         The widget ID of a DtPrintSetupBox, or NULL if no
4450  *         DtPrintSetupBox is available.
4451  *
4452  *     print_data
4453  *         A pointer to an existing DtPrintSetupData structure that
4454  *         DtPrintFillSetupData will update with valid X printer
4455  *         connection information.
4456  *
4457  * Return value:
4458  *
4459  *     DtPRINT_SUCCESS
4460  *         The X printer connection was successfully obtained.
4461  *
4462  *     DtPRINT_FAILURE
4463  *         The X printer connection could not be established. The
4464  *         specific reason has been reported by the print setup box to
4465  *         the user.
4466  *
4467  *     DtPRINT_INVALID_DISPLAY
4468  *         The indicated X print server could not be found.
4469  *
4470  *     DtPRINT_NOT_XP_DISPLAY
4471  *         The indicated X server does not support the X Printing
4472  *         Extension.
4473  *
4474  *     DtPRINT_NO_PRINTER
4475  *         The indicated printer could not be found on the X print
4476  *         server.
4477  *
4478  *     DtPRINT_NO_DEFAULT
4479  *         A default printer could not be determined.
4480  *
4481  *     DtPRINT_BAD_PARM
4482  *         The value passed for print_data is NULL.
4483  *
4484  */
4485 XtEnum DtPrintFillSetupData(
4486                             Widget w,
4487                             DtPrintSetupData* print_data)
4488 {
4489     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)w;
4490     
4491     if(print_data == (DtPrintSetupData*)NULL)
4492         return DtPRINT_BAD_PARM;
4493     
4494     if(psub == (DtPrintSetupBoxWidget)NULL)
4495     {
4496         XtEnum status;
4497         String new_printer_spec;
4498         Display* new_display;
4499         XPContext new_context;
4500         /*
4501          * GUI-less printing; verify the printer name and establish the
4502          * print connection without involving the print setup box.
4503          */
4504         status = _DtPrintVerifyXPrinter(NULL,
4505                                         print_data->printer_name,
4506                                         &new_printer_spec,
4507                                         &new_display,
4508                                         &new_context);
4509         if(status == DtPRINT_SUCCESS)
4510         {
4511             print_data->print_display = new_display;
4512             print_data->print_context = new_context;
4513         }
4514         if(new_printer_spec != (String)NULL)
4515         {
4516             XtFree(print_data->printer_name);
4517             print_data->printer_name = new_printer_spec;
4518         }
4519         return status;
4520     }
4521     else
4522     {
4523         DtPrintSetupData psd;
4524         XtEnum status;
4525         _DtPrintWidgetToAppContext((Widget)psub);
4526         /*
4527          * return if the passed widget's setup mode is not Xp
4528          */
4529         if(PSUB_PrintSetupMode(psub) != DtPRINT_SETUP_XP)
4530             return DtPRINT_BAD_PARM;
4531         /*
4532          * intialize an internal version of the print setup data struct
4533          */
4534         memset(&psd, 0, sizeof(DtPrintSetupData));
4535         /*
4536          * get the latest printer name from the widget
4537          */
4538         _DtPrintAppLock(app);
4539         SynthGetPrinterName(psub);
4540         /*
4541          * check to see if the passed printer name is different than
4542          * the psub printer name
4543          */
4544         if(print_data->printer_name != (String)NULL)
4545         {
4546             if((PSUB_PrinterName(psub) == NULL)
4547                ? True
4548                : strcmp(print_data->printer_name, PSUB_PrinterName(psub)) != 0)
4549             {
4550                 /*
4551                  * if different, set the passed printer name into the
4552                  * passed print setup box widget
4553                  */
4554                 SynthSetPrinterName(psub,
4555                                     XtNewString(print_data->printer_name),
4556                                     PSUB_PrinterName(psub));
4557             }
4558         }
4559         /*
4560          * establish a connection to the X printer
4561          */
4562         psd.messages_hint = DtPRINT_HINT_NO_MESSAGES;
4563         status = EstablishPrinter(psub, &psd);
4564         if(status == DtPRINT_SUCCESS)
4565         {
4566             /*
4567              * set printing attributes
4568              */
4569             SetPrintAttributes(psub);
4570             /*
4571              * setup the destination info
4572              */
4573             SetPSDDestination(psub, &psd);
4574             /*
4575              * update the passed print setup data struct based on the
4576              * internal version of the print setup data struct
4577              */
4578             DtPrintCopySetupData(print_data, &psd);
4579         }
4580         else
4581         {
4582             /*
4583              * Unable to establish the printer connection; manage the
4584              * print setup box in order to present the error box created
4585              * by EstablishPrinter() to the user, allowing the user to
4586              * select a new printer or cancel.
4587              */
4588             XtManageChild((Widget)psub);
4589             /*
4590              * if the default verifyPrintProc created an error box,
4591              * display it. If the app installed its own verify proc, the
4592              * app will need to check the return status of
4593              * DtPrintFillSetupData, and manage its error dialog itself.
4594              */
4595             _DtPrintDefProcManageErrorBox(&PSUB_DefaultProcData(psub));
4596         }
4597         _DtPrintAppUnlock(app);
4598         return status;
4599     }
4600 }
4601
4602 /*
4603  * ------------------------------------------------------------------------
4604  * Name: DtPrintFreeSetupData
4605  *
4606  * Description:
4607  *
4608  *     DtPrintFreeSetupData calls XtFree to deallocate memory pointed to
4609  *     by elements of the DtPrintSetupData structure indicated by
4610  *     'target'. 'target' is then re-initialized to zeros.
4611  *
4612  * Arguments:
4613  *
4614  *     target
4615  *         points to the DtPrintSetupData structure whose elements are to
4616  *         be freed.
4617  *
4618  * Return value:
4619  *
4620  *     None.
4621  *
4622  */
4623 void DtPrintFreeSetupData(
4624                           DtPrintSetupData* target)
4625 {
4626     XtFree(target->printer_name);
4627     XtFree(target->dest_info);
4628     memset(target, 0, sizeof(DtPrintSetupData));
4629 }
4630
4631 /*
4632  * ------------------------------------------------------------------------
4633  * Name: DtPrintResetConnection
4634  *
4635  * Arguments:
4636  *
4637  *     psub
4638  *         The DtPrintSetupBox widget ID.
4639  *
4640  *     mode
4641  *         Indicates whether DtPrintResetConnection should close the X
4642  *         print server connection, or simply cause the DtPrintSetupBox
4643  *         to cease managing the connection.
4644  *
4645  * Description:
4646  *
4647  *     DtPrintResetConnection is intended to be used by applications that
4648  *     fork a child process to perform the print rendering
4649  *     operation. After the fork is performed, the parent process will
4650  *     close its X print server connection, and maintain its connection
4651  *     to the video X server. The forked child on the other hand will
4652  *     close its video X server connection and perform the rendering
4653  *     operation on the X print server connection.
4654  *
4655  *     Valid values for the 'mode' parameter are:
4656  *
4657  *         DtPRINT_CLOSE_CONNECTION
4658  *             Set by the parent process when the application forks a
4659  *             child to perform the print rendering. This will cause the
4660  *             DtNclosePrintDisplayCallback list set for the passed
4661  *             DtPrintSetupBox to be called.
4662  *
4663  *         DtPRINT_RELEASE_CONNECTION
4664  *             Set when the application wishes to destroy the
4665  *             DtPrintSetupBox widget instance and still perform print
4666  *             rendering using the X print server connection initiated by
4667  *             the widget. For example, the child process of an
4668  *             application that forks to perform print rendering will
4669  *             close the video display connection (thereby destroying the
4670  *             DtPrintSetupBox widget) prior to print rendering.
4671  *
4672  * Return value:
4673  *
4674  *     DtPRINT_SUCCESS
4675  *         DtPrintResetConnection was successful.
4676  *
4677  *     DtPRINT_NO_CONNECTION
4678  *         An open X print server connection is not currently being
4679  *         managed by the DtPrintSetupBox.
4680  *
4681  *     DtPRINT_BAD_PARM
4682  *         The value passed for wid is NULL, or an invalid mode was
4683  *         passed.
4684  *
4685  */
4686 XtEnum
4687 DtPrintResetConnection(
4688                        Widget w,
4689                        DtPrintResetConnectionMode mode)
4690 {
4691     DtPrintSetupBoxWidget psub = (DtPrintSetupBoxWidget)w;
4692     _DtPrintWidgetToAppContext((Widget)psub);
4693
4694     if(psub == (DtPrintSetupBoxWidget)NULL)
4695         return DtPRINT_BAD_PARM;
4696
4697     _DtPrintAppLock(app);
4698
4699     if(PSUB_PrintSetupMode(psub) != DtPRINT_SETUP_XP)
4700     {
4701         _DtPrintAppUnlock(app);
4702         return DtPRINT_BAD_PARM;
4703     }
4704
4705     if(PSUB_Display(psub) == (Display*)NULL)
4706     {
4707         _DtPrintAppUnlock(app);
4708         return DtPRINT_NO_CONNECTION;
4709     }
4710     
4711     switch(mode)
4712     {
4713     case DtPRINT_RELEASE_CONNECTION:
4714         /*
4715          * simply disavow knowledge of the X print connection
4716          */
4717         PSUB_Display(psub) = (Display*)NULL;
4718         PSUB_Context(psub) = (XPContext)NULL;
4719         break;
4720         
4721     case DtPRINT_CLOSE_CONNECTION:
4722         /*
4723          * call the widget's close print connection routine
4724          */
4725         ClosePrintConnection(psub, PSUB_PrinterName(psub), True);
4726         break;
4727
4728     default:
4729         _DtPrintAppUnlock(app);
4730         return DtPRINT_BAD_PARM;
4731     }
4732     /*
4733      * cause the printer to be re-verified if new connection is
4734      * is required later, and return
4735      */
4736     PSUB_VerifyPrinterState(psub) = DtPRINT_NOT_VERIFIED;
4737     _DtPrintAppUnlock(app);
4738     return DtPRINT_SUCCESS;
4739 }