///////////////////////////////////////////////////////////////////////////// // Name: emulator.cpp // Purpose: Emulator wxWidgets sample // Author: Julian Smart // Modified by: // Created: 04/01/98 // RCS-ID: $Id: emulator.cpp 35650 2005-09-23 12:56:45Z MR $ // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ // declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif // for all others, include the necessary headers (this file is usually all you // need because it includes almost all "standard" wxWidgets headers) #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "wx/confbase.h" #include "wx/fileconf.h" #include "wx/cmdline.h" #include "wx/image.h" #include "wx/file.h" #ifdef __WXX11__ #include "wx/x11/reparent.h" #endif #include "emulator.h" // ---------------------------------------------------------------------------- // resources // ---------------------------------------------------------------------------- // the application icon (under Windows and OS/2 it is in resources) #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__) #include "emulator.xpm" #endif // ---------------------------------------------------------------------------- // event tables and other macros for wxWidgets // ---------------------------------------------------------------------------- // the event tables connect the wxWidgets events with the functions (event // handlers) which process them. It can be also done at run-time, but for the // simple menu events like this the static method is much simpler. BEGIN_EVENT_TABLE(wxEmulatorFrame, wxFrame) EVT_MENU(Emulator_Quit, wxEmulatorFrame::OnQuit) EVT_MENU(Emulator_About, wxEmulatorFrame::OnAbout) EVT_CLOSE(wxEmulatorFrame::OnCloseWindow) END_EVENT_TABLE() // Create a new application object: this macro will allow wxWidgets to create // the application object during program execution (it's better than using a // static object for many reasons) and also declares the accessor function // wxGetApp() which will return the reference of the right type (i.e. wxEmulatorApp and // not wxApp) IMPLEMENT_APP(wxEmulatorApp) static const wxCmdLineEntryDesc sg_cmdLineDesc[] = { { wxCMD_LINE_OPTION, _T("u"), _T("use-display"), _T("display number to use (default 100)"), (wxCmdLineParamType)0, 0 }, { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("displays help on the command line parameters"), (wxCmdLineParamType)0, 0 }, { wxCMD_LINE_SWITCH, _T("v"), _T("version"), _T("print version"), (wxCmdLineParamType)0, 0 }, { wxCMD_LINE_PARAM, NULL, NULL, _T("config file 1"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_NONE, NULL, NULL, NULL, (wxCmdLineParamType)0, 0 } }; // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- // the application class // ---------------------------------------------------------------------------- wxEmulatorApp::wxEmulatorApp() { m_xnestWindow = NULL; m_containerWindow = NULL; m_displayNumber = wxT("100"); m_xnestPID = 0; } // 'Main program' equivalent: the program execution "starts" here bool wxEmulatorApp::OnInit() { #if wxUSE_LOG wxLog::SetTimestamp(NULL); #endif // wxUSE_LOG wxInitAllImageHandlers(); wxString currentDir = wxGetCwd(); // Use argv to get current app directory m_appDir = wxFindAppPath(argv[0], currentDir, wxT("WXEMUDIR")); // If the development version, go up a directory. #ifdef __WXMSW__ if ((m_appDir.Right(5).CmpNoCase(_T("DEBUG")) == 0) || (m_appDir.Right(11).CmpNoCase(_T("DEBUGSTABLE")) == 0) || (m_appDir.Right(7).CmpNoCase(_T("RELEASE")) == 0) || (m_appDir.Right(13).CmpNoCase(_T("RELEASESTABLE")) == 0) ) m_appDir = wxPathOnly(m_appDir); #endif // Parse the command-line parameters and options wxCmdLineParser parser(sg_cmdLineDesc, argc, argv); int res; { wxLogNull log; res = parser.Parse(); } if (res == -1 || res > 0 || parser.Found(wxT("h"))) { #ifdef __X__ wxLog::SetActiveTarget(new wxLogStderr); #endif parser.Usage(); return false; } if (parser.Found(wxT("v"))) { #ifdef __X__ wxLog::SetActiveTarget(new wxLogStderr); #endif wxString msg; msg.Printf(wxT("wxWidgets PDA Emulator (c) Julian Smart, 2002 Version %.2f, %s"), wxEMULATOR_VERSION, __DATE__); wxLogMessage(msg); return false; } if (parser.Found(wxT("u"), & m_displayNumber)) { // Should only be number, so strip out anything before // and including a : character if (m_displayNumber.Find(wxT(':')) != -1) { m_displayNumber = m_displayNumber.AfterFirst(wxT(':')); } } if (parser.GetParamCount() == 0) { m_emulatorInfo.m_emulatorFilename = wxT("default.wxe"); } else if (parser.GetParamCount() > 0) { m_emulatorInfo.m_emulatorFilename = parser.GetParam(0); } // Load the emulation info if (!LoadEmulator(m_appDir)) { //wxMessageBox(wxT("Sorry, could not load this emulator. Please check bitmaps are valid.")); return false; } // create the main application window wxEmulatorFrame *frame = new wxEmulatorFrame(_T("wxEmulator"), wxPoint(50, 50), wxSize(450, 340)); #if wxUSE_STATUSBAR frame->SetStatusText(m_emulatorInfo.m_emulatorTitle, 0); wxString sizeStr; sizeStr.Printf(wxT("Screen: %dx%d"), (int) m_emulatorInfo.m_emulatorScreenSize.x, (int) m_emulatorInfo.m_emulatorScreenSize.y); frame->SetStatusText(sizeStr, 1); #endif // wxUSE_STATUSBAR m_containerWindow = new wxEmulatorContainer(frame, wxID_ANY); frame->SetClientSize(m_emulatorInfo.m_emulatorDeviceSize.x, m_emulatorInfo.m_emulatorDeviceSize.y); // and show it (the frames, unlike simple controls, are not shown when // created initially) frame->Show(true); #ifdef __WXX11__ m_xnestWindow = new wxAdoptedWindow; wxString cmd; cmd.Printf(wxT("Xnest :%s -geometry %dx%d"), m_displayNumber.c_str(), (int) m_emulatorInfo.m_emulatorScreenSize.x, (int) m_emulatorInfo.m_emulatorScreenSize.y); // Asynchronously executes Xnest m_xnestPID = wxExecute(cmd); if (0 == m_xnestPID) { frame->Destroy(); wxMessageBox(wxT("Sorry, could not run Xnest. Please check your PATH.")); return false; } wxReparenter reparenter; if (!reparenter.WaitAndReparent(m_containerWindow, m_xnestWindow, wxT("Xnest"))) { wxMessageBox(wxT("Sorry, could not reparent Xnest..")); frame->Destroy(); return false; } #endif m_containerWindow->DoResize(); // success: wxApp::OnRun() will be called which will enter the main message // loop and the application will run. If we returned false here, the // application would exit immediately. return true; } // Prepend the current program directory to the name wxString wxEmulatorApp::GetFullAppPath(const wxString& filename) const { wxString path(m_appDir); if (path.Last() != '\\' && path.Last() != '/' && filename[0] != '\\' && filename[0] != '/') #ifdef __X__ path += '/'; #else path += '\\'; #endif path += filename; return path; } // Load the specified emulator. // For now, hard-wired. TODO: make this configurable bool wxEmulatorApp::LoadEmulator(const wxString& appDir) { // Load config file and bitmaps return m_emulatorInfo.Load(appDir); } // ---------------------------------------------------------------------------- // main frame // ---------------------------------------------------------------------------- // frame constructor wxEmulatorFrame::wxEmulatorFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // set the frame icon SetIcon(wxICON(emulator)); #if wxUSE_MENUS // create a menu bar wxMenu *menuFile = new wxMenu; // the "About" item should be in the help menu wxMenu *helpMenu = new wxMenu; helpMenu->Append(Emulator_About, _T("&About...\tF1"), _T("Show about dialog")); menuFile->Append(Emulator_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); // now append the freshly created menu to the menu bar... wxMenuBar *menuBar = new wxMenuBar(); menuBar->Append(menuFile, _T("&File")); menuBar->Append(helpMenu, _T("&Help")); // ... and attach this menu bar to the frame SetMenuBar(menuBar); #endif // wxUSE_MENUS #if wxUSE_STATUSBAR // create a status bar just for fun (by default with 1 pane only) CreateStatusBar(2); #endif // wxUSE_STATUSBAR } // event handlers void wxEmulatorFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { // true is to force the frame to close Close(true); } void wxEmulatorFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxString msg; msg.Printf( _T("wxEmulator is an environment for testing embedded X11 apps.\n")); wxMessageBox(msg, _T("About wxEmulator"), wxOK | wxICON_INFORMATION, this); } void wxEmulatorFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) { #ifdef __WXX11__ if (wxGetApp().m_xnestWindow) { wxGetApp().m_xnestWindow->SetHandle((WXWindow) NULL); } #endif this->Destroy(); if (wxGetApp().m_xnestPID > 0) { wxKill(wxGetApp().m_xnestPID); wxGetApp().m_xnestPID = 0; } } IMPLEMENT_CLASS(wxEmulatorContainer, wxWindow) BEGIN_EVENT_TABLE(wxEmulatorContainer, wxWindow) EVT_SIZE(wxEmulatorContainer::OnSize) EVT_PAINT(wxEmulatorContainer::OnPaint) EVT_ERASE_BACKGROUND(wxEmulatorContainer::OnEraseBackground) END_EVENT_TABLE() wxEmulatorContainer::wxEmulatorContainer(wxWindow* parent, wxWindowID id): wxWindow(parent, id, wxDefaultPosition, wxDefaultSize) { } void wxEmulatorContainer::OnSize(wxSizeEvent& WXUNUSED(event)) { DoResize(); } void wxEmulatorContainer::DoResize() { wxSize sz = GetClientSize(); if (wxGetApp().m_xnestWindow #ifdef __WXX11__ && wxGetApp().m_xnestWindow->GetMainWindow() #endif ) { int deviceWidth = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.x; int deviceHeight = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.y; int x = wxMax(0, (int) ((sz.x - deviceWidth)/2.0)); int y = wxMax(0, (int) ((sz.y - deviceHeight)/2.0)); x += wxGetApp().m_emulatorInfo.m_emulatorScreenPosition.x; y += wxGetApp().m_emulatorInfo.m_emulatorScreenPosition.y; wxGetApp().m_xnestWindow->Move(x, y); } Refresh(); } void wxEmulatorContainer::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); wxSize sz = GetClientSize(); if (wxGetApp().m_emulatorInfo.m_emulatorBackgroundBitmap.Ok()) { int deviceWidth = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.x; int deviceHeight = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.y; int x = wxMax(0, (int) ((sz.x - deviceWidth)/2.0)); int y = wxMax(0, (int) ((sz.y - deviceHeight)/2.0)); dc.DrawBitmap(wxGetApp().m_emulatorInfo.m_emulatorBackgroundBitmap, x, y); } } void wxEmulatorContainer::OnEraseBackground(wxEraseEvent& event) { wxDC* dc wxDUMMY_INITIALIZE(NULL); if (event.GetDC()) { dc = event.GetDC(); } else { dc = new wxClientDC(this); } dc->SetBackground(wxBrush(wxGetApp().m_emulatorInfo.m_emulatorBackgroundColour, wxSOLID)); dc->Clear(); if (!event.GetDC()) delete dc; } // Information about the emulator decorations void wxEmulatorInfo::Copy(const wxEmulatorInfo& info) { m_emulatorFilename = info.m_emulatorFilename; m_emulatorTitle = info.m_emulatorTitle; m_emulatorDescription = info.m_emulatorDescription; m_emulatorScreenPosition = info.m_emulatorScreenPosition; m_emulatorScreenSize = info.m_emulatorScreenSize; m_emulatorBackgroundBitmap = info.m_emulatorBackgroundBitmap; m_emulatorBackgroundBitmapName = info.m_emulatorBackgroundBitmapName; m_emulatorBackgroundColour = info.m_emulatorBackgroundColour; m_emulatorDeviceSize = info.m_emulatorDeviceSize; } // Initialisation void wxEmulatorInfo::Init() { m_emulatorDeviceSize = wxSize(260, 340); m_emulatorScreenSize = wxSize(240, 320); } // Loads bitmaps bool wxEmulatorInfo::Load(const wxString& appDir) { // Try to find absolute path wxString absoluteConfigPath = m_emulatorFilename; if ( !::wxIsAbsolutePath(absoluteConfigPath) ) { wxString currDir = wxGetCwd(); absoluteConfigPath = currDir + wxString(wxFILE_SEP_PATH) + m_emulatorFilename; if ( !wxFile::Exists(absoluteConfigPath) ) { absoluteConfigPath = appDir + wxString(wxFILE_SEP_PATH) + m_emulatorFilename; } } if ( !wxFile::Exists(absoluteConfigPath) ) { wxString str; str.Printf( wxT("Could not find config file %s"), absoluteConfigPath.c_str() ); wxMessageBox(str); return false; } wxString rootPath = wxPathOnly(absoluteConfigPath); { wxFileConfig config(wxT("wxEmulator"), wxT("wxWidgets"), absoluteConfigPath, wxEmptyString, wxCONFIG_USE_LOCAL_FILE); config.Read(wxT("/General/title"), & m_emulatorTitle); config.Read(wxT("/General/description"), & m_emulatorDescription); config.Read(wxT("/General/backgroundBitmap"), & m_emulatorBackgroundBitmapName); wxString colString; if (config.Read(wxT("/General/backgroundColour"), & colString) || config.Read(wxT("/General/backgroundColor"), & colString) ) { m_emulatorBackgroundColour = wxHexStringToColour(colString); } int x = 0, y = 0, w = 0, h = 0, dw = 0, dh = 0; config.Read(wxT("/General/screenX"), & x); config.Read(wxT("/General/screenY"), & y); config.Read(wxT("/General/screenWidth"), & w); config.Read(wxT("/General/screenHeight"), & h); if (config.Read(wxT("/General/deviceWidth"), & dw) && config.Read(wxT("/General/deviceHeight"), & dh)) { m_emulatorDeviceSize = wxSize(dw, dh); } m_emulatorScreenPosition = wxPoint(x, y); m_emulatorScreenSize = wxSize(w, h); } if (!m_emulatorBackgroundBitmapName.empty()) { wxString absoluteBackgroundBitmapName = rootPath + wxString(wxFILE_SEP_PATH) + m_emulatorBackgroundBitmapName; if ( !wxFile::Exists(absoluteBackgroundBitmapName) ) { wxString str; str.Printf( wxT("Could not find bitmap %s"), absoluteBackgroundBitmapName.c_str() ); wxMessageBox(str); return false; } wxBitmapType type = wxDetermineImageType(m_emulatorBackgroundBitmapName); if (type == wxBITMAP_TYPE_INVALID) return false; if (!m_emulatorBackgroundBitmap.LoadFile(m_emulatorBackgroundBitmapName, type)) { wxString str; str.Printf( wxT("Could not load bitmap file %s"), m_emulatorBackgroundBitmapName.c_str() ); wxMessageBox(str); return false; } m_emulatorDeviceSize = wxSize(m_emulatorBackgroundBitmap.GetWidth(), m_emulatorBackgroundBitmap.GetHeight()); } return true; } // Returns the image type, or -1, determined from the extension. wxBitmapType wxDetermineImageType(const wxString& filename) { wxString path, name, ext; wxSplitPath(filename, & path, & name, & ext); ext.MakeLower(); if (ext == _T("jpg") || ext == _T("jpeg")) return wxBITMAP_TYPE_JPEG; if (ext == _T("gif")) return wxBITMAP_TYPE_GIF; if (ext == _T("bmp")) return wxBITMAP_TYPE_BMP; if (ext == _T("png")) return wxBITMAP_TYPE_PNG; if (ext == _T("pcx")) return wxBITMAP_TYPE_PCX; if (ext == _T("tif") || ext == _T("tiff")) return wxBITMAP_TYPE_TIF; return wxBITMAP_TYPE_INVALID; } // Convert a colour to a 6-digit hex string wxString wxColourToHexString(const wxColour& col) { wxString hex; hex += wxDecToHex(col.Red()); hex += wxDecToHex(col.Green()); hex += wxDecToHex(col.Blue()); return hex; } // Convert 6-digit hex string to a colour wxColour wxHexStringToColour(const wxString& hex) { unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2)); unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2)); unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2)); return wxColour(r, g, b); } // Find the absolute path where this application has been run from. // argv0 is wxTheApp->argv[0] // cwd is the current working directory (at startup) // appVariableName is the name of a variable containing the directory for this app, e.g. // MYAPPDIR. This is checked first. wxString wxFindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName) { wxString str; // Try appVariableName if (!appVariableName.empty()) { str = wxGetenv(appVariableName); if (!str.empty()) return str; } if (wxIsAbsolutePath(argv0)) return wxPathOnly(argv0); else { // Is it a relative path? wxString currentDir(cwd); if (!wxEndsWithPathSeparator(currentDir)) currentDir += wxFILE_SEP_PATH; str = currentDir + argv0; if ( wxFile::Exists(str) ) return wxPathOnly(str); } // OK, it's neither an absolute path nor a relative path. // Search PATH. wxPathList pathList; pathList.AddEnvList(wxT("PATH")); str = pathList.FindAbsoluteValidPath(argv0); if (!str.empty()) return wxPathOnly(str); // Failed return wxEmptyString; }