Don't try to define abs() on linux, stdlib will handle it.
[oweals/cde.git] / cde / programs / dtpdm / MainWindow.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: MainWindow.c /main/7 1996/10/31 02:04:14 cde-hp $ */
24 /*
25  * dtpdm/MainWindow.c
26  */
27 /*
28  * (c) Copyright 1996 Digital Equipment Corporation.
29  * (c) Copyright 1996 Hewlett-Packard Company.
30  * (c) Copyright 1996 International Business Machines Corp.
31  * (c) Copyright 1996 Sun Microsystems, Inc.
32  * (c) Copyright 1996 Novell, Inc. 
33  * (c) Copyright 1996 FUJITSU LIMITED.
34  * (c) Copyright 1996 Hitachi.
35  */
36 #include <Xm/XmAll.h>
37 #include <Dt/HelpDialog.h>
38 #include <Dt/dtpdmd.h>
39 #include <Dt/DtNlUtils.h>
40
41 #ifdef USE_EXM_TABS
42 #include <Exm/TabB.h>
43 #endif
44
45 #include "MainWindow.h"
46
47 /*
48  * PdmMainWindow-specific fallback resources
49  */
50 static String PdmMainWinFallbackResources[] =
51 {
52     "*Notebook.ExmTabButton.notebookChildType: XmMINOR_TAB",
53     "*Notebook.XmPushButton.notebookChildType: XmMINOR_TAB",
54     "*HelpDialog_popup.title: Print Setup - Help",
55     "*Notebook.backPageNumber: 4",
56     "*Notebook.backPagePlacement: XmTOP_RIGHT",
57     "*Notebook.bindingType: XmNONE",
58     "*Notebook.minorTabSpacing: 8",
59     "*NotebookLabel.labelString: Setup Options:",
60     "*PrinterDescriptionLabel.labelString: Printer Description:",
61     "*PrinterNameLabel.labelString: Printer:",
62     "*helpVolume: PrnSetup"
63 };
64
65 /*
66  * static function declarations
67  */
68 static void PdmMainWinCreateSetupBoxes(PdmMainWin* me);
69 static Widget PdmMainWinCreateWindow(PdmMainWin* me, Widget parent);
70 static void PdmMainWinGetAttributes(PdmMainWin* me);
71 static void PdmMainWinOkCB(Widget, XtPointer, XtPointer);
72 static void PdmMainWinCancelCB(Widget, XtPointer, XtPointer);
73 static void PdmMainWinHelpCB(Widget, XtPointer, XtPointer);
74 static void PdmMainWinHelpDestroyCB(Widget, XtPointer, XtPointer);
75
76 /*
77  * ------------------------------------------------------------------------
78  * Name: PdmMainWinNew
79  *
80  * Description:
81  *
82  *     Allocates a new PdmMainWin instance structure.
83  *
84  * Return value:
85  *
86  *     A pointer to the new PdmMainWin instance.
87  *
88  */
89 PdmMainWin*
90 PdmMainWinNew()
91 {
92     PdmMainWin* me = (PdmMainWin*)XtCalloc(1, sizeof(PdmMainWin));
93     me->pdm_xp = PdmXpNew();
94
95     return me;
96 }
97
98 /*
99  * ------------------------------------------------------------------------
100  * Name: PdmMainWinDelete
101  *
102  * Description:
103  *
104  *     Frees the passed PdmMainWin instance structure.
105  *
106  * Return value:
107  *
108  *     None
109  *
110  */
111 void
112 PdmMainWinDelete(PdmMainWin* me)
113 {
114     PdmBoxNode* node;
115     /*
116      * close the print server connection
117      */
118     if(me->pdm_xp != (PdmXp*)NULL)
119         PdmXpDelete(me->pdm_xp);
120     /*
121      * destroy the help dialog
122      */
123     if((Widget)NULL != me->help_dialog)
124     {
125         XtDestroyWidget(me->help_dialog);
126     }
127     /*
128      * clean up the child setup box list
129      */
130     while((node = me->box_list_head) != (PdmBoxNode*)NULL)
131     {
132         me->box_list_head = node->next;
133         XtFree((char*)node);
134     }
135     /*
136      * clean up string members
137      */
138     XtFree((char*)me->print_display_spec);
139     /*
140      * free the instance structure
141      */
142     XtFree((char*)me);
143 }
144
145 /*
146  * ------------------------------------------------------------------------
147  * Name: PdmMainWinAddSetupBox
148  *
149  * Description:
150  *
151  *     Adds a PDM setup box to the list of setup boxes managed by the
152  *     main window.
153  *
154  * Return value:
155  *
156  *     The passed PdmSetupBox pointer.
157  *
158  */
159 PdmSetupBox*
160 PdmMainWinAddSetupBox(PdmMainWin* me, PdmSetupBox* box)
161 {
162     /*
163      * create a new setup box node for the passed setup box
164      * and add it to the end of the list
165      */
166     PdmBoxList new_node = (PdmBoxList)XtCalloc(1, sizeof(PdmBoxNode));
167     new_node->box = box;
168     if(me->box_list_tail)
169         me->box_list_tail = me->box_list_tail->next = new_node;
170     else
171         me->box_list_head = me->box_list_tail = new_node;
172 }
173
174 /*
175  * ------------------------------------------------------------------------
176  * Name: PdmMainWinMergeFallbacks
177  *
178  * Description:
179  *
180  *     Merges the fallback resources defined by the main window and each
181  *     of the setup boxes with the passed set of fallback resources.
182  *
183  * Return value:
184  *
185  *     The merged array of fallback resources. The passed set of
186  *     fallback appear first in the list, followed by the main window
187  *     fallbacks, followed by the fallbacks for each setup box. The last
188  *     entry in the list is set to NULL. It is the caller's
189  *     responsibility to free the returned list using XtFree.
190  *
191  */
192 String* PdmMainWinMergeFallbacks(PdmMainWin* me,
193                                  const String* app_fallbacks,
194                                  int count)
195 {
196     String* new_fallbacks;
197     int res_count;
198     PdmBoxNode* node;
199     String* ptr;
200     
201     res_count = count;
202     res_count += XtNumber(PdmMainWinFallbackResources);
203     for(node = me->box_list_head; node != (PdmBoxNode*)NULL; node = node->next)
204         res_count += node->box->fallback_resources_count;
205     
206     new_fallbacks = (String*)XtCalloc(res_count+1, sizeof(String));
207     
208     ptr = new_fallbacks;
209     memcpy(ptr, app_fallbacks, count*sizeof(String));
210     ptr += count;
211     memcpy(ptr, PdmMainWinFallbackResources,
212            XtNumber(PdmMainWinFallbackResources)*sizeof(String));
213     ptr += XtNumber(PdmMainWinFallbackResources);
214     for(node = me->box_list_head; node != (PdmBoxNode*)NULL; node = node->next)
215     {
216         memcpy(ptr, node->box->fallback_resources,
217                node->box->fallback_resources_count*sizeof(String));
218         ptr += node->box->fallback_resources_count;
219     }
220     return new_fallbacks;
221 }
222
223
224 /*
225  * ------------------------------------------------------------------------
226  * Name: PdmMainWinCreateSetupBoxes
227  *
228  * Description:
229  *
230  *     For each setup box added to the setup box list,
231  *     PdmMainWinCreateSetupBoxes calls the setup box's create method,
232  *     passing the notebook as the parent. A tab button is created for
233  *     each setup box.
234  *
235  * Return value:
236  *
237  *     None.
238  *
239  */
240 static void
241 PdmMainWinCreateSetupBoxes(PdmMainWin* me)
242 {
243     PdmBoxNode* node;
244     
245     for(node = me->box_list_head; node != (PdmBoxNode*)NULL; node = node->next)
246     {
247         PdmSetupBox* box = node->box;
248         /*
249          * create the setup box widget as a child of the notebook
250          */
251         (*box->create_proc)(box, me->notebook);
252         /*
253          * create a tab for the new setup box notebook page
254          */
255 #ifdef USE_EXM_TABS
256         node->tab =
257             XtVaCreateManagedWidget(box->tab_name,
258                                     exmTabButtonWidgetClass,
259                                     me->notebook,
260                                     NULL);
261 #else
262         node->tab =
263             XtVaCreateManagedWidget(box->tab_name,
264                                     xmPushButtonWidgetClass,
265                                     me->notebook,
266                                     NULL);
267 #endif /* USE_EXM_TABS */
268     }
269 }
270
271
272 /*
273  * ------------------------------------------------------------------------
274  * Name: PdmMainWinGetAttributes
275  *
276  * Description:
277  *
278  *     
279  *
280  * Return value:
281  *
282  *     None
283  *
284  */
285 static void
286 PdmMainWinGetAttributes(PdmMainWin* me)
287 {
288     PdmBoxNode* node;
289     /*
290      * get attributes for the main window
291      */
292     me->printer_descriptor = PdmXpGetStringValue(me->pdm_xp,
293                                                  XPPrinterAttr,
294                                                  pdmoid_att_descriptor);
295     me->printer_name = PdmXpGetStringValue(me->pdm_xp,
296                                            XPPrinterAttr,
297                                            pdmoid_att_printer_name);
298     /*
299      * call the get attributes proc for each setup box child
300      */
301     for(node = me->box_list_head; node != (PdmBoxNode*)NULL; node = node->next)
302     {
303         PdmSetupBox* box = node->box;
304         
305         (*box->get_attr_proc)(box, me->pdm_xp);
306     }
307 }
308
309 /*
310  * ------------------------------------------------------------------------
311  * Name: PdmMainWinOkCB
312  *
313  * Description:
314  *
315  *     Callback for the main window OK button. This function first calls
316  *     the verify values method for each of the child setup boxes. If the
317  *     values for all of the children are Ok, the new values are set into
318  *     the print context, and the program exits. Otherwise the program
319  *     resumes. In this case, it is assumed that the child setup box will
320  *     present a message to the user indicating that its values are not
321  *     Ok. This function will move the invalid child setup notebook page
322  *     to the top.
323  *
324  * Return value:
325  *
326  *     None, although it usually ends the program with an exit code of
327  *     PDM_EXIT_OK.
328  *
329  */
330 static void
331 PdmMainWinOkCB(
332                Widget w,
333                XtPointer client_data,
334                XtPointer call_data)
335 {
336     PdmMainWin* me = (PdmMainWin*)client_data;
337     PdmBoxNode* node;
338     int page;
339     /*
340      * call the verify values proc for each setup box child
341      */
342     for(node = me->box_list_head, page = 1;
343         node != (PdmBoxNode*)NULL;
344         node = node->next, page++)
345     {
346         PdmSetupBox* box = node->box;
347
348         if((*box->verify_attr_proc)(box, me->pdm_xp) != PDM_SUCCESS)
349         {
350             /*
351              * Ensure this setup box is the top notebook page; the setup
352              * box is responsible for providing error messages to the
353              * user.
354              *
355              * developer hint: do not use the setup box as the parent of
356              *                 a message box; if the setup box is not the
357              *                 current notebook page, the message box
358              *                 will not be positioned properly; use the
359              *                 first shell ancestor (or even the parent)
360              *                 of the setup box instead
361              */
362             XtVaSetValues(me->notebook, XmNcurrentPageNumber, page, NULL);
363             /*
364              * stop verifying and return
365              */
366             return;
367         }
368     }
369     /*
370      * call the set attributes proc for each setup box child
371      */
372     for(node = me->box_list_head; node != (PdmBoxNode*)NULL; node = node->next)
373     {
374         PdmSetupBox* box = node->box;
375         
376         (*box->set_attr_proc)(box, me->pdm_xp);
377     }
378     /*
379      * set the updated attributes into the print context
380      */
381     PdmXpUpdateAttributes(me->pdm_xp);
382     /*
383      * exit the PDM
384      */
385     PdmMainWinDelete(me);
386     exit(PDM_EXIT_OK);
387 }
388
389 /*
390  * ------------------------------------------------------------------------
391  * Name: PdmMainWinCancelCB
392  *
393  * Description:
394  *
395  *     Callback for the main window Cancel button. This function simply
396  *     ends the PDM program.
397  *
398  * Return value:
399  *
400  *     None, although it will end the program with an exit code of
401  *     PDM_EXIT_CANCEL.
402  *
403  */
404 static void
405 PdmMainWinCancelCB(
406                    Widget w,
407                    XtPointer client_data,
408                    XtPointer call_data)
409 {
410     PdmMainWin* me = (PdmMainWin*)client_data;
411     PdmMainWinDelete(me);
412     exit(PDM_EXIT_CANCEL);
413 }
414
415 /*
416  * ------------------------------------------------------------------------
417  * Name: PdmMainWinHelpCB
418  *
419  * Description:
420  *
421  *
422  * Return value:
423  *
424  *
425  */
426 static void
427 PdmMainWinHelpCB(Widget w, XtPointer client_data, XtPointer call_data)
428 {
429     PdmMainWin* me = (PdmMainWin*)client_data;
430     PdmSetupBox* box;
431     struct _box_resources
432     {
433         String help_volume;
434         String location_id;
435     } box_resources;
436     /*
437      * create the help dialog if needed
438      */
439     if((Widget)NULL == me->help_dialog)
440     {
441         me->help_dialog =
442             DtCreateHelpDialog(XtParent(me->widget), "HelpDialog", NULL, 0);
443         XtAddCallback(me->help_dialog, XmNdestroyCallback,
444                       PdmMainWinHelpDestroyCB, (XtPointer)me);
445     }
446     /*
447      * determine the current setup box
448      */
449     {
450         int current_page, i;
451         PdmBoxNode* node;
452         
453         XtVaGetValues(me->notebook, XmNcurrentPageNumber, &current_page, NULL);
454         node = me->box_list_head;
455         for(i = 1; i < current_page; i++)
456             node = node->next;
457         box = node->box;
458     }
459     /*
460      * the help volume name and location id are obtained up as application
461      * resources qualified for each setup box
462      */
463     {
464         XtResource resources[2];
465         /*
466          * initialize res struct for help volume
467          */
468         resources[0].resource_name = DtNhelpVolume;
469         resources[0].resource_class = DtCHelpVolume;
470         resources[0].resource_type =  XmRString;
471         resources[0].resource_size = sizeof(String);
472         resources[0].resource_offset =
473             XtOffsetOf(struct _box_resources, help_volume);
474         resources[0].default_type = XmRImmediate;
475         resources[0].default_addr = (XtPointer)NULL;
476         /*
477          * initialize res struct for location id
478          */
479         resources[1].resource_name = DtNlocationId;
480         resources[1].resource_class = DtCLocationId;
481         resources[1].resource_type =  XmRString;
482         resources[1].resource_size = sizeof(String);
483         resources[1].resource_offset =
484             XtOffsetOf(struct _box_resources, location_id);
485         resources[1].default_type = XmRImmediate;
486         resources[1].default_addr = (XtPointer)NULL;
487         /*
488          * get the resource values for the current setup box widget
489          */
490         XtGetApplicationResources(box->widget, (XtPointer)&box_resources,
491                                   resources, XtNumber(resources),
492                                   (ArgList)NULL, 0);
493     }
494     /*
495      * set the help volume and location
496      */
497     XtVaSetValues(me->help_dialog,
498                   DtNhelpVolume, box_resources.help_volume,
499                   DtNlocationId, box_resources.location_id,
500                   DtNhelpType, DtHELP_TYPE_TOPIC,
501                   NULL);
502     /*
503      * pop up the help dialog
504      */
505     XtManageChild(me->help_dialog);
506 }
507
508 /*
509  * ------------------------------------------------------------------------
510  * Name: PdmMainWinHelpCB
511  *
512  * Description:
513  *
514  *     Update the main window instance structure to reflect destruction
515  *     of the help dialog.
516  *
517  * Return value:
518  *
519  *     None.
520  */
521 static void
522 PdmMainWinHelpDestroyCB(Widget w, XtPointer client_data, XtPointer call_data)
523 {
524     PdmMainWin* me = (PdmMainWin*)client_data;
525     me->help_dialog = (Widget)NULL;
526 }
527
528 /*
529  * ------------------------------------------------------------------------
530  * Name: PdmMainWinCreate
531  *
532  * Description:
533  *
534  *     Creates the PDM main window, including setup box children added
535  *     via PdmMainWinAddSetupBox.
536  *
537  * Return value:
538  *
539  *     The passed PdmMainWin pointer.
540  *
541  */
542 PdmMainWin*
543 PdmMainWinCreate(PdmMainWin* me,
544                  Widget parent,
545                  String print_display_spec,
546                  String print_context_str)
547 {
548     /*
549      * establish the print server connection
550      */
551     if(PdmXpOpen(me->pdm_xp, print_display_spec, print_context_str)
552        == (Display*)NULL)
553     {
554         /*
555          * unable to open the print display
556          */
557         PdmMainWinDelete(me);
558         exit(PDM_EXIT_PXAUTH);
559     }
560     /*
561      * make a copy of the print display spec
562      */
563     me->print_display_spec = XtNewString(print_display_spec);
564     /*
565      * get attributes for the main window and the setup box children
566      */
567     PdmMainWinGetAttributes(me);
568     /*
569      * create the main window
570      */
571     PdmMainWinCreateWindow(me, parent);
572     /*
573      * add the registered setup boxes to the notebook
574      */
575     PdmMainWinCreateSetupBoxes(me);
576     /*
577      * return
578      */
579     return me;
580 }
581
582 /*
583  * ------------------------------------------------------------------------
584  * Name: PdmMainWinCreateWindow
585  *
586  * Description:
587  *
588  *     Creates the PDM main window, including setup box children added
589  *     via PdmMainWinAddSetupBox.
590  *
591  * Return value:
592  *
593  *     The main window widget ID.
594  *
595  */
596 static Widget
597 PdmMainWinCreateWindow(PdmMainWin* me,
598                        Widget parent)
599 {
600     Widget manager;
601     Widget row;
602     Widget w;
603     XmString label;
604
605     /*
606      * create the main window
607      */
608     me->widget =
609         XtVaCreateManagedWidget("Main",
610                                 xmMessageBoxWidgetClass,
611                                 parent,
612                                 XmNdialogType, XmDIALOG_MESSAGE,
613                                 NULL);
614     XtUnmanageChild(XtNameToWidget(me->widget, "Message"));
615     XtUnmanageChild(XtNameToWidget(me->widget, "Symbol"));
616     /*
617      * add OK, Cancel and Help pushbutton callbacks
618      */
619     XtAddCallback(me->widget, XmNokCallback,
620                   PdmMainWinOkCB, (XtPointer)me);
621     XtAddCallback(me->widget, XmNcancelCallback,
622                   PdmMainWinCancelCB, (XtPointer)me);
623     XtAddCallback(me->widget, XmNhelpCallback,
624                   PdmMainWinHelpCB, (XtPointer)me);
625     /*
626      * create the main manager widget
627      */
628     manager = XtVaCreateManagedWidget("Manager",
629                                       xmRowColumnWidgetClass,
630                                       me->widget,
631                                       NULL);
632     /*
633      * create the printer description row
634      */
635     if(me->printer_descriptor != (const char*)NULL)
636     {
637         char* desc;
638         char* ptr;
639         
640         row = XtVaCreateManagedWidget(
641                                       "PrinterDescriptionRow",
642                                       xmRowColumnWidgetClass,
643                                       manager,
644                                       XmNorientation, XmHORIZONTAL,
645                                       NULL);
646         /*
647          * create the printer description label
648          */
649         w = XtVaCreateManagedWidget("PrinterDescriptionLabel",
650                                     xmLabelGadgetClass,
651                                     row,
652                                     NULL);
653         /*
654          * create the printer description using just the 1st line
655          */
656         desc = XtNewString(me->printer_descriptor);
657         ptr = Dt_strchr(desc, '\n');
658         if(ptr != NULL)
659             *ptr = '\0';
660         label = XmStringCreateLocalized(desc);
661         XtFree(desc);
662         w = XtVaCreateManagedWidget("PrinterDescription",
663                                     xmLabelGadgetClass,
664                                     row,
665                                     XmNlabelString, label,
666                                     NULL);
667         XmStringFree(label);
668     }
669     /*
670      * create the printer name row
671      */
672     if(me->printer_name != (const char*)NULL)
673     {
674         char* printer_spec;
675         int printer_spec_len;
676
677         row = XtVaCreateManagedWidget(
678                                       "PrinterNameRow",
679                                       xmRowColumnWidgetClass,
680                                       manager,
681                                       XmNorientation, XmHORIZONTAL,
682                                       NULL);
683         /*
684          * create the printer name label
685          */
686         w = XtVaCreateManagedWidget("PrinterNameLabel",
687                                     xmLabelGadgetClass,
688                                     row,
689                                     NULL);
690         /*
691          * build the X printer specifier
692          */
693         printer_spec_len = strlen(me->printer_name);
694         if(me->print_display_spec != (char*)NULL)
695             printer_spec_len += strlen(me->print_display_spec) + 1;
696         printer_spec = XtMalloc(printer_spec_len + 1);
697         strcpy(printer_spec, me->printer_name);
698         if(me->print_display_spec != (char*)NULL)
699         {
700             strcat(printer_spec, "@");
701             strcat(printer_spec, me->print_display_spec);
702         }
703         /*
704          * create the printer name
705          */
706         label = XmStringCreateLocalized(printer_spec);
707         XtFree(printer_spec);
708         w = XtVaCreateManagedWidget("PrinterName",
709                                     xmLabelGadgetClass,
710                                     row,
711                                     XmNlabelString, label,
712                                     NULL);
713         XmStringFree(label);
714     }
715     /*
716      * top separator
717      */
718     w = XtVaCreateManagedWidget("TopSeparator",
719                                 xmSeparatorGadgetClass,
720                                 manager,
721                                 NULL);
722     /*
723      * notebook label
724      */
725     row = XtVaCreateManagedWidget(
726                                   "PrinterNameRow",
727                                   xmRowColumnWidgetClass,
728                                   manager,
729                                   XmNorientation, XmHORIZONTAL,
730                                   NULL);
731     w = XtVaCreateManagedWidget("NotebookLabel",
732                                 xmLabelGadgetClass,
733                                 row,
734                                 NULL);
735     /*
736      * create the notebook
737      */
738     row = XtVaCreateManagedWidget(
739                                   "NotebookRow",
740                                   xmRowColumnWidgetClass,
741                                   manager,
742                                   XmNorientation, XmHORIZONTAL,
743                                   NULL);
744     me->notebook =
745         XtVaCreateManagedWidget(
746                                 "Notebook",
747                                 xmNotebookWidgetClass,
748                                 row,
749                                 NULL);
750     /*
751      * Create an unmanaged notebook page scroller (i.e. a widget that has
752      * the XmQTnavigator trait), otherwise the notebook widget will
753      * create a default page scroller when it is realized. If this
754      * default page scroller is unmanaged after realization, the parent
755      * manager of the notebook does not shrink in order to reclaim the
756      * space previously occupied by the page scroller.
757      */
758     XtVaCreateWidget("DummyPageScroller",
759                      xmScrollBarWidgetClass,
760                      me->notebook,
761                      NULL);
762     /*
763      * return
764      */
765     return me->widget;
766 }