dtmail: Further Coverity fixes
[oweals/cde.git] / cde / programs / dtmail / MotifApp / 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 /* $TOG: MainWindow.C /main/13 1998/04/06 13:22:40 mgreess $ */
24 /*
25  *+SNOTICE
26  *
27  *      $TOG: MainWindow.C /main/13 1998/04/06 13:22:40 mgreess $
28  *
29  *      RESTRICTED CONFIDENTIAL INFORMATION:
30  *      
31  *      The information in this document is subject to special
32  *      restrictions in a confidential disclosure agreement bertween
33  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34  *      document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
35  *      Sun's specific written approval.  This documment and all copies
36  *      and derivative works thereof must be returned or destroyed at
37  *      Sun's request.
38  *
39  *      Copyright 1993, 1994, 1995 Sun Microsystems, Inc.  All rights reserved.
40  *
41  *+ENOTICE
42  */
43
44 ///////////////////////////////////////////////////////////////////////////////
45 //////////////////////////////////////////////////////////////////////////////
46 //         This example code is from the book:
47 //
48 //           Object-Oriented Programming with C++ and OSF/Motif
49 //         by
50 //           Douglas Young
51 //           Prentice Hall, 1992
52 //           ISBN 0-13-630252-1 
53 //
54 //         Copyright 1991 by Prentice Hall
55 //         All Rights Reserved
56 //
57 //  Permission to use, copy, modify, and distribute this software for 
58 //  any purpose except publication and without fee is hereby granted, provided 
59 //  that the above copyright notice appear in all copies of the software.
60 ///////////////////////////////////////////////////////////////////////////////
61 //////////////////////////////////////////////////////////////////////////////
62
63
64 ////////////////////////////////////////////////////////////////////
65 // MainWindow.C: Support a toplevel window
66 ////////////////////////////////////////////////////////////////////
67 #include <assert.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <Xm/Protocols.h>
71 #include <Xm/AtomMgr.h>
72 #include <Xm/MainW.h>
73 #include <Dt/Wsm.h>
74 #include <Dt/Session.h>
75 #include <DtMail/IO.hh>
76 #include <X11/Shell.h>
77 #include <X11/Xmu/Editres.h>
78 #include "Application.h"
79 #include "MainWindow.h"
80 #include "Help.hh"
81
82 // The following headers are private to CDE and should NOT be required
83 // but unfortunately are.
84 //
85 extern "C" {
86 #include <Dt/HourGlass.h>
87 }
88 #include <Dt/Icon.h>
89 #include <Dt/IconP.h>
90 #include <Dt/IconFile.h>
91
92 // This is a private CDE function that should be public, but is not,
93 // and does not even have a prototype in a header. Yes, it is required.
94 //
95 extern "C" Pixmap _DtGetMask(Screen * screen, char * image_name);
96
97 #if 0
98 static const char * DefaultIcon = "Dtablnk";
99 #endif
100 static const unsigned long FLASH_INTERVAL = 250; // milliseconds
101
102 MainWindow::MainWindow( char *name, Boolean allowResize ) : UIComponent ( name )
103 {
104     _workArea = NULL;
105     _flashing = 0;
106     _icon_invert = NULL;
107     _window_invert = NULL;
108     _icon = 0;
109     _allow_resize = allowResize;
110     _last_state = 0;
111     _flash_owin = 0;
112     _flash_iwin = 0;
113     _main = NULL;
114     memset(&_window_attributes, 0, sizeof(XWindowAttributes));
115
116     assert ( theApplication != NULL ); // Application object must exist
117     // before any MainWindow object
118     theApplication->registerWindow ( this );
119 }
120
121 void
122 MainWindow::initialize( )
123 {
124     char *appWorkspaces;
125
126     // All toplevel windows in the MotifApp framework are 
127     // implemented as a popup shell off the Application's
128     // base widget.
129     //
130     // XmNdeleteResponse is being set to DO_NOTHING so 
131     // that the user can Cancel their close request.
132
133     _w = XtVaCreatePopupShell ( _name, 
134                                 topLevelShellWidgetClass,
135                                 theApplication->baseWidget(),
136                                 XmNdeleteResponse, XmDO_NOTHING,
137                                 XmNallowShellResize, _allow_resize,
138                                 NULL, NULL );
139
140 #ifdef USE_EDITRES
141     XtAddEventHandler(
142                 _w, (EventMask) 0, True,
143                 (XtEventHandler) _XEditResCheckMessages, NULL);
144 #endif
145
146     installDestroyHandler();
147     
148     // Use a Motif XmMainWindow widget to handle window layout
149     
150     _main = XtCreateManagedWidget ( "mainWindow", 
151                                    xmMainWindowWidgetClass,
152                                    _w, 
153                                    NULL, 0 );
154     printHelpId("_main", _main);
155     /* install callback */
156     // XtAddCallback(_main, XmNhelpCallback, HelpCB, helpId);
157     XtAddCallback(_main, XmNhelpCallback, 
158                             HelpCB, (void *)"_HOMETOPIC");
159     
160     // Called derived class to create the work area
161     
162     _workArea = createWorkArea ( _main );  
163     assert ( _workArea != NULL );
164     
165     // Designate the _workArea widget as the XmMainWindow
166     // widget's XmNworkWindow widget
167     
168     XtVaSetValues ( _main, 
169                    XmNworkWindow, _workArea,
170                    NULL );
171
172     Atom WM_DELETE_WINDOW=XmInternAtom( XtDisplay( _w ),
173                                         "WM_DELETE_WINDOW",
174                                         False );
175
176     XmAddWMProtocolCallback( _w,
177                              WM_DELETE_WINDOW,
178                              ( XtCallbackProc ) quitCallback,
179                              this );
180
181 #if 0
182     // Why are we setting the icon to Dtablnk.  This is simply going to
183     // be overriden by some other function setting it to the appropriate 
184     // icon.
185     setIconName(DefaultIcon);
186 #endif
187
188     _window_invert = NULL;
189     _last_state = 0;
190     _flash_owin = (Window) NULL;
191     _flash_iwin = (Window) NULL;
192     memset((char*) &(this->_window_attributes), 0, sizeof(XWindowAttributes));
193
194     // Manage the work area if the derived class hasn't already.
195     
196     if ( !XtIsManaged ( _workArea ) )
197         XtManageChild ( _workArea ); 
198
199     XtRealizeWidget(_w);
200     appWorkspaces = theApplication->getAppWorkspaceList();
201     setWorkspacesOccupied(appWorkspaces);
202 }
203
204 MainWindow::~MainWindow( )
205 {
206     // Unregister this window with the Application object
207
208     if (_w) {
209         Atom WM_DELETE_WINDOW=XmInternAtom( XtDisplay( _w ),
210                                             "WM_DELETE_WINDOW",
211                                             False );
212         XmRemoveWMProtocolCallback( _w,
213                                     WM_DELETE_WINDOW,
214                                     ( XtCallbackProc ) quitCallback,
215                                     NULL );
216
217         if (_icon_invert) XFreeGC(XtDisplay(_w), _icon_invert);
218         if (_window_invert) XFreeGC(XtDisplay(_w), _window_invert);
219         if (_flash_iwin != (Window) NULL)
220           XDestroyWindow( XtDisplay(_w), _flash_iwin );
221         if (_flash_owin != (Window) NULL)
222           XDestroyWindow( XtDisplay(_w), _flash_owin );
223     }
224     
225     theApplication->unregisterWindow ( this );
226 }
227
228 void
229 MainWindow::enableWorkAreaResize()
230 {
231     XtVaSetValues(_workArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
232 }
233
234 void
235 MainWindow::disableWorkAreaResize()
236 {
237     XtVaSetValues(_workArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
238 }
239
240 void
241 MainWindow::manage()
242 {
243     assert ( _w != NULL );
244     XtPopup ( _w, XtGrabNone );
245     
246     // Map the window, in case the window is iconified
247
248     if ( XtIsRealized ( _w ) ) 
249         XMapRaised ( XtDisplay ( _w ), XtWindow ( _w ) );
250 }
251
252 void
253 MainWindow::unmanage()
254 {
255     assert ( _w != NULL );
256     XtPopdown ( _w );
257 }
258
259 void
260 MainWindow::iconify()
261 {
262     assert ( _w != NULL );
263     
264     // Set the widget to have an initial iconic state
265     // in case the base widget has not yet been realized
266     
267     XtVaSetValues ( _w, XmNiconic, TRUE, NULL );
268     
269     // If the widget has already been realized,
270     // iconify the window
271     
272     if ( XtIsRealized ( _w ) )
273         XIconifyWindow ( XtDisplay ( _w ), XtWindow ( _w ), 0 );
274 }
275
276 void
277 MainWindow::setIconTitle(const char * title)
278 {
279     XtVaSetValues(_w, XmNiconName, title, NULL);
280 }
281
282 void
283 MainWindow::setIconName(const char * path)
284 {
285     char * icon_filename = XmGetIconFileName(XtScreen(_w),
286                                              NULL,
287                                              (char *)path, // Bug!
288                                              NULL,
289                                              DtLARGE);
290
291     if (icon_filename == NULL) {
292         return;
293     }
294
295     Pixel fg = 0, bg = 0;
296
297     getIconColors(fg, bg);
298
299     _icon = XmGetPixmap(XtScreen(_w),
300                         icon_filename,
301                         fg, bg);
302
303     Pixmap icon_mask_map = _DtGetMask(XtScreen(_w), icon_filename);
304
305     if (!_icon || !icon_mask_map) {
306         return;
307     }
308
309     XtVaSetValues(_w,
310                   XmNiconPixmap, _icon,
311                   XmNiconMask, icon_mask_map,
312                   NULL);
313
314     // Build the inverted icon mask for flashing.
315     //
316     if (_icon_invert) {
317         XFreeGC(XtDisplay(_w), _icon_invert);
318     }
319
320     XGCValues   gc_vals;
321
322     gc_vals.foreground = bg;
323     gc_vals.function = GXxor;
324     _icon_invert = XCreateGC(XtDisplay(_w), _icon, GCForeground | GCFunction,
325                              &gc_vals);
326
327     XtFree(icon_filename);
328 }
329
330 void
331 MainWindow::busyCursor()
332 {
333     // Do nothing if the widget has not been realized
334
335     if (XtIsRealized(_w)) {
336         _DtTurnOnHourGlass(_w);
337     }
338 }
339
340 void
341 MainWindow::normalCursor()
342 {
343     // Do nothing if the widget has not been realized
344     
345     if (XtIsRealized ( _w ))
346     {
347         _DtTurnOffHourGlass(_w);
348     }
349 }
350
351 void
352 MainWindow::setStatus(const char *)
353 {
354     // Noop in our case.
355 }
356
357 void
358 MainWindow::clearStatus(void)
359 {
360     // Noop in our case.
361 }
362
363 void
364 MainWindow::title(const char *text )
365 {
366     XtVaSetValues ( _w, XmNtitle, (char *)text, NULL );
367 }
368
369 void
370 MainWindow::quitCallback( Widget,
371                           XtPointer clientData,
372                           XmAnyCallbackStruct *)
373 {
374     MainWindow *window=( MainWindow *) clientData;
375     window->quit();
376 }
377
378 void
379 MainWindow::getIconColors(Pixel & fore, Pixel & back)
380 {
381     XtVaGetValues (_w,
382                    XmNforeground, &fore,
383                    XmNbackground, &back,
384                    NULL);
385 }
386
387 struct WM_STATE {
388     int         state;
389     Window      icon;
390 };
391
392 static int
393 getWindowState(Widget w)
394 {
395     Atom        wmStateAtom, actualType;
396     int         actualFormat;
397     int         retval;
398     unsigned long nitems, leftover;
399     WM_STATE *wmState;
400  
401     /*  Getting the WM_STATE property to see if iconified or not */
402     wmStateAtom = XInternAtom(XtDisplay(w), "WM_STATE", False);
403  
404     XGetWindowProperty (XtDisplay(w), XtWindow(w), 
405                         wmStateAtom, 0L,
406                         (long)BUFSIZ, False, wmStateAtom, &actualType,
407                         &actualFormat, &nitems, &leftover,
408                         (unsigned char **) &wmState);
409
410     if (wmState)
411         retval = wmState->state;
412     else
413         retval = 0;
414
415     free((void*) wmState);
416     return retval;
417 }
418
419 void
420 MainWindow::flash(const int count)
421 {
422     XWindowAttributes   window_attributes;
423
424     if (count == 0) return;
425     if (_flashing > 0) return;
426
427     if (_window_invert == NULL) {
428         // Create a GC to flash the window.
429         //
430         XGCValues       gc_vals;
431         Pixel   fg, bg;
432         getIconColors(fg, bg);
433         
434         gc_vals.foreground = bg;
435         gc_vals.function = GXxor;
436         _window_invert = XCreateGC(XtDisplay(_w), XtWindow(_w),
437                                    GCForeground | GCFunction, &gc_vals);
438         XSetSubwindowMode(XtDisplay(_w), _window_invert, IncludeInferiors);
439     }
440
441     _last_state = getWindowState(_w);
442
443     //
444     //  The original method here, to invert the window and timeout
445     //  before inverting back to the original (pixels), breaks when
446     //  the window is left with pixels XOR'd in the flash ON state.
447     //
448     //  One quick fix, uses a transparent window (or windows) on top
449     //  of the window to be flashed.  The temp window(s) are used to
450     //  prevent updates while flash is ON and/or cause a full update
451     //  (expose) after each flash.
452     //
453     //  First, (this part optional) put an "InputOnly" window on top of
454     //  the window to be flashed and ignore all events to this window.
455     //  This has the effect of preventing user input (events) from
456     //  causing application updates to the window.  This temp window
457     //  can be left up (with the wait cursor) until flashing is done.  
458     //
459     //  Next, handle expose events by using a transparent "InputOutput"
460     //  window on top of everything only when flash is ON.  This has
461     //  the effect of preventing expose events from causing application
462     //  updates to the real window when flash is ON.  It especially,
463     //  ensures other problems (e.g. updates to the window caused by
464     //  other application timeout events and overlapping window pixels
465     //  from an expose event) are cleaned up by an expose event when
466     //  this temp window is unmapped or destroyed (between each flash).
467     //
468     
469     XGetWindowAttributes(XtDisplay(_w), XtWindow(_w), &window_attributes);
470
471     if ((Window) NULL != _flash_owin &&
472         (window_attributes.width != _window_attributes.width ||
473          window_attributes.height != _window_attributes.height ||
474          window_attributes.border_width != _window_attributes.border_width))
475     {
476         XDestroyWindow( XtDisplay(_w), _flash_iwin );
477         XDestroyWindow( XtDisplay(_w), _flash_owin );
478         _flash_iwin = (Window) NULL;
479         _flash_owin = (Window) NULL;
480     }
481
482     if ((Window) NULL == _flash_owin)
483     {
484         XSetWindowAttributes    sw_attr;
485
486         memcpy((char*) &(this->_window_attributes), 
487                (char*) &window_attributes,
488                sizeof(window_attributes));
489
490         sw_attr.event_mask = 0;
491         _flash_iwin = XCreateWindow(
492                         XtDisplay(_w), XtWindow(_w), 0, 0,
493                         _window_attributes.width, _window_attributes.height,
494                         _window_attributes.border_width, (int) CopyFromParent,
495                         InputOnly, CopyFromParent,
496                         CWEventMask, &sw_attr );
497         XMapWindow( XtDisplay(_w), _flash_iwin );
498         _flash_owin = XCreateWindow(
499                         XtDisplay(_w), XtWindow(_w), 0, 0,
500                         _window_attributes.width, _window_attributes.height,
501                         _window_attributes.border_width, (int) CopyFromParent,
502                         InputOutput, CopyFromParent,
503                         CWEventMask, &sw_attr );
504     }
505
506     _flashing = count * 2;
507     XtAppAddTimeOut(
508                 XtWidgetToApplicationContext(_w),
509                 FLASH_INTERVAL, flashCallback, this);
510 }
511
512 void
513 MainWindow::flashCallback(XtPointer client_data, XtIntervalId * interval_id)
514 {
515     MainWindow * mw = (MainWindow *)client_data;
516
517     mw->doFlash(interval_id);
518 }
519
520 void
521 MainWindow::doFlash(XtIntervalId *)
522 {
523     static int busy_cursor = 0;
524     int state = getWindowState(_w);
525
526     // We are going to make things flash an even number of times.
527     // to do this, we will lie about the state, and leave it at the
528     // old state for one iteration.
529     if (state != _last_state && (_flashing % 2) != 0)
530       state = _last_state;
531  
532     if (! busy_cursor) {
533         busyCursor();
534         busy_cursor = 1;
535     }
536
537     if (state == IconicState) {
538         Pixmap  image = _icon;
539
540         XFillRectangle(XtDisplay(_w), image, _icon_invert, 0, 0, 48, 48);
541         XtVaSetValues(_w, XmNiconPixmap, NULL, NULL);
542         XtVaSetValues(_w, XmNiconPixmap, image, NULL);
543     }
544     else if (state != 0) {
545
546         // Map temp window to prevent expose updates and other
547         // application event updates ... when flash is on.
548         if ( (_flashing % 2) == 0 )
549           XMapWindow( XtDisplay(_w), _flash_owin );
550
551         XFillRectangle(
552                 XtDisplay(_w), XtWindow(_w),
553                 _window_invert, 0, 0,
554                 _window_attributes.width, _window_attributes.height);
555
556         // Remove temp window to update display when flash is off.
557         if ( (_flashing % 2) != 0 )
558           XUnmapWindow( XtDisplay(_w), _flash_owin );
559     }
560
561     _flashing -= 1;
562
563     if (_flashing > 0) {
564         XtAppAddTimeOut(
565                         XtWidgetToApplicationContext(_w),
566                         FLASH_INTERVAL, flashCallback, this);
567         _last_state = state;
568     }
569     else {
570         XUnmapWindow( XtDisplay(_w), _flash_iwin );
571         XUnmapWindow( XtDisplay(_w), _flash_owin );
572         normalCursor();
573         busy_cursor = 0;
574     }
575 }
576
577 Boolean
578 MainWindow::isIconified()
579 {
580  
581     Atom        wmStateAtom, actualType;
582     int         actualFormat;
583     unsigned long nitems, leftover;
584     WM_STATE *wmState;
585     Boolean retval = FALSE;
586  
587     assert ( _w != NULL );
588
589     /*  Getting the WM_STATE property to see if iconified or not */
590     wmStateAtom = XInternAtom(XtDisplay(_w), "WM_STATE", False);
591  
592     XGetWindowProperty (XtDisplay(_w), XtWindow(_w), 
593                         wmStateAtom, 0L,
594                         (long)BUFSIZ, False, wmStateAtom, &actualType,
595                         &actualFormat, &nitems, &leftover,
596                         (unsigned char **) &wmState);
597
598
599     if (wmState && wmState->state == IconicState)
600       retval = TRUE;
601     
602     free((void*) wmState);
603     return retval;
604 }
605
606 /************************************************************************
607  * MbStrchr -
608  ************************************************************************/
609 char *
610 MainWindow::MbStrchr(char *str, int ch)
611 {
612     size_t mbCurMax = MB_CUR_MAX;
613     wchar_t targetChar, curChar;
614     char tmpChar;
615     int i, numBytes, byteLen;
616
617     if(mbCurMax <= 1) return strchr(str, ch);
618
619     tmpChar = (char)ch;
620     mbtowc(&targetChar, &tmpChar, mbCurMax);
621     for(i = 0, numBytes = 0, byteLen = strlen(str); i < byteLen; i += numBytes)
622     {
623         numBytes = mbtowc(&curChar, &str[i], mbCurMax);
624         if(curChar == targetChar) return &str[i];
625     }
626     return (char *)NULL;
627 }
628
629 void
630 MainWindow::setWorkspacesOccupied(char *workspaces)
631 {
632     char        *ptr;
633     Atom        *workspace_atoms = NULL;
634     int         nworkspaces=0;
635
636     if (workspaces)
637     {
638         do
639         {
640             ptr = MbStrchr (workspaces, ' ');
641
642             if (ptr != NULL) *ptr = '\0';
643
644             workspace_atoms = (Atom*) XtRealloc(
645                                                 (char *) workspace_atoms,
646                                                 sizeof(Atom)*(nworkspaces+1));
647             workspace_atoms[nworkspaces] = XmInternAtom(
648                                                 XtDisplay(_w),
649                                                 workspaces, True);
650             nworkspaces++;
651
652             if (ptr != NULL)
653             {
654                 *ptr = ' ';
655                 workspaces = ptr + 1;
656             }
657         } while (ptr != NULL);
658
659         DtWsmSetWorkspacesOccupied(
660                                 XtDisplay(_w), XtWindow (_w), 
661                                 workspace_atoms, nworkspaces);
662
663         XtFree ((char *) workspace_atoms);
664         workspace_atoms = NULL;
665     }
666     else
667     {
668         Window  rootWindow;
669         Atom    pCurrent;
670         Screen  *currentScreen;
671         int     screen;
672
673         screen = XDefaultScreen(XtDisplay(_w));
674         currentScreen = XScreenOfDisplay(XtDisplay(_w), screen);
675         rootWindow = RootWindowOfScreen(currentScreen);
676
677         if (DtWsmGetCurrentWorkspace(
678                                 XtDisplay(_w),
679                                 rootWindow,
680                                 &pCurrent) == Success)
681           DtWsmSetWorkspacesOccupied(
682                                 XtDisplay(_w),
683                                 XtWindow(_w), 
684                                 &pCurrent, 1);
685     }
686 }