dtinfo: Fix coverity warning related to using delete not delete []
[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 #if 0 && defined(PRINTING_SUPPORTED)
293     me->printer_descriptor = PdmXpGetStringValue(me->pdm_xp,
294                                                  XPPrinterAttr,
295                                                  pdmoid_att_descriptor);
296     me->printer_name = PdmXpGetStringValue(me->pdm_xp,
297                                            XPPrinterAttr,
298                                            pdmoid_att_printer_name);
299 #endif /* PRINTING_SUPPORTED */
300     /*
301      * call the get attributes proc for each setup box child
302      */
303     for(node = me->box_list_head; node != (PdmBoxNode*)NULL; node = node->next)
304     {
305         PdmSetupBox* box = node->box;
306         
307         (*box->get_attr_proc)(box, me->pdm_xp);
308     }
309 }
310
311 /*
312  * ------------------------------------------------------------------------
313  * Name: PdmMainWinOkCB
314  *
315  * Description:
316  *
317  *     Callback for the main window OK button. This function first calls
318  *     the verify values method for each of the child setup boxes. If the
319  *     values for all of the children are Ok, the new values are set into
320  *     the print context, and the program exits. Otherwise the program
321  *     resumes. In this case, it is assumed that the child setup box will
322  *     present a message to the user indicating that its values are not
323  *     Ok. This function will move the invalid child setup notebook page
324  *     to the top.
325  *
326  * Return value:
327  *
328  *     None, although it usually ends the program with an exit code of
329  *     PDM_EXIT_OK.
330  *
331  */
332 static void
333 PdmMainWinOkCB(
334                Widget w,
335                XtPointer client_data,
336                XtPointer call_data)
337 {
338     PdmMainWin* me = (PdmMainWin*)client_data;
339     PdmBoxNode* node;
340     int page;
341     /*
342      * call the verify values proc for each setup box child
343      */
344     for(node = me->box_list_head, page = 1;
345         node != (PdmBoxNode*)NULL;
346         node = node->next, page++)
347     {
348         PdmSetupBox* box = node->box;
349
350         if((*box->verify_attr_proc)(box, me->pdm_xp) != PDM_SUCCESS)
351         {
352             /*
353              * Ensure this setup box is the top notebook page; the setup
354              * box is responsible for providing error messages to the
355              * user.
356              *
357              * developer hint: do not use the setup box as the parent of
358              *                 a message box; if the setup box is not the
359              *                 current notebook page, the message box
360              *                 will not be positioned properly; use the
361              *                 first shell ancestor (or even the parent)
362              *                 of the setup box instead
363              */
364             XtVaSetValues(me->notebook, XmNcurrentPageNumber, page, NULL);
365             /*
366              * stop verifying and return
367              */
368             return;
369         }
370     }
371     /*
372      * call the set attributes proc for each setup box child
373      */
374     for(node = me->box_list_head; node != (PdmBoxNode*)NULL; node = node->next)
375     {
376         PdmSetupBox* box = node->box;
377         
378         (*box->set_attr_proc)(box, me->pdm_xp);
379     }
380     /*
381      * set the updated attributes into the print context
382      */
383     PdmXpUpdateAttributes(me->pdm_xp);
384     /*
385      * exit the PDM
386      */
387     PdmMainWinDelete(me);
388     exit(PDM_EXIT_OK);
389 }
390
391 /*
392  * ------------------------------------------------------------------------
393  * Name: PdmMainWinCancelCB
394  *
395  * Description:
396  *
397  *     Callback for the main window Cancel button. This function simply
398  *     ends the PDM program.
399  *
400  * Return value:
401  *
402  *     None, although it will end the program with an exit code of
403  *     PDM_EXIT_CANCEL.
404  *
405  */
406 static void
407 PdmMainWinCancelCB(
408                    Widget w,
409                    XtPointer client_data,
410                    XtPointer call_data)
411 {
412     PdmMainWin* me = (PdmMainWin*)client_data;
413     PdmMainWinDelete(me);
414     exit(PDM_EXIT_CANCEL);
415 }
416
417 /*
418  * ------------------------------------------------------------------------
419  * Name: PdmMainWinHelpCB
420  *
421  * Description:
422  *
423  *
424  * Return value:
425  *
426  *
427  */
428 static void
429 PdmMainWinHelpCB(Widget w, XtPointer client_data, XtPointer call_data)
430 {
431     PdmMainWin* me = (PdmMainWin*)client_data;
432     PdmSetupBox* box;
433     struct _box_resources
434     {
435         String help_volume;
436         String location_id;
437     } box_resources;
438     /*
439      * create the help dialog if needed
440      */
441     if((Widget)NULL == me->help_dialog)
442     {
443         me->help_dialog =
444             DtCreateHelpDialog(XtParent(me->widget), "HelpDialog", NULL, 0);
445         XtAddCallback(me->help_dialog, XmNdestroyCallback,
446                       PdmMainWinHelpDestroyCB, (XtPointer)me);
447     }
448     /*
449      * determine the current setup box
450      */
451     {
452         XtArgVal current_page;
453         int i;
454         PdmBoxNode* node;
455         
456         XtVaGetValues(me->notebook, XmNcurrentPageNumber, &current_page, NULL);
457         node = me->box_list_head;
458         for(i = 1; i < (int)current_page; i++)
459             node = node->next;
460         box = node->box;
461     }
462     /*
463      * the help volume name and location id are obtained up as application
464      * resources qualified for each setup box
465      */
466     {
467         XtResource resources[2];
468         /*
469          * initialize res struct for help volume
470          */
471         resources[0].resource_name = DtNhelpVolume;
472         resources[0].resource_class = DtCHelpVolume;
473         resources[0].resource_type =  XmRString;
474         resources[0].resource_size = sizeof(String);
475         resources[0].resource_offset =
476             XtOffsetOf(struct _box_resources, help_volume);
477         resources[0].default_type = XmRImmediate;
478         resources[0].default_addr = (XtPointer)NULL;
479         /*
480          * initialize res struct for location id
481          */
482         resources[1].resource_name = DtNlocationId;
483         resources[1].resource_class = DtCLocationId;
484         resources[1].resource_type =  XmRString;
485         resources[1].resource_size = sizeof(String);
486         resources[1].resource_offset =
487             XtOffsetOf(struct _box_resources, location_id);
488         resources[1].default_type = XmRImmediate;
489         resources[1].default_addr = (XtPointer)NULL;
490         /*
491          * get the resource values for the current setup box widget
492          */
493         XtGetApplicationResources(box->widget, (XtPointer)&box_resources,
494                                   resources, XtNumber(resources),
495                                   (ArgList)NULL, 0);
496     }
497     /*
498      * set the help volume and location
499      */
500     XtVaSetValues(me->help_dialog,
501                   DtNhelpVolume, box_resources.help_volume,
502                   DtNlocationId, box_resources.location_id,
503                   DtNhelpType, DtHELP_TYPE_TOPIC,
504                   NULL);
505     /*
506      * pop up the help dialog
507      */
508     XtManageChild(me->help_dialog);
509 }
510
511 /*
512  * ------------------------------------------------------------------------
513  * Name: PdmMainWinHelpCB
514  *
515  * Description:
516  *
517  *     Update the main window instance structure to reflect destruction
518  *     of the help dialog.
519  *
520  * Return value:
521  *
522  *     None.
523  */
524 static void
525 PdmMainWinHelpDestroyCB(Widget w, XtPointer client_data, XtPointer call_data)
526 {
527     PdmMainWin* me = (PdmMainWin*)client_data;
528     me->help_dialog = (Widget)NULL;
529 }
530
531 /*
532  * ------------------------------------------------------------------------
533  * Name: PdmMainWinCreate
534  *
535  * Description:
536  *
537  *     Creates the PDM main window, including setup box children added
538  *     via PdmMainWinAddSetupBox.
539  *
540  * Return value:
541  *
542  *     The passed PdmMainWin pointer.
543  *
544  */
545 PdmMainWin*
546 PdmMainWinCreate(PdmMainWin* me,
547                  Widget parent,
548                  String print_display_spec,
549                  String print_context_str)
550 {
551     /*
552      * establish the print server connection
553      */
554     if(PdmXpOpen(me->pdm_xp, print_display_spec, print_context_str)
555        == (Display*)NULL)
556     {
557         /*
558          * unable to open the print display
559          */
560         PdmMainWinDelete(me);
561         exit(PDM_EXIT_PXAUTH);
562     }
563     /*
564      * make a copy of the print display spec
565      */
566     me->print_display_spec = XtNewString(print_display_spec);
567     /*
568      * get attributes for the main window and the setup box children
569      */
570     PdmMainWinGetAttributes(me);
571     /*
572      * create the main window
573      */
574     PdmMainWinCreateWindow(me, parent);
575     /*
576      * add the registered setup boxes to the notebook
577      */
578     PdmMainWinCreateSetupBoxes(me);
579     /*
580      * return
581      */
582     return me;
583 }
584
585 /*
586  * ------------------------------------------------------------------------
587  * Name: PdmMainWinCreateWindow
588  *
589  * Description:
590  *
591  *     Creates the PDM main window, including setup box children added
592  *     via PdmMainWinAddSetupBox.
593  *
594  * Return value:
595  *
596  *     The main window widget ID.
597  *
598  */
599 static Widget
600 PdmMainWinCreateWindow(PdmMainWin* me,
601                        Widget parent)
602 {
603     Widget manager;
604     Widget row;
605     Widget w;
606     XmString label;
607
608     /*
609      * create the main window
610      */
611     me->widget =
612         XtVaCreateManagedWidget("Main",
613                                 xmMessageBoxWidgetClass,
614                                 parent,
615                                 XmNdialogType, XmDIALOG_MESSAGE,
616                                 NULL);
617     XtUnmanageChild(XtNameToWidget(me->widget, "Message"));
618     XtUnmanageChild(XtNameToWidget(me->widget, "Symbol"));
619     /*
620      * add OK, Cancel and Help pushbutton callbacks
621      */
622     XtAddCallback(me->widget, XmNokCallback,
623                   PdmMainWinOkCB, (XtPointer)me);
624     XtAddCallback(me->widget, XmNcancelCallback,
625                   PdmMainWinCancelCB, (XtPointer)me);
626     XtAddCallback(me->widget, XmNhelpCallback,
627                   PdmMainWinHelpCB, (XtPointer)me);
628     /*
629      * create the main manager widget
630      */
631     manager = XtVaCreateManagedWidget("Manager",
632                                       xmRowColumnWidgetClass,
633                                       me->widget,
634                                       NULL);
635     /*
636      * create the printer description row
637      */
638     if(me->printer_descriptor != (const char*)NULL)
639     {
640         char* desc;
641         char* ptr;
642         
643         row = XtVaCreateManagedWidget(
644                                       "PrinterDescriptionRow",
645                                       xmRowColumnWidgetClass,
646                                       manager,
647                                       XmNorientation, XmHORIZONTAL,
648                                       NULL);
649         /*
650          * create the printer description label
651          */
652         w = XtVaCreateManagedWidget("PrinterDescriptionLabel",
653                                     xmLabelGadgetClass,
654                                     row,
655                                     NULL);
656         /*
657          * create the printer description using just the 1st line
658          */
659         desc = XtNewString(me->printer_descriptor);
660         ptr = Dt_strchr(desc, '\n');
661         if(ptr != NULL)
662             *ptr = '\0';
663         label = XmStringCreateLocalized(desc);
664         XtFree(desc);
665         w = XtVaCreateManagedWidget("PrinterDescription",
666                                     xmLabelGadgetClass,
667                                     row,
668                                     XmNlabelString, label,
669                                     NULL);
670         XmStringFree(label);
671     }
672     /*
673      * create the printer name row
674      */
675     if(me->printer_name != (const char*)NULL)
676     {
677         char* printer_spec;
678         int printer_spec_len;
679
680         row = XtVaCreateManagedWidget(
681                                       "PrinterNameRow",
682                                       xmRowColumnWidgetClass,
683                                       manager,
684                                       XmNorientation, XmHORIZONTAL,
685                                       NULL);
686         /*
687          * create the printer name label
688          */
689         w = XtVaCreateManagedWidget("PrinterNameLabel",
690                                     xmLabelGadgetClass,
691                                     row,
692                                     NULL);
693         /*
694          * build the X printer specifier
695          */
696         printer_spec_len = strlen(me->printer_name);
697         if(me->print_display_spec != (char*)NULL)
698             printer_spec_len += strlen(me->print_display_spec) + 1;
699         printer_spec = XtMalloc(printer_spec_len + 1);
700         strcpy(printer_spec, me->printer_name);
701         if(me->print_display_spec != (char*)NULL)
702         {
703             strcat(printer_spec, "@");
704             strcat(printer_spec, me->print_display_spec);
705         }
706         /*
707          * create the printer name
708          */
709         label = XmStringCreateLocalized(printer_spec);
710         XtFree(printer_spec);
711         w = XtVaCreateManagedWidget("PrinterName",
712                                     xmLabelGadgetClass,
713                                     row,
714                                     XmNlabelString, label,
715                                     NULL);
716         XmStringFree(label);
717     }
718     /*
719      * top separator
720      */
721     w = XtVaCreateManagedWidget("TopSeparator",
722                                 xmSeparatorGadgetClass,
723                                 manager,
724                                 NULL);
725     /*
726      * notebook label
727      */
728     row = XtVaCreateManagedWidget(
729                                   "PrinterNameRow",
730                                   xmRowColumnWidgetClass,
731                                   manager,
732                                   XmNorientation, XmHORIZONTAL,
733                                   NULL);
734     w = XtVaCreateManagedWidget("NotebookLabel",
735                                 xmLabelGadgetClass,
736                                 row,
737                                 NULL);
738     /*
739      * create the notebook
740      */
741     row = XtVaCreateManagedWidget(
742                                   "NotebookRow",
743                                   xmRowColumnWidgetClass,
744                                   manager,
745                                   XmNorientation, XmHORIZONTAL,
746                                   NULL);
747     me->notebook =
748         XtVaCreateManagedWidget(
749                                 "Notebook",
750                                 xmNotebookWidgetClass,
751                                 row,
752                                 NULL);
753     /*
754      * Create an unmanaged notebook page scroller (i.e. a widget that has
755      * the XmQTnavigator trait), otherwise the notebook widget will
756      * create a default page scroller when it is realized. If this
757      * default page scroller is unmanaged after realization, the parent
758      * manager of the notebook does not shrink in order to reclaim the
759      * space previously occupied by the page scroller.
760      */
761     XtVaCreateWidget("DummyPageScroller",
762                      xmScrollBarWidgetClass,
763                      me->notebook,
764                      NULL);
765     /*
766      * return
767      */
768     return me->widget;
769 }