• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2005 The Android Open Source Project
3 //
4 // Main window, menu bar, and associated goodies.
5 //
6 
7 // For compilers that support precompilation, include "wx/wx.h".
8 #include "wx/wxprec.h"
9 
10 // Otherwise, include all standard headers
11 #ifndef WX_PRECOMP
12 # include "wx/wx.h"
13 #endif
14 #include "wx/button.h"
15 #include "wx/help.h"
16 #include "wx/filedlg.h"
17 #include "wx/slider.h"
18 #include "wx/textctrl.h"
19 
20 #include "MainFrame.h"
21 #include "MyApp.h"
22 #include "Resource.h"
23 #include "PhoneCollection.h"
24 #include "PhoneData.h"
25 #include "PhoneWindow.h"
26 #include "DeviceWindow.h"
27 #include "UserEventMessage.h"
28 #include "PrefsDialog.h"
29 
30 #include "SimRuntime.h"
31 
32 
33 static wxString kStatusNotRunning = wxT("Idle");
34 static wxString kStatusRunning = wxT("Run");
35 
36 static wxString kDeviceMenuString = wxT("&Device");
37 
38 static const wxString gStdJavaApps[] = {
39     wxT(""),
40     wxT("com.android.testharness.TestList"),
41     wxT("com.android.apps.contacts.ContactsList"),
42     wxT("mikeapp")
43 };
44 
45 
BEGIN_EVENT_TABLE(MainFrame::MainFrame,wxFrame)46 BEGIN_EVENT_TABLE(MainFrame::MainFrame, wxFrame)
47     EVT_CLOSE(MainFrame::OnClose)
48     EVT_TIMER(kHalfSecondTimerId, MainFrame::OnTimer)
49     //EVT_IDLE(MainFrame::OnIdle)
50 
51     EVT_ACTIVATE(MainFrame::OnActivate)
52     EVT_ACTIVATE_APP(MainFrame::OnActivate)
53     EVT_COMBOBOX(IDC_MODE_SELECT, MainFrame::OnComboBox)
54     EVT_COMBOBOX(IDC_JAVA_VM, MainFrame::OnComboBox)
55     EVT_CHECKBOX(IDC_USE_GDB, MainFrame::OnCheckBox)
56     EVT_CHECKBOX(IDC_USE_VALGRIND, MainFrame::OnCheckBox)
57     EVT_CHECKBOX(IDC_CHECK_JNI, MainFrame::OnCheckBox)
58     EVT_CHECKBOX(IDC_OVERLAY_ONION_SKIN, MainFrame::OnCheckBox)
59     EVT_TEXT(IDC_JAVA_APP_NAME, MainFrame::OnText)
60     EVT_TEXT_ENTER(IDC_ONION_SKIN_FILE_NAME, MainFrame::OnTextEnter)
61     EVT_BUTTON(IDC_ONION_SKIN_BUTTON, MainFrame::OnButton)
62     EVT_COMMAND_SCROLL(IDC_ONION_SKIN_ALPHA_VAL, MainFrame::OnSliderChange)
63 
64     EVT_MENU(IDM_FILE_PREFERENCES, MainFrame::OnFilePreferences)
65     EVT_MENU(IDM_FILE_EXIT, MainFrame::OnFileExit)
66     EVT_MENU(IDM_RUNTIME_START, MainFrame::OnSimStart)
67     EVT_UPDATE_UI(IDM_RUNTIME_START, MainFrame::OnUpdateSimStart)
68     EVT_MENU(IDM_RUNTIME_STOP, MainFrame::OnSimStop)
69     EVT_UPDATE_UI(IDM_RUNTIME_STOP, MainFrame::OnUpdateSimStop)
70     EVT_MENU(IDM_RUNTIME_RESTART, MainFrame::OnSimRestart)
71     EVT_UPDATE_UI(IDM_RUNTIME_RESTART, MainFrame::OnUpdateSimRestart)
72     EVT_MENU(IDM_RUNTIME_KILL, MainFrame::OnSimKill)
73     EVT_UPDATE_UI(IDM_RUNTIME_KILL, MainFrame::OnUpdateSimKill)
74     EVT_MENU_RANGE(IDM_DEVICE_SEL0, IDM_DEVICE_SELN,
75         MainFrame::OnDeviceSelected)
76     EVT_MENU(IDM_DEVICE_RESCAN, MainFrame::OnDeviceRescan)
77     EVT_UPDATE_UI(IDM_DEBUG_SHOW_LOG, MainFrame::OnUpdateDebugShowLog)
78     EVT_MENU(IDM_DEBUG_SHOW_LOG, MainFrame::OnDebugShowLog)
79     EVT_MENU(IDM_HELP_CONTENTS, MainFrame::OnHelpContents)
80     EVT_MENU(IDM_HELP_ABOUT, MainFrame::OnHelpAbout)
81 
82     EVT_USER_EVENT(MainFrame::OnUserEvent)
83 END_EVENT_TABLE()
84 
85 
86 /*
87  * Main window constructor.
88  *
89  * Creates menus and status bar.
90  */
91 MainFrame::MainFrame(const wxString& title, const wxPoint& pos,
92     const wxSize& size, long style)
93     : wxFrame((wxFrame *)NULL, -1, title, pos, size, style),
94       mSimRunning(false),
95       mRestartRequested(false),
96       mpPhoneWindow(NULL),
97       mPhoneWindowPosn(wxDefaultPosition),
98       mTimer(this, kHalfSecondTimerId)
99 {
100     mSimAssetPath = ((MyApp*)wxTheApp)->GetSimAssetPath();
101     mSimAssetPath += wxT("/simulator/default/default");
102 
103     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
104     int val;
105 
106     val = mPhoneWindowPosn.x;
107     pPrefs->GetInt("window-device-x", &val);
108     mPhoneWindowPosn.x = val;
109     val = mPhoneWindowPosn.y;
110     pPrefs->GetInt("window-device-y", &val);
111     mPhoneWindowPosn.y = val;
112 
113     /*
114      * Create main menu.
115      */
116     ConstructMenu();
117 
118     /*
119      * Create the status bar.
120      */
121     int widths[2] = { -1, 50 };
122     CreateStatusBar(2, wxFULL_REPAINT_ON_RESIZE);   // no wxST_SIZEGRIP
123     SetStatusWidths(2, widths);
124     SetStatusText(wxT("Ready"));
125     SetStatusText(kStatusNotRunning, 1);
126 
127     /*
128      * Create main window controls.
129      */
130     ConstructControls();
131 
132 #if 0
133     /*
134      * Use the standard window color for the main frame (which usually
135      * has a darker color).  This has a dramatic effect under Windows.
136      */
137     wxColour color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
138     SetOwnBackgroundColour(color);
139 #endif
140 
141     /*
142      * Create the log window.
143      */
144     wxRect layout = LogWindow::GetPrefWindowRect();
145     mpLogWindow = new LogWindow(this);
146     mpLogWindow->Move(layout.GetTopLeft());
147     mpLogWindow->SetSize(layout.GetSize());
148     bool showLogWindow = true;
149     pPrefs->GetBool("window-log-show", &showLogWindow);
150     if (showLogWindow)
151         mpLogWindow->Show();
152 
153     /*
154      * Set up a frequent timer.  We use this to keep our "run/idle"
155      * display up to date.  (Ideally this will go away.)
156      */
157     mTimer.Start(400);      // arg is delay in ms
158 
159     /*
160      * Handle auto-power-on by sending ourselves an event.  That way it
161      * gets handled after window initialization finishes.
162      */
163     bool autoPowerOn = false;
164     pPrefs->GetBool("auto-power-on", &autoPowerOn);
165     if (autoPowerOn) {
166         printf("Sim: Auto power-up\n");
167         wxCommandEvent startEvent(wxEVT_COMMAND_MENU_SELECTED, IDM_RUNTIME_START);
168         this->AddPendingEvent(startEvent);
169     }
170 
171     /*
172      * wxThread wants these to be on the heap -- it will call delete on the
173      * object when the thread exits.
174      */
175     mExternalRuntimeThread = new ExternalRuntime();
176     mExternalRuntimeThread->StartThread();
177     mPropertyServerThread = new PropertyServer();
178     mPropertyServerThread->StartThread();
179 }
180 
181 /*
182  * Construct the main menu.  Called from the constructor.
183  */
ConstructMenu(void)184 void MainFrame::ConstructMenu(void)
185 {
186     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
187 
188     /*
189      * Scan for available phones.
190      */
191     PhoneCollection* pCollection = PhoneCollection::GetInstance();
192     pCollection->ScanForPhones(mSimAssetPath.ToAscii());
193 
194     /*
195      * Create the "File" menu.
196      */
197     wxMenu* menuFile = new wxMenu;
198 
199     menuFile->Append(IDM_FILE_PREFERENCES, wxT("&Preferences..."),
200         wxT("Edit simulator preferences"));
201     menuFile->AppendSeparator();
202     menuFile->Append(IDM_FILE_EXIT, wxT("E&xit\tCtrl-Q"),
203         wxT("Stop simulator and exit"));
204 
205     /*
206      * Create the "Runtime" menu.
207      */
208     wxMenu* menuRuntime = new wxMenu;
209     menuRuntime->Append(IDM_RUNTIME_START, wxT("&Power On\tCtrl-G"),
210         wxT("Start the device"));
211 //    menuRuntime->Append(IDM_RUNTIME_STOP, wxT("Power &Off"),
212 //        wxT("Stop the device"));
213     menuRuntime->AppendSeparator();
214 //    menuRuntime->Append(IDM_RUNTIME_RESTART, wxT("&Restart"),
215 //        wxT("Restart the device"));
216     menuRuntime->Append(IDM_RUNTIME_KILL, wxT("&Kill\tCtrl-K"),
217         wxT("Kill the runtime processes"));
218 
219     /*
220      * Create "Device" menu.
221      */
222     wxString defaultDevice = wxT("Sooner");
223     pPrefs->GetString("default-device", /*ref*/ defaultDevice);
224     wxMenu* menuDevice = CreateDeviceMenu(defaultDevice.ToAscii());
225 
226     /*
227      * Create "Debug" menu.
228      */
229     wxMenu* menuDebug = new wxMenu;
230     menuDebug->AppendCheckItem(IDM_DEBUG_SHOW_LOG, wxT("View &Log Output"),
231         wxT("View log output window"));
232 
233     /*
234      * Create the "Help" menu.
235      */
236     wxMenu* menuHelp = new wxMenu;
237     menuHelp->Append(IDM_HELP_CONTENTS, wxT("&Contents...\tF1"),
238         wxT("Simulator help"));
239     menuHelp->AppendSeparator();
240     menuHelp->Append(IDM_HELP_ABOUT, wxT("&About..."),
241         wxT("See the fabulous 'about' box"));
242 
243     /*
244      * Create the menu bar.
245      */
246     wxMenuBar *menuBar = new wxMenuBar;
247     menuBar->Append(menuFile, wxT("&File"));
248     menuBar->Append(menuDevice, kDeviceMenuString);
249     menuBar->Append(menuRuntime, wxT("&Runtime"));
250     menuBar->Append(menuDebug, wxT("&Debug"));
251     menuBar->Append(menuHelp, wxT("&Help"));
252 
253     SetMenuBar(menuBar);
254 
255 }
256 
257 /*
258  * Construct the "device" menu from our phone collection.
259  */
CreateDeviceMenu(const char * defaultItemName)260 wxMenu* MainFrame::CreateDeviceMenu(const char* defaultItemName)
261 {
262     wxMenu* menuDevice = new wxMenu;
263     PhoneCollection* pCollection = PhoneCollection::GetInstance();
264     int defaultModel = 0;
265 
266     for (int i = 0; i < pCollection->GetPhoneCount(); i++) {
267         PhoneData* pPhoneData = pCollection->GetPhoneData(i);
268         assert(pPhoneData != NULL);
269 
270         menuDevice->AppendRadioItem(IDM_DEVICE_SEL0 + i,
271             wxString::FromAscii(pPhoneData->GetTitle()));
272 
273         // use this one as default if the string matches
274         if (strcasecmp(pPhoneData->GetName(), defaultItemName) == 0)
275             defaultModel = i;
276     }
277 
278     menuDevice->Check(IDM_DEVICE_SEL0 + defaultModel, true);
279 
280     menuDevice->AppendSeparator();
281     menuDevice->Append(IDM_DEVICE_RESCAN, wxT("Re-scan"));
282 
283     return menuDevice;
284 }
285 
286 /*
287  * Create some controls in the main window.
288  *
289  * The main frame doesn't use the normal background color that you find
290  * in dialog windows, so we create a "panel" and put all the controls
291  * on that.
292  */
ConstructControls(void)293 void MainFrame::ConstructControls(void)
294 {
295     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
296     wxPanel* base = new wxPanel(this, wxID_ANY);
297     wxBoxSizer* masterSizer = new wxBoxSizer(wxVERTICAL);
298     wxBoxSizer* tmpSizer;
299     wxStaticBoxSizer* displayOptSizer;
300     wxStaticBoxSizer* runtimeOptSizer;
301     wxStaticBoxSizer* onionSkinOptSizer;
302     wxComboBox* pModeSelection;
303     wxCheckBox* pUseGDB;
304     wxCheckBox* pUseValgrind;
305     wxCheckBox* pCheckJni;
306     wxCheckBox* pOverlayOnionSkin;
307 
308     displayOptSizer = new wxStaticBoxSizer(wxHORIZONTAL, base,
309         wxT("Configuration"));
310     runtimeOptSizer = new wxStaticBoxSizer(wxVERTICAL, base,
311         wxT("Runtime Options"));
312     onionSkinOptSizer = new wxStaticBoxSizer(wxVERTICAL, base,
313         wxT("Onion Skin Options"));
314 
315     /*
316      * Set up the configuration sizer (nee "display options").
317      */
318     tmpSizer = new wxBoxSizer(wxHORIZONTAL);
319     displayOptSizer->Add(tmpSizer);
320     tmpSizer->Add(
321             new wxStaticText(base, wxID_ANY, wxT("Device mode:"),
322             wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT), 0, wxALIGN_CENTER_VERTICAL);
323     pModeSelection = new wxComboBox(base, IDC_MODE_SELECT, wxT(""),
324             wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY);
325     tmpSizer->AddSpacer(kInterSpacing);
326     tmpSizer->Add(pModeSelection);
327 
328     displayOptSizer->AddSpacer(kInterSpacing);
329 
330     /*
331      * Configure the runtime options sizer.
332      */
333     wxComboBox* pJavaAppName;
334     tmpSizer = new wxBoxSizer(wxHORIZONTAL);
335     pUseGDB = new wxCheckBox(base, IDC_USE_GDB, wxT("Use &debugger"));
336     tmpSizer->Add(pUseGDB);
337     tmpSizer->AddSpacer(kInterSpacing);
338     pUseValgrind = new wxCheckBox(base, IDC_USE_VALGRIND, wxT("Use &valgrind"));
339     tmpSizer->Add(pUseValgrind);
340     tmpSizer->AddSpacer(kInterSpacing);
341     pCheckJni = new wxCheckBox(base, IDC_CHECK_JNI, wxT("Check &JNI"));
342     tmpSizer->Add(pCheckJni);
343 
344     pJavaAppName = new wxComboBox(base, IDC_JAVA_APP_NAME, wxT(""),
345         wxDefaultPosition, wxSize(320, -1), NELEM(gStdJavaApps), gStdJavaApps,
346         wxCB_DROPDOWN);
347     wxBoxSizer* javaAppSizer = new wxBoxSizer(wxHORIZONTAL);
348     javaAppSizer->Add(
349             new wxStaticText(base, wxID_ANY,
350                 wxT("Java app:"),
351                 wxDefaultPosition, wxDefaultSize,
352                 wxALIGN_LEFT),
353             0, wxALIGN_CENTER_VERTICAL);
354     javaAppSizer->AddSpacer(kInterSpacing);
355     javaAppSizer->Add(pJavaAppName);
356 
357     runtimeOptSizer->Add(tmpSizer);
358 
359     runtimeOptSizer->AddSpacer(kInterSpacing);
360     runtimeOptSizer->Add(javaAppSizer);
361     runtimeOptSizer->AddSpacer(kInterSpacing);
362 
363     wxString tmpStr;
364     SetCheckFromPref(pUseGDB, "debug", false);
365     SetCheckFromPref(pUseValgrind, "valgrind", false);
366     SetCheckFromPref(pCheckJni, "check-jni", false);
367     if (pPrefs->GetString("java-app-name", /*ref*/ tmpStr))
368         pJavaAppName->SetValue(tmpStr);
369 
370     /*
371      * Configure the onion skin options sizer.
372      */
373     wxTextCtrl* pOnionSkinFileNameText;
374     wxButton* pOnionSkinFileButton;
375     wxSlider* pOnionSkinAlphaSlider;
376     tmpSizer = new wxBoxSizer(wxHORIZONTAL);
377     pOverlayOnionSkin = new wxCheckBox(base,
378         IDC_OVERLAY_ONION_SKIN, wxT("Overlay &onion skin"));
379     tmpSizer->Add(pOverlayOnionSkin);
380 
381     pOnionSkinFileNameText = new wxTextCtrl(base,
382         IDC_ONION_SKIN_FILE_NAME, wxT(""),
383         wxDefaultPosition, wxSize(250, -1),
384         wxTE_PROCESS_ENTER);
385     pOnionSkinFileButton = new wxButton(base, IDC_ONION_SKIN_BUTTON,
386         wxT("Choose"));
387 
388     wxBoxSizer* onionSkinFileNameSizer = new wxBoxSizer(wxHORIZONTAL);
389     onionSkinFileNameSizer->Add(
390         new wxStaticText(base, wxID_ANY,
391             wxT("Filename:"),
392             wxDefaultPosition, wxDefaultSize,
393             wxALIGN_LEFT),
394         0, wxALIGN_CENTER_VERTICAL);
395     onionSkinFileNameSizer->AddSpacer(kInterSpacing);
396     onionSkinFileNameSizer->Add(pOnionSkinFileNameText);
397     onionSkinFileNameSizer->Add(pOnionSkinFileButton);
398 
399     wxBoxSizer * onionSkinAlphaSizer = new wxBoxSizer(wxHORIZONTAL);
400     int initialAlphaVal = 127;
401     pPrefs->GetInt("onion-skin-alpha-value", &initialAlphaVal);
402     pOnionSkinAlphaSlider = new wxSlider(base, IDC_ONION_SKIN_ALPHA_VAL,
403         initialAlphaVal, 0, 255, wxDefaultPosition, wxSize(150, 20));
404     onionSkinAlphaSizer->Add(
405         new wxStaticText(base, wxID_ANY,
406             wxT("Transparency:"),
407             wxDefaultPosition, wxDefaultSize,
408             wxALIGN_LEFT),
409         0, wxALIGN_CENTER_VERTICAL);
410     onionSkinAlphaSizer->AddSpacer(kInterSpacing);
411     onionSkinAlphaSizer->Add(pOnionSkinAlphaSlider, 1, wxCENTRE | wxALL, 5);
412 
413     onionSkinOptSizer->Add(tmpSizer);
414     onionSkinOptSizer->AddSpacer(kInterSpacing);
415     onionSkinOptSizer->Add(onionSkinFileNameSizer);
416     onionSkinOptSizer->Add(onionSkinAlphaSizer);
417 
418     wxString tmpStr2;
419     SetCheckFromPref(pOverlayOnionSkin, "overlay-onion-skin", false);
420     if (pPrefs->GetString("onion-skin-file-name", /*ref*/ tmpStr2))
421         pOnionSkinFileNameText->SetValue(tmpStr2);
422 
423     /*
424      * Add the various components to the master sizer.
425      */
426     masterSizer->Add(displayOptSizer);
427     masterSizer->AddSpacer(kInterSpacing * 2);
428     masterSizer->Add(runtimeOptSizer);
429     masterSizer->AddSpacer(kInterSpacing * 2);
430     masterSizer->Add(onionSkinOptSizer);
431     //masterSizer->AddSpacer(kInterSpacing);
432 
433     /*
434      * I don't see a way to guarantee that the window is wide enough to
435      * show the entire menu bar, so just throw some pixels at it.
436      */
437     wxBoxSizer* minWidthSizer = new wxBoxSizer(wxVERTICAL);
438     minWidthSizer->Add(300, kEdgeSpacing);       // forces minimum width
439     minWidthSizer->Add(masterSizer);
440     minWidthSizer->AddSpacer(kInterSpacing * 2);
441 
442     /* move us a few pixels in from the left */
443     wxBoxSizer* indentSizer = new wxBoxSizer(wxHORIZONTAL);
444     indentSizer->AddSpacer(kEdgeSpacing);
445     indentSizer->Add(minWidthSizer);
446     indentSizer->AddSpacer(kEdgeSpacing);
447 
448     base->SetSizer(indentSizer);
449 
450     indentSizer->Fit(this);
451     indentSizer->SetSizeHints(this);
452 }
453 
454 /*
455  * Set the value of a checkbox based on a value from the config file.
456  */
SetCheckFromPref(wxCheckBox * pControl,const char * prefStr,bool defaultVal)457 void MainFrame::SetCheckFromPref(wxCheckBox* pControl, const char* prefStr,
458     bool defaultVal)
459 {
460     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
461     assert(pPrefs != NULL);
462 
463     bool val = defaultVal;
464     pPrefs->GetBool(prefStr, &val);
465 
466     pControl->SetValue(val);
467 }
468 
469 /*
470  * Destructor.
471  */
~MainFrame(void)472 MainFrame::~MainFrame(void)
473 {
474     PhoneCollection::DestroyInstance();
475 
476     delete mExternalRuntimeThread;
477     delete mPropertyServerThread;
478 
479     // don't touch mpModeSelection -- child of window
480 }
481 
482 /*
483  * File->Quit or click on close box.
484  *
485  * If we want an "are you sure you want to quit" box, add it here.
486  */
OnClose(wxCloseEvent & event)487 void MainFrame::OnClose(wxCloseEvent& event)
488 {
489     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
490 
491 /*
492     if (event.CanVeto())
493         printf("Closing (can veto)\n");
494     else
495         printf("Closing (mandatory)\n");
496 */
497 
498     /*
499      * Generally speaking, Close() is not guaranteed to close the window.
500      * However, we want to use it here because (a) our windows are
501      * guaranteed to close, and (b) it provides our windows an opportunity
502      * to tell others that they are about to vanish.
503      */
504     if (mpPhoneWindow != NULL)
505         mpPhoneWindow->Close(true);
506 
507     /* save position of main window */
508     wxPoint pos = GetPosition();
509     pPrefs->SetInt("window-main-x", pos.x);
510     pPrefs->SetInt("window-main-y", pos.y);
511 
512     /* save default device selection */
513     int idx = GetSelectedDeviceIndex();
514     if (idx >= 0) {
515         PhoneCollection* pCollection = PhoneCollection::GetInstance();
516         PhoneData* pPhoneData = pCollection->GetPhoneData(idx);
517         pPrefs->SetString("default-device", pPhoneData->GetName());
518     }
519 
520     if (mpLogWindow != NULL)
521         mpLogWindow->Close(true);
522     Destroy();
523 }
524 
525 /*
526  * File->Preferences
527  */
OnFilePreferences(wxCommandEvent & WXUNUSED (event))528 void MainFrame::OnFilePreferences(wxCommandEvent& WXUNUSED(event))
529 {
530     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
531     PrefsDialog dialog(this);
532     int result;
533 
534     result = dialog.ShowModal();
535     if (result == wxID_OK) {
536         /*
537          * The dialog handles writing changes to Preferences, so all we
538          * need to deal with here are changes that have an immediate
539          * impact on us. (which is currently nothing)
540          */
541     }
542 }
543 
544 /*
545  * File->Exit
546  */
OnFileExit(wxCommandEvent & WXUNUSED (event))547 void MainFrame::OnFileExit(wxCommandEvent& WXUNUSED(event))
548 {
549     Close(FALSE);       // false means "allow veto"
550 }
551 
552 /*
553  * Decide whether Simulator->Start should be enabled.
554  */
OnUpdateSimStart(wxUpdateUIEvent & event)555 void MainFrame::OnUpdateSimStart(wxUpdateUIEvent& event)
556 {
557     if (IsRuntimeRunning())
558         event.Enable(FALSE);
559     else
560         event.Enable(TRUE);
561 }
562 
563 /*
564  * Simulator->Start
565  */
OnSimStart(wxCommandEvent & WXUNUSED (event))566 void MainFrame::OnSimStart(wxCommandEvent& WXUNUSED(event))
567 {
568     // keyboard equivalents can still get here even if menu item disabled
569     if (IsRuntimeRunning())
570         return;
571 
572     int id = GetSelectedDeviceIndex();
573     if (id < 0) {
574         fprintf(stderr, "Sim: could not identify currently selected device\n");
575         return;
576     }
577 
578 #if 0
579     static int foo = 0;
580     foo++;
581     if (foo == 2) {
582         Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
583 
584         pPrefs->SetBool("debug", true);
585     }
586 #endif
587 
588     SetupPhoneUI(id, NULL);
589     if (mpPhoneWindow != NULL)
590         mpPhoneWindow->GetDeviceManager()->StartRuntime();
591 }
592 
593 /*
594  * Decide whether Simulator->Stop should be enabled.
595  */
OnUpdateSimStop(wxUpdateUIEvent & event)596 void MainFrame::OnUpdateSimStop(wxUpdateUIEvent& event)
597 {
598     if (IsRuntimeRunning())
599         event.Enable(TRUE);
600     else
601         event.Enable(FALSE);
602 }
603 
604 /*
605  * Simulator->Stop
606  */
OnSimStop(wxCommandEvent & WXUNUSED (event))607 void MainFrame::OnSimStop(wxCommandEvent& WXUNUSED(event))
608 {
609     if (!IsRuntimeRunning())
610         return;
611     assert(mpPhoneWindow != NULL);
612     mpPhoneWindow->GetDeviceManager()->StopRuntime();
613 }
614 
615 /*
616  * Decide whether Simulator->Restart should be enabled.
617  */
OnUpdateSimRestart(wxUpdateUIEvent & event)618 void MainFrame::OnUpdateSimRestart(wxUpdateUIEvent& event)
619 {
620     if (IsRuntimeRunning())
621         event.Enable(TRUE);
622     else
623         event.Enable(FALSE);
624 }
625 
626 /*
627  * Simulator->Restart - stop then start the device runtime.
628  */
OnSimRestart(wxCommandEvent & WXUNUSED (event))629 void MainFrame::OnSimRestart(wxCommandEvent& WXUNUSED(event))
630 {
631     if (!IsRuntimeRunning())
632         return;
633 
634     printf("Restart requested\n");
635     mpPhoneWindow->GetDeviceManager()->StopRuntime();
636 
637     mRestartRequested = true;
638 }
639 
640 /*
641  * Decide whether Simulator->Kill should be enabled.
642  */
OnUpdateSimKill(wxUpdateUIEvent & event)643 void MainFrame::OnUpdateSimKill(wxUpdateUIEvent& event)
644 {
645     if (IsRuntimeKillable())
646         event.Enable(TRUE);
647     else
648         event.Enable(FALSE);
649 }
650 
651 /*
652  * Simulator->Kill
653  */
OnSimKill(wxCommandEvent & WXUNUSED (event))654 void MainFrame::OnSimKill(wxCommandEvent& WXUNUSED(event))
655 {
656     if (!IsRuntimeKillable())
657         return;
658     assert(mpPhoneWindow != NULL);
659     mpPhoneWindow->GetDeviceManager()->KillRuntime();
660 }
661 
662 
663 /*
664  * Device->[select]
665  */
OnDeviceSelected(wxCommandEvent & event)666 void MainFrame::OnDeviceSelected(wxCommandEvent& event)
667 {
668     wxBusyCursor busyc;
669     int id = event.GetId() - IDM_DEVICE_SEL0;
670 
671     SetupPhoneUI(id, NULL);
672 }
673 
674 /*
675  * Device->Rescan
676  */
OnDeviceRescan(wxCommandEvent & event)677 void MainFrame::OnDeviceRescan(wxCommandEvent& event)
678 {
679     wxBusyCursor busyc;
680     wxMenuBar* pMenuBar;
681     PhoneCollection* pCollection;
682     wxMenu* pOldMenu;
683     wxMenu* pNewMenu;
684     const char* curDevName = NULL;
685     int idx;
686 
687     /* figure out the current device name */
688     pCollection = PhoneCollection::GetInstance();
689     idx = GetSelectedDeviceIndex();
690     if (idx >= 0) {
691         PhoneData* pPhoneData;
692 
693         pPhoneData = pCollection->GetPhoneData(idx);
694         curDevName = pPhoneData->GetName();
695         printf("--- device name is '%s'\n", (const char*) curDevName);
696     }
697 
698     /* reconstruct device menu with new data */
699 #ifdef BEFORE_ASSET
700     pCollection->ScanForPhones(mSimAssetPath);
701 #else
702     pCollection->ScanForPhones(NULL);
703 #endif
704 
705     pMenuBar = GetMenuBar();
706     idx = pMenuBar->FindMenu(kDeviceMenuString);
707     if (idx == wxNOT_FOUND) {
708         fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii());
709         return;
710     }
711 
712     pNewMenu = CreateDeviceMenu(curDevName);
713 
714     pOldMenu = pMenuBar->Replace(idx, pNewMenu, kDeviceMenuString);
715     delete pOldMenu;
716 
717     /* tell the PhoneWindow about it; may cause runtime to exit */
718     if (mpPhoneWindow != NULL)
719         mpPhoneWindow->DevicesRescanned();
720 }
721 
722 /*
723  * Set checkbox on menu item.
724  */
OnUpdateDebugShowLog(wxUpdateUIEvent & event)725 void MainFrame::OnUpdateDebugShowLog(wxUpdateUIEvent& event)
726 {
727     if (mpLogWindow == NULL) {
728         event.Enable(false);
729     } else {
730         event.Enable(true);
731         event.Check(mpLogWindow->IsShown());
732     }
733 }
734 
735 /*
736  * Debug->ShowLog toggle.
737  */
OnDebugShowLog(wxCommandEvent & WXUNUSED (event))738 void MainFrame::OnDebugShowLog(wxCommandEvent& WXUNUSED(event))
739 {
740     mpLogWindow->Show(!mpLogWindow->IsShown());
741 }
742 
743 /*
744  * Help->Contents
745  */
OnHelpContents(wxCommandEvent & WXUNUSED (event))746 void MainFrame::OnHelpContents(wxCommandEvent& WXUNUSED(event))
747 {
748     ((MyApp*)wxTheApp)->GetHelpController()->DisplayContents();
749 }
750 
751 /*
752  * Help->About
753  */
OnHelpAbout(wxCommandEvent & WXUNUSED (event))754 void MainFrame::OnHelpAbout(wxCommandEvent& WXUNUSED(event))
755 {
756     wxMessageBox(wxT("Android Simulator v0.1\n"
757                      "Copyright 2006 The Android Open Source Project"),
758         wxT("About..."), wxOK | wxICON_INFORMATION, this);
759 }
760 
761 /*
762  * Sent from phonewindow or when activated
763  */
OnActivate(wxActivateEvent & event)764 void MainFrame::OnActivate(wxActivateEvent& event)
765 {
766 #if 0
767     if (event.GetActive())
768     {
769         if (mpPhoneWindow != NULL &&
770             mpPhoneWindow->GetDeviceManager()->RefreshRuntime())
771         {
772             wxString msg;
773             int sel;
774 
775             msg = wxT("Newer runtime executable found. Would you like to reload the device?");
776 
777             sel = wxMessageBox(msg, wxT("Android Safety Patrol"),
778                 wxYES | wxNO | wxICON_QUESTION, mpPhoneWindow);
779             //printf("BUTTON was %d (yes=%d)\n", sel, wxYES);
780             if (sel == wxYES)
781             {
782                 mpPhoneWindow->GetDeviceManager()->StopRuntime();
783                 mpPhoneWindow->Close();
784                 mpPhoneWindow = NULL;
785                 mRestartRequested = true;
786             }
787             else
788             {
789                 mpPhoneWindow->GetDeviceManager()->UserCancelledRefresh();
790             }
791         }
792     }
793 #endif
794 
795     // let wxWidgets do whatever it needs to do
796     event.Skip();
797 }
798 
799 
800 /*
801  * Device mode selection box.
802  */
OnComboBox(wxCommandEvent & event)803 void MainFrame::OnComboBox(wxCommandEvent& event)
804 {
805     const char* pref;
806     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
807     assert(pPrefs != NULL);
808 
809     if (IDC_MODE_SELECT == event.GetId())
810     {
811         int id = GetSelectedDeviceIndex();
812         if (id < 0)
813             return;
814         //printf("--- mode selected: '%s'\n", (const char*) event.GetString().ToAscii());
815 
816         /*
817          * Call the phone window's setup function.  Don't call our SetupPhoneUI
818          * function from here -- updating the combo box from a combo box callback
819          * could cause problems.
820          */
821         if (mpPhoneWindow != NULL) {
822             mpPhoneWindow->SetCurrentMode(event.GetString());
823             mpPhoneWindow->Setup(id);
824         }
825     } else if (event.GetId() == IDC_JAVA_VM) {
826         wxComboBox* pBox = (wxComboBox*) FindWindow(IDC_JAVA_VM);
827         pPrefs->SetString("java-vm", pBox->GetValue().ToAscii());
828     }
829 }
830 
831 /*
832  * One of our option checkboxes has been changed.
833  *
834  * We update the prefs database so that the settings are retained when
835  * the simulator is next used.
836  */
OnCheckBox(wxCommandEvent & event)837 void MainFrame::OnCheckBox(wxCommandEvent& event)
838 {
839     const char* pref;
840 
841     switch (event.GetId()) {
842     case IDC_USE_GDB:               pref = "debug";                 break;
843     case IDC_USE_VALGRIND:          pref = "valgrind";              break;
844     case IDC_CHECK_JNI:             pref = "check-jni";             break;
845     case IDC_OVERLAY_ONION_SKIN:    pref = "overlay-onion-skin";    break;
846     default:
847         printf("Sim: unrecognized checkbox %d in OnCheckBox\n", event.GetId());
848         return;
849     }
850 
851     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
852     assert(pPrefs != NULL);
853 
854     pPrefs->SetBool(pref, (bool) event.GetInt());
855     //printf("--- set pref '%s' to %d\n", pref, (bool) event.GetInt());
856     if (event.GetId() == IDC_OVERLAY_ONION_SKIN) {
857         BroadcastOnionSkinUpdate();
858     }
859     if (event.GetId() == IDC_CHECK_JNI) {
860         const char* val = "0";
861         if ((bool) event.GetInt())
862             val = "1";
863         mPropertyServerThread->SetProperty(PropertyServer::kPropCheckJni, val);
864 
865     }
866 }
867 
BroadcastOnionSkinUpdate()868 void MainFrame::BroadcastOnionSkinUpdate() {
869     if (mpPhoneWindow != NULL) {
870         // broadcast a user event indicating an onion skin update
871         UserEvent uev(0, (void*) -1);
872         mpPhoneWindow->GetDeviceManager()->BroadcastEvent(uev);
873     }
874 }
875 
876 /*
877  * A text control on the main page is being updated.
878  *
879  * The current implementation updates the preferences database on every
880  * change, which is a bit silly but is easy to do.
881  */
OnText(wxCommandEvent & event)882 void MainFrame::OnText(wxCommandEvent& event)
883 {
884     const char* pref;
885 
886     switch (event.GetId()) {
887     case IDC_JAVA_APP_NAME:     pref = "java-app-name"; break;
888     default:
889         printf("Sim: unrecognized textctrl %d in OnText\n", event.GetId());
890         return;
891     }
892 
893     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
894     assert(pPrefs != NULL);
895 
896     // event.GetString() does not work on Mac -- always blank
897     //pPrefs->SetString(pref, event.GetString());
898     assert(event.GetId() == IDC_JAVA_APP_NAME); // fix if we add more
899     wxComboBox* pBox;
900     pBox = (wxComboBox*) FindWindow(IDC_JAVA_APP_NAME);
901     pPrefs->SetString(pref, pBox->GetValue().ToAscii());
902     //printf("--- set pref '%s' to '%s'\n", pref,(const char*)pBox->GetValue());
903 }
904 
905 /*
906  * A user pressed enter in a text control on the main page.
907  *
908  * The current implementation updates the preferences database on every
909  * change, which is a bit silly but is easy to do.
910  */
OnTextEnter(wxCommandEvent & event)911 void MainFrame::OnTextEnter(wxCommandEvent& event)
912 {
913     const char* pref;
914 
915     switch (event.GetId()) {
916     case IDC_ONION_SKIN_FILE_NAME:
917         pref = "onion-skin-file-name";
918         break;
919     default:
920         printf("Sim: unrecognized textctrl %d in OnTextEnter\n", event.GetId());
921         return;
922     }
923 
924     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
925     assert(pPrefs != NULL);
926 
927     assert(event.GetId() == IDC_ONION_SKIN_FILE_NAME); // fix if we add more
928     wxTextCtrl* pTextCtrl;
929     pTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME);
930     wxString onionSkinFileNameWxString = pTextCtrl->GetValue();
931     char* onionSkinFileName = "";
932     if (onionSkinFileNameWxString.Len() > 0) {
933         onionSkinFileName = android::strdupNew(onionSkinFileNameWxString.ToAscii());
934     }
935     pPrefs->SetString(pref, onionSkinFileName);
936     BroadcastOnionSkinUpdate();
937 }
938 
939 /*
940  * A user pressed a button on the main page
941  *
942  */
OnButton(wxCommandEvent & event)943  void MainFrame::OnButton(wxCommandEvent& event)
944  {
945     wxWindow* base;
946     wxFileDialog* pOnionSkinFileChooser;
947     int retVal;
948     switch (event.GetId()) {
949     case IDC_ONION_SKIN_BUTTON:
950         base = FindWindow(IDC_ONION_SKIN_BUTTON)->GetParent();
951         pOnionSkinFileChooser = new wxFileDialog(base,
952             wxT("Choose the onion skin image file."),
953             wxT(""), wxT(""), wxT("*.*"),
954             wxOPEN | wxFILE_MUST_EXIST);
955         retVal = pOnionSkinFileChooser->ShowModal();
956         if (retVal == pOnionSkinFileChooser->GetAffirmativeId()) {
957             Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
958             assert(pPrefs != NULL);
959             wxString fileNameWxString = pOnionSkinFileChooser->GetPath();
960             const char* fileName = android::strdupNew(fileNameWxString.ToAscii());
961             wxTextCtrl* fileTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME);
962             fileTextCtrl->SetValue(fileNameWxString);
963             pPrefs->SetString("onion-skin-file-name", fileName);
964             BroadcastOnionSkinUpdate();
965         }
966         break;
967     default:
968         printf("Sim: unrecognized button %d in OnButton\n", event.GetId());
969         return;
970     }
971  }
972 
973  /*
974   * The user moved a slider on the main page
975   */
OnSliderChange(wxScrollEvent & event)976  void MainFrame::OnSliderChange(wxScrollEvent& event)
977  {
978     wxSlider* pSlider;
979     Preferences* pPrefs;
980     switch (event.GetId()) {
981     case IDC_ONION_SKIN_ALPHA_VAL:
982         pSlider = (wxSlider*) FindWindow(IDC_ONION_SKIN_ALPHA_VAL);
983         pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
984         assert(pPrefs != NULL);
985         pPrefs->SetInt("onion-skin-alpha-value", pSlider->GetValue());
986         BroadcastOnionSkinUpdate();
987         break;
988     default:
989         printf("Sim: unrecognized scroller or slider %d in OnSliderChange\n", event.GetId());
990         return;
991     }
992  }
993 
994 #if 0
995 /*
996  * Idle processing.  Under wxWidgets this only called once after UI
997  * activity unless you call event.RequestMore().
998  */
999 void MainFrame::OnIdle(wxIdleEvent& event)
1000 {
1001     event.Skip();       // let base class handler do stuff
1002 }
1003 #endif
1004 
1005 /*
1006  * Handle the timer.
1007  *
1008  * This is being called in the main thread, so multithreading with the
1009  * rest of MainFrame isn't a concern here.
1010  */
OnTimer(wxTimerEvent & event)1011 void MainFrame::OnTimer(wxTimerEvent& event)
1012 {
1013     bool status;
1014 
1015     /*
1016      * Check to see if the runtime died without telling us.  This can only
1017      * happen if we forcibly kill our thread.  We shouldn't really be
1018      * doing that anymore, but keep this in for now just in case.
1019      */
1020     status = IsRuntimeRunning();
1021 
1022     if (mSimRunning != status) {
1023         if (!status) {
1024             printf("Sim: fixed mSimRunning=%d actual=%d\n",
1025                 mSimRunning, status);
1026             mSimRunning = status;
1027 
1028             if (!status)
1029                 HandleRuntimeStop();
1030         } else {
1031             /*
1032              * This was happening when we were shutting down but the
1033              * device management thread hadn't completely gone away.  The
1034              * simple IsRunning test passes, so we get a false positive.
1035              * Ignore it.
1036              */
1037         }
1038     }
1039 
1040     if (gWantToKill) {
1041         if (IsRuntimeRunning()) {
1042             printf("Sim: handling kill request\n");
1043             mpPhoneWindow->GetDeviceManager()->KillRuntime();
1044         }
1045         gWantToKill = false;
1046 
1047         /* see if Ctrl-C should kill us too */
1048         Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
1049         bool die = false;
1050 
1051         pPrefs->GetBool("trap-sigint-suicide", &die);
1052         if (die) {
1053             printf("Sim: goodbye cruel world!\n");
1054             exit(0);
1055         }
1056     }
1057 }
1058 
1059 /*
1060  * Determine whether or not the simulator is running.
1061  */
IsRuntimeRunning(void)1062 bool MainFrame::IsRuntimeRunning(void)
1063 {
1064     bool result;
1065 
1066     if (mpPhoneWindow == NULL)
1067         result = false;
1068     else if (!mpPhoneWindow->IsReady())
1069         result = false;
1070     else
1071         result = mpPhoneWindow->GetDeviceManager()->IsRunning();
1072 
1073     return result;
1074 }
1075 
1076 /*
1077  * Determine whether or not the runtime can be killed.
1078  */
IsRuntimeKillable(void)1079 bool MainFrame::IsRuntimeKillable(void)
1080 {
1081     bool result;
1082 
1083     result = IsRuntimeRunning();
1084     if (result)
1085         result = mpPhoneWindow->GetDeviceManager()->IsKillable();
1086 
1087     return result;
1088 }
1089 
1090 /*
1091  * Determine whether two devices are sufficiently compatible.
1092  */
CompatibleDevices(PhoneData * pData1,PhoneData * pData2)1093 bool MainFrame::CompatibleDevices(PhoneData* pData1, PhoneData* pData2)
1094 {
1095     int displayCount;
1096 
1097     displayCount = pData1->GetNumDisplays();
1098     if (pData2->GetNumDisplays() != displayCount)
1099         return false;
1100 
1101     for (int i = 0; i < displayCount; i++) {
1102         PhoneDisplay* pDisplay1 = pData1->GetPhoneDisplay(i);
1103         PhoneDisplay* pDisplay2 = pData2->GetPhoneDisplay(i);
1104 
1105         if (!PhoneDisplay::IsCompatible(pDisplay1, pDisplay2))
1106             return false;
1107     }
1108 
1109     return true;
1110 }
1111 
1112 /*
1113  * (Re-)arrange the UI for the currently selected phone model.
1114  *
1115  * If the simulator is running, and the set of displays for the current
1116  * device are incompatible with the new device, we need to restart the
1117  * runtime.  We need to ask for permission first though.
1118  */
SetupPhoneUI(int idx,const char * defaultMode)1119 void MainFrame::SetupPhoneUI(int idx, const char* defaultMode)
1120 {
1121     PhoneCollection* pCollection;
1122     PhoneData* pPhoneData;
1123     wxString* choices = NULL;
1124     int numChoices = 0;
1125     int numKeyboards = 0;
1126     bool haveDefaultMode = false;
1127     wxCharBuffer currentMode;
1128     int i;
1129 
1130     pCollection = PhoneCollection::GetInstance();
1131     pPhoneData = pCollection->GetPhoneData(idx);
1132     if (pPhoneData == NULL) {
1133         fprintf(stderr, "ERROR: device index %d not valid\n", idx);
1134         goto bail;
1135     }
1136 
1137     /*
1138      * We have a window up.  If the displays aren't compatible, we'll
1139      * need to recreate it.
1140      */
1141     if (mpPhoneWindow != NULL) {
1142         PhoneData* pCurData = mpPhoneWindow->GetPhoneData();
1143 
1144         if (!CompatibleDevices(pCurData, pPhoneData)) {
1145             /*
1146              * We need to trash the window.  This will also kill the
1147              * runtime.  If it's running, ask permission.
1148              */
1149             if (IsRuntimeRunning()) {
1150                 wxString msg;
1151                 int sel;
1152 
1153                 msg =  wxT("Switching to the new device requires restarting the");
1154                 msg += wxT(" runtime.  Continue?");
1155 
1156                 sel = wxMessageBox(msg, wxT("Android Safety Patrol"),
1157                     wxOK | wxCANCEL | wxICON_QUESTION, this);
1158                 printf("BUTTON was %d (ok=%d)\n", sel, wxOK);
1159                 if (sel == wxCANCEL)
1160                     goto bail;
1161 
1162                 /* shut it down (politely), ask for an eventual restart */
1163                 mpPhoneWindow->GetDeviceManager()->StopRuntime();
1164                 mpPhoneWindow->Close();
1165                 mpPhoneWindow = NULL;
1166                 mRestartRequested = true;
1167                 goto bail;
1168             } else {
1169                 /* not running, just trash the window and continue */
1170                 mpPhoneWindow->Close();
1171                 mpPhoneWindow = NULL;
1172             }
1173         }
1174     }
1175 
1176     /*
1177      * Figure out the set of available modes.
1178      */
1179 
1180     numChoices = pPhoneData->GetNumModes();
1181     if (numChoices > 0) {
1182         choices = new wxString[numChoices];
1183         for (i = 0; i < numChoices; i++) {
1184             PhoneMode* pPhoneMode;
1185             pPhoneMode = pPhoneData->GetPhoneMode(i);
1186             choices[i] = wxString::FromAscii(pPhoneMode->GetName());
1187             if (defaultMode != NULL &&
1188                 strcmp(defaultMode, pPhoneMode->GetName()) == 0)
1189             {
1190                 haveDefaultMode = true;
1191             }
1192         }
1193     }
1194 
1195     if (choices == NULL) {
1196         /* had a failure earlier; configure UI with default stuff */
1197         choices = new wxString[1];
1198         choices[0] = wxT("(none)");
1199     }
1200 
1201     if (!haveDefaultMode) {
1202         /*
1203          * Default mode wasn't found.  If we specify it as the default
1204          * in the wxComboBox create call it shows up in the combo box
1205          * under Linux, even if it doesn't exist in the list.  So, we
1206          * make sure that it doesn't get used if we can't find it.
1207          */
1208         if (defaultMode != NULL) {
1209             printf("Sim: HEY: default mode '%s' not found in list\n",
1210                 defaultMode);
1211         }
1212         currentMode = choices[0].ToAscii();
1213     } else {
1214         currentMode = defaultMode;
1215     }
1216 
1217 
1218     /*
1219      * Create the window if necessary.
1220      */
1221     if (mpPhoneWindow == NULL) {
1222         // create, setup, and then show window
1223         mpPhoneWindow = new PhoneWindow(this, mPhoneWindowPosn);
1224         mpPhoneWindow->SetCurrentMode((const char*)currentMode);
1225         if (!mpPhoneWindow->Setup(idx)) {
1226             delete mpPhoneWindow;
1227             mpPhoneWindow = NULL;
1228         }
1229         if (mpPhoneWindow != NULL) {
1230             mpPhoneWindow->Show();
1231             //mpPhoneWindow->CheckPlacement();
1232         }
1233     } else {
1234         // just set up for new device
1235         mpPhoneWindow->SetCurrentMode((const char*)currentMode);
1236         if (!mpPhoneWindow->Setup(idx)) {
1237             // it's in an uncertain state, blow it away
1238             delete mpPhoneWindow;
1239             mpPhoneWindow = NULL;
1240         }
1241     }
1242 
1243     /*
1244      * Reconfigure mode selection box.
1245      */
1246     wxComboBox* pModeSelection;
1247     pModeSelection = (wxComboBox*)FindWindow(IDC_MODE_SELECT);
1248     pModeSelection->Clear();
1249     for (i = 0; i < numChoices; i++)
1250         pModeSelection->Append(choices[i]);
1251     pModeSelection->SetSelection(0);
1252     pModeSelection->Enable(numChoices > 1);
1253 
1254     /*
1255      * configure qwerty keyboard attribute
1256      */
1257     numKeyboards = pPhoneData->GetNumKeyboards();
1258     if (numKeyboards > 0) {
1259         // only use the first keyboard for now
1260         PhoneKeyboard* pPhoneKeyboard;
1261         pPhoneKeyboard = pPhoneData->GetPhoneKeyboard(0);
1262         if (pPhoneKeyboard->getQwerty()) {
1263             printf("Sim: set 'qwerty' env\n");
1264             setenv("qwerty", "true", true);
1265         }
1266     }
1267 
1268 bail:
1269     delete[] choices;
1270 }
1271 
1272 /*
1273  * Figure out which device is currently selected.
1274  *
1275  * The easiest way to do this is just run down the list of possible IDs
1276  * and stop when something claims to be checked.
1277  *
1278  * Returns -1 if it can't find a checked item (which can happen if no
1279  * device layouts were found).
1280  */
GetSelectedDeviceIndex(void)1281 int MainFrame::GetSelectedDeviceIndex(void)
1282 {
1283     wxMenuBar* pMenuBar;
1284     wxMenu* pMenu;
1285     int idx;
1286 
1287     pMenuBar = GetMenuBar();
1288     idx = pMenuBar->FindMenu(kDeviceMenuString);
1289     if (idx == wxNOT_FOUND) {
1290         fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii());
1291         return -1;
1292     }
1293 
1294     pMenu = pMenuBar->GetMenu(idx);
1295 
1296     //printf("Menu.MenuItemCount = %d\n", pMenu->GetMenuItemCount());
1297     for (int j = pMenu->GetMenuItemCount() -1; j >= 0; j--) {
1298         wxMenuItem* pItem;
1299 
1300         pItem = pMenu->FindItemByPosition(j);
1301         //printf("ITEM %d: %s\n", j, (const char*) pItem->GetLabel());
1302         if (pItem->IsChecked()) {
1303             printf("Sim: selected device is '%s'\n",
1304                 (const char*) pItem->GetLabel().ToAscii());
1305             return j;
1306         }
1307     }
1308 
1309     return -1;
1310 }
1311 
1312 /*
1313  * Receive a status message from the runtime thread.
1314  */
OnUserEvent(UserEvent & event)1315 void MainFrame::OnUserEvent(UserEvent& event)
1316 {
1317     UserEventMessage* pUem;
1318 
1319     pUem = (UserEventMessage*) event.GetData();
1320     assert(pUem != NULL);
1321 
1322     switch (pUem->GetType()) {
1323     case UserEventMessage::kRuntimeStarted:
1324         printf("Sim: runtime thread started!\n");
1325         HandleRuntimeStart();
1326         break;
1327     case UserEventMessage::kRuntimeStopped:
1328         printf("Sim: runtime thread stopped!\n");
1329         HandleRuntimeStop();
1330         break;
1331     case UserEventMessage::kErrorMessage:
1332         {
1333             wxString msg = pUem->GetString();
1334             wxMessageBox(msg, wxT("Android Runtime Error"),
1335                 wxOK | wxICON_WARNING, this);
1336         }
1337         break;
1338     case UserEventMessage::kLogMessage:
1339         mpLogWindow->AddLogMessage(pUem->GetLogMessage());
1340         break;
1341     case UserEventMessage::kExternalRuntime:
1342         HandleExternalRuntime(pUem->GetReader(), pUem->GetWriter());
1343         break;
1344     default:
1345         printf("Sim: MESSAGE: unknown UserEventMessage rcvd (type=%d)\n",
1346             pUem->GetType());
1347         break;
1348     }
1349 
1350     delete pUem;
1351 }
1352 
1353 /*
1354  * The device management thread is up, so the runtime should be fully
1355  * running shortly.
1356  */
HandleRuntimeStart(void)1357 void MainFrame::HandleRuntimeStart(void)
1358 {
1359     mSimRunning = true;
1360 
1361     SetStatusText(kStatusRunning, 1);
1362 }
1363 
1364 /*
1365  * The device management thread is exiting, so the runtime must be dead.
1366  */
HandleRuntimeStop(void)1367 void MainFrame::HandleRuntimeStop(void)
1368 {
1369     mSimRunning = false;
1370 
1371     SetStatusText(kStatusNotRunning, 1);
1372 
1373     if (mRestartRequested) {
1374         printf("Sim: restarting runtime\n");
1375         mRestartRequested = false;
1376         SetupPhoneUI(GetSelectedDeviceIndex(), NULL);
1377         if (mpPhoneWindow != NULL)
1378             mpPhoneWindow->GetDeviceManager()->StartRuntime();
1379     }
1380 }
1381 
1382 /*
1383  * Handle a connection from an external runtime.
1384  */
HandleExternalRuntime(android::Pipe * reader,android::Pipe * writer)1385 void MainFrame::HandleExternalRuntime(android::Pipe* reader,
1386     android::Pipe* writer)
1387 {
1388     android::MessageStream msgStream;
1389     android::Message msg;
1390 
1391     if (IsRuntimeRunning()) {
1392         /*
1393          * Tell the new guy to go away.
1394          */
1395         if (!msgStream.init(reader, writer, true)) {
1396             fprintf(stderr, "Sim: WARNING: unable to talk to remote runtime\n");
1397             goto bail;
1398         }
1399 
1400         printf("Sim: telling external runtime to go away\n");
1401         msg.setCommand(android::Simulator::kCommandGoAway, 0);
1402         msgStream.send(&msg);
1403     } else {
1404         printf("Sim: new external runtime wants to talk to us\n");
1405 
1406         /*
1407          * Launch the pieces necessary to talk to this guy.
1408          */
1409         int id = GetSelectedDeviceIndex();
1410         if (id < 0) {
1411             fprintf(stderr,
1412                 "Sim: could not identify currently selected device\n");
1413             goto bail;
1414         }
1415 
1416         /* kill existing window, so it pops up and reclaims focus */
1417         if (mpPhoneWindow != NULL) {
1418             Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
1419             bool okay;
1420 
1421             if (pPrefs->GetBool("refocus-on-restart", &okay) && okay) {
1422                 printf("Sim: inducing phone window refocus\n");
1423                 mpPhoneWindow->Close(TRUE);     // no veto
1424                 mpPhoneWindow = NULL;
1425             }
1426         }
1427 
1428         SetupPhoneUI(id, NULL);
1429         if (mpPhoneWindow != NULL) {
1430             mpPhoneWindow->GetDeviceManager()->StartRuntime(reader, writer);
1431         } else {
1432             fprintf(stderr, "Sim: ERROR: unable to get runtime going\n");
1433             goto bail;
1434         }
1435 
1436         // we don't own these anymore
1437         reader = writer = NULL;
1438     }
1439 
1440 bail:
1441     delete reader;
1442     delete writer;
1443 }
1444 
1445 /*
1446  * The phone window is about to destroy itself.  Get rid of our pointer
1447  * to it, and record its last position so we can create the new one in
1448  * the same place.
1449  */
PhoneWindowClosing(int x,int y)1450 void MainFrame::PhoneWindowClosing(int x, int y)
1451 {
1452     Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
1453 
1454     mpPhoneWindow = NULL;
1455 
1456     mPhoneWindowPosn.x = x;
1457     mPhoneWindowPosn.y = y;
1458 
1459     pPrefs->SetInt("window-device-x", x);
1460     pPrefs->SetInt("window-device-y", y);
1461 }
1462 
1463