Remove Unixware and openserver support
[oweals/cde.git] / cde / programs / dtmail / MotifApp / Application.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 libraries 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: Application.C /main/15 1998/10/01 12:10:26 mgreess $ */
24 /*
25  *+SNOTICE
26  *
27  *      RESTRICTED CONFIDENTIAL INFORMATION:
28  *      
29  *      The information in this document is subject to special
30  *      restrictions in a confidential disclosure agreement bertween
31  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
32  *      document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
33  *      Sun's specific written approval.  This documment and all copies
34  *      and derivative works thereof must be returned or destroyed at
35  *      Sun's request.
36  *
37  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
38  *
39  *+ENOTICE
40  */
41 ///////////////////////////////////////////////////////////////////////////////
42 //////////////////////////////////////////////////////////////////////////////
43 //         This example code is from the book:
44 //
45 //           Object-Oriented Programming with C++ and OSF/Motif
46 //         by
47 //           Douglas Young
48 //           Prentice Hall, 1992
49 //           ISBN 0-13-630252-1 
50 //
51 //         Copyright 1991 by Prentice Hall
52 //         All Rights Reserved
53 //
54 //  Permission to use, copy, modify, and distribute this software for 
55 //  any purpose except publication and without fee is hereby granted, provided 
56 //  that the above copyright notice appear in all copies of the software.
57 ///////////////////////////////////////////////////////////////////////////////
58 //////////////////////////////////////////////////////////////////////////////
59
60
61 ////////////////////////////////////////////////////////////
62 // Application.C: 
63 ////////////////////////////////////////////////////////////
64 #include "Application.h"
65 #include "MainWindow.h"
66 #include <X11/StringDefs.h>
67 #include <X11/Shell.h>
68 #include <assert.h>
69 #include <stdlib.h>
70 #include <sys/types.h>
71 #include <time.h>
72 #include <unistd.h>
73 #include <nl_types.h>
74 #include <string.h>
75
76 #include "EUSDebug.hh"
77
78
79 XtResource
80 Application::_appResources[] = {
81   {
82     "workspaceList", "WorkspaceList", XtRString, sizeof(XtRString),
83     XtOffset(Application *, _appWorkspaceList), XtRString, (XtPointer) NULL
84   }
85 };
86
87 // XPG3 compatible. NL_CAT_LOCALE is set to 1 (non-zero) in XPG4. Use NL_CAT_LOCALE
88 // for all catopen() calls. This is also defined in include/DtMail/Common.h for dtmail
89 // and libDtMail catopen calls, if later on we have a common include file for
90 // dtmail, libDtMail and MotifApp, we can move this define over there.
91
92 #if defined(sun) && (_XOPEN_VERSION == 3)
93 #undef NL_CAT_LOCALE
94 #define NL_CAT_LOCALE 0
95
96 // If NL_CAT_LOCALE is not defined in other platforms, set it to 0
97 #elif !defined(NL_CAT_LOCALE)   
98 #define NL_CAT_LOCALE 0
99 #endif
100
101 #ifdef hpV4
102 /*
103  * Wrapper around catgets -- this makes sure the message string is saved
104  * in a safe location; so repeated calls to catgets() do not overwrite
105  * the catgets() internal buffer.  This has been a problem on HP systems.
106  */
107 char *catgets_cache2(nl_catd catd, int set, int num, char *dflt)
108 {
109
110 #define MSGS_PER_SET_MAX        12
111 #define NUM_SETS_MAX            2
112
113   /* array to hold messages from catalog */
114   static  char *MsgCat[NUM_SETS_MAX][MSGS_PER_SET_MAX];
115   
116   /* convert to a zero based index */
117   int setIdx = set - 1;
118   int numIdx = num - 1;
119   
120   if ( ! MsgCat[setIdx][numIdx] ) {
121     MsgCat[setIdx][numIdx] = strdup( catgets(catd, set, num, dflt));
122   }
123   
124   return MsgCat[setIdx][numIdx];
125 }
126
127 #endif
128
129 Application *theApplication = NULL;
130
131 nl_catd catd = (nl_catd) -1;    // catgets file descriptor
132
133 extern String ApplicationFallbacks[];
134
135 Application::Application ( char *appClassName ) : 
136                     UIComponent ( appClassName )
137 {
138     // Set the global Application pointer
139     DebugPrintf(2, "Application::Application(%p \"%s\")\n", appClassName, appClassName);
140     
141     theApplication = this;  
142     
143     // Initialize data members
144     
145     _display    = NULL;
146     _appContext = NULL;
147     _bMenuButton = 0;
148     _windows    = NULL;
149     _numWindows = 0;
150     _shutdownEnabled = 1;
151     _applicationClass = strdup ( appClassName );
152     _appWorkspaceList = NULL;
153     _lastInteractiveEventTime = 0;
154     _originalEgid = 0;
155     _originalRgid = 0;
156 }
157
158 void Application::initialize ( int *argcp, char **argv )
159 {
160     DebugPrintf(2, "Application::initialize(%p %d, %p)\n", argcp, *argcp, argv);
161
162     DebugPrintf(3, "Application::initialize - Initializing privileges.\n");
163
164     // The Solaris sendmail operates differently than the HP/IBM sendmail. 
165     // sendmail on Solaris runs as 'root' and so has access permissions 
166     // to any file on the system. sendmail on HP/IBM runs as set-group-id 
167     // 'mail' and so requires that all mailboxes that it may deliver e-mail 
168     // to be writable either by being group mail group writable, or by being 
169     // writable by the world. On those platforms, then, dtmail is required 
170     // to always run with set-group-id mail otherwise, when mailboxes are 
171     // saved, they will loose their group ownership and sendmail will no 
172     // onger be able to deliver to those mailboxes.
173
174     // we have to be set-gid to group "mail" when opening and storing
175     // folders.  But we don't want to do everything as group mail.
176     // here we record our original gid, and set the effective gid
177     // back the the real gid.  We'll set it back when we're dealing
178     // with folders...
179     //
180     _originalEgid = getegid();  // remember effective group ID
181     _originalRgid = getgid();   // remember real group ID
182     disableGroupPrivileges();   // disable group privileges from here on
183
184     DebugPrintf(3, "Application::initialize - Initializing Xt.\n");
185
186     _w = XtOpenApplication (
187                         &_appContext, 
188                         _applicationClass, 
189                         (XrmOptionDescList) NULL, 0, 
190                         argcp, argv, ApplicationFallbacks,
191                         sessionShellWidgetClass, (ArgList) NULL, 0 );
192     
193     // Extract and save a pointer to the X display structure
194     DebugPrintf(3, "Application::initialize - Extracting display.\n");
195     _display = XtDisplay ( _w );
196
197     // Set virtual BMenu mouse binding
198     int numButtons = XGetPointerMapping(_display, (unsigned char *)NULL, 0);
199     _bMenuButton = (numButtons < 3) ? Button2 : Button3;
200     
201     // The Application class is less likely to need to handle
202     // "surprise" widget destruction than other classes, but
203     // we might as well install a callback to be safe and consistent
204     DebugPrintf(3, "Application::initialize - Installing destroy handler.\n");
205     installDestroyHandler();
206     
207     // Center the shell, and make sure it isn't visible
208     DebugPrintf(3, "Application::initialize - Setting window size.\n");
209     XtVaSetValues ( _w,
210                    XmNmappedWhenManaged, FALSE,
211                    XmNx, DisplayWidth ( _display, 0 ) / 2,
212                    XmNy, DisplayHeight ( _display, 0 ) / 2,
213                    XmNwidth,  1,
214                    XmNheight, 1,
215                    NULL );
216     
217     // The instance name of this object was set in the UIComponent 
218     // constructor, before the name of the program was available
219     // Free the old name and reset it to argv[0]
220     DebugPrintf(3, "Application::initialize - Deleting name %p\n", _name);
221     free(_name);
222     _name = strdup ( argv[0] );
223
224     // Force the shell window to exist so dialogs popped up from
225     // this shell behave correctly
226     DebugPrintf(3, "Application::initialize - Realizing shell window.\n");
227     XtRealizeWidget ( _w );
228     
229     getResources(_appResources, XtNumber(_appResources));
230
231     // Initialize and manage any windows registered
232     // with this application.
233     
234     for ( int i = 0; i < _numWindows; i++ )
235     {
236         DebugPrintf(3, "Application::initialize - Initializing windows[%d]\n", i);
237         _windows[i]->initialize();
238         DebugPrintf(3, "Application::initialize - Managing windows[%d]\n", i);
239         _windows[i]->manage();
240     }
241 }
242
243 // Calling _exit() now to work around a problem with threads
244 // deadlocking if exit() is called.
245 // Need to fix the threads deadlocking bug and then replace
246 // _exit() with exit().
247
248 Application::~Application()
249 {
250     //
251     // Allocated using strdup, so free using free.
252     //
253     free((void*) _applicationClass);
254     delete []_windows;
255
256 #ifdef CDExc21492
257   #if defined(__hpux)
258     this->BasicComponent::~BasicComponent();
259   #elif  __osf__
260     BasicComponent * The_End = this;
261     The_End->BasicComponent::~BasicComponent();
262   #else
263     BasicComponent::~BasicComponent();
264   #endif
265 #endif
266
267     catclose(catd);
268
269     // In an MT environment, calling exit() causes threads to
270     // hang and a deadlock results.
271     // Call _exit() instead
272
273     _exit(0);
274 }
275
276 // ApplicationExtractEventTime - extract the time the
277 // current event happened if it is one we are interested
278 // in - this is used to delay actions that can lock the application
279 // while the user is being interactive with the application
280 //
281
282 inline void Application::extractAndRememberEventTime(XEvent *event)
283 {
284   switch (((XAnyEvent *)event)->type)
285     {
286     case KeyPress:      // press any key on the keyboard
287     case ButtonPress:   // press any botton on the screen
288     case MotionNotify:  // motion events
289       _lastInteractiveEventTime = time((time_t *)0);
290       break;
291     }
292 }
293
294 void Application::handleEvents()
295 {
296     // Just loop forever
297 #if 0    
298     XtAppMainLoop ( _appContext );
299 #else
300     XEvent      event;
301
302     _lastInteractiveEventTime = time((time_t *)0);
303     
304     for (;;) {
305       XtAppNextEvent( _appContext, &event );
306       extractAndRememberEventTime( &event );
307       XtDispatchEvent( &event );
308     }
309 #endif
310 }
311
312 void Application::registerWindow ( MainWindow *window )
313 {
314     int i;
315     MainWindow **newList;
316     
317     // Allocate a new list large enough to hold the new
318     // object, and copy the contents of the current list 
319     // to the new list
320     
321     newList = new MainWindow*[_numWindows + 1];
322     
323     for ( i = 0; i < _numWindows; i++ )
324         newList[i] = _windows[i];
325     
326     // Install the new list and add the window to the list
327     
328     if (_numWindows > 0) delete []_windows;
329     _windows =  newList;
330     _windows[_numWindows] = window;
331     
332     _numWindows++;
333 }
334
335 void Application::unregisterWindow ( MainWindow *window )
336 {
337     int i, index;
338     
339     // If this is the last window bye bye.
340
341     if (isEnabledShutdown() && _numWindows == 1)
342     {
343         _numWindows--;
344
345         // Call derived class's shutdown method.
346         shutdown();
347         return;
348     }
349
350     // Copy all objects, except the one to be removed, to a new list
351
352     MainWindow **newList = new MainWindow*[_numWindows - 1];
353     
354     for (i=0, index=0; i<_numWindows; i++)
355       if (_windows[i] != window)
356         newList[index++] = _windows[i];
357     
358     delete []_windows;
359     _windows = newList;
360     _numWindows--;
361 }
362
363 void Application::manage()
364 {
365     // Manage all application windows. This will pop up
366     // iconified windows as well.
367     
368     for ( int i = 0; i < _numWindows; i++ )
369         _windows[i]->manage();
370 }
371
372 void Application::unmanage()
373 {
374     // Unmanage all application windows
375     
376     for ( int i = 0; i < _numWindows; i++ )
377         _windows[i]->unmanage();
378 }
379
380 void Application::iconify()
381 {
382     // Iconify all top-level windows.
383     
384     for ( int i = 0; i < _numWindows; i++ )
385         _windows[i]->iconify();
386 }
387
388
389 void
390 Application::open_catalog()
391 {
392     // open message catalog file
393     catd = catopen("MotifApp", NL_CAT_LOCALE);
394 }
395
396 void
397 Application::setAppWorkspaceList(char *workspaceList)
398 {
399     // open message catalog file
400     if (NULL != _appWorkspaceList)
401       free(_appWorkspaceList);
402
403     _appWorkspaceList = strdup(workspaceList);
404 }