| // |
| // Copyright 2005 The Android Open Source Project |
| // |
| // Main window, menu bar, and associated goodies. |
| // |
| |
| // For compilers that support precompilation, include "wx/wx.h". |
| #include "wx/wxprec.h" |
| |
| // Otherwise, include all standard headers |
| #ifndef WX_PRECOMP |
| # include "wx/wx.h" |
| #endif |
| #include "wx/button.h" |
| #include "wx/help.h" |
| #include "wx/filedlg.h" |
| #include "wx/slider.h" |
| #include "wx/textctrl.h" |
| |
| #include "MainFrame.h" |
| #include "MyApp.h" |
| #include "Resource.h" |
| #include "PhoneCollection.h" |
| #include "PhoneData.h" |
| #include "PhoneWindow.h" |
| #include "DeviceWindow.h" |
| #include "UserEventMessage.h" |
| #include "PrefsDialog.h" |
| |
| #include "SimRuntime.h" |
| |
| |
| static wxString kStatusNotRunning = wxT("Idle"); |
| static wxString kStatusRunning = wxT("Run"); |
| |
| static wxString kDeviceMenuString = wxT("&Device"); |
| |
| static const wxString gStdJavaApps[] = { |
| wxT(""), |
| wxT("com.android.testharness.TestList"), |
| wxT("com.android.apps.contacts.ContactsList"), |
| wxT("mikeapp") |
| }; |
| |
| |
| BEGIN_EVENT_TABLE(MainFrame::MainFrame, wxFrame) |
| EVT_CLOSE(MainFrame::OnClose) |
| EVT_TIMER(kHalfSecondTimerId, MainFrame::OnTimer) |
| //EVT_IDLE(MainFrame::OnIdle) |
| |
| EVT_ACTIVATE(MainFrame::OnActivate) |
| EVT_ACTIVATE_APP(MainFrame::OnActivate) |
| EVT_COMBOBOX(IDC_MODE_SELECT, MainFrame::OnComboBox) |
| EVT_COMBOBOX(IDC_JAVA_VM, MainFrame::OnComboBox) |
| EVT_CHECKBOX(IDC_USE_GDB, MainFrame::OnCheckBox) |
| EVT_CHECKBOX(IDC_USE_VALGRIND, MainFrame::OnCheckBox) |
| EVT_CHECKBOX(IDC_CHECK_JNI, MainFrame::OnCheckBox) |
| EVT_CHECKBOX(IDC_OVERLAY_ONION_SKIN, MainFrame::OnCheckBox) |
| EVT_TEXT(IDC_JAVA_APP_NAME, MainFrame::OnText) |
| EVT_TEXT_ENTER(IDC_ONION_SKIN_FILE_NAME, MainFrame::OnTextEnter) |
| EVT_BUTTON(IDC_ONION_SKIN_BUTTON, MainFrame::OnButton) |
| EVT_COMMAND_SCROLL(IDC_ONION_SKIN_ALPHA_VAL, MainFrame::OnSliderChange) |
| |
| EVT_MENU(IDM_FILE_PREFERENCES, MainFrame::OnFilePreferences) |
| EVT_MENU(IDM_FILE_EXIT, MainFrame::OnFileExit) |
| EVT_MENU(IDM_RUNTIME_START, MainFrame::OnSimStart) |
| EVT_UPDATE_UI(IDM_RUNTIME_START, MainFrame::OnUpdateSimStart) |
| EVT_MENU(IDM_RUNTIME_STOP, MainFrame::OnSimStop) |
| EVT_UPDATE_UI(IDM_RUNTIME_STOP, MainFrame::OnUpdateSimStop) |
| EVT_MENU(IDM_RUNTIME_RESTART, MainFrame::OnSimRestart) |
| EVT_UPDATE_UI(IDM_RUNTIME_RESTART, MainFrame::OnUpdateSimRestart) |
| EVT_MENU(IDM_RUNTIME_KILL, MainFrame::OnSimKill) |
| EVT_UPDATE_UI(IDM_RUNTIME_KILL, MainFrame::OnUpdateSimKill) |
| EVT_MENU_RANGE(IDM_DEVICE_SEL0, IDM_DEVICE_SELN, |
| MainFrame::OnDeviceSelected) |
| EVT_MENU(IDM_DEVICE_RESCAN, MainFrame::OnDeviceRescan) |
| EVT_UPDATE_UI(IDM_DEBUG_SHOW_LOG, MainFrame::OnUpdateDebugShowLog) |
| EVT_MENU(IDM_DEBUG_SHOW_LOG, MainFrame::OnDebugShowLog) |
| EVT_MENU(IDM_HELP_CONTENTS, MainFrame::OnHelpContents) |
| EVT_MENU(IDM_HELP_ABOUT, MainFrame::OnHelpAbout) |
| |
| EVT_USER_EVENT(MainFrame::OnUserEvent) |
| END_EVENT_TABLE() |
| |
| |
| /* |
| * Main window constructor. |
| * |
| * Creates menus and status bar. |
| */ |
| MainFrame::MainFrame(const wxString& title, const wxPoint& pos, |
| const wxSize& size, long style) |
| : wxFrame((wxFrame *)NULL, -1, title, pos, size, style), |
| mSimRunning(false), |
| mRestartRequested(false), |
| mpPhoneWindow(NULL), |
| mPhoneWindowPosn(wxDefaultPosition), |
| mTimer(this, kHalfSecondTimerId) |
| { |
| mSimAssetPath = ((MyApp*)wxTheApp)->GetSimAssetPath(); |
| mSimAssetPath += wxT("/simulator/default/default"); |
| |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| int val; |
| |
| val = mPhoneWindowPosn.x; |
| pPrefs->GetInt("window-device-x", &val); |
| mPhoneWindowPosn.x = val; |
| val = mPhoneWindowPosn.y; |
| pPrefs->GetInt("window-device-y", &val); |
| mPhoneWindowPosn.y = val; |
| |
| /* |
| * Create main menu. |
| */ |
| ConstructMenu(); |
| |
| /* |
| * Create the status bar. |
| */ |
| int widths[2] = { -1, 50 }; |
| CreateStatusBar(2, wxFULL_REPAINT_ON_RESIZE); // no wxST_SIZEGRIP |
| SetStatusWidths(2, widths); |
| SetStatusText(wxT("Ready")); |
| SetStatusText(kStatusNotRunning, 1); |
| |
| /* |
| * Create main window controls. |
| */ |
| ConstructControls(); |
| |
| #if 0 |
| /* |
| * Use the standard window color for the main frame (which usually |
| * has a darker color). This has a dramatic effect under Windows. |
| */ |
| wxColour color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); |
| SetOwnBackgroundColour(color); |
| #endif |
| |
| /* |
| * Create the log window. |
| */ |
| wxRect layout = LogWindow::GetPrefWindowRect(); |
| mpLogWindow = new LogWindow(this); |
| mpLogWindow->Move(layout.GetTopLeft()); |
| mpLogWindow->SetSize(layout.GetSize()); |
| bool showLogWindow = true; |
| pPrefs->GetBool("window-log-show", &showLogWindow); |
| if (showLogWindow) |
| mpLogWindow->Show(); |
| |
| /* |
| * Set up a frequent timer. We use this to keep our "run/idle" |
| * display up to date. (Ideally this will go away.) |
| */ |
| mTimer.Start(400); // arg is delay in ms |
| |
| /* |
| * Handle auto-power-on by sending ourselves an event. That way it |
| * gets handled after window initialization finishes. |
| */ |
| bool autoPowerOn = false; |
| pPrefs->GetBool("auto-power-on", &autoPowerOn); |
| if (autoPowerOn) { |
| printf("Sim: Auto power-up\n"); |
| wxCommandEvent startEvent(wxEVT_COMMAND_MENU_SELECTED, IDM_RUNTIME_START); |
| this->AddPendingEvent(startEvent); |
| } |
| |
| /* |
| * wxThread wants these to be on the heap -- it will call delete on the |
| * object when the thread exits. |
| */ |
| mExternalRuntimeThread = new ExternalRuntime(); |
| mExternalRuntimeThread->StartThread(); |
| mPropertyServerThread = new PropertyServer(); |
| mPropertyServerThread->StartThread(); |
| } |
| |
| /* |
| * Construct the main menu. Called from the constructor. |
| */ |
| void MainFrame::ConstructMenu(void) |
| { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| |
| /* |
| * Scan for available phones. |
| */ |
| PhoneCollection* pCollection = PhoneCollection::GetInstance(); |
| pCollection->ScanForPhones(mSimAssetPath.ToAscii()); |
| |
| /* |
| * Create the "File" menu. |
| */ |
| wxMenu* menuFile = new wxMenu; |
| |
| menuFile->Append(IDM_FILE_PREFERENCES, wxT("&Preferences..."), |
| wxT("Edit simulator preferences")); |
| menuFile->AppendSeparator(); |
| menuFile->Append(IDM_FILE_EXIT, wxT("E&xit\tCtrl-Q"), |
| wxT("Stop simulator and exit")); |
| |
| /* |
| * Create the "Runtime" menu. |
| */ |
| wxMenu* menuRuntime = new wxMenu; |
| menuRuntime->Append(IDM_RUNTIME_START, wxT("&Power On\tCtrl-G"), |
| wxT("Start the device")); |
| // menuRuntime->Append(IDM_RUNTIME_STOP, wxT("Power &Off"), |
| // wxT("Stop the device")); |
| menuRuntime->AppendSeparator(); |
| // menuRuntime->Append(IDM_RUNTIME_RESTART, wxT("&Restart"), |
| // wxT("Restart the device")); |
| menuRuntime->Append(IDM_RUNTIME_KILL, wxT("&Kill\tCtrl-K"), |
| wxT("Kill the runtime processes")); |
| |
| /* |
| * Create "Device" menu. |
| */ |
| wxString defaultDevice = wxT("Sooner"); |
| pPrefs->GetString("default-device", /*ref*/ defaultDevice); |
| wxMenu* menuDevice = CreateDeviceMenu(defaultDevice.ToAscii()); |
| |
| /* |
| * Create "Debug" menu. |
| */ |
| wxMenu* menuDebug = new wxMenu; |
| menuDebug->AppendCheckItem(IDM_DEBUG_SHOW_LOG, wxT("View &Log Output"), |
| wxT("View log output window")); |
| |
| /* |
| * Create the "Help" menu. |
| */ |
| wxMenu* menuHelp = new wxMenu; |
| menuHelp->Append(IDM_HELP_CONTENTS, wxT("&Contents...\tF1"), |
| wxT("Simulator help")); |
| menuHelp->AppendSeparator(); |
| menuHelp->Append(IDM_HELP_ABOUT, wxT("&About..."), |
| wxT("See the fabulous 'about' box")); |
| |
| /* |
| * Create the menu bar. |
| */ |
| wxMenuBar *menuBar = new wxMenuBar; |
| menuBar->Append(menuFile, wxT("&File")); |
| menuBar->Append(menuDevice, kDeviceMenuString); |
| menuBar->Append(menuRuntime, wxT("&Runtime")); |
| menuBar->Append(menuDebug, wxT("&Debug")); |
| menuBar->Append(menuHelp, wxT("&Help")); |
| |
| SetMenuBar(menuBar); |
| |
| } |
| |
| /* |
| * Construct the "device" menu from our phone collection. |
| */ |
| wxMenu* MainFrame::CreateDeviceMenu(const char* defaultItemName) |
| { |
| wxMenu* menuDevice = new wxMenu; |
| PhoneCollection* pCollection = PhoneCollection::GetInstance(); |
| int defaultModel = 0; |
| |
| for (int i = 0; i < pCollection->GetPhoneCount(); i++) { |
| PhoneData* pPhoneData = pCollection->GetPhoneData(i); |
| assert(pPhoneData != NULL); |
| |
| menuDevice->AppendRadioItem(IDM_DEVICE_SEL0 + i, |
| wxString::FromAscii(pPhoneData->GetTitle())); |
| |
| // use this one as default if the string matches |
| if (strcasecmp(pPhoneData->GetName(), defaultItemName) == 0) |
| defaultModel = i; |
| } |
| |
| menuDevice->Check(IDM_DEVICE_SEL0 + defaultModel, true); |
| |
| menuDevice->AppendSeparator(); |
| menuDevice->Append(IDM_DEVICE_RESCAN, wxT("Re-scan")); |
| |
| return menuDevice; |
| } |
| |
| /* |
| * Create some controls in the main window. |
| * |
| * The main frame doesn't use the normal background color that you find |
| * in dialog windows, so we create a "panel" and put all the controls |
| * on that. |
| */ |
| void MainFrame::ConstructControls(void) |
| { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| wxPanel* base = new wxPanel(this, wxID_ANY); |
| wxBoxSizer* masterSizer = new wxBoxSizer(wxVERTICAL); |
| wxBoxSizer* tmpSizer; |
| wxStaticBoxSizer* displayOptSizer; |
| wxStaticBoxSizer* runtimeOptSizer; |
| wxStaticBoxSizer* onionSkinOptSizer; |
| wxComboBox* pModeSelection; |
| wxCheckBox* pUseGDB; |
| wxCheckBox* pUseValgrind; |
| wxCheckBox* pCheckJni; |
| wxCheckBox* pOverlayOnionSkin; |
| |
| displayOptSizer = new wxStaticBoxSizer(wxHORIZONTAL, base, |
| wxT("Configuration")); |
| runtimeOptSizer = new wxStaticBoxSizer(wxVERTICAL, base, |
| wxT("Runtime Options")); |
| onionSkinOptSizer = new wxStaticBoxSizer(wxVERTICAL, base, |
| wxT("Onion Skin Options")); |
| |
| /* |
| * Set up the configuration sizer (nee "display options"). |
| */ |
| tmpSizer = new wxBoxSizer(wxHORIZONTAL); |
| displayOptSizer->Add(tmpSizer); |
| tmpSizer->Add( |
| new wxStaticText(base, wxID_ANY, wxT("Device mode:"), |
| wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT), 0, wxALIGN_CENTER_VERTICAL); |
| pModeSelection = new wxComboBox(base, IDC_MODE_SELECT, wxT(""), |
| wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY); |
| tmpSizer->AddSpacer(kInterSpacing); |
| tmpSizer->Add(pModeSelection); |
| |
| displayOptSizer->AddSpacer(kInterSpacing); |
| |
| /* |
| * Configure the runtime options sizer. |
| */ |
| wxComboBox* pJavaAppName; |
| tmpSizer = new wxBoxSizer(wxHORIZONTAL); |
| pUseGDB = new wxCheckBox(base, IDC_USE_GDB, wxT("Use &debugger")); |
| tmpSizer->Add(pUseGDB); |
| tmpSizer->AddSpacer(kInterSpacing); |
| pUseValgrind = new wxCheckBox(base, IDC_USE_VALGRIND, wxT("Use &valgrind")); |
| tmpSizer->Add(pUseValgrind); |
| tmpSizer->AddSpacer(kInterSpacing); |
| pCheckJni = new wxCheckBox(base, IDC_CHECK_JNI, wxT("Check &JNI")); |
| tmpSizer->Add(pCheckJni); |
| |
| pJavaAppName = new wxComboBox(base, IDC_JAVA_APP_NAME, wxT(""), |
| wxDefaultPosition, wxSize(320, -1), NELEM(gStdJavaApps), gStdJavaApps, |
| wxCB_DROPDOWN); |
| wxBoxSizer* javaAppSizer = new wxBoxSizer(wxHORIZONTAL); |
| javaAppSizer->Add( |
| new wxStaticText(base, wxID_ANY, |
| wxT("Java app:"), |
| wxDefaultPosition, wxDefaultSize, |
| wxALIGN_LEFT), |
| 0, wxALIGN_CENTER_VERTICAL); |
| javaAppSizer->AddSpacer(kInterSpacing); |
| javaAppSizer->Add(pJavaAppName); |
| |
| runtimeOptSizer->Add(tmpSizer); |
| |
| runtimeOptSizer->AddSpacer(kInterSpacing); |
| runtimeOptSizer->Add(javaAppSizer); |
| runtimeOptSizer->AddSpacer(kInterSpacing); |
| |
| wxString tmpStr; |
| SetCheckFromPref(pUseGDB, "debug", false); |
| SetCheckFromPref(pUseValgrind, "valgrind", false); |
| SetCheckFromPref(pCheckJni, "check-jni", false); |
| if (pPrefs->GetString("java-app-name", /*ref*/ tmpStr)) |
| pJavaAppName->SetValue(tmpStr); |
| |
| /* |
| * Configure the onion skin options sizer. |
| */ |
| wxTextCtrl* pOnionSkinFileNameText; |
| wxButton* pOnionSkinFileButton; |
| wxSlider* pOnionSkinAlphaSlider; |
| tmpSizer = new wxBoxSizer(wxHORIZONTAL); |
| pOverlayOnionSkin = new wxCheckBox(base, |
| IDC_OVERLAY_ONION_SKIN, wxT("Overlay &onion skin")); |
| tmpSizer->Add(pOverlayOnionSkin); |
| |
| pOnionSkinFileNameText = new wxTextCtrl(base, |
| IDC_ONION_SKIN_FILE_NAME, wxT(""), |
| wxDefaultPosition, wxSize(250, -1), |
| wxTE_PROCESS_ENTER); |
| pOnionSkinFileButton = new wxButton(base, IDC_ONION_SKIN_BUTTON, |
| wxT("Choose")); |
| |
| wxBoxSizer* onionSkinFileNameSizer = new wxBoxSizer(wxHORIZONTAL); |
| onionSkinFileNameSizer->Add( |
| new wxStaticText(base, wxID_ANY, |
| wxT("Filename:"), |
| wxDefaultPosition, wxDefaultSize, |
| wxALIGN_LEFT), |
| 0, wxALIGN_CENTER_VERTICAL); |
| onionSkinFileNameSizer->AddSpacer(kInterSpacing); |
| onionSkinFileNameSizer->Add(pOnionSkinFileNameText); |
| onionSkinFileNameSizer->Add(pOnionSkinFileButton); |
| |
| wxBoxSizer * onionSkinAlphaSizer = new wxBoxSizer(wxHORIZONTAL); |
| int initialAlphaVal = 127; |
| pPrefs->GetInt("onion-skin-alpha-value", &initialAlphaVal); |
| pOnionSkinAlphaSlider = new wxSlider(base, IDC_ONION_SKIN_ALPHA_VAL, |
| initialAlphaVal, 0, 255, wxDefaultPosition, wxSize(150, 20)); |
| onionSkinAlphaSizer->Add( |
| new wxStaticText(base, wxID_ANY, |
| wxT("Transparency:"), |
| wxDefaultPosition, wxDefaultSize, |
| wxALIGN_LEFT), |
| 0, wxALIGN_CENTER_VERTICAL); |
| onionSkinAlphaSizer->AddSpacer(kInterSpacing); |
| onionSkinAlphaSizer->Add(pOnionSkinAlphaSlider, 1, wxCENTRE | wxALL, 5); |
| |
| onionSkinOptSizer->Add(tmpSizer); |
| onionSkinOptSizer->AddSpacer(kInterSpacing); |
| onionSkinOptSizer->Add(onionSkinFileNameSizer); |
| onionSkinOptSizer->Add(onionSkinAlphaSizer); |
| |
| wxString tmpStr2; |
| SetCheckFromPref(pOverlayOnionSkin, "overlay-onion-skin", false); |
| if (pPrefs->GetString("onion-skin-file-name", /*ref*/ tmpStr2)) |
| pOnionSkinFileNameText->SetValue(tmpStr2); |
| |
| /* |
| * Add the various components to the master sizer. |
| */ |
| masterSizer->Add(displayOptSizer); |
| masterSizer->AddSpacer(kInterSpacing * 2); |
| masterSizer->Add(runtimeOptSizer); |
| masterSizer->AddSpacer(kInterSpacing * 2); |
| masterSizer->Add(onionSkinOptSizer); |
| //masterSizer->AddSpacer(kInterSpacing); |
| |
| /* |
| * I don't see a way to guarantee that the window is wide enough to |
| * show the entire menu bar, so just throw some pixels at it. |
| */ |
| wxBoxSizer* minWidthSizer = new wxBoxSizer(wxVERTICAL); |
| minWidthSizer->Add(300, kEdgeSpacing); // forces minimum width |
| minWidthSizer->Add(masterSizer); |
| minWidthSizer->AddSpacer(kInterSpacing * 2); |
| |
| /* move us a few pixels in from the left */ |
| wxBoxSizer* indentSizer = new wxBoxSizer(wxHORIZONTAL); |
| indentSizer->AddSpacer(kEdgeSpacing); |
| indentSizer->Add(minWidthSizer); |
| indentSizer->AddSpacer(kEdgeSpacing); |
| |
| base->SetSizer(indentSizer); |
| |
| indentSizer->Fit(this); |
| indentSizer->SetSizeHints(this); |
| } |
| |
| /* |
| * Set the value of a checkbox based on a value from the config file. |
| */ |
| void MainFrame::SetCheckFromPref(wxCheckBox* pControl, const char* prefStr, |
| bool defaultVal) |
| { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| assert(pPrefs != NULL); |
| |
| bool val = defaultVal; |
| pPrefs->GetBool(prefStr, &val); |
| |
| pControl->SetValue(val); |
| } |
| |
| /* |
| * Destructor. |
| */ |
| MainFrame::~MainFrame(void) |
| { |
| PhoneCollection::DestroyInstance(); |
| |
| delete mExternalRuntimeThread; |
| delete mPropertyServerThread; |
| |
| // don't touch mpModeSelection -- child of window |
| } |
| |
| /* |
| * File->Quit or click on close box. |
| * |
| * If we want an "are you sure you want to quit" box, add it here. |
| */ |
| void MainFrame::OnClose(wxCloseEvent& event) |
| { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| |
| /* |
| if (event.CanVeto()) |
| printf("Closing (can veto)\n"); |
| else |
| printf("Closing (mandatory)\n"); |
| */ |
| |
| /* |
| * Generally speaking, Close() is not guaranteed to close the window. |
| * However, we want to use it here because (a) our windows are |
| * guaranteed to close, and (b) it provides our windows an opportunity |
| * to tell others that they are about to vanish. |
| */ |
| if (mpPhoneWindow != NULL) |
| mpPhoneWindow->Close(true); |
| |
| /* save position of main window */ |
| wxPoint pos = GetPosition(); |
| pPrefs->SetInt("window-main-x", pos.x); |
| pPrefs->SetInt("window-main-y", pos.y); |
| |
| /* save default device selection */ |
| int idx = GetSelectedDeviceIndex(); |
| if (idx >= 0) { |
| PhoneCollection* pCollection = PhoneCollection::GetInstance(); |
| PhoneData* pPhoneData = pCollection->GetPhoneData(idx); |
| pPrefs->SetString("default-device", pPhoneData->GetName()); |
| } |
| |
| if (mpLogWindow != NULL) |
| mpLogWindow->Close(true); |
| Destroy(); |
| } |
| |
| /* |
| * File->Preferences |
| */ |
| void MainFrame::OnFilePreferences(wxCommandEvent& WXUNUSED(event)) |
| { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| PrefsDialog dialog(this); |
| int result; |
| |
| result = dialog.ShowModal(); |
| if (result == wxID_OK) { |
| /* |
| * The dialog handles writing changes to Preferences, so all we |
| * need to deal with here are changes that have an immediate |
| * impact on us. (which is currently nothing) |
| */ |
| } |
| } |
| |
| /* |
| * File->Exit |
| */ |
| void MainFrame::OnFileExit(wxCommandEvent& WXUNUSED(event)) |
| { |
| Close(FALSE); // false means "allow veto" |
| } |
| |
| /* |
| * Decide whether Simulator->Start should be enabled. |
| */ |
| void MainFrame::OnUpdateSimStart(wxUpdateUIEvent& event) |
| { |
| if (IsRuntimeRunning()) |
| event.Enable(FALSE); |
| else |
| event.Enable(TRUE); |
| } |
| |
| /* |
| * Simulator->Start |
| */ |
| void MainFrame::OnSimStart(wxCommandEvent& WXUNUSED(event)) |
| { |
| // keyboard equivalents can still get here even if menu item disabled |
| if (IsRuntimeRunning()) |
| return; |
| |
| int id = GetSelectedDeviceIndex(); |
| if (id < 0) { |
| fprintf(stderr, "Sim: could not identify currently selected device\n"); |
| return; |
| } |
| |
| #if 0 |
| static int foo = 0; |
| foo++; |
| if (foo == 2) { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| |
| pPrefs->SetBool("debug", true); |
| } |
| #endif |
| |
| SetupPhoneUI(id, NULL); |
| if (mpPhoneWindow != NULL) |
| mpPhoneWindow->GetDeviceManager()->StartRuntime(); |
| } |
| |
| /* |
| * Decide whether Simulator->Stop should be enabled. |
| */ |
| void MainFrame::OnUpdateSimStop(wxUpdateUIEvent& event) |
| { |
| if (IsRuntimeRunning()) |
| event.Enable(TRUE); |
| else |
| event.Enable(FALSE); |
| } |
| |
| /* |
| * Simulator->Stop |
| */ |
| void MainFrame::OnSimStop(wxCommandEvent& WXUNUSED(event)) |
| { |
| if (!IsRuntimeRunning()) |
| return; |
| assert(mpPhoneWindow != NULL); |
| mpPhoneWindow->GetDeviceManager()->StopRuntime(); |
| } |
| |
| /* |
| * Decide whether Simulator->Restart should be enabled. |
| */ |
| void MainFrame::OnUpdateSimRestart(wxUpdateUIEvent& event) |
| { |
| if (IsRuntimeRunning()) |
| event.Enable(TRUE); |
| else |
| event.Enable(FALSE); |
| } |
| |
| /* |
| * Simulator->Restart - stop then start the device runtime. |
| */ |
| void MainFrame::OnSimRestart(wxCommandEvent& WXUNUSED(event)) |
| { |
| if (!IsRuntimeRunning()) |
| return; |
| |
| printf("Restart requested\n"); |
| mpPhoneWindow->GetDeviceManager()->StopRuntime(); |
| |
| mRestartRequested = true; |
| } |
| |
| /* |
| * Decide whether Simulator->Kill should be enabled. |
| */ |
| void MainFrame::OnUpdateSimKill(wxUpdateUIEvent& event) |
| { |
| if (IsRuntimeKillable()) |
| event.Enable(TRUE); |
| else |
| event.Enable(FALSE); |
| } |
| |
| /* |
| * Simulator->Kill |
| */ |
| void MainFrame::OnSimKill(wxCommandEvent& WXUNUSED(event)) |
| { |
| if (!IsRuntimeKillable()) |
| return; |
| assert(mpPhoneWindow != NULL); |
| mpPhoneWindow->GetDeviceManager()->KillRuntime(); |
| } |
| |
| |
| /* |
| * Device->[select] |
| */ |
| void MainFrame::OnDeviceSelected(wxCommandEvent& event) |
| { |
| wxBusyCursor busyc; |
| int id = event.GetId() - IDM_DEVICE_SEL0; |
| |
| SetupPhoneUI(id, NULL); |
| } |
| |
| /* |
| * Device->Rescan |
| */ |
| void MainFrame::OnDeviceRescan(wxCommandEvent& event) |
| { |
| wxBusyCursor busyc; |
| wxMenuBar* pMenuBar; |
| PhoneCollection* pCollection; |
| wxMenu* pOldMenu; |
| wxMenu* pNewMenu; |
| const char* curDevName = NULL; |
| int idx; |
| |
| /* figure out the current device name */ |
| pCollection = PhoneCollection::GetInstance(); |
| idx = GetSelectedDeviceIndex(); |
| if (idx >= 0) { |
| PhoneData* pPhoneData; |
| |
| pPhoneData = pCollection->GetPhoneData(idx); |
| curDevName = pPhoneData->GetName(); |
| printf("--- device name is '%s'\n", (const char*) curDevName); |
| } |
| |
| /* reconstruct device menu with new data */ |
| #ifdef BEFORE_ASSET |
| pCollection->ScanForPhones(mSimAssetPath); |
| #else |
| pCollection->ScanForPhones(NULL); |
| #endif |
| |
| pMenuBar = GetMenuBar(); |
| idx = pMenuBar->FindMenu(kDeviceMenuString); |
| if (idx == wxNOT_FOUND) { |
| fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii()); |
| return; |
| } |
| |
| pNewMenu = CreateDeviceMenu(curDevName); |
| |
| pOldMenu = pMenuBar->Replace(idx, pNewMenu, kDeviceMenuString); |
| delete pOldMenu; |
| |
| /* tell the PhoneWindow about it; may cause runtime to exit */ |
| if (mpPhoneWindow != NULL) |
| mpPhoneWindow->DevicesRescanned(); |
| } |
| |
| /* |
| * Set checkbox on menu item. |
| */ |
| void MainFrame::OnUpdateDebugShowLog(wxUpdateUIEvent& event) |
| { |
| if (mpLogWindow == NULL) { |
| event.Enable(false); |
| } else { |
| event.Enable(true); |
| event.Check(mpLogWindow->IsShown()); |
| } |
| } |
| |
| /* |
| * Debug->ShowLog toggle. |
| */ |
| void MainFrame::OnDebugShowLog(wxCommandEvent& WXUNUSED(event)) |
| { |
| mpLogWindow->Show(!mpLogWindow->IsShown()); |
| } |
| |
| /* |
| * Help->Contents |
| */ |
| void MainFrame::OnHelpContents(wxCommandEvent& WXUNUSED(event)) |
| { |
| ((MyApp*)wxTheApp)->GetHelpController()->DisplayContents(); |
| } |
| |
| /* |
| * Help->About |
| */ |
| void MainFrame::OnHelpAbout(wxCommandEvent& WXUNUSED(event)) |
| { |
| wxMessageBox(wxT("Android Simulator v0.1\n" |
| "Copyright 2006 The Android Open Source Project"), |
| wxT("About..."), wxOK | wxICON_INFORMATION, this); |
| } |
| |
| /* |
| * Sent from phonewindow or when activated |
| */ |
| void MainFrame::OnActivate(wxActivateEvent& event) |
| { |
| #if 0 |
| if (event.GetActive()) |
| { |
| if (mpPhoneWindow != NULL && |
| mpPhoneWindow->GetDeviceManager()->RefreshRuntime()) |
| { |
| wxString msg; |
| int sel; |
| |
| msg = wxT("Newer runtime executable found. Would you like to reload the device?"); |
| |
| sel = wxMessageBox(msg, wxT("Android Safety Patrol"), |
| wxYES | wxNO | wxICON_QUESTION, mpPhoneWindow); |
| //printf("BUTTON was %d (yes=%d)\n", sel, wxYES); |
| if (sel == wxYES) |
| { |
| mpPhoneWindow->GetDeviceManager()->StopRuntime(); |
| mpPhoneWindow->Close(); |
| mpPhoneWindow = NULL; |
| mRestartRequested = true; |
| } |
| else |
| { |
| mpPhoneWindow->GetDeviceManager()->UserCancelledRefresh(); |
| } |
| } |
| } |
| #endif |
| |
| // let wxWidgets do whatever it needs to do |
| event.Skip(); |
| } |
| |
| |
| /* |
| * Device mode selection box. |
| */ |
| void MainFrame::OnComboBox(wxCommandEvent& event) |
| { |
| const char* pref; |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| assert(pPrefs != NULL); |
| |
| if (IDC_MODE_SELECT == event.GetId()) |
| { |
| int id = GetSelectedDeviceIndex(); |
| if (id < 0) |
| return; |
| //printf("--- mode selected: '%s'\n", (const char*) event.GetString().ToAscii()); |
| |
| /* |
| * Call the phone window's setup function. Don't call our SetupPhoneUI |
| * function from here -- updating the combo box from a combo box callback |
| * could cause problems. |
| */ |
| if (mpPhoneWindow != NULL) { |
| mpPhoneWindow->SetCurrentMode(event.GetString()); |
| mpPhoneWindow->Setup(id); |
| } |
| } else if (event.GetId() == IDC_JAVA_VM) { |
| wxComboBox* pBox = (wxComboBox*) FindWindow(IDC_JAVA_VM); |
| pPrefs->SetString("java-vm", pBox->GetValue().ToAscii()); |
| } |
| } |
| |
| /* |
| * One of our option checkboxes has been changed. |
| * |
| * We update the prefs database so that the settings are retained when |
| * the simulator is next used. |
| */ |
| void MainFrame::OnCheckBox(wxCommandEvent& event) |
| { |
| const char* pref; |
| |
| switch (event.GetId()) { |
| case IDC_USE_GDB: pref = "debug"; break; |
| case IDC_USE_VALGRIND: pref = "valgrind"; break; |
| case IDC_CHECK_JNI: pref = "check-jni"; break; |
| case IDC_OVERLAY_ONION_SKIN: pref = "overlay-onion-skin"; break; |
| default: |
| printf("Sim: unrecognized checkbox %d in OnCheckBox\n", event.GetId()); |
| return; |
| } |
| |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| assert(pPrefs != NULL); |
| |
| pPrefs->SetBool(pref, (bool) event.GetInt()); |
| //printf("--- set pref '%s' to %d\n", pref, (bool) event.GetInt()); |
| if (event.GetId() == IDC_OVERLAY_ONION_SKIN) { |
| BroadcastOnionSkinUpdate(); |
| } |
| if (event.GetId() == IDC_CHECK_JNI) { |
| const char* val = "0"; |
| if ((bool) event.GetInt()) |
| val = "1"; |
| mPropertyServerThread->SetProperty(PropertyServer::kPropCheckJni, val); |
| |
| } |
| } |
| |
| void MainFrame::BroadcastOnionSkinUpdate() { |
| if (mpPhoneWindow != NULL) { |
| // broadcast a user event indicating an onion skin update |
| UserEvent uev(0, (void*) -1); |
| mpPhoneWindow->GetDeviceManager()->BroadcastEvent(uev); |
| } |
| } |
| |
| /* |
| * A text control on the main page is being updated. |
| * |
| * The current implementation updates the preferences database on every |
| * change, which is a bit silly but is easy to do. |
| */ |
| void MainFrame::OnText(wxCommandEvent& event) |
| { |
| const char* pref; |
| |
| switch (event.GetId()) { |
| case IDC_JAVA_APP_NAME: pref = "java-app-name"; break; |
| default: |
| printf("Sim: unrecognized textctrl %d in OnText\n", event.GetId()); |
| return; |
| } |
| |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| assert(pPrefs != NULL); |
| |
| // event.GetString() does not work on Mac -- always blank |
| //pPrefs->SetString(pref, event.GetString()); |
| assert(event.GetId() == IDC_JAVA_APP_NAME); // fix if we add more |
| wxComboBox* pBox; |
| pBox = (wxComboBox*) FindWindow(IDC_JAVA_APP_NAME); |
| pPrefs->SetString(pref, pBox->GetValue().ToAscii()); |
| //printf("--- set pref '%s' to '%s'\n", pref,(const char*)pBox->GetValue()); |
| } |
| |
| /* |
| * A user pressed enter in a text control on the main page. |
| * |
| * The current implementation updates the preferences database on every |
| * change, which is a bit silly but is easy to do. |
| */ |
| void MainFrame::OnTextEnter(wxCommandEvent& event) |
| { |
| const char* pref; |
| |
| switch (event.GetId()) { |
| case IDC_ONION_SKIN_FILE_NAME: |
| pref = "onion-skin-file-name"; |
| break; |
| default: |
| printf("Sim: unrecognized textctrl %d in OnTextEnter\n", event.GetId()); |
| return; |
| } |
| |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| assert(pPrefs != NULL); |
| |
| assert(event.GetId() == IDC_ONION_SKIN_FILE_NAME); // fix if we add more |
| wxTextCtrl* pTextCtrl; |
| pTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME); |
| wxString onionSkinFileNameWxString = pTextCtrl->GetValue(); |
| char* onionSkinFileName = ""; |
| if (onionSkinFileNameWxString.Len() > 0) { |
| onionSkinFileName = android::strdupNew(onionSkinFileNameWxString.ToAscii()); |
| } |
| pPrefs->SetString(pref, onionSkinFileName); |
| BroadcastOnionSkinUpdate(); |
| } |
| |
| /* |
| * A user pressed a button on the main page |
| * |
| */ |
| void MainFrame::OnButton(wxCommandEvent& event) |
| { |
| wxWindow* base; |
| wxFileDialog* pOnionSkinFileChooser; |
| int retVal; |
| switch (event.GetId()) { |
| case IDC_ONION_SKIN_BUTTON: |
| base = FindWindow(IDC_ONION_SKIN_BUTTON)->GetParent(); |
| pOnionSkinFileChooser = new wxFileDialog(base, |
| wxT("Choose the onion skin image file."), |
| wxT(""), wxT(""), wxT("*.*"), |
| wxOPEN | wxFILE_MUST_EXIST); |
| retVal = pOnionSkinFileChooser->ShowModal(); |
| if (retVal == pOnionSkinFileChooser->GetAffirmativeId()) { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| assert(pPrefs != NULL); |
| wxString fileNameWxString = pOnionSkinFileChooser->GetPath(); |
| const char* fileName = android::strdupNew(fileNameWxString.ToAscii()); |
| wxTextCtrl* fileTextCtrl = (wxTextCtrl*) FindWindow(IDC_ONION_SKIN_FILE_NAME); |
| fileTextCtrl->SetValue(fileNameWxString); |
| pPrefs->SetString("onion-skin-file-name", fileName); |
| BroadcastOnionSkinUpdate(); |
| } |
| break; |
| default: |
| printf("Sim: unrecognized button %d in OnButton\n", event.GetId()); |
| return; |
| } |
| } |
| |
| /* |
| * The user moved a slider on the main page |
| */ |
| void MainFrame::OnSliderChange(wxScrollEvent& event) |
| { |
| wxSlider* pSlider; |
| Preferences* pPrefs; |
| switch (event.GetId()) { |
| case IDC_ONION_SKIN_ALPHA_VAL: |
| pSlider = (wxSlider*) FindWindow(IDC_ONION_SKIN_ALPHA_VAL); |
| pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| assert(pPrefs != NULL); |
| pPrefs->SetInt("onion-skin-alpha-value", pSlider->GetValue()); |
| BroadcastOnionSkinUpdate(); |
| break; |
| default: |
| printf("Sim: unrecognized scroller or slider %d in OnSliderChange\n", event.GetId()); |
| return; |
| } |
| } |
| |
| #if 0 |
| /* |
| * Idle processing. Under wxWidgets this only called once after UI |
| * activity unless you call event.RequestMore(). |
| */ |
| void MainFrame::OnIdle(wxIdleEvent& event) |
| { |
| event.Skip(); // let base class handler do stuff |
| } |
| #endif |
| |
| /* |
| * Handle the timer. |
| * |
| * This is being called in the main thread, so multithreading with the |
| * rest of MainFrame isn't a concern here. |
| */ |
| void MainFrame::OnTimer(wxTimerEvent& event) |
| { |
| bool status; |
| |
| /* |
| * Check to see if the runtime died without telling us. This can only |
| * happen if we forcibly kill our thread. We shouldn't really be |
| * doing that anymore, but keep this in for now just in case. |
| */ |
| status = IsRuntimeRunning(); |
| |
| if (mSimRunning != status) { |
| if (!status) { |
| printf("Sim: fixed mSimRunning=%d actual=%d\n", |
| mSimRunning, status); |
| mSimRunning = status; |
| |
| if (!status) |
| HandleRuntimeStop(); |
| } else { |
| /* |
| * This was happening when we were shutting down but the |
| * device management thread hadn't completely gone away. The |
| * simple IsRunning test passes, so we get a false positive. |
| * Ignore it. |
| */ |
| } |
| } |
| |
| if (gWantToKill) { |
| if (IsRuntimeRunning()) { |
| printf("Sim: handling kill request\n"); |
| mpPhoneWindow->GetDeviceManager()->KillRuntime(); |
| } |
| gWantToKill = false; |
| |
| /* see if Ctrl-C should kill us too */ |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| bool die = false; |
| |
| pPrefs->GetBool("trap-sigint-suicide", &die); |
| if (die) { |
| printf("Sim: goodbye cruel world!\n"); |
| exit(0); |
| } |
| } |
| } |
| |
| /* |
| * Determine whether or not the simulator is running. |
| */ |
| bool MainFrame::IsRuntimeRunning(void) |
| { |
| bool result; |
| |
| if (mpPhoneWindow == NULL) |
| result = false; |
| else if (!mpPhoneWindow->IsReady()) |
| result = false; |
| else |
| result = mpPhoneWindow->GetDeviceManager()->IsRunning(); |
| |
| return result; |
| } |
| |
| /* |
| * Determine whether or not the runtime can be killed. |
| */ |
| bool MainFrame::IsRuntimeKillable(void) |
| { |
| bool result; |
| |
| result = IsRuntimeRunning(); |
| if (result) |
| result = mpPhoneWindow->GetDeviceManager()->IsKillable(); |
| |
| return result; |
| } |
| |
| /* |
| * Determine whether two devices are sufficiently compatible. |
| */ |
| bool MainFrame::CompatibleDevices(PhoneData* pData1, PhoneData* pData2) |
| { |
| int displayCount; |
| |
| displayCount = pData1->GetNumDisplays(); |
| if (pData2->GetNumDisplays() != displayCount) |
| return false; |
| |
| for (int i = 0; i < displayCount; i++) { |
| PhoneDisplay* pDisplay1 = pData1->GetPhoneDisplay(i); |
| PhoneDisplay* pDisplay2 = pData2->GetPhoneDisplay(i); |
| |
| if (!PhoneDisplay::IsCompatible(pDisplay1, pDisplay2)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* |
| * (Re-)arrange the UI for the currently selected phone model. |
| * |
| * If the simulator is running, and the set of displays for the current |
| * device are incompatible with the new device, we need to restart the |
| * runtime. We need to ask for permission first though. |
| */ |
| void MainFrame::SetupPhoneUI(int idx, const char* defaultMode) |
| { |
| PhoneCollection* pCollection; |
| PhoneData* pPhoneData; |
| wxString* choices = NULL; |
| int numChoices = 0; |
| int numKeyboards = 0; |
| bool haveDefaultMode = false; |
| wxCharBuffer currentMode; |
| int i; |
| |
| pCollection = PhoneCollection::GetInstance(); |
| pPhoneData = pCollection->GetPhoneData(idx); |
| if (pPhoneData == NULL) { |
| fprintf(stderr, "ERROR: device index %d not valid\n", idx); |
| goto bail; |
| } |
| |
| /* |
| * We have a window up. If the displays aren't compatible, we'll |
| * need to recreate it. |
| */ |
| if (mpPhoneWindow != NULL) { |
| PhoneData* pCurData = mpPhoneWindow->GetPhoneData(); |
| |
| if (!CompatibleDevices(pCurData, pPhoneData)) { |
| /* |
| * We need to trash the window. This will also kill the |
| * runtime. If it's running, ask permission. |
| */ |
| if (IsRuntimeRunning()) { |
| wxString msg; |
| int sel; |
| |
| msg = wxT("Switching to the new device requires restarting the"); |
| msg += wxT(" runtime. Continue?"); |
| |
| sel = wxMessageBox(msg, wxT("Android Safety Patrol"), |
| wxOK | wxCANCEL | wxICON_QUESTION, this); |
| printf("BUTTON was %d (ok=%d)\n", sel, wxOK); |
| if (sel == wxCANCEL) |
| goto bail; |
| |
| /* shut it down (politely), ask for an eventual restart */ |
| mpPhoneWindow->GetDeviceManager()->StopRuntime(); |
| mpPhoneWindow->Close(); |
| mpPhoneWindow = NULL; |
| mRestartRequested = true; |
| goto bail; |
| } else { |
| /* not running, just trash the window and continue */ |
| mpPhoneWindow->Close(); |
| mpPhoneWindow = NULL; |
| } |
| } |
| } |
| |
| /* |
| * Figure out the set of available modes. |
| */ |
| |
| numChoices = pPhoneData->GetNumModes(); |
| if (numChoices > 0) { |
| choices = new wxString[numChoices]; |
| for (i = 0; i < numChoices; i++) { |
| PhoneMode* pPhoneMode; |
| pPhoneMode = pPhoneData->GetPhoneMode(i); |
| choices[i] = wxString::FromAscii(pPhoneMode->GetName()); |
| if (defaultMode != NULL && |
| strcmp(defaultMode, pPhoneMode->GetName()) == 0) |
| { |
| haveDefaultMode = true; |
| } |
| } |
| } |
| |
| if (choices == NULL) { |
| /* had a failure earlier; configure UI with default stuff */ |
| choices = new wxString[1]; |
| choices[0] = wxT("(none)"); |
| } |
| |
| if (!haveDefaultMode) { |
| /* |
| * Default mode wasn't found. If we specify it as the default |
| * in the wxComboBox create call it shows up in the combo box |
| * under Linux, even if it doesn't exist in the list. So, we |
| * make sure that it doesn't get used if we can't find it. |
| */ |
| if (defaultMode != NULL) { |
| printf("Sim: HEY: default mode '%s' not found in list\n", |
| defaultMode); |
| } |
| currentMode = choices[0].ToAscii(); |
| } else { |
| currentMode = defaultMode; |
| } |
| |
| |
| /* |
| * Create the window if necessary. |
| */ |
| if (mpPhoneWindow == NULL) { |
| // create, setup, and then show window |
| mpPhoneWindow = new PhoneWindow(this, mPhoneWindowPosn); |
| mpPhoneWindow->SetCurrentMode((const char*)currentMode); |
| if (!mpPhoneWindow->Setup(idx)) { |
| delete mpPhoneWindow; |
| mpPhoneWindow = NULL; |
| } |
| if (mpPhoneWindow != NULL) { |
| mpPhoneWindow->Show(); |
| //mpPhoneWindow->CheckPlacement(); |
| } |
| } else { |
| // just set up for new device |
| mpPhoneWindow->SetCurrentMode((const char*)currentMode); |
| if (!mpPhoneWindow->Setup(idx)) { |
| // it's in an uncertain state, blow it away |
| delete mpPhoneWindow; |
| mpPhoneWindow = NULL; |
| } |
| } |
| |
| /* |
| * Reconfigure mode selection box. |
| */ |
| wxComboBox* pModeSelection; |
| pModeSelection = (wxComboBox*)FindWindow(IDC_MODE_SELECT); |
| pModeSelection->Clear(); |
| for (i = 0; i < numChoices; i++) |
| pModeSelection->Append(choices[i]); |
| pModeSelection->SetSelection(0); |
| pModeSelection->Enable(numChoices > 1); |
| |
| /* |
| * configure qwerty keyboard attribute |
| */ |
| numKeyboards = pPhoneData->GetNumKeyboards(); |
| if (numKeyboards > 0) { |
| // only use the first keyboard for now |
| PhoneKeyboard* pPhoneKeyboard; |
| pPhoneKeyboard = pPhoneData->GetPhoneKeyboard(0); |
| if (pPhoneKeyboard->getQwerty()) { |
| printf("Sim: set 'qwerty' env\n"); |
| setenv("qwerty", "true", true); |
| } |
| } |
| |
| bail: |
| delete[] choices; |
| } |
| |
| /* |
| * Figure out which device is currently selected. |
| * |
| * The easiest way to do this is just run down the list of possible IDs |
| * and stop when something claims to be checked. |
| * |
| * Returns -1 if it can't find a checked item (which can happen if no |
| * device layouts were found). |
| */ |
| int MainFrame::GetSelectedDeviceIndex(void) |
| { |
| wxMenuBar* pMenuBar; |
| wxMenu* pMenu; |
| int idx; |
| |
| pMenuBar = GetMenuBar(); |
| idx = pMenuBar->FindMenu(kDeviceMenuString); |
| if (idx == wxNOT_FOUND) { |
| fprintf(stderr, "Sim: couldn't find %s menu\n", (const char*) kDeviceMenuString.ToAscii()); |
| return -1; |
| } |
| |
| pMenu = pMenuBar->GetMenu(idx); |
| |
| //printf("Menu.MenuItemCount = %d\n", pMenu->GetMenuItemCount()); |
| for (int j = pMenu->GetMenuItemCount() -1; j >= 0; j--) { |
| wxMenuItem* pItem; |
| |
| pItem = pMenu->FindItemByPosition(j); |
| //printf("ITEM %d: %s\n", j, (const char*) pItem->GetLabel()); |
| if (pItem->IsChecked()) { |
| printf("Sim: selected device is '%s'\n", |
| (const char*) pItem->GetLabel().ToAscii()); |
| return j; |
| } |
| } |
| |
| return -1; |
| } |
| |
| /* |
| * Receive a status message from the runtime thread. |
| */ |
| void MainFrame::OnUserEvent(UserEvent& event) |
| { |
| UserEventMessage* pUem; |
| |
| pUem = (UserEventMessage*) event.GetData(); |
| assert(pUem != NULL); |
| |
| switch (pUem->GetType()) { |
| case UserEventMessage::kRuntimeStarted: |
| printf("Sim: runtime thread started!\n"); |
| HandleRuntimeStart(); |
| break; |
| case UserEventMessage::kRuntimeStopped: |
| printf("Sim: runtime thread stopped!\n"); |
| HandleRuntimeStop(); |
| break; |
| case UserEventMessage::kErrorMessage: |
| { |
| wxString msg = pUem->GetString(); |
| wxMessageBox(msg, wxT("Android Runtime Error"), |
| wxOK | wxICON_WARNING, this); |
| } |
| break; |
| case UserEventMessage::kLogMessage: |
| mpLogWindow->AddLogMessage(pUem->GetLogMessage()); |
| break; |
| case UserEventMessage::kExternalRuntime: |
| HandleExternalRuntime(pUem->GetReader(), pUem->GetWriter()); |
| break; |
| default: |
| printf("Sim: MESSAGE: unknown UserEventMessage rcvd (type=%d)\n", |
| pUem->GetType()); |
| break; |
| } |
| |
| delete pUem; |
| } |
| |
| /* |
| * The device management thread is up, so the runtime should be fully |
| * running shortly. |
| */ |
| void MainFrame::HandleRuntimeStart(void) |
| { |
| mSimRunning = true; |
| |
| SetStatusText(kStatusRunning, 1); |
| } |
| |
| /* |
| * The device management thread is exiting, so the runtime must be dead. |
| */ |
| void MainFrame::HandleRuntimeStop(void) |
| { |
| mSimRunning = false; |
| |
| SetStatusText(kStatusNotRunning, 1); |
| |
| if (mRestartRequested) { |
| printf("Sim: restarting runtime\n"); |
| mRestartRequested = false; |
| SetupPhoneUI(GetSelectedDeviceIndex(), NULL); |
| if (mpPhoneWindow != NULL) |
| mpPhoneWindow->GetDeviceManager()->StartRuntime(); |
| } |
| } |
| |
| /* |
| * Handle a connection from an external runtime. |
| */ |
| void MainFrame::HandleExternalRuntime(android::Pipe* reader, |
| android::Pipe* writer) |
| { |
| android::MessageStream msgStream; |
| android::Message msg; |
| |
| if (IsRuntimeRunning()) { |
| /* |
| * Tell the new guy to go away. |
| */ |
| if (!msgStream.init(reader, writer, true)) { |
| fprintf(stderr, "Sim: WARNING: unable to talk to remote runtime\n"); |
| goto bail; |
| } |
| |
| printf("Sim: telling external runtime to go away\n"); |
| msg.setCommand(android::Simulator::kCommandGoAway, 0); |
| msgStream.send(&msg); |
| } else { |
| printf("Sim: new external runtime wants to talk to us\n"); |
| |
| /* |
| * Launch the pieces necessary to talk to this guy. |
| */ |
| int id = GetSelectedDeviceIndex(); |
| if (id < 0) { |
| fprintf(stderr, |
| "Sim: could not identify currently selected device\n"); |
| goto bail; |
| } |
| |
| /* kill existing window, so it pops up and reclaims focus */ |
| if (mpPhoneWindow != NULL) { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| bool okay; |
| |
| if (pPrefs->GetBool("refocus-on-restart", &okay) && okay) { |
| printf("Sim: inducing phone window refocus\n"); |
| mpPhoneWindow->Close(TRUE); // no veto |
| mpPhoneWindow = NULL; |
| } |
| } |
| |
| SetupPhoneUI(id, NULL); |
| if (mpPhoneWindow != NULL) { |
| mpPhoneWindow->GetDeviceManager()->StartRuntime(reader, writer); |
| } else { |
| fprintf(stderr, "Sim: ERROR: unable to get runtime going\n"); |
| goto bail; |
| } |
| |
| // we don't own these anymore |
| reader = writer = NULL; |
| } |
| |
| bail: |
| delete reader; |
| delete writer; |
| } |
| |
| /* |
| * The phone window is about to destroy itself. Get rid of our pointer |
| * to it, and record its last position so we can create the new one in |
| * the same place. |
| */ |
| void MainFrame::PhoneWindowClosing(int x, int y) |
| { |
| Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs(); |
| |
| mpPhoneWindow = NULL; |
| |
| mPhoneWindowPosn.x = x; |
| mPhoneWindowPosn.y = y; |
| |
| pPrefs->SetInt("window-device-x", x); |
| pPrefs->SetInt("window-device-y", y); |
| } |
| |