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