camelot.cpp

Go to the documentation of this file.
00001 // $Id: camelot.cpp 1771 2007-06-17 20:14:43Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 /***************************************************************************************************************************/
00099 //
00100 // camelot.cpp - main application class derived from wxApp
00101 //
00102 /***************************************************************************************************************************/
00103 
00104 #include "camtypes.h"
00105 
00106 #include "camdoc.h"
00107 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "camview.h"
00109 #include "camframe.h"
00110 //#include "Res/UKEnglish/stringtbl.h"
00111 #include "kernel.h"
00112 #include "grndrgn.h"
00113 #include "oilmenus.h"
00114 
00115 #if !defined(__WXMSW__)
00116 #include "gdraw.h"
00117 #endif
00118 
00119 #include "cversion.h"
00120 #include "camelot.h"
00121 #include "camdoctp.h"
00122 
00123 #include "keypress.h"
00124 #include "ccdc.h"
00125 #include "camprofile.h"
00126 #include "dlgevt.h"
00127 #include "cartprov.h"
00128 #include "ctrllist.h"
00129 #include "cartctl.h"
00130 #include "xmlutils.h"
00131 #include "camplatform.h"
00132 #include "filedlgs.h"
00133 #include "progress.h"
00134 #include "prdlgctl.h"
00135 #include "prncamvw.h"
00136 #include "gbrush.h"
00137 #include "selmedia.h"
00138 #include "filedlgs.h"
00139 #include "rendwnd.h"
00140 
00141 #include "camprocess.h"
00142 
00143 //
00144 // Define FILELIST for recent file list on file menu.
00145 // Note that this currently seems to be rather unreliable.
00146 //
00147 //#if defined(_DEBUG)
00148 //#define FILELIST
00149 //#endif
00150 
00151 //
00152 // Define XARA_MENUGEN to use Xtreme style menu creation.
00153 // Note that this currently doesn't have full functionality
00154 // but it's getting there
00155 //#if defined(_DEBUG)
00156 #define XARA_MENUGEN
00157 //#endif
00158 
00159 BOOL CCamApp::InInitOrDeInit = TRUE;
00160 IMPLEMENT_DYNAMIC_CLASS( wxWindowDeletionWatcher, wxObject);
00161 WindowToWindowDeletionWatcher * wxWindowDeletionWatcher::s_UndeletedWindowHash = NULL;
00162 
00163 /********************************************************************************************
00164 
00165     Preference: MainWndMax
00166     Section:    Windows
00167     Range:      0 (FALSE) or 1 (TRUE)
00168     Purpose:    If non-zero then main window defaults to maximized, else normal position.
00169                 This default will be overridden if the user explicitly asked for a mode
00170                 when starting the app (e.g. minimized). If the user exits while maximized,
00171                 the flag will be set ready for next time.
00172 
00173 ********************************************************************************************/
00174 BOOL CCamApp::MainWndMaximized = FALSE;
00175 
00176 
00177 /********************************************************************************************
00178 
00179     Preference: MainWndMin
00180     Section:    Windows
00181     Range:      0 (FALSE) or 1 (TRUE)
00182     Purpose:    If non-zero then main window defaults to minimized, else normal position.
00183                 This default will be overridden if the user explicitly asked for a mode
00184                 when starting the app (e.g. minimized). If the user exits while minimized,
00185                 the flag will be set ready for next time.
00186 
00187 ********************************************************************************************/
00188 BOOL CCamApp::MainWndMinimized = FALSE;
00189 
00190 
00191 /********************************************************************************************
00192 
00193     Preference: MainWndPos
00194     Section:    Windows
00195     Range:      Six numbers, separated with spaces, which are x y w h sx sy
00196     Purpose:    Remembers users last 'normal' window position for them. Also remembers the
00197                 screen size so can be scaled if next time runs in different screen mode.
00198 
00199 ********************************************************************************************/
00200 String_256 CCamApp::MainWndPosString;
00201 
00202 
00203 /********************************************************************************************
00204 
00205     Preference: FirstRun
00206     Section:    Preferences
00207     Range:      0 (FALSE) or 1 (TRUE)
00208     Purpose:    If 1 then this is the first time this application has been run with
00209                 this set of preferences
00210                 If 0 then it has been run before
00211 
00212 ********************************************************************************************/
00213 BOOL CCamApp::bFirstRun = TRUE;
00214 
00215 
00216 /***************************************************************************************************************************/
00217 //
00218 // Timer used for background redraw.
00219 // For now we have gone back to using the idle system for redraw as it does seem to work
00220 // The background redraw may be changed to use a timer or some other method
00221 //
00222 
00223 #define CAM_TIMER_ID         42
00224 #define CAM_TIMER_FREQUENCY 100
00225 
00226 /***************************************************************************************************************************/
00227 
00228 IMPLEMENT_APP( CCamApp )
00229 BEGIN_EVENT_TABLE( CCamApp, wxApp )
00230     EVT_IDLE( CCamApp::OnIdle )
00231 //  EVT_TIMER( CAM_TIMER_ID, CCamApp::OnTimer )
00232 END_EVENT_TABLE()
00233 
00234 DialogManager           CCamApp::m_DlgMgr;
00235 bool                    CCamApp::s_bIsDisabled = false; // Initially system is not disabled.
00236 wxString                CCamApp::m_strResourcePath;
00237 String_256              CCamApp::m_strResourceDirPath;
00238 String_256              CCamApp::m_strResourceDirPathOverride;
00239 String_256              CCamApp::m_strMediaApplication;
00240 
00241 /***************************************************************************************************************************/
00242 
00243 CCamApp::CCamApp()
00244 {
00245 }
00246 
00247 /*********************************************************************************************
00248 >   int TYPENOTE: Correct CCamApp::FilterEvent( wxEvent& event )
00249 
00250     Author:     Luke_Hart (Xara Group Ltd) <LukeH@xara.com>
00251     Created:    09/05/06
00252     Inputs:     A reference to the event to filter
00253     Outputs:    -
00254     Returns:    -
00255     Purpose:    This function is used to collect the key press information for handling by
00256                 applictaion. It passes event unmolested for controls that are allowed focus and
00257                 controls within modal dialogs. It also has code to make sure that key events
00258                 that are passed on aren't checked again, based on the event timestamp. All other 
00259                 keys are passed into application keypress handling code.
00260     Errors:     -
00261     Scope:      Protected
00262     SeeAlso:    The focus handling document
00263 
00264 **********************************************************************************************/ 
00265 
00266 int /*TYPENOTE: Correct*/ CCamApp::FilterEvent( wxEvent& event )
00267 {
00268     static /*TYPENOTE: Correct*/ long   lLastTimeStamp = 0;
00269 
00270     wxObject* pEventObject = event.GetEventObject();
00271 
00272     if (( event.GetEventType() == wxEVT_DESTROY ) && pEventObject->IsKindOf(CLASSINFO(wxWindow)))
00273     {
00274         // Register window destruction
00275         wxWindowDeletionWatcher::RegisterWindowDeletion((wxWindow *)pEventObject);
00276     }
00277 
00278     if (PrintMonitor::IsPrintingNow())
00279     {
00280         // Disable processing of paint messages for various controls which may use GDraw or GBrush to paint, as this
00281         // appears to upset printing
00282         if (event.IsKindOf(CLASSINFO(wxPaintEvent)))
00283         {
00284             if (!pEventObject->IsKindOf(CLASSINFO(wxCamArtControl)))
00285             {   
00286                 // TRACEUSER("amb", _T("CCamApp::FilterEvent caught paint for %s"), pEventObject->GetClassInfo()->GetClassName());
00287                 return false;
00288             }
00289         }
00290     }
00291 
00292     if( event.GetEventType() == wxEVT_ACTIVATE )
00293     {
00294         TRACEUSER("luke", _T("CCamApp::FilterEvent activate to %s"), pEventObject->GetClassInfo()->GetClassName());
00295 
00296         if( pEventObject->IsKindOf( CLASSINFO(wxAuiFloatingFrame) ) )
00297         {
00298             wxClassInfo* pClassInfo = pEventObject->GetClassInfo();
00299             while( NULL != pClassInfo )
00300             {
00301                 TRACEUSER( "luke", _T("Class = %s"), (PCTSTR)pClassInfo->GetClassName() );
00302 
00303                 const wxChar* pszBaseClass = pClassInfo->GetBaseClassName1();
00304                 pClassInfo = NULL == pszBaseClass ? NULL : wxClassInfo::FindClass( pszBaseClass );
00305             }
00306             TRACEUSER( "luke", _T("Parent = %x, %x"), ((wxWindow*)pEventObject)->GetParent(), m_pMainFrame );
00307             TRACEUSER( "luke", _T("Active = %x"), ((wxTopLevelWindow*)pEventObject)->IsActive() );
00308 
00309             GiveActiveCanvasFocus();
00310             return 1;               // Don't let the recipent know it was activated
00311         } 
00312     }
00313 
00314 // useful code to see where focus events originate from. Set a breakpoint below and look
00315 // at the call stack
00316     if ( event.GetEventType() == wxEVT_SET_FOCUS )
00317     {
00318         TRACEUSER("luke", _T("CCamApp::FilterEvent focus to %s"), pEventObject->GetClassInfo()->GetClassName());
00319 /*      if (pEventObject->IsKindOf(CLASSINFO(CRenderWnd)))
00320         {
00321             INT32 i=1;
00322         } */
00323     }
00324 
00325     if ( event.GetEventType() == wxEVT_KILL_FOCUS )
00326     {
00327 #if defined(_DEBUG)
00328         wxFocusEvent&   FocusEvent = (wxFocusEvent&)event;
00329         TRACEUSER( "luke", _T("CCamApp::FilterEvent kill focus to %016x from 0x%016x"), FocusEvent.GetWindow(), 
00330                 FocusEvent.GetEventObject() );
00331 #endif
00332 
00333         // Any loss of focus could well a good time to kill cursor
00334         wxSetCursor( *wxSTANDARD_CURSOR );
00335     }
00336 
00337     if (( event.GetEventType() == wxEVT_CREATE )
00338         && pEventObject
00339         && (pEventObject->IsKindOf(CLASSINFO(wxTopLevelWindow)))
00340         && !(pEventObject->IsKindOf(CLASSINFO(wxAdvSplashScreen))) // Don't trigger this on the creation of the splash screen itself
00341         && !(pEventObject->IsKindOf(CLASSINFO(wxSplashScreen)))
00342         )
00343     {
00344         // a top level window is about to be created. End the splash screen if it is up as it may obscure it
00345         CamResource::DoneInit(FALSE);   
00346     }
00347 
00348 #if defined(_DEBUG)
00349     if( event.GetEventType() == wxEVT_CHAR )
00350     {
00351         if (pEventObject)
00352         {
00353             TRACEUSER( "jlh92", _T("KeyEvent 4 %s CH\n"),
00354                 ((wxWindow*)pEventObject)->GetClassInfo()->GetClassName() );
00355         }
00356     }
00357 #endif
00358 
00359     if( event.GetEventType() == wxEVT_KEY_DOWN ||
00360         event.GetEventType() == wxEVT_KEY_UP )
00361     {
00362         // Use timestamp to detect events which are passing
00363         // down the chain (which we've tested)
00364         if( lLastTimeStamp == event.GetTimestamp() )
00365             return -1;
00366         lLastTimeStamp = event.GetTimestamp();
00367 
00368         TRACEUSER( "jlh92", _T("KeyEvent 4 %s %s\n"),
00369             ((wxWindow*)pEventObject)->GetClassInfo()->GetClassName(),
00370             event.GetEventType() == wxEVT_KEY_DOWN ? _T("KD") : _T("KU") );
00371         
00372         // Is the object allowed to recieve keys? We have to go done the object hierarchy
00373         // since some control (notably Combos) will produce temporary windows which can get
00374         // key events.
00375         wxWindow* pScanObj = (wxWindow*)pEventObject;
00376         while( NULL != pScanObj )
00377         {
00378             wxClassInfo* pClassInfo = pScanObj->GetClassInfo();
00379 #if defined(DEBUG_KEYPRESS_SPEW)
00380             {
00381                 wxClassInfo *pTmpInfo = pClassInfo;
00382                 while( NULL != pTmpInfo )
00383                 {
00384                     TRACEUSER( "jlh92", _T("Class %s\n"), PCTSTR(pTmpInfo->GetClassName()) );
00385         
00386                     PCTSTR  pszName = pTmpInfo->GetBaseClassName1();
00387                     pTmpInfo = NULL == pszName ? NULL : wxClassInfo::FindClass( pszName );
00388                 }
00389                 TRACEUSER( "jlh92", _T("----------------------\n") );
00390             }
00391 #endif
00392             TRACEUSER("amb", _T("CCamApp::FilterEvent key for %s"), pClassInfo->GetClassName());
00393 
00394             if( pClassInfo->IsKindOf( CLASSINFO(wxTextCtrl) ) ||
00395                 pClassInfo->IsKindOf( CLASSINFO(wxComboBox) ) ||
00396                 pClassInfo->IsKindOf( CLASSINFO(wxSliderCombo) ) ||
00397                 pClassInfo->IsKindOf( CLASSINFO(wxOwnerDrawnComboBox) ) ||
00398                 pClassInfo->IsKindOf( CLASSINFO(wxComboCtrl) )
00399                 )
00400             {
00401                 TRACEUSER("amb", _T("CCamApp::FilterEvent gets keys as special"));
00402                 TRACEUSER( "jlh92", _T("Control gets keys") );
00403                 // Yes, pass on as usual
00404                 return -1;
00405             }
00406 
00407             pScanObj = pScanObj->GetParent();
00408         }
00409 
00410         // Scan down ancestors looking for either wxPanels (always non-modal) and
00411         // wxDailogs (can be modal, so we check)
00412         wxWindow *pWnd = (wxWindow*)pEventObject;
00413         while( NULL != pWnd && !pWnd->IsKindOf( CLASSINFO(wxPanel) ) )
00414         {
00415             // Dialogs may-be modal so check
00416             if( pWnd->IsKindOf( CLASSINFO(wxDialog) ) )
00417             {
00418                 // Pass event down chain if modal
00419                 if( ((wxDialog*)pWnd)->IsModal() )
00420                 {
00421                     TRACEUSER( "jlh92", _T("Modal dialog\n") );
00422                     TRACEUSER("amb", _T("CCamApp::FilterEvent gets keys as modal"));
00423                     return -1;
00424                 }
00425 
00426                 // Non-modal dialog so do focus handling
00427                 break;
00428             }
00429 
00430             pWnd = pWnd->GetParent();
00431         }
00432 
00433         TRACEUSER("amb", _T("CCamApp::FilterEvent handle"));
00434         TRACEUSER( "jlh92", _T("Handled!\n") );
00435 
00436         // Do our best to see if the object is deleted.
00437         wxWindowDeletionWatcher * wd = NULL;
00438         if (pEventObject->IsKindOf(CLASSINFO(wxWindow)))
00439         {
00440             wd = new wxWindowDeletionWatcher((wxWindow*)pEventObject);
00441             if (!wd)
00442                 return -1;
00443         }
00444 
00445         // Process keyboard messages (and mark event as handled)
00446         if( HandleKeyPress( (wxKeyEvent&)event ) )
00447         {
00448             BOOL deleted = wd && wd->HasBeenDeleted();
00449             if (wd)
00450                 delete wd;
00451             if (deleted)
00452                 return 1; // event handled. Do NOT anything else here as the object may by now
00453                         // have been deleted (e.g. FileClose hotkey).
00454             else
00455                 return -1;
00456         }
00457         if (wd)
00458             delete wd;
00459     }
00460     
00461     return -1;
00462 }
00463 
00464 static bool GiveFocusToFocusableOffspring( wxWindow* pWnd )
00465 {
00466     TRACEUSER( "jlh92", _T("GF2FO class %s\n"), pWnd->GetClassInfo()->GetClassName() );
00467 
00468     // Can we give focus to passed window. Yes, give focus
00469     // and return happy
00470     if( pWnd->AcceptsFocus() )
00471     {
00472         TRACEUSER( "jlh92", _T("Focused!\n") );
00473         pWnd->SetFocus();
00474         return true;
00475     }
00476 
00477     // No, lets try the children then
00478     wxWindowList&       lstChild = pWnd->GetChildren();
00479     wxWindowListNode*   pNode = lstChild.GetFirst();
00480     while( NULL != pNode )
00481     {
00482         if( GiveFocusToFocusableOffspring( pNode->GetData() ) )
00483             return true;
00484 
00485         pNode = pNode->GetNext();
00486     }
00487     
00488     return false;
00489 }
00490 
00491 
00492 /***************************************************************************************************************************/
00493 //
00494 // Initialisation.
00495 //
00496 
00497 const wxString camIPC_START = _T("StartOther");
00498 
00499 class CamIPCConnection : public wxConnection
00500 {
00501 
00502 public:
00503     CamIPCConnection() : wxConnection(m_pBuffer, WXSIZEOF(m_pBuffer)) {}
00504 
00505     virtual bool OnExecute (const wxString& WXUNUSED(topic),
00506                             wxChar *data,
00507                             int /* TYPENOTE: Correct */ size,
00508                             wxIPCFormat WXUNUSED(format))
00509     {
00510         // argv buffer
00511         INT32 argc = 0;
00512 
00513         INT32 i;
00514         for (i=0; i<size; i++)
00515         {
00516             // exit if this is a NULL, and the last character was a NULL
00517             if (!data[i] && i && !data[i-1])
00518                 break;
00519 
00520             if (!data[i])
00521                 argc++;
00522         }
00523 
00524         wxChar ** argv = new wxChar*[argc];
00525 
00526         wxChar* p = data;
00527         for (i=0; i<argc; i++)
00528         {
00529             argv[i] = camStrdup(p);
00530             p+=wxStrlen(argv[i])+1; // move past null
00531         }
00532 
00533         BOOL result = wxGetApp().OnSecondInstance(argv, argc);
00534 
00535         // free memory
00536         for (i=0; i<argc; i++)
00537         {
00538             free(argv[i]);
00539         }
00540         delete [] argv;
00541 
00542         // return
00543         return result;
00544     }
00545 
00546 private:
00547     wxChar m_pBuffer[4096];
00548 
00549 };
00550 
00551 class CamIPCServer : public wxServer
00552 {
00553 public:
00554     virtual wxConnectionBase *OnAcceptConnection (const wxString& topic)
00555     {
00556         if (topic != camIPC_START)
00557             return NULL;
00558         else
00559             return new CamIPCConnection;
00560     }
00561 };
00562 
00563 // Global so we can use it for parsing second instance
00564 static const wxCmdLineEntryDesc cmdLineDesc[] =
00565 {
00566 #if defined(_DEBUG)
00567     { wxCMD_LINE_OPTION, _T("u"), _T("user"), _T("set username for debug tracing") },
00568     { wxCMD_LINE_SWITCH, _T("m"), _T("memorycheck"), _T("check memory") },
00569     { wxCMD_LINE_OPTION, _T("l"), _T("listdebug"), _T("list debug level") , wxCMD_LINE_VAL_NUMBER },
00570 #endif
00571     { wxCMD_LINE_SWITCH, _T("h"), _T("help"),   _T("Display this help"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
00572     { wxCMD_LINE_SWITCH, _T("v"), _T("version"),    _T("Display the version information") },
00573     { wxCMD_LINE_OPTION, _T("r"), _T("resource"),   _T("resource directory") },
00574     { wxCMD_LINE_SWITCH, _T("x"), _T("xrccheckgen"), _T("generate xrc.check file") },
00575     { wxCMD_LINE_PARAM, NULL, NULL, _T("input file"), wxCMD_LINE_VAL_STRING, 
00576                                         wxCMD_LINE_PARAM_OPTIONAL|wxCMD_LINE_PARAM_MULTIPLE },
00577     { wxCMD_LINE_NONE }
00578 };
00579 
00580 BOOL CCamApp::OnSecondInstance(wxChar** argv, INT32 argc)
00581 {
00582     // Parse command line. We do this early so we get flags which
00583     // are useful for init, such as -u
00584     //
00585     wxCmdLineParser parser(argc,argv);
00586     parser.SetDesc(cmdLineDesc);
00587     if (parser.Parse()) // Handles help automatically
00588     {
00589         return FALSE;
00590     }
00591     if (parser.GetParamCount()>=1)
00592     {
00593         for ( UINT32 i=0 ; i<parser.GetParamCount() ; i++ )
00594             m_docManager->CreateDocument(parser.GetParam(i),wxDOC_SILENT);
00595     }
00596     m_pMainFrame->Raise();
00597     return TRUE;
00598 }
00599 
00600 bool CCamApp::OnInit()
00601 {
00602     InInitOrDeInit = TRUE; // Don't allow the user to try carrying on working
00603     ::wxHandleFatalExceptions(TRUE);
00604 
00605     //
00606     // Parse command line. We do this early so we get flags which
00607     // are useful for init, such as -u
00608     //
00609     wxCmdLineParser parser(argc,argv);
00610     parser.SetDesc(cmdLineDesc);
00611     if (parser.Parse()) // Handles help automatically
00612     {
00613         return FALSE;
00614     }
00615 
00616     wxString ResourceDir = _T("");
00617     if (parser.Found(_T("r"), &ResourceDir))
00618     {
00619         if (!ResourceDir.IsEmpty())
00620         {
00621             CamResource::SetResourceFilePath(ResourceDir);
00622         }
00623 
00624         if ( parser.Found( _T("x") ) )
00625         {
00626             CamResource::SetGenerateXRCCheck(TRUE);
00627         }
00628     }
00629 
00630     if( parser.Found( _T("v") ) )
00631     {
00632         wxString            strMessage;
00633 
00634 #if defined(__WXMSW__)
00635         strMessage = wxString::Format( wxT("Xara Xtreme\nVersion: %s\nCDraw Version: %d.%03d\n"), 
00636             g_pszAppVersion, HIWORD(GDraw_GetVersion()), LOWORD(GDraw_GetVersion()) );
00637 #else
00638 #if FALSE == wxUSE_UNICODE
00639         TCHAR*          pszCDrawVer = GDraw_GetSvnVersion();
00640 #else
00641         TCHAR           pszCDrawVer[32];
00642         camMbstowcs( pszCDrawVer, GDraw_GetSvnVersion(), 31 );
00643 #endif
00644         strMessage = wxString::Format( wxT("Xara Xtreme\nVersion: %s (%s)\nCDraw Version: %d.%03d (%s)\nBuild date: %s\n"), 
00645             g_pszAppVersion, g_pszSvnVersion, HIWORD(GDraw_GetVersion()), LOWORD(GDraw_GetVersion()), pszCDrawVer, CAMELOT_BUILD_DATE );
00646 #endif
00647 
00648         camPrintf( strMessage.c_str() );
00649         
00650         return FALSE;
00651     }
00652     
00653 #if defined(_DEBUG)
00654     if (parser.Found(_T("m"))) SimpleCCObject::CheckMemoryFlag=1;
00655 
00656     long listlevel; // TYPENOTE: Correct - wxWidgets doesn't know about INT32 etc.
00657     if (parser.Found(_T("l"), &listlevel))
00658     {
00659         List::ListDebugLevel = listlevel;
00660     }
00661 
00662     // Set up the username for tracing
00663     // We should default this to the environment setting for (say) LOGNAME
00664     wxString Username = _T("");
00665 
00666     // Overwrite with LOGNAME if it is set
00667     wxGetEnv(_T("LOGNAME"), &Username);
00668 
00669     // Overwrite with -u option if it is set
00670     parser.Found(_T("u"), &Username);
00671 
00672     Error::SetUserName(Username);
00673 
00674     if (Username==_T(""))
00675     {
00676         TRACEUSER("ALL", _T("No user specific trace output\n"));
00677     }
00678     else
00679     {
00680 //      TRACEUSER("ALL",_T("Tracing output where user is %s\n"),(const char *)Username.mb_str(wxConvUTF8));
00681         TRACEUSER("ALL",_T("Tracing output where user is %s\n"),(const TCHAR *)Username.c_str());
00682     }
00683 
00684     TRACEUSER("ALL",_T("Memory debugging %d, List debugging %d\n"), SimpleCCObject::CheckMemoryFlag, List::ListDebugLevel);
00685 
00686 #endif
00687 
00688     // OK, now we've handled the help case, and some VERY early init, we should see if another instance
00689     // is running.
00690 
00691     // Set and check for single instance running
00692     wxString SIname = wxString(_T(".XARA-XTREME-WX-"))  +GetAppName()+wxString::Format(_T("-%s"), wxGetUserId().c_str());
00693     wxFileName IPCfn(wxGetHomeDir(),SIname+_T(".ipc"));
00694     wxString IPCname = IPCfn.GetFullPath();
00695 
00696     m_pSingleInstanceChecker = NULL;
00697     m_pServer = NULL;
00698 
00699 #ifdef _DEBUG
00700     BOOL SingleInstanceCheck = FALSE;
00701 #else
00702     BOOL SingleInstanceCheck = TRUE;
00703 #endif
00704 
00705     if (SingleInstanceCheck)
00706     {
00707         // Create a single instance checker at that location
00708         m_pSingleInstanceChecker = new wxSingleInstanceChecker(SIname);
00709         if (!m_pSingleInstanceChecker)
00710         {
00711             ERROR2(FALSE, "Failed to create single instance checker");
00712         }
00713     
00714         // Now see if another is running
00715         if (m_pSingleInstanceChecker->IsAnotherRunning())
00716         {
00717             wxClient Client;
00718             wxConnectionBase * Connection = Client.MakeConnection(wxEmptyString, IPCname, camIPC_START);
00719     
00720             // If there is no connection, perhaps the other end is dead. We will start up anyway.
00721             if (Connection)
00722             {
00723                 INT32 len=1; // terminating null
00724                 INT32 i;
00725     
00726                 wxArrayString docs;
00727                 INT32 doccount = parser.GetParamCount()+1; // add one for the dummy
00728     
00729                 // Add all docs with a dummy argv[0]
00730                 for ( i=0 ; i<doccount; i++ )
00731                 {
00732                     wxString docname;
00733                     if (i)
00734                     {
00735                         docname = parser.GetParam(i-1);
00736                         wxFileName fn(docname);
00737                         fn.Normalize(wxPATH_NORM_ALL);
00738                         docname=fn.GetFullPath();
00739                     }
00740                     else
00741                     {
00742                         docname=argv[0];
00743                     }
00744                     len+=docname.length()+1; // include the trailing zero
00745                     docs.Add(docname);
00746                 }
00747     
00748                 wxChar * Data = new wxChar[len];
00749                 if (!Data)
00750                 {
00751                     ERROR2(FALSE, "Failed to create single instance checker data");
00752                 }
00753     
00754                 // Copy the 
00755                 wxChar * p = Data;
00756                 for (i = 0; i < doccount; i++)
00757                 {
00758                     wxStrcpy(p, docs[i]);
00759                     p+=docs[i].length()+1; // move past string and terminating NULL
00760                 }
00761                 *p = _T('\0'); // add a final terminating NULL
00762     
00763                 // Now send the data over the connection
00764                 if (Connection->Execute (Data, len*sizeof(wxChar)))
00765                 {
00766                     delete [] Data;
00767                     delete Connection;
00768     
00769                     //.Free up the single instance checker
00770                     delete m_pSingleInstanceChecker;
00771                     m_pSingleInstanceChecker = NULL;
00772     
00773                     // We're out of here...
00774                     return FALSE;
00775                 }
00776     
00777                 // Hmmmm, it didn't want to execute it. perhaps the other process is stuck. We'll run anyway
00778                 delete [] Data;
00779                 delete Connection;
00780             }
00781         }
00782     }
00783 
00784     // OK, we are the only instance running. Delete any stale socket (ours has not been created yet).
00785     ::wxRemoveFile(IPCname);
00786 
00787     // Register the image handler which loads CURs (used for Cursors, obviously)
00788     wxImage::AddHandler( new wxCURHandler );
00789 
00790     // Register the image handler which loads PNGs (used for TBs)
00791     wxImage::AddHandler( new wxPNGHandler );
00792 
00793     // Init the BinReloc stuff (we don't really care if this fails, since it
00794     // fails safe)
00795     BrInitError error;
00796     br_init( &error );
00797     
00798     // Useful debug tracing enablers, left here for next debug session...
00799 //  wxLog::AddTraceMask( _T("focus") );
00800 //  wxLog::AddTraceMask( _T("keyevent") );
00801 
00802     // Initialise the MonotonicTime class
00803     MonotonicTime::Init();
00804 
00805     // We initialize profiling here to allow the rest of the app to be profiled
00806     CamProfile::Init();
00807     // Don't start profiling until Alex has finished the code!
00808     CamProfile::ActivateProfiling(TRUE);
00809     // Indicate time from now on should be assigned to "OTHER"
00810     CamProfile::AtBase(CAMPROFILE_OTHER);
00811 
00812     TRACET(_T("CCamApp::OnInit first available time to trace"));
00813 
00814     // Initialize resources system
00815     if (!CamResource::Init()) return FALSE;
00816     // Initialize the art provider - needed for dialogs
00817     wxPlatformDependent::Init(CLASSINFO(CamPlatformDependent));
00818     if (!CamArtProvider::Init()) return FALSE;
00819     // We need this pretty early so we can handle ERROR boxes etc
00820     if (!DialogEventHandler::Init()) return FALSE;
00821     if (!ControlList::Init()) return FALSE;
00822 
00823     TRACET(_T("CCamApp::Calling Camelot.Init"));
00824 
00825     // Initialise the kernel application object & Prefs
00826     if( !Camelot.Init() )
00827         return false;
00828 
00829     // --------------------------------------------------------------------------
00830     // Detect first-time run and make Open File dialog default to Examples folder
00831     if (Camelot.DeclareSection(TEXT("Preferences"), 10))
00832     {
00833         Camelot.DeclarePref(NULL, TEXT("FirstRun"), &bFirstRun, 0, 1);
00834     }
00835 
00836     // Check the resource dir exists
00837     Camelot.DeclarePref( NULL, TEXT("ResourceDirOverride"), &m_strResourceDirPathOverride );
00838     m_strResourceDirPath = m_strResourceDirPathOverride; // this way, the path we find never gets put within the preferences
00839     if( /*bFirstRun ||*/ m_strResourceDirPath == _T("") || !wxDir::Exists( (PCTSTR)m_strResourceDirPath ) ) // AB: don't need to do this on first run especially
00840     {
00841 #if !defined(RESOURCE_DIR)
00842         // we can't use auto pointers here because they free using delete but BR allocates using malloc (strdup actually)
00843         char * pszDataPath = br_find_data_dir( "/usr/share" );
00844         if (pszDataPath)
00845         {
00846             m_strResourceDirPath = wxString( pszDataPath, wxConvFile );
00847             free(pszDataPath);
00848             m_strResourceDirPath += _T("/xaralx");
00849             TRACEUSER( "luke", _T("Using resource directory \"%s\"\n"), PCTSTR(m_strResourceDirPath) );
00850 #if defined(_DEBUG)
00851             if( !wxDir::Exists( PCTSTR(m_strResourceDirPath) ) )
00852             {
00853                 // We'll try default location under debug to make life easier
00854                 m_strResourceDirPath = _T("/usr/share/xaralx");
00855                 TRACEUSER( "luke", _T("Try = \"%s\"\n"), PCTSTR(m_strResourceDirPath) );
00856             }
00857 #endif
00858         }
00859 #else
00860         // The "" is needed to stop the macro expanding to LRESOURCE_DIR
00861         m_strResourceDirPath = _T(""RESOURCE_DIR);
00862 #endif
00863     }
00864     TRACEUSER( "luke", _T("ResDir = %s\n"), PCTSTR(m_strResourceDirPath) );
00865 
00866     // Get the media replay application setting
00867     Camelot.DeclarePref( NULL, TEXT("MediaApplication"), &m_strMediaApplication );
00868 
00869     TRACET(_T("CCamApp::Calling InitKernel"));
00870     // then initialise the kernel (and almost everything else)  
00871     if( !InitKernel() )
00872         return false;
00873 
00874     if( !Camelot.LateInit() )
00875         return false;
00876 
00877     TRACET(_T("CCamApp::Calling GRenderRegion::Init"));
00878     if (!GRenderRegion::Init(true))
00879         return false;
00880 
00881     // Declare the prefs for the window size and state
00882     if (Camelot.DeclareSection(TEXT("Windows"), 10))
00883     {
00884         Camelot.DeclarePref(NULL, TEXT("MainWndMax"), &MainWndMaximized, 0, 1);
00885         Camelot.DeclarePref(NULL, TEXT("MainWndMin"), &MainWndMinimized, 0, 1);
00886         Camelot.DeclarePref(NULL, TEXT("MainWndPos"), &MainWndPosString);
00887     }
00888 
00889     TRACET(_T("CCamApp::Making Doc Manager"));
00890     
00891     // Create the document manager and register our doc template
00892     m_docManager = std::auto_ptr<wxDocManager>( new wxDocManager() );
00893 
00894     wxDocTemplate      *pDocTemplate;
00895     pDocTemplate = new CCamDocTemplate(
00896         m_docManager.get(), wxT("Xara"), wxT("*.xar;*.web"), wxT(""), wxT("xar"), wxT("Xara document"), 
00897         wxT("Text View"),
00898         CLASSINFO(CCamDoc),
00899         CLASSINFO(CCamView) );
00900 //  pDocTemplate = new CCamDocTemplate(
00901 //      m_docManager.get(), wxT("Xara"), wxT("*.web"), wxT(""), wxT("web"), wxT("Xara document"), 
00902 //      wxT("Text View"),
00903 //      CLASSINFO(CCamDoc),
00904 //      CLASSINFO(ScreenCamView) );
00905 
00906     // Reload the file history (9 entries)
00907     wxFileHistory*      pFileHist = m_docManager->GetFileHistory();
00908     for( UINT32 ord = 0; ord < 9; ++ord )
00909     {
00910         // This is safe since we control all variables!
00911         TCHAR           pszTag[8];
00912         camSprintf( pszTag, _T("File%d"), ord );
00913 
00914         String_256      strFileName;
00915         Camelot.GetPrefDirect( _T("Recent File list"), pszTag, &strFileName );
00916         
00917         if( strFileName != _T("") )
00918             pFileHist->AddFileToHistory( PCTSTR(strFileName) );
00919     }
00920 
00921     if (bFirstRun)
00922     {
00923         // Set File Open dialog location to our Examples folder
00924         wxString    strConfigPath( (TCHAR*)m_strResourceDirPath );
00925         strConfigPath += _T("/Examples");
00926 
00927 #if defined(_DEBUG)
00928         // Debug-only fallback
00929         if (!wxDir::Exists(strConfigPath))
00930             strConfigPath = _T("/usr/share/xaralx/Examples");
00931 #endif
00932 
00933         if (wxDir::Exists(strConfigPath))
00934             BaseFileDialog::DefaultOpenFilePath = strConfigPath;
00935     }
00936 
00937     // NOTE! Set bFirstRun = FALSE in OnExit handler below
00938     // --------------------------------------------------------------------------
00939 
00940     // Set idles to only get sent to windows that want them
00941     wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); 
00942 
00943     // Create the Frame window
00944     //
00945     // get user preference info for main window
00946     wxSize ScreenSize = ::wxGetDisplaySize();
00947     wxRect WndRect;
00948     wxSize OldScreenSize;
00949     if ((camSscanf(MainWndPosString, _T("%d %d %d %d %d %d"),
00950             &WndRect.x, &WndRect.y, &WndRect.width, &WndRect.height, &OldScreenSize.x, &OldScreenSize.y) == 6) &&
00951             (WndRect.width > 0) && (WndRect.height > 0))
00952     {
00953         // numbers scanned OK, scale them to fit current screen size
00954         if (OldScreenSize.x != ScreenSize.x)
00955         {
00956             // if screen size different from last time, them scale them
00957             WndRect.x = MulDiv(WndRect.x, ScreenSize.x, OldScreenSize.x);
00958             WndRect.width = MulDiv(WndRect.width, ScreenSize.x, OldScreenSize.x);
00959         }
00960         if (OldScreenSize.y != ScreenSize.y)
00961         {
00962             WndRect.y = MulDiv(WndRect.y, ScreenSize.y, OldScreenSize.y);
00963             WndRect.height = MulDiv(WndRect.height, ScreenSize.y, OldScreenSize.y);
00964         }
00965     }
00966     else
00967     {
00968         // make up a sensible default position for the window, inset five percent
00969         // in x and 10 percent in y to avoid taskbars on linux
00970         WndRect.x = ScreenSize.x / 20;
00971         WndRect.width = ScreenSize.x - WndRect.x * 2;
00972         WndRect.y = ScreenSize.y / 10;
00973         WndRect.height = ScreenSize.y - WndRect.y * 2;
00974     }
00975 
00976     TRACET(_T("CCamApp::Making Frame Window"));
00977     m_pMainFrame = new CCamFrame( m_docManager.get(), (wxFrame *)NULL, wxT("Xara Xtreme"), 
00978         WndRect.GetPosition(), WndRect.GetSize(), wxDEFAULT_FRAME_STYLE);
00979 
00980     m_pMainFrame->Show(FALSE); // Don't show it yet
00981 
00982 #if !defined(XARA_MENUGEN)
00983     TRACET(_T("CCamApp::Making Menu structure"));
00984     //
00985     // Build the MDI style file menu
00986     // This is just a simple menu. The full menu is created
00987     // after loading a document.
00988     //
00989     wxMenu* pFileMenu = new wxMenu;
00990 
00991     pFileMenu->Append( wxID_NEW,  wxT("&New...") );
00992     pFileMenu->Append( wxID_OPEN, wxT("&Open...") );
00993 
00994 #if defined(FILELIST)
00995     wxMenu* pRecentFilesMenu = new wxMenu;
00996     m_docManager->FileHistoryUseMenu(pRecentFilesMenu);
00997     m_docManager->FileHistoryAddFilesToMenu(pRecentFilesMenu);
00998 
00999     pFileMenu->AppendSeparator();
01000     pFileMenu->Append( -1, wxT("&Recent files"),pRecentFilesMenu );
01001 #endif //defiend(FILELIST)
01002 
01003     pFileMenu->AppendSeparator();
01004     pFileMenu->Append( wxID_EXIT, wxT("E&xit") );
01005 
01006     // Build help menu
01007     wxMenu             *pHelpMenu = new wxMenu;
01008     pHelpMenu->Append( _R(DOCVIEW_ABOUT), wxT("&About...") );
01009 
01010     // Place menus into the menu bar
01011     wxMenuBar          *pMenuBar = new wxMenuBar;
01012     pMenuBar->Append( pFileMenu, wxT("File") );
01013     pMenuBar->Append( pHelpMenu, wxT("Help") );
01014 
01015 #ifdef __WXMAC__
01016     wxMenuBar::MacSetCommonMenuBar( pMenuBar );
01017 #endif //def __WXMAC__
01018 
01019     // Set up menu bar...
01020     m_pMainFrame->SetMenuBar( pMenuBar );
01021 
01022 #else
01023 
01024 #ifdef __WXMAC__
01025     wxMenuBar::MacSetCommonMenuBar( WinMDIMenu );
01026 #endif //def __WXMAC__
01027 
01028     // Set up menu bar...
01029     m_pMainFrame->SetMenuBar( WinMDIMenu );
01030     WinMDIMenu->ClearAccelTable();
01031 
01032 #endif
01033 
01034     // We don't want auto-accelerators, this is done using our hotkeys
01035     // I don't know how to do this yet, but I'm looking....
01036 //  wxAcceleratorTable* pAccelTable = pMenuBar->GetAccelTable();
01037 //  *pAccelTable = wxAcceleratorTable();
01038 
01039     TRACET(_T("CCamApp::Init Setting mainframe as top window"));
01040 
01041     m_pMainFrame->CreateToolbars();
01042     m_pMainFrame->UpdateFrameManager();
01043 
01044     // Show the main frame window
01045     // make maximized if thats what we were last time, unless overridden by user
01046     if (MainWndMaximized)
01047     {
01048         m_pMainFrame->Maximize();
01049     }
01050     if (MainWndMinimized)
01051     {
01052         m_pMainFrame->Iconize();
01053     }
01054     SetTopWindow( m_pMainFrame );
01055     ::wxYield(); // allow resizing to take place
01056     m_pMainFrame->Show( true );
01057     ::wxYield(); // allow resizing to take place
01058     wxPlatformDependent::Get()->FixUpdate(m_pMainFrame); // Force the main frame to be redrawn properly
01059     ::wxYield(); // allow resizing to take place
01060 
01061 #ifndef EXCLUDE_FROM_XARALX
01062     m_pMainFrame->CacheNormalPlaceMode();
01063     m_pMainFrame->CheckFullScreenMode();
01064 
01065     // if the splash box is up, draw our window behind it (will be a big pending WM_PAINT)
01066     // IT MUST NOT BE ACTIVE else palette problems
01067     if (AfxOleGetUserCtrl())
01068     {
01069         if (m_nCmdShow == SW_SHOWMINIMIZED || m_nCmdShow == SW_SHOWMINNOACTIVE)
01070         {
01071             pMainFrame->ShowWindow(SW_SHOWMINNOACTIVE);
01072         }
01073         else
01074         {
01075             if (m_nCmdShow == SW_SHOWMAXIMIZED)
01076                 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
01077             else
01078                 pMainFrame->ShowWindow(SW_SHOWNOACTIVATE);
01079 
01080             // the ShowWindow() above has made the main window active so make the splash box active, else
01081             // we get nasty palette problems later on
01082             pSplashbox->SetActiveWindow();
01083         }
01084     }
01085 #endif
01086 
01087     Tool::SelectFirstTool();
01088 
01089     // Go through the command line and load documents
01090     TRACET(_T("CCamApp::Init Loading docs (if any) from command line"));
01091 
01092     if( 0 == parser.GetParamCount() )
01093         m_docManager->CreateDocument( _T(""), wxDOC_NEW );
01094     else
01095     {
01096         for ( UINT32 i=0 ; i<parser.GetParamCount() ; i++ )
01097             m_docManager->CreateDocument(parser.GetParam(i),wxDOC_SILENT);
01098     }
01099 
01100     // Remove the splash screen
01101     CamResource::DoneInit();
01102 
01103     CXMLUtils::Initialise();
01104 
01105     if (SingleInstanceCheck)
01106     {
01107         // We are able to load documents, so now start our own IPC server
01108         m_pServer = new CamIPCServer();
01109         if (!m_pServer)
01110         {
01111             delete (m_pSingleInstanceChecker);
01112             m_pSingleInstanceChecker = NULL;
01113             ERROR2(FALSE, "Failed to create IPC server");
01114         }
01115     
01116         // and initialize it
01117         if (!(m_pServer->Create(IPCname)))
01118         {
01119             delete m_pServer;
01120             m_pServer = NULL;
01121     
01122             delete (m_pSingleInstanceChecker);
01123             m_pSingleInstanceChecker = NULL;
01124             ERROR2(FALSE, "Failed to init IPC server");
01125         }
01126     }
01127 
01128     // Give focus to any child that will take it, parent can't have it since
01129     // it's a frame (see gtk_widget_grab_focus)
01130     GiveFocusToFocusableOffspring( m_pMainFrame );
01131     
01132     // Create timer used for background rendering.
01133 //  m_Timer.SetOwner(this,CAM_TIMER_ID);
01134 //  m_Timer.Start(CAM_TIMER_FREQUENCY);
01135 
01136     InInitOrDeInit = FALSE; // Now allow the user a chance to save their work on a SEGV
01137 
01138     return true;
01139 }
01140 
01141 /***************************************************************************************************************************/
01142 //
01143 // Deinitialisation.
01144 //
01145 
01146 INT32 CCamApp::OnExit( void )
01147 {
01148     InInitOrDeInit = TRUE; // Don't allow them to save their work on a SEGV
01149     // We can no longer stop the closedown, so flag this fact
01150     Camelot.ShuttingDown(TRUE);
01151 
01152     // Dump the file history (9 entries as for Xtreme 4 Win)
01153     wxFileHistory*      pFileHist = m_docManager->GetFileHistory();
01154     UINT32              cRecent   = UINT32(pFileHist->GetCount());
01155     for( UINT32 ord = 0; ord < 9; ++ord )
01156     {
01157         // This is safe since we control all variables!
01158         TCHAR           pszTag[8];
01159         camSprintf( pszTag, _T("File%d"), ord );
01160 
01161         if( ord < cRecent )
01162         {
01163             wxString    strFileName( pFileHist->GetHistoryFile( ord ) );
01164             Camelot.SetPrefDirect( _T("Recent File list"), pszTag, PCTSTR(strFileName), TRUE );
01165         }
01166         else
01167             Camelot.SetPrefDirect( _T("Recent File list"), pszTag, _T(""), TRUE );
01168     }
01169 
01170     // we can't load documents any more - delete IPC server
01171     if (m_pServer)
01172     {
01173         delete m_pServer;
01174         m_pServer = NULL;
01175     }
01176 
01177     // delete single instance checked
01178     if (m_pSingleInstanceChecker)
01179     {
01180         delete m_pSingleInstanceChecker;
01181         m_pSingleInstanceChecker = NULL;
01182     }
01183 
01184     // Rendering is back on idle events for now as it actually works
01185 //  m_Timer.Stop();
01186 
01187 #if defined(FILELIST)
01188     {
01189         m_docManager->FileHistorySave(Preferences::GetOilPrefs());
01190     }
01191 #endif
01192     m_docManager = std::auto_ptr<wxDocManager>( NULL );
01193 
01194     bFirstRun = FALSE;
01195 
01196     // Now deinit everything
01197 
01198     CXMLUtils::DeInitialise();
01199 
01200     DeinitKernel();
01201 
01202 #if CUSTOM_INONE == 2
01203     DLLControlClass::DeinitAllControls();
01204 #endif
01205 
01206     GRenderRegion::DeInit();                        // tidy up GDraw
01207 
01208 PORTNOTE("other","Removed GDI+, filelist and profilename support")
01209 #ifndef EXCLUDE_FROM_XARALX
01210     Gdiplus::GdiplusShutdown(gdiplusToken);
01211 
01212     // Finished with preferences/registry so remove the allocated ProfileName. Was not here before 18/2/97
01213     if (m_pszProfileName != NULL)
01214     {
01215         free((void *) m_pszProfileName);
01216         m_pszProfileName = NULL;
01217     }
01218 #endif
01219 
01220     ControlList::DeInit();
01221     DialogEventHandler::DeInit();
01222     // Kill of art provider
01223     CamArtProvider::DeInit();
01224     wxPlatformDependent::DeInit();
01225     // Kill of resources
01226     CamResource::DeInit();
01227 
01228     // Kill off profiling
01229     CamProfile::ActivateProfiling(FALSE);
01230 
01231 #if DUMP_MEM_AT_END
01232     MemoryState.DumpAllObjectsSince();
01233 #endif
01234 
01235     // We want a memory dump on Debug builds only
01236 #ifdef _DEBUG
01237     SimpleCCObject::MemoryDump();
01238     DumpCCMallocTrace();
01239 #endif
01240     
01241 PORTNOTE("other","Removed 3D, Extras and UserHelp support")
01242 #ifndef EXCLUDE_FROM_XARALX
01243     // For fabby 3D
01244     if (Is3dWanted())
01245         pCtl3dUnregister(AfxGetInstanceHandle()); 
01246 
01247     OILModule::DeinitExtras();                          // free all DLLs (e.g. ctl3d)
01248 
01249     // Last of all, deinit the help system now that there's very little else to go wrong.
01250     DeInitUserHelp();
01251 #endif
01252 
01253     // zap this after we know all windows have gone
01254     wxWindowDeletionWatcher::DeInit();
01255 
01256     ::wxHandleFatalExceptions(FALSE);
01257     return wxApp::OnExit();
01258 }
01259 
01260 //  WEBSTER-ranbirr-12/11/96
01261 #ifndef WEBSTER
01262 void CCamApp::OnFilePrintSetup()
01263 {
01264 #ifndef STANDALONE
01265     Document *pDoc = Document::GetSelected();
01266     DocView *pDocView = DocView::GetSelected();
01267 
01268     if (pDoc && pDocView && pDocView->GetConnectionToOilView())
01269     {
01270         // Inform the user if we have switched to using the default printer on the system
01271         // before opening the print setup dlg.
01272         CCPrintDialog::InformResetToDefaultPrinter(FALSE);
01273     
01274         // This no longer calls the base class OnFilePrint() function.
01275         // Instead, we involke the print dlg ourselves so that we can update our
01276         // printer settings when the dlg is closed via the user clicking on OK
01277         // (7/4/95 - Markn)
01278 
01279         CCPrintInfo printinfo(pDoc, pDocView->GetConnectionToOilView());
01280         printinfo.OnPreparePrinting(TRUE);          
01281     }
01282     
01283 #endif
01284 }
01285 #endif
01286 
01287 void CCamApp::OnAppExit()
01288 {
01289 PORTNOTE("other","Removed multi-instance flag stuff")
01290 #ifndef EXCLUDE_FROM_XARALX
01291     // remove the flag that prevents camelot starting more than once; BUT only if were
01292     // the camelot that set it!
01293 
01294     HWND mainWindow = m_pMainWnd->m_hWnd;
01295     
01296     if (mainWindow)
01297     {
01298         BOOL* ret = (BOOL*) RemoveProp (m_pMainWnd->m_hWnd, "Xara X sfs");
01299 
01300         if (ret) delete (ret);
01301     }
01302 #endi