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