mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
998 lines
No EOL
24 KiB
Beef
998 lines
No EOL
24 KiB
Beef
using System;
|
|
using Beefy;
|
|
using Beefy.widgets;
|
|
using Beefy.gfx;
|
|
using Beefy.theme.dark;
|
|
using Beefy.theme;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using Beefy.events;
|
|
using Beefy.sys;
|
|
using System.Text;
|
|
using System.Net;
|
|
|
|
namespace BeefPerf
|
|
{
|
|
class BPApp : BFApp
|
|
{
|
|
public new static BPApp sApp;
|
|
public float mTimePerFrame = 1.0f / 60;
|
|
public bool mWantsFullscreen = false;
|
|
public int32 mListenPort = 4208;
|
|
//public int32 mListenPort = 135;
|
|
|
|
WidgetWindow mMainWindow;
|
|
Widget mRootWidget;
|
|
|
|
public Widget mMainWidget;
|
|
public List<String> mLogLines = new List<String>() ~ DeleteContainerAndItems!(_);
|
|
|
|
//public PopupMenuManager mPopupMenuManager;
|
|
//public Trainer mTrainer ~ delete _;
|
|
|
|
public ScriptManager mScriptManager = new ScriptManager() ~ delete _;
|
|
public DarkDockingFrame mDockingFrame;
|
|
public MainFrame mMainFrame;
|
|
|
|
public WorkspacePanel mWorkspacePanel;
|
|
public Board mBoard;
|
|
public ProfilePanel mProfilePanel;
|
|
public FindPanel mFindPanel;
|
|
public Windows.ProcessInformation mProcessInformation;
|
|
|
|
public Socket mListenSocket ~ delete _;
|
|
public Thread mSocketThread ~ delete _;
|
|
public List<BpClient> mClients = new List<BpClient>() ~ delete _;
|
|
public List<BpSession> mSessions = new List<BpSession> ~ DeleteContainerAndItems!(_);
|
|
public Monitor mClientMonitor = new Monitor() ~ delete _;
|
|
public WaitEvent mShutdownEvent = new WaitEvent() ~ delete _;
|
|
public BpSession mCurSession;
|
|
bool mEnableGCCollect = true;
|
|
|
|
public bool mIsAutoOpened;
|
|
public int32 mStatBytesReceived;
|
|
public int32 mStatReportTick;
|
|
public int32 mStatBytesPerSec;
|
|
public bool mFailed;
|
|
public int32 mFailIdx;
|
|
|
|
public bool Listening
|
|
{
|
|
get
|
|
{
|
|
return mListenSocket.IsOpen;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value)
|
|
{
|
|
if (!mListenSocket.IsOpen)
|
|
{
|
|
if (mListenSocket.Listen(mListenPort) case .Err)
|
|
{
|
|
Fail(scope String()..AppendF("Failed to listen on port {0}", mListenPort));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mListenSocket.IsOpen)
|
|
{
|
|
mListenSocket.Close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public this()
|
|
{
|
|
sApp = this;
|
|
gApp = this;
|
|
|
|
//RefreshRate = 120;
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
if (mSocketThread != null)
|
|
mSocketThread.Join();
|
|
|
|
for (var client in mClients)
|
|
{
|
|
if (!client.IsSessionInitialized)
|
|
delete client;
|
|
}
|
|
|
|
Widget.RemoveAndDelete(mWorkspacePanel);
|
|
Widget.RemoveAndDelete(mBoard);
|
|
Widget.RemoveAndDelete(mProfilePanel);
|
|
Widget.RemoveAndDelete(mFindPanel);
|
|
|
|
if (!mLogLines.IsEmpty)
|
|
{
|
|
var fs = scope FileStream();
|
|
if (fs.Open("BeefPerf.txt", .Append, .ReadWrite, .ReadWrite, 4096, .None, null) case .Ok)
|
|
{
|
|
var streamWriter = scope StreamWriter(fs, Encoding.UTF8, 4096);
|
|
for (var line in mLogLines)
|
|
streamWriter.WriteLine(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint32 TimeToUnixTime(DateTime ft)
|
|
{
|
|
// takes the last modified date
|
|
int64 date = ft.ToFileTime();
|
|
|
|
// 100-nanoseconds = milliseconds * 10000
|
|
int64 adjust = 11644473600000L * 10000;
|
|
|
|
// removes the diff between 1970 and 1601
|
|
date -= adjust;
|
|
|
|
// converts back from 100-nanoseconds to seconds
|
|
return (uint32)(date / 10000000L);
|
|
}
|
|
|
|
public void LogLine(String text)
|
|
{
|
|
mLogLines.Add(new String(text));
|
|
}
|
|
|
|
public void Fail(String text)
|
|
{
|
|
//MessageBeep(MessageBeepType.Error);
|
|
|
|
// Always write to STDOUT even if we're running as a GUI, allowing cases like RunAndWait to pass us a stdout handle
|
|
Console.WriteLine("ERROR: {0}", text);
|
|
|
|
mFailIdx++;
|
|
|
|
if (gApp.mScriptManager.mRunningCommand)
|
|
return;
|
|
|
|
if (mMainWindow == null)
|
|
{
|
|
LogLine(text);
|
|
|
|
mFailed = true;
|
|
if (!mShuttingDown)
|
|
Shutdown();
|
|
return;
|
|
}
|
|
|
|
Dialog aDialog = ThemeFactory.mDefault.CreateDialog("ERROR", text, DarkTheme.sDarkTheme.mIconError);
|
|
aDialog.mDefaultButton = aDialog.AddButton("OK");
|
|
aDialog.mEscButton = aDialog.mDefaultButton;
|
|
aDialog.PopupWindow(mMainWindow);
|
|
}
|
|
|
|
void StartFakeClient()
|
|
{
|
|
return;
|
|
#unwarn
|
|
ProcessStartInfo procInfo = scope ProcessStartInfo();
|
|
procInfo.UseShellExecute = false;
|
|
procInfo.RedirectStandardError = true;
|
|
procInfo.SetFileName(@"c:\proj\BeefPerf\x64\Debug\BeefPerf.exe");
|
|
procInfo.CreateNoWindow = true;
|
|
|
|
var spawnedProcess = scope SpawnedProcess();
|
|
spawnedProcess.Start(procInfo).IgnoreError();
|
|
|
|
//Process process = Process.Start(procInfo).GetValueOrDefault();
|
|
//delete process;
|
|
}
|
|
|
|
public void UpdateTitle()
|
|
{
|
|
String title = scope String();
|
|
if ((mBoard.mPerfView != null) && (mBoard.mPerfView.mSession.mClientName != null))
|
|
{
|
|
title.Append(mBoard.mPerfView.mSession.mClientName);
|
|
title.Append(" - ");
|
|
}
|
|
title.Append("BeefPerf");
|
|
mMainWindow.SetTitle(title);
|
|
}
|
|
|
|
public override void Init()
|
|
{
|
|
/*uint timeNow = GetCurrentUnixTime();
|
|
|
|
FitEntry[] fitEntries = new FitEntry[200];
|
|
for (int i = 0; i < fitEntries.Length; i++)
|
|
{
|
|
fitEntries[i].mElapsedTimeMS = i * 500;
|
|
fitEntries[i].mPower = i;
|
|
fitEntries[i].mCadence = 90;
|
|
}
|
|
|
|
int[] lapOffsets = scope int[] {100};
|
|
|
|
WriteFit("c:\\temp\\test.fit", UnixTimeToFitTime(timeNow), fitEntries.CArray(), fitEntries.Length, lapOffsets.CArray(), lapOffsets.Length);*/
|
|
|
|
base.Init();
|
|
mAutoDirty = false;
|
|
|
|
Socket.Init();
|
|
|
|
mListenSocket = new Socket();
|
|
Listening = true;
|
|
|
|
mSocketThread = new Thread(new => SocketThreadProc);
|
|
mSocketThread.Start(false);
|
|
|
|
DarkTheme aTheme = new DarkTheme();
|
|
aTheme.Init();
|
|
ThemeFactory.mDefault = aTheme;
|
|
|
|
mMainFrame = new MainFrame();
|
|
mDockingFrame = mMainFrame.mDockingFrame;
|
|
|
|
BFWindow.Flags windowFlags = BFWindow.Flags.Border | BFWindow.Flags.SysMenu | //| BFWindow.Flags.CaptureMediaKeys |
|
|
BFWindow.Flags.Caption | BFWindow.Flags.Minimize | BFWindow.Flags.QuitOnClose | BFWindowBase.Flags.Resizable |
|
|
BFWindow.Flags.Menu | BFWindow.Flags.SysMenu;
|
|
if (mWantsFullscreen)
|
|
windowFlags |= BFWindowBase.Flags.Fullscreen;
|
|
|
|
//mRootWidget = new Widget();
|
|
mWorkspacePanel = new WorkspacePanel();
|
|
mBoard = new Board();
|
|
mProfilePanel = new ProfilePanel();
|
|
mFindPanel = new FindPanel();
|
|
|
|
//mRootWidget = mBoard;
|
|
mMainWindow = new WidgetWindow(null, "BeefPerf", 0, 0, 1600, 1200, windowFlags, mMainFrame);
|
|
mMainWindow.mOnWindowKeyDown.Add(new => SysKeyDown);
|
|
mMainWindow.SetMinimumSize(480, 360);
|
|
mMainWindow.mIsMainWindow = true;
|
|
CreateMenu();
|
|
|
|
ShowWorkspacePanel();
|
|
ShowTimelinePanel();
|
|
ShowProfilePanel();
|
|
ShowFindPanel();
|
|
|
|
StartFakeClient();
|
|
|
|
GC.SetAutoCollectPeriod(mEnableGCCollect ? 20 : -1);
|
|
GC.SetCollectFreeThreshold(mEnableGCCollect ? 64*1024*1024 : -1);
|
|
}
|
|
|
|
public override void Stop()
|
|
{
|
|
base.Stop();
|
|
mListenSocket.Close();
|
|
}
|
|
|
|
void ShowWorkspacePanel()
|
|
{
|
|
if (mWorkspacePanel.mWidgetWindow != null)
|
|
{
|
|
return;
|
|
}
|
|
TabbedView tabbedView = CreateTabbedView();
|
|
SetupTab(tabbedView, "Workspace", mWorkspacePanel);
|
|
tabbedView.SetRequestedSize(320, 320);
|
|
if ((mDockingFrame.mSplitType == .Vert) || (mDockingFrame.mDockedWidgets.Count == 1))
|
|
mDockingFrame.AddDockedWidget(tabbedView, mDockingFrame.mDockedWidgets[0], DockingFrame.WidgetAlign.Left);
|
|
else
|
|
mDockingFrame.AddDockedWidget(tabbedView, null, DockingFrame.WidgetAlign.Top);
|
|
}
|
|
|
|
void ShowTimelinePanel()
|
|
{
|
|
if (mBoard.mWidgetWindow != null)
|
|
{
|
|
return;
|
|
}
|
|
TabbedView tabbedView = CreateTabbedView();
|
|
SetupTab(tabbedView, "Timeline", mBoard);
|
|
tabbedView.SetRequestedSize(250, 250);
|
|
tabbedView.mIsFillWidget = true;
|
|
if ((mDockingFrame.mSplitType == .Vert) || (mDockingFrame.mDockedWidgets.Count == 1))
|
|
mDockingFrame.AddDockedWidget(tabbedView, mDockingFrame.mDockedWidgets[0], DockingFrame.WidgetAlign.Right);
|
|
else
|
|
mDockingFrame.AddDockedWidget(tabbedView, null, DockingFrame.WidgetAlign.Top);
|
|
}
|
|
|
|
void ShowProfilePanel()
|
|
{
|
|
if (mProfilePanel.mWidgetWindow != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var tabbedView = CreateTabbedView();
|
|
SetupTab(tabbedView, "Profile", mProfilePanel);
|
|
tabbedView.SetRequestedSize(300, 300);
|
|
|
|
if ((mDockingFrame.mSplitType == .Vert) && (mDockingFrame.mDockedWidgets.Count > 0))
|
|
mDockingFrame.AddDockedWidget(tabbedView, mDockingFrame.mDockedWidgets.Back, DockingFrame.WidgetAlign.Left);
|
|
else
|
|
mDockingFrame.AddDockedWidget(tabbedView, null, DockingFrame.WidgetAlign.Bottom);
|
|
}
|
|
|
|
void ShowFindPanel()
|
|
{
|
|
if (mFindPanel.mWidgetWindow != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var tabbedView = CreateTabbedView();
|
|
SetupTab(tabbedView, "Find", mFindPanel);
|
|
tabbedView.SetRequestedSize(300, 300);
|
|
if ((mDockingFrame.mSplitType == .Vert) && (mDockingFrame.mDockedWidgets.Count > 0))
|
|
mDockingFrame.AddDockedWidget(tabbedView, mDockingFrame.mDockedWidgets.Back, DockingFrame.WidgetAlign.Right);
|
|
else
|
|
mDockingFrame.AddDockedWidget(tabbedView, null, DockingFrame.WidgetAlign.Bottom);
|
|
}
|
|
|
|
void SetupTab(TabbedView tabbedView, String label, Widget widget)
|
|
{
|
|
var tabButton = tabbedView.AddTab(label, 0, widget, false);
|
|
tabButton.mCloseClickedEvent.Add(new () =>
|
|
{
|
|
var tabbedView = tabButton.mTabbedView;
|
|
tabbedView.RemoveTab(tabButton);
|
|
if (tabbedView.mTabs.IsEmpty)
|
|
{
|
|
tabbedView.mParentDockingFrame.RemoveDockedWidget(tabbedView);
|
|
gApp.DeferDelete(tabbedView);
|
|
}
|
|
});
|
|
}
|
|
|
|
void ToggleCheck(IMenu menu, ref bool checkVal)
|
|
{
|
|
checkVal = !checkVal;
|
|
var sysMenu = (SysMenu)menu;
|
|
sysMenu.Modify(null, null, null, true, checkVal ? 1 : 0);
|
|
}
|
|
|
|
void ShowInfo()
|
|
{
|
|
int streamSize = 0;
|
|
int lodStreamSize = 0;
|
|
|
|
for (var client in mClients)
|
|
{
|
|
for (var thread in client.mThreads)
|
|
{
|
|
for (var streamData in thread.mStreamDataList)
|
|
{
|
|
streamSize += streamData.mBuffer.Count;
|
|
}
|
|
|
|
for (var streamLOD in thread.mStreamLODs)
|
|
{
|
|
for (var streamData in streamLOD.mStreamDataList)
|
|
{
|
|
lodStreamSize += streamData.mBuffer.Count;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug.WriteLine("Stream Size: {0}k", streamSize / 1024);
|
|
Debug.WriteLine("LOD Stream Size: {0}k", lodStreamSize / 1024);
|
|
}
|
|
|
|
public void CloseSession()
|
|
{
|
|
SetSession(null);
|
|
}
|
|
|
|
public void OpenSession()
|
|
{
|
|
List<int> iList = scope List<int>();
|
|
iList.Add(123);
|
|
|
|
var fileDialog = scope OpenFileDialog();
|
|
fileDialog.ShowReadOnly = false;
|
|
fileDialog.Title = "Open Session";
|
|
fileDialog.Multiselect = true;
|
|
fileDialog.ValidateNames = true;
|
|
fileDialog.DefaultExt = ".bfps";
|
|
fileDialog.SetFilter("BeefPerf Session (*.bfps)|*.bfps|All files (*.*)|*.*");
|
|
if (fileDialog.ShowDialog() case .Ok)
|
|
{
|
|
for (String origProjFilePath in fileDialog.FileNames)
|
|
{
|
|
var session = new BpSession(false);
|
|
switch (session.Load(origProjFilePath))
|
|
{
|
|
case .Ok:
|
|
mSessions.Add(session);
|
|
MarkDirty();
|
|
case .Err(let err):
|
|
switch (err)
|
|
{
|
|
case .FileNotFound, .FileError:
|
|
Fail(scope String()..AppendF("Failed to open file '{0}'", origProjFilePath));
|
|
case .InvalidData:
|
|
Fail(scope String()..AppendF("Invalid data in file '{0}'", origProjFilePath));
|
|
case .InvalidVersion:
|
|
Fail(scope String()..AppendF("Unsupported version in file '{0}'", origProjFilePath));
|
|
}
|
|
delete session;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SaveSession()
|
|
{
|
|
if (mCurSession == null)
|
|
return;
|
|
|
|
var fileDialog = scope SaveFileDialog();
|
|
//fileDialog.ShowReadOnly = false;
|
|
fileDialog.Title = "Save Session";
|
|
fileDialog.Multiselect = true;
|
|
fileDialog.ValidateNames = true;
|
|
fileDialog.DefaultExt = ".bfps";
|
|
fileDialog.SetFilter("BeefPerf Session (*.bfps)|*.bfps|All files (*.*)|*.*");
|
|
if (fileDialog.ShowDialog() case .Ok)
|
|
{
|
|
for (String origProjFilePath in fileDialog.FileNames)
|
|
{
|
|
if (mCurSession.Save(origProjFilePath) case .Err)
|
|
{
|
|
Fail(scope String()..AppendF("Failed to save file '{0}'", origProjFilePath));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RemoveSession()
|
|
{
|
|
if (mCurSession == null)
|
|
return;
|
|
|
|
var session = mCurSession;
|
|
|
|
SetSession(null);
|
|
mSessions.Remove(session);
|
|
|
|
using (mClientMonitor.Enter())
|
|
{
|
|
var client = session as BpClient;
|
|
if (client != null)
|
|
mClients.Remove(client);
|
|
delete session;
|
|
}
|
|
MarkDirty();
|
|
}
|
|
|
|
public void RemoveAllSessions()
|
|
{
|
|
SetSession(null);
|
|
|
|
using (mClientMonitor.Enter())
|
|
{
|
|
ClearAndDeleteItems(mSessions);
|
|
mSessions.Clear();
|
|
mClients.Clear();
|
|
}
|
|
MarkDirty();
|
|
}
|
|
|
|
public void CreateMenu()
|
|
{
|
|
SysMenu root = mMainWindow.mSysMenu;
|
|
|
|
SysMenu subMenu = root.AddMenuItem("&File");
|
|
subMenu.AddMenuItem("&Open Session", "Ctrl+O", new (menu) => { OpenSession(); });
|
|
subMenu.AddMenuItem("&Save Session", "Ctrl+S", new (menu) => { SaveSession(); });
|
|
subMenu.AddMenuItem("&Close Session", "Ctrl+W", new (menu) => { CloseSession(); });
|
|
subMenu.AddMenuItem("&Remove Session", null, new (menu) => { RemoveSession(); });
|
|
subMenu.AddMenuItem("Remove &All Sessions", null, new (menu) => { RemoveAllSessions(); });
|
|
subMenu.AddMenuItem("&Info", "Ctrl+I", new (menu) => { ShowInfo(); });
|
|
subMenu.AddMenuItem("E&xit", null, new (menu) => { mMainWindow.Close(); });
|
|
|
|
subMenu = root.AddMenuItem("&View");
|
|
subMenu.AddMenuItem("&Workspace", "Ctrl+Alt+W", new (menu) => { ShowWorkspacePanel(); });
|
|
subMenu.AddMenuItem("&Timeline", "Ctrl+Alt+T", new (menu) => { ShowTimelinePanel(); });
|
|
subMenu.AddMenuItem("&Profile", "Ctrl+Alt+P", new (menu) => { ShowProfilePanel(); });
|
|
subMenu.AddMenuItem("&Find", "Ctrl+Alt+F", new (menu) => { ShowFindPanel(); });
|
|
|
|
subMenu = root.AddMenuItem("&Debug");
|
|
subMenu.AddMenuItem("GC Collect", null, new (menu) =>
|
|
{
|
|
if (Profiler.StartSampling() case .Ok(let id))
|
|
{
|
|
GC.Collect();
|
|
id.Dispose();
|
|
}
|
|
});
|
|
subMenu.AddMenuItem("Enable GC Collect", null, new (menu) => { ToggleCheck(menu, ref mEnableGCCollect); }, null, null, true, mEnableGCCollect ? 1 : 0);
|
|
}
|
|
|
|
public override void Shutdown()
|
|
{
|
|
base.Shutdown();
|
|
|
|
mShutdownEvent.Set(true);
|
|
}
|
|
|
|
public override bool HandleCommandLineParam(String key, String value)
|
|
{
|
|
switch (key)
|
|
{
|
|
case "-autoOpened":
|
|
mIsAutoOpened = true;
|
|
return true;
|
|
case "-cmd":
|
|
if (value == null)
|
|
return false;
|
|
|
|
Socket.Init();
|
|
|
|
LogLine(scope String()..AppendF("Cmd: {0}", value));
|
|
|
|
bool alreadyRunning = false;
|
|
|
|
//
|
|
{
|
|
Socket socket = scope Socket();
|
|
if (socket.Listen(mListenPort) case .Err)
|
|
alreadyRunning = true;
|
|
}
|
|
|
|
if (!alreadyRunning)
|
|
{
|
|
LogLine("Launching BeefPerf process");
|
|
|
|
var exePath = scope String();
|
|
|
|
var curProcess = scope Process();
|
|
curProcess.GetProcessById(Process.CurrentId);
|
|
exePath.Append(curProcess.ProcessName);
|
|
|
|
ProcessStartInfo procInfo = scope ProcessStartInfo();
|
|
procInfo.SetFileName(exePath);
|
|
procInfo.SetArguments("-autoOpened");
|
|
SpawnedProcess spawnedProcess = scope SpawnedProcess();
|
|
spawnedProcess.Start(procInfo);
|
|
}
|
|
|
|
// Try for 10 seconds
|
|
for (int i < 100)
|
|
{
|
|
Socket socket = scope Socket();
|
|
if (socket.Connect("127.0.0.1", mListenPort) case .Err)
|
|
{
|
|
Thread.Sleep(100);
|
|
continue;
|
|
}
|
|
|
|
DynMemStream memStream = scope DynMemStream();
|
|
memStream.Write((int32)0); // Size placeholder
|
|
|
|
memStream.Write((uint8)BpCmd.Cmd);
|
|
String cmdStr = value;
|
|
memStream.Write(cmdStr);
|
|
memStream.Write((uint8)0);
|
|
|
|
(*(int32*)memStream.Ptr) = (int32)memStream.Length - 4;
|
|
|
|
// Try 10 seconds to send
|
|
for (int sendItr < 100)
|
|
{
|
|
if (memStream.IsEmpty)
|
|
break;
|
|
|
|
switch (socket.Send(memStream.Ptr, memStream.Length))
|
|
{
|
|
case .Ok(let sendLen):
|
|
memStream.RemoveFromStart(sendLen);
|
|
case .Err:
|
|
Fail("Failed to send command");
|
|
}
|
|
|
|
if (memStream.IsEmpty)
|
|
break;
|
|
Thread.Sleep(100); // Wait until we can send more...
|
|
}
|
|
|
|
// Try 10 seconds for a response
|
|
bool gotResult = false;
|
|
RecvLoop: for (int recvStr < 100)
|
|
{
|
|
int result = 0;
|
|
switch (socket.Recv(&result, 1))
|
|
{
|
|
case .Ok(let recvLen):
|
|
if (recvLen > 0)
|
|
{
|
|
if (result != 1)
|
|
Fail("Command failed");
|
|
gotResult = true;
|
|
break RecvLoop;
|
|
}
|
|
case .Err:
|
|
break;
|
|
}
|
|
Thread.Sleep(100);
|
|
}
|
|
|
|
if (!gotResult)
|
|
{
|
|
Fail("Failed to receive command response");
|
|
}
|
|
|
|
if (!mShuttingDown)
|
|
Shutdown();
|
|
return true;
|
|
}
|
|
Fail("Failed to connect to BeefPerf");
|
|
case "-fullscreen":
|
|
mWantsFullscreen = true;
|
|
case "-windowed":
|
|
mWantsFullscreen = false;
|
|
default:
|
|
return base.HandleCommandLineParam(key, value);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override void UnhandledCommandLine(String key, String value)
|
|
{
|
|
Fail(StackStringFormat!("Unhandled command line param: {0}", key));
|
|
}
|
|
|
|
void SetupNewWindow(WidgetWindow window)
|
|
{
|
|
window.mOnWindowKeyDown.Add(new => SysKeyDown);
|
|
//window.mWindowCloseQueryHandler.Add(new => SecondaryAllowClose);
|
|
}
|
|
|
|
DarkTabbedView CreateTabbedView()
|
|
{
|
|
var tabbedView = new DarkTabbedView();
|
|
tabbedView.mSharedData.mOpenNewWindowDelegate.Add(new (fromTabbedView, newWindow) => SetupNewWindow(newWindow));
|
|
return tabbedView;
|
|
}
|
|
|
|
public void PushMainWidget(Widget widget)
|
|
{
|
|
if (mMainWidget != null)
|
|
{
|
|
mMainWidget.RemoveSelf();
|
|
DeferDelete(mMainWidget);
|
|
}
|
|
|
|
mMainWidget = widget;
|
|
|
|
mRootWidget.AddWidget(widget);
|
|
widget.Resize(0, 0, mRootWidget.mWidth, mRootWidget.mHeight);
|
|
widget.SetFocus();
|
|
}
|
|
|
|
void SocketThreadProc()
|
|
{
|
|
while (true)
|
|
{
|
|
if (mShutdownEvent.WaitFor(0))
|
|
return;
|
|
|
|
//TODO: Add client sockets to the select set
|
|
|
|
var readSet = default(Socket.FDSet);
|
|
var writeSet = default(Socket.FDSet);
|
|
var exceptSet = default(Socket.FDSet);
|
|
|
|
void Add(Socket socket)
|
|
{
|
|
readSet.Add(socket.[Friend]mHandle);
|
|
exceptSet.Add(socket.[Friend]mHandle);
|
|
}
|
|
|
|
Add(mListenSocket);
|
|
using (mClientMonitor.Enter())
|
|
{
|
|
for (var client in mClients)
|
|
Add(client.mSocket);
|
|
}
|
|
|
|
#unwarn
|
|
int selectResult = Socket.Select(&readSet, &writeSet, &exceptSet, 20*1000);
|
|
|
|
int clientIdx = 0;
|
|
while (true)
|
|
{
|
|
BpClient client = null;
|
|
using (mClientMonitor.Enter())
|
|
{
|
|
if (clientIdx < mClients.Count)
|
|
{
|
|
client = mClients[clientIdx++];
|
|
}
|
|
|
|
if (client == null)
|
|
break;
|
|
|
|
client.TryRecv();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Update(bool batchStart)
|
|
{
|
|
base.Update(batchStart);
|
|
|
|
/*if (!mListenSocket.IsConnected)
|
|
{
|
|
Listen();
|
|
}*/
|
|
|
|
Socket newConnection = new Socket();
|
|
if (newConnection.AcceptFrom(mListenSocket) case .Ok)
|
|
{
|
|
using (mClientMonitor.Enter())
|
|
{
|
|
BpClient client = new BpClient();
|
|
//client.mProfileId = Profiler.StartSampling();
|
|
client.mConnectTime = DateTime.Now;
|
|
client.mSocket = newConnection;
|
|
mClients.Add(client);
|
|
}
|
|
|
|
/*{
|
|
// Kill all old clients - remove this when we support switching between clients
|
|
ClearAndDeleteItems(mClients);
|
|
|
|
mFindPanel.Clear();
|
|
mProfilePanel.Clear();
|
|
mFindPanel.mNeedsRestartSearch = true;
|
|
|
|
BpClient client = new BpClient();
|
|
client.mSocket = newConnection;
|
|
mClients.Add(client);
|
|
|
|
SetClient(client);
|
|
}*/
|
|
}
|
|
else
|
|
delete newConnection;
|
|
|
|
using (mClientMonitor.Enter())
|
|
{
|
|
for (var client in mClients)
|
|
{
|
|
client.Update();
|
|
|
|
if (client.mSessionOver)
|
|
{
|
|
if (!client.IsSessionInitialized)
|
|
delete client;
|
|
@client.Remove();
|
|
|
|
if (mClients.Count == 0)
|
|
{
|
|
gApp.mStatBytesPerSec = 0;
|
|
}
|
|
MarkDirty();
|
|
}
|
|
|
|
if (mUpdateCnt % 20 == 0)
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
if (mUpdateCnt - mStatReportTick >= 60)
|
|
{
|
|
mStatBytesPerSec = mStatBytesReceived;
|
|
mStatBytesReceived = 0;
|
|
mStatReportTick = mUpdateCnt;
|
|
}
|
|
}
|
|
|
|
void SysKeyDown(KeyDownEvent evt)
|
|
{
|
|
var window = (WidgetWindow)evt.mSender;
|
|
|
|
#unwarn
|
|
Widget focusWidget = window.mFocusWidget;
|
|
|
|
if (evt.mKeyFlags == 0) // No ctrl/shift/alt
|
|
{
|
|
switch (evt.mKeyCode)
|
|
{
|
|
default:
|
|
|
|
}
|
|
}
|
|
|
|
if (evt.mKeyFlags == .Ctrl)
|
|
{
|
|
switch (evt.mKeyCode)
|
|
{
|
|
case (KeyCode)'F':
|
|
ShowFind();
|
|
case (KeyCode)'C':
|
|
if (DarkTooltipManager.sTooltip != null)
|
|
{
|
|
SetClipboardText(DarkTooltipManager.sTooltip.mText);
|
|
}
|
|
default:
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
enum ShowTabResult
|
|
{
|
|
Existing,
|
|
OpenedNew
|
|
}
|
|
|
|
public void WithDocumentTabbedViews(Action<DarkTabbedView> func)
|
|
{
|
|
for (int32 windowIdx = 0; windowIdx < mWindows.Count; windowIdx++)
|
|
{
|
|
var window = mWindows[windowIdx];
|
|
var widgetWindow = window as WidgetWindow;
|
|
if (widgetWindow != null)
|
|
{
|
|
var darkDockingFrame = widgetWindow.mRootWidget as DarkDockingFrame;
|
|
if (widgetWindow == mMainWindow)
|
|
darkDockingFrame = mDockingFrame;
|
|
|
|
if (darkDockingFrame != null)
|
|
{
|
|
darkDockingFrame.WithAllDockedWidgets(scope (dockedWidget) =>
|
|
{
|
|
var tabbedView = dockedWidget as DarkTabbedView;
|
|
if (tabbedView != null)
|
|
func(tabbedView);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void WithTabs(Action<TabbedView.TabButton> func)
|
|
{
|
|
WithDocumentTabbedViews(scope (documentTabbedView) =>
|
|
{
|
|
documentTabbedView.WithTabs(func);
|
|
});
|
|
}
|
|
|
|
public TabbedView.TabButton GetTab(Widget content)
|
|
{
|
|
TabbedView.TabButton tab = null;
|
|
WithTabs(scope [&] (checkTab) =>
|
|
{
|
|
if (checkTab.mContent == content)
|
|
tab = checkTab;
|
|
});
|
|
return tab;
|
|
}
|
|
|
|
TabbedView FindTabbedView(DockingFrame dockingFrame, int32 xDir, int32 yDir)
|
|
{
|
|
bool useFirst = true;
|
|
if (dockingFrame.mSplitType == DockingFrame.SplitType.Horz)
|
|
{
|
|
useFirst = xDir > 0;
|
|
}
|
|
else
|
|
useFirst = yDir > 0;
|
|
|
|
for (int32 pass = 0; pass < 2; pass++)
|
|
{
|
|
for (int32 i = 0; i < dockingFrame.mDockedWidgets.Count; i++)
|
|
{
|
|
if ((useFirst) && (i == 0) && (pass == 0))
|
|
continue;
|
|
|
|
var widget = dockingFrame.mDockedWidgets[i];
|
|
if (widget is TabbedView)
|
|
return (TabbedView)widget;
|
|
DockingFrame childFrame = widget as DockingFrame;
|
|
if (childFrame != null)
|
|
{
|
|
TabbedView tabbedView = FindTabbedView(childFrame, xDir, yDir);
|
|
if (tabbedView != null)
|
|
return tabbedView;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
ShowTabResult ShowTab(Widget tabContent, String name, float width, bool ownsContent)
|
|
{
|
|
var result = ShowTabResult.Existing;
|
|
var tabButton = GetTab(tabContent);
|
|
if (tabButton == null)
|
|
{
|
|
TabbedView tabbedView = FindTabbedView(mDockingFrame, -1, 1);
|
|
if (tabbedView != null)
|
|
{
|
|
tabButton = tabbedView.AddTab(name, width, tabContent, ownsContent);
|
|
result = ShowTabResult.OpenedNew;
|
|
}
|
|
}
|
|
if (tabButton != null)
|
|
tabButton.Activate();
|
|
return result;
|
|
}
|
|
|
|
void ShowPanel(Widget panel, String label)
|
|
{
|
|
//RecordHistoryLocation();
|
|
ShowTab(panel, label, 150, false);
|
|
//panel.FocusForKeyboard();
|
|
}
|
|
|
|
public void ShowFind()
|
|
{
|
|
ShowPanel(mFindPanel, "Find");
|
|
mFindPanel.mEntryEdit.SetFocus();
|
|
}
|
|
|
|
public void SetSession(BpSession session)
|
|
{
|
|
if (session == mCurSession)
|
|
return;
|
|
|
|
mFindPanel.Clear();
|
|
mProfilePanel.Clear();
|
|
mFindPanel.mNeedsRestartSearch = true;
|
|
|
|
mCurSession = session;
|
|
mBoard.ShowSession(session);
|
|
|
|
mFindPanel.Show(mBoard.mPerfView);
|
|
mFindPanel.Clear();
|
|
|
|
MarkDirty();
|
|
|
|
/*if (mBoard.mPerfView != null)
|
|
{
|
|
mBoard.mPerfView.SaveSummary("BfCompiler_Compile", @"c:\temp\save.txt");
|
|
}*/
|
|
}
|
|
|
|
public void ZoneSelected(PerfView perfView, BPSelection selection)
|
|
{
|
|
mProfilePanel.Show(perfView, selection);
|
|
}
|
|
|
|
public void ReportBytesReceived(int32 count)
|
|
{
|
|
mStatBytesReceived += count;
|
|
}
|
|
|
|
public bool HandleClientCommand(BpClient client, StringView cmd)
|
|
{
|
|
int failIdx = mFailIdx;
|
|
mScriptManager.Exec(cmd);
|
|
return failIdx == mFailIdx;
|
|
}
|
|
|
|
public void SessionInitialized(BpClient bpClient)
|
|
{
|
|
mSessions.Add(bpClient);
|
|
UpdateTitle();
|
|
MarkDirty();
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
{
|
|
static BeefPerf.BPApp gApp;
|
|
} |