1///////////////////////////////////////////////////////////////////////////// 2// Name: emulator.cpp 3// Purpose: Emulator wxWidgets sample 4// Author: Julian Smart 5// Modified by: 6// Created: 04/01/98 7// RCS-ID: $Id: emulator.cpp 35650 2005-09-23 12:56:45Z MR $ 8// Copyright: (c) Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx/wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27// for all others, include the necessary headers (this file is usually all you 28// need because it includes almost all "standard" wxWidgets headers) 29#ifndef WX_PRECOMP 30 #include "wx/wx.h" 31#endif 32 33#include "wx/confbase.h" 34#include "wx/fileconf.h" 35#include "wx/cmdline.h" 36#include "wx/image.h" 37#include "wx/file.h" 38 39#ifdef __WXX11__ 40#include "wx/x11/reparent.h" 41#endif 42 43#include "emulator.h" 44 45// ---------------------------------------------------------------------------- 46// resources 47// ---------------------------------------------------------------------------- 48 49// the application icon (under Windows and OS/2 it is in resources) 50#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__) 51 #include "emulator.xpm" 52#endif 53 54// ---------------------------------------------------------------------------- 55// event tables and other macros for wxWidgets 56// ---------------------------------------------------------------------------- 57 58// the event tables connect the wxWidgets events with the functions (event 59// handlers) which process them. It can be also done at run-time, but for the 60// simple menu events like this the static method is much simpler. 61BEGIN_EVENT_TABLE(wxEmulatorFrame, wxFrame) 62 EVT_MENU(Emulator_Quit, wxEmulatorFrame::OnQuit) 63 EVT_MENU(Emulator_About, wxEmulatorFrame::OnAbout) 64 EVT_CLOSE(wxEmulatorFrame::OnCloseWindow) 65END_EVENT_TABLE() 66 67// Create a new application object: this macro will allow wxWidgets to create 68// the application object during program execution (it's better than using a 69// static object for many reasons) and also declares the accessor function 70// wxGetApp() which will return the reference of the right type (i.e. wxEmulatorApp and 71// not wxApp) 72IMPLEMENT_APP(wxEmulatorApp) 73 74static const wxCmdLineEntryDesc sg_cmdLineDesc[] = 75{ 76 { wxCMD_LINE_OPTION, _T("u"), _T("use-display"), _T("display number to use (default 100)"), (wxCmdLineParamType)0, 0 }, 77 78 { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("displays help on the command line parameters"), (wxCmdLineParamType)0, 0 }, 79 { wxCMD_LINE_SWITCH, _T("v"), _T("version"), _T("print version"), (wxCmdLineParamType)0, 0 }, 80 81 { wxCMD_LINE_PARAM, NULL, NULL, _T("config file 1"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, 82 83 { wxCMD_LINE_NONE, NULL, NULL, NULL, (wxCmdLineParamType)0, 0 } 84}; 85 86 87// ============================================================================ 88// implementation 89// ============================================================================ 90 91// ---------------------------------------------------------------------------- 92// the application class 93// ---------------------------------------------------------------------------- 94 95wxEmulatorApp::wxEmulatorApp() 96{ 97 m_xnestWindow = NULL; 98 m_containerWindow = NULL; 99 m_displayNumber = wxT("100"); 100 m_xnestPID = 0; 101 102} 103 104// 'Main program' equivalent: the program execution "starts" here 105bool wxEmulatorApp::OnInit() 106{ 107#if wxUSE_LOG 108 wxLog::SetTimestamp(NULL); 109#endif // wxUSE_LOG 110 wxInitAllImageHandlers(); 111 112 wxString currentDir = wxGetCwd(); 113 114 // Use argv to get current app directory 115 m_appDir = wxFindAppPath(argv[0], currentDir, wxT("WXEMUDIR")); 116 117 // If the development version, go up a directory. 118#ifdef __WXMSW__ 119 if ((m_appDir.Right(5).CmpNoCase(_T("DEBUG")) == 0) || 120 (m_appDir.Right(11).CmpNoCase(_T("DEBUGSTABLE")) == 0) || 121 (m_appDir.Right(7).CmpNoCase(_T("RELEASE")) == 0) || 122 (m_appDir.Right(13).CmpNoCase(_T("RELEASESTABLE")) == 0) 123 ) 124 m_appDir = wxPathOnly(m_appDir); 125#endif 126 127 // Parse the command-line parameters and options 128 wxCmdLineParser parser(sg_cmdLineDesc, argc, argv); 129 int res; 130 { 131 wxLogNull log; 132 res = parser.Parse(); 133 } 134 if (res == -1 || res > 0 || parser.Found(wxT("h"))) 135 { 136#ifdef __X__ 137 wxLog::SetActiveTarget(new wxLogStderr); 138#endif 139 parser.Usage(); 140 return false; 141 } 142 if (parser.Found(wxT("v"))) 143 { 144#ifdef __X__ 145 wxLog::SetActiveTarget(new wxLogStderr); 146#endif 147 wxString msg; 148 msg.Printf(wxT("wxWidgets PDA Emulator (c) Julian Smart, 2002 Version %.2f, %s"), wxEMULATOR_VERSION, __DATE__); 149 wxLogMessage(msg); 150 return false; 151 } 152 if (parser.Found(wxT("u"), & m_displayNumber)) 153 { 154 // Should only be number, so strip out anything before 155 // and including a : character 156 if (m_displayNumber.Find(wxT(':')) != -1) 157 { 158 m_displayNumber = m_displayNumber.AfterFirst(wxT(':')); 159 } 160 } 161 if (parser.GetParamCount() == 0) 162 { 163 m_emulatorInfo.m_emulatorFilename = wxT("default.wxe"); 164 } 165 else if (parser.GetParamCount() > 0) 166 { 167 m_emulatorInfo.m_emulatorFilename = parser.GetParam(0); 168 } 169 170 // Load the emulation info 171 if (!LoadEmulator(m_appDir)) 172 { 173 //wxMessageBox(wxT("Sorry, could not load this emulator. Please check bitmaps are valid.")); 174 return false; 175 } 176 177 // create the main application window 178 wxEmulatorFrame *frame = new wxEmulatorFrame(_T("wxEmulator"), 179 wxPoint(50, 50), wxSize(450, 340)); 180 181#if wxUSE_STATUSBAR 182 frame->SetStatusText(m_emulatorInfo.m_emulatorTitle, 0); 183 184 wxString sizeStr; 185 sizeStr.Printf(wxT("Screen: %dx%d"), (int) m_emulatorInfo.m_emulatorScreenSize.x, 186 (int) m_emulatorInfo.m_emulatorScreenSize.y); 187 frame->SetStatusText(sizeStr, 1); 188#endif // wxUSE_STATUSBAR 189 190 m_containerWindow = new wxEmulatorContainer(frame, wxID_ANY); 191 192 frame->SetClientSize(m_emulatorInfo.m_emulatorDeviceSize.x, 193 m_emulatorInfo.m_emulatorDeviceSize.y); 194 195 // and show it (the frames, unlike simple controls, are not shown when 196 // created initially) 197 frame->Show(true); 198 199#ifdef __WXX11__ 200 m_xnestWindow = new wxAdoptedWindow; 201 202 wxString cmd; 203 cmd.Printf(wxT("Xnest :%s -geometry %dx%d"), 204 m_displayNumber.c_str(), 205 (int) m_emulatorInfo.m_emulatorScreenSize.x, 206 (int) m_emulatorInfo.m_emulatorScreenSize.y); 207 208 // Asynchronously executes Xnest 209 m_xnestPID = wxExecute(cmd); 210 if (0 == m_xnestPID) 211 { 212 frame->Destroy(); 213 wxMessageBox(wxT("Sorry, could not run Xnest. Please check your PATH.")); 214 return false; 215 } 216 217 wxReparenter reparenter; 218 if (!reparenter.WaitAndReparent(m_containerWindow, m_xnestWindow, wxT("Xnest"))) 219 { 220 wxMessageBox(wxT("Sorry, could not reparent Xnest..")); 221 frame->Destroy(); 222 return false; 223 } 224 225#endif 226 m_containerWindow->DoResize(); 227 228 // success: wxApp::OnRun() will be called which will enter the main message 229 // loop and the application will run. If we returned false here, the 230 // application would exit immediately. 231 return true; 232} 233 234// Prepend the current program directory to the name 235wxString wxEmulatorApp::GetFullAppPath(const wxString& filename) const 236{ 237 wxString path(m_appDir); 238 if (path.Last() != '\\' && path.Last() != '/' && filename[0] != '\\' && filename[0] != '/') 239#ifdef __X__ 240 path += '/'; 241#else 242 path += '\\'; 243#endif 244 path += filename; 245 246 return path; 247} 248 249 250// Load the specified emulator. 251// For now, hard-wired. TODO: make this configurable 252bool wxEmulatorApp::LoadEmulator(const wxString& appDir) 253{ 254 // Load config file and bitmaps 255 return m_emulatorInfo.Load(appDir); 256} 257 258// ---------------------------------------------------------------------------- 259// main frame 260// ---------------------------------------------------------------------------- 261 262// frame constructor 263wxEmulatorFrame::wxEmulatorFrame(const wxString& title, 264 const wxPoint& pos, const wxSize& size) 265 : wxFrame(NULL, wxID_ANY, title, pos, size) 266{ 267 // set the frame icon 268 SetIcon(wxICON(emulator)); 269 270#if wxUSE_MENUS 271 // create a menu bar 272 wxMenu *menuFile = new wxMenu; 273 274 // the "About" item should be in the help menu 275 wxMenu *helpMenu = new wxMenu; 276 helpMenu->Append(Emulator_About, _T("&About...\tF1"), _T("Show about dialog")); 277 278 menuFile->Append(Emulator_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); 279 280 // now append the freshly created menu to the menu bar... 281 wxMenuBar *menuBar = new wxMenuBar(); 282 menuBar->Append(menuFile, _T("&File")); 283 menuBar->Append(helpMenu, _T("&Help")); 284 285 // ... and attach this menu bar to the frame 286 SetMenuBar(menuBar); 287#endif // wxUSE_MENUS 288 289#if wxUSE_STATUSBAR 290 // create a status bar just for fun (by default with 1 pane only) 291 CreateStatusBar(2); 292#endif // wxUSE_STATUSBAR 293} 294 295 296// event handlers 297 298void wxEmulatorFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) 299{ 300 // true is to force the frame to close 301 Close(true); 302} 303 304void wxEmulatorFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) 305{ 306 wxString msg; 307 msg.Printf( _T("wxEmulator is an environment for testing embedded X11 apps.\n")); 308 309 wxMessageBox(msg, _T("About wxEmulator"), wxOK | wxICON_INFORMATION, this); 310} 311 312void wxEmulatorFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) 313{ 314#ifdef __WXX11__ 315 if (wxGetApp().m_xnestWindow) 316 { 317 wxGetApp().m_xnestWindow->SetHandle((WXWindow) NULL); 318 } 319#endif 320 this->Destroy(); 321 if (wxGetApp().m_xnestPID > 0) 322 { 323 wxKill(wxGetApp().m_xnestPID); 324 wxGetApp().m_xnestPID = 0; 325 } 326} 327 328IMPLEMENT_CLASS(wxEmulatorContainer, wxWindow) 329 330BEGIN_EVENT_TABLE(wxEmulatorContainer, wxWindow) 331 EVT_SIZE(wxEmulatorContainer::OnSize) 332 EVT_PAINT(wxEmulatorContainer::OnPaint) 333 EVT_ERASE_BACKGROUND(wxEmulatorContainer::OnEraseBackground) 334END_EVENT_TABLE() 335 336wxEmulatorContainer::wxEmulatorContainer(wxWindow* parent, wxWindowID id): 337 wxWindow(parent, id, wxDefaultPosition, wxDefaultSize) 338{ 339} 340 341void wxEmulatorContainer::OnSize(wxSizeEvent& WXUNUSED(event)) 342{ 343 DoResize(); 344} 345 346void wxEmulatorContainer::DoResize() 347{ 348 wxSize sz = GetClientSize(); 349 if (wxGetApp().m_xnestWindow 350#ifdef __WXX11__ 351 && wxGetApp().m_xnestWindow->GetMainWindow() 352#endif 353 ) 354 { 355 int deviceWidth = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.x; 356 int deviceHeight = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.y; 357 358 int x = wxMax(0, (int) ((sz.x - deviceWidth)/2.0)); 359 int y = wxMax(0, (int) ((sz.y - deviceHeight)/2.0)); 360 361 x += wxGetApp().m_emulatorInfo.m_emulatorScreenPosition.x; 362 y += wxGetApp().m_emulatorInfo.m_emulatorScreenPosition.y; 363 364 wxGetApp().m_xnestWindow->Move(x, y); 365 } 366 Refresh(); 367} 368 369void wxEmulatorContainer::OnPaint(wxPaintEvent& WXUNUSED(event)) 370{ 371 wxPaintDC dc(this); 372 373 wxSize sz = GetClientSize(); 374 if (wxGetApp().m_emulatorInfo.m_emulatorBackgroundBitmap.Ok()) 375 { 376 int deviceWidth = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.x; 377 int deviceHeight = wxGetApp().m_emulatorInfo.m_emulatorDeviceSize.y; 378 379 int x = wxMax(0, (int) ((sz.x - deviceWidth)/2.0)); 380 int y = wxMax(0, (int) ((sz.y - deviceHeight)/2.0)); 381 382 dc.DrawBitmap(wxGetApp().m_emulatorInfo.m_emulatorBackgroundBitmap, x, y); 383 } 384} 385 386void wxEmulatorContainer::OnEraseBackground(wxEraseEvent& event) 387{ 388 wxDC* dc wxDUMMY_INITIALIZE(NULL); 389 390 if (event.GetDC()) 391 { 392 dc = event.GetDC(); 393 } 394 else 395 { 396 dc = new wxClientDC(this); 397 } 398 399 dc->SetBackground(wxBrush(wxGetApp().m_emulatorInfo.m_emulatorBackgroundColour, wxSOLID)); 400 dc->Clear(); 401 402 if (!event.GetDC()) 403 delete dc; 404} 405 406// Information about the emulator decorations 407 408void wxEmulatorInfo::Copy(const wxEmulatorInfo& info) 409{ 410 m_emulatorFilename = info.m_emulatorFilename; 411 m_emulatorTitle = info.m_emulatorTitle; 412 m_emulatorDescription = info.m_emulatorDescription; 413 m_emulatorScreenPosition = info.m_emulatorScreenPosition; 414 m_emulatorScreenSize = info.m_emulatorScreenSize; 415 m_emulatorBackgroundBitmap = info.m_emulatorBackgroundBitmap; 416 m_emulatorBackgroundBitmapName = info.m_emulatorBackgroundBitmapName; 417 m_emulatorBackgroundColour = info.m_emulatorBackgroundColour; 418 m_emulatorDeviceSize = info.m_emulatorDeviceSize; 419} 420 421// Initialisation 422void wxEmulatorInfo::Init() 423{ 424 m_emulatorDeviceSize = wxSize(260, 340); 425 m_emulatorScreenSize = wxSize(240, 320); 426} 427 428// Loads bitmaps 429bool wxEmulatorInfo::Load(const wxString& appDir) 430{ 431 // Try to find absolute path 432 wxString absoluteConfigPath = m_emulatorFilename; 433 if ( !::wxIsAbsolutePath(absoluteConfigPath) ) 434 { 435 wxString currDir = wxGetCwd(); 436 absoluteConfigPath = currDir + wxString(wxFILE_SEP_PATH) + m_emulatorFilename; 437 if ( !wxFile::Exists(absoluteConfigPath) ) 438 { 439 absoluteConfigPath = appDir + wxString(wxFILE_SEP_PATH) 440 + m_emulatorFilename; 441 } 442 } 443 444 if ( !wxFile::Exists(absoluteConfigPath) ) 445 { 446 wxString str; 447 str.Printf( wxT("Could not find config file %s"), 448 absoluteConfigPath.c_str() ); 449 450 wxMessageBox(str); 451 return false; 452 } 453 454 wxString rootPath = wxPathOnly(absoluteConfigPath); 455 456 { 457 wxFileConfig config(wxT("wxEmulator"), wxT("wxWidgets"), 458 absoluteConfigPath, wxEmptyString, wxCONFIG_USE_LOCAL_FILE); 459 460 config.Read(wxT("/General/title"), & m_emulatorTitle); 461 config.Read(wxT("/General/description"), & m_emulatorDescription); 462 config.Read(wxT("/General/backgroundBitmap"), & m_emulatorBackgroundBitmapName); 463 464 wxString colString; 465 if (config.Read(wxT("/General/backgroundColour"), & colString) || 466 config.Read(wxT("/General/backgroundColor"), & colString) 467 ) 468 { 469 m_emulatorBackgroundColour = wxHexStringToColour(colString); 470 } 471 472 int x = 0, y = 0, w = 0, h = 0, dw = 0, dh = 0; 473 config.Read(wxT("/General/screenX"), & x); 474 config.Read(wxT("/General/screenY"), & y); 475 config.Read(wxT("/General/screenWidth"), & w); 476 config.Read(wxT("/General/screenHeight"), & h); 477 if (config.Read(wxT("/General/deviceWidth"), & dw) && config.Read(wxT("/General/deviceHeight"), & dh)) 478 { 479 m_emulatorDeviceSize = wxSize(dw, dh); 480 } 481 482 m_emulatorScreenPosition = wxPoint(x, y); 483 m_emulatorScreenSize = wxSize(w, h); 484 } 485 486 if (!m_emulatorBackgroundBitmapName.empty()) 487 { 488 wxString absoluteBackgroundBitmapName = rootPath + wxString(wxFILE_SEP_PATH) + m_emulatorBackgroundBitmapName; 489 if ( !wxFile::Exists(absoluteBackgroundBitmapName) ) 490 { 491 wxString str; 492 str.Printf( wxT("Could not find bitmap %s"), 493 absoluteBackgroundBitmapName.c_str() ); 494 wxMessageBox(str); 495 return false; 496 } 497 498 wxBitmapType type = wxDetermineImageType(m_emulatorBackgroundBitmapName); 499 if (type == wxBITMAP_TYPE_INVALID) 500 return false; 501 502 if (!m_emulatorBackgroundBitmap.LoadFile(m_emulatorBackgroundBitmapName, type)) 503 { 504 wxString str; 505 str.Printf( wxT("Could not load bitmap file %s"), 506 m_emulatorBackgroundBitmapName.c_str() ); 507 wxMessageBox(str); 508 return false; 509 } 510 511 m_emulatorDeviceSize = wxSize(m_emulatorBackgroundBitmap.GetWidth(), 512 m_emulatorBackgroundBitmap.GetHeight()); 513 } 514 return true; 515} 516 517// Returns the image type, or -1, determined from the extension. 518wxBitmapType wxDetermineImageType(const wxString& filename) 519{ 520 wxString path, name, ext; 521 522 wxSplitPath(filename, & path, & name, & ext); 523 524 ext.MakeLower(); 525 if (ext == _T("jpg") || ext == _T("jpeg")) 526 return wxBITMAP_TYPE_JPEG; 527 if (ext == _T("gif")) 528 return wxBITMAP_TYPE_GIF; 529 if (ext == _T("bmp")) 530 return wxBITMAP_TYPE_BMP; 531 if (ext == _T("png")) 532 return wxBITMAP_TYPE_PNG; 533 if (ext == _T("pcx")) 534 return wxBITMAP_TYPE_PCX; 535 if (ext == _T("tif") || ext == _T("tiff")) 536 return wxBITMAP_TYPE_TIF; 537 538 return wxBITMAP_TYPE_INVALID; 539} 540 541// Convert a colour to a 6-digit hex string 542wxString wxColourToHexString(const wxColour& col) 543{ 544 wxString hex; 545 546 hex += wxDecToHex(col.Red()); 547 hex += wxDecToHex(col.Green()); 548 hex += wxDecToHex(col.Blue()); 549 550 return hex; 551} 552 553// Convert 6-digit hex string to a colour 554wxColour wxHexStringToColour(const wxString& hex) 555{ 556 unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2)); 557 unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2)); 558 unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2)); 559 560 return wxColour(r, g, b); 561} 562 563// Find the absolute path where this application has been run from. 564// argv0 is wxTheApp->argv[0] 565// cwd is the current working directory (at startup) 566// appVariableName is the name of a variable containing the directory for this app, e.g. 567// MYAPPDIR. This is checked first. 568 569wxString wxFindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName) 570{ 571 wxString str; 572 573 // Try appVariableName 574 if (!appVariableName.empty()) 575 { 576 str = wxGetenv(appVariableName); 577 if (!str.empty()) 578 return str; 579 } 580 581 if (wxIsAbsolutePath(argv0)) 582 return wxPathOnly(argv0); 583 else 584 { 585 // Is it a relative path? 586 wxString currentDir(cwd); 587 if (!wxEndsWithPathSeparator(currentDir)) 588 currentDir += wxFILE_SEP_PATH; 589 590 str = currentDir + argv0; 591 if ( wxFile::Exists(str) ) 592 return wxPathOnly(str); 593 } 594 595 // OK, it's neither an absolute path nor a relative path. 596 // Search PATH. 597 598 wxPathList pathList; 599 pathList.AddEnvList(wxT("PATH")); 600 str = pathList.FindAbsoluteValidPath(argv0); 601 if (!str.empty()) 602 return wxPathOnly(str); 603 604 // Failed 605 return wxEmptyString; 606} 607 608