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