mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Move Servo into a Control Template
This commit is contained in:
parent
3658a8cc59
commit
663ec48e00
11 changed files with 516 additions and 328 deletions
|
@ -9,259 +9,77 @@
|
||||||
#include "ImmersiveView.h"
|
#include "ImmersiveView.h"
|
||||||
#include "OpenGLES.h"
|
#include "OpenGLES.h"
|
||||||
|
|
||||||
using namespace std::placeholders;
|
|
||||||
using namespace winrt::Windows::UI::Xaml;
|
using namespace winrt::Windows::UI::Xaml;
|
||||||
using namespace winrt::Windows::UI::Core;
|
using namespace winrt::Windows::UI::Core;
|
||||||
using namespace winrt::Windows::UI::ViewManagement;
|
using namespace winrt::Windows::UI::ViewManagement;
|
||||||
using namespace winrt::Windows::Foundation;
|
|
||||||
using namespace winrt::Windows::Graphics::Holographic;
|
using namespace winrt::Windows::Graphics::Holographic;
|
||||||
using namespace concurrency;
|
using namespace winrt::Windows::ApplicationModel::Core;
|
||||||
using namespace servo;
|
|
||||||
|
|
||||||
namespace winrt::ServoApp::implementation {
|
namespace winrt::ServoApp::implementation {
|
||||||
BrowserPage::BrowserPage() {
|
BrowserPage::BrowserPage() {
|
||||||
log("BrowserPage::BrowserPage()");
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializeConditionVariable(&mGLCondVar);
|
BindServoEvents();
|
||||||
InitializeCriticalSection(&mGLLock);
|
|
||||||
Loaded(std::bind(&BrowserPage::OnPageLoaded, this, _1, _2));
|
|
||||||
Window::Current().CoreWindow().VisibilityChanged(
|
|
||||||
std::bind(&BrowserPage::OnVisibilityChanged, this, _1, _2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserPage::Shutdown() {
|
void BrowserPage::BindServoEvents() {
|
||||||
log("BrowserPage::Shutdown()");
|
servoControl().OnURLChanged(
|
||||||
|
[=](const auto &, hstring url) { urlTextbox().Text(url); });
|
||||||
if (mServo != nullptr) {
|
servoControl().OnTitleChanged([=](const auto &, hstring title) {});
|
||||||
if (!mLooping) {
|
servoControl().OnHistoryChanged([=](bool back, bool forward) {
|
||||||
// FIXME: this should not happen. In that case, we can't send the
|
backButton().IsEnabled(back);
|
||||||
// shutdown event to Servo.
|
forwardButton().IsEnabled(forward);
|
||||||
} else {
|
});
|
||||||
RunOnGLThread([=] { mServo->RequestShutdown(); });
|
servoControl().OnLoadStarted([=] {
|
||||||
mLoopTask->wait();
|
|
||||||
mLoopTask.reset();
|
|
||||||
mServo.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::OnPageLoaded(IInspectable const &, RoutedEventArgs const &) {
|
|
||||||
log("BrowserPage::OnPageLoaded()");
|
|
||||||
CreateRenderSurface();
|
|
||||||
StartRenderLoop();
|
|
||||||
swapChainPanel().PointerReleased(
|
|
||||||
std::bind(&BrowserPage::OnSurfaceClicked, this, _1, _2));
|
|
||||||
swapChainPanel().ManipulationDelta(
|
|
||||||
std::bind(&BrowserPage::OnSurfaceManipulationDelta, this, _1, _2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::OnVisibilityChanged(CoreWindow const &,
|
|
||||||
VisibilityChangedEventArgs const &args) {
|
|
||||||
auto visible = args.Visible();
|
|
||||||
|
|
||||||
// FIXME: for now, this is disabled as we get this message before shutdown,
|
|
||||||
// stopping the event loop, which we can't recover from yet (see comment in
|
|
||||||
// Loop())
|
|
||||||
|
|
||||||
// if (visible && !mLooping) {
|
|
||||||
// StartRenderLoop();
|
|
||||||
//}
|
|
||||||
// if (!visible && mLooping) {
|
|
||||||
// StopRenderLoop();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::CreateRenderSurface() {
|
|
||||||
if (mRenderSurface == EGL_NO_SURFACE) {
|
|
||||||
mRenderSurface = mOpenGLES.CreateSurface(swapChainPanel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::DestroyRenderSurface() {
|
|
||||||
mOpenGLES.DestroySurface(mRenderSurface);
|
|
||||||
mRenderSurface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::RecoverFromLostDevice() {
|
|
||||||
StopRenderLoop();
|
|
||||||
DestroyRenderSurface();
|
|
||||||
mOpenGLES.Reset();
|
|
||||||
CreateRenderSurface();
|
|
||||||
StartRenderLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**** GL THREAD LOOP ****/
|
|
||||||
|
|
||||||
void BrowserPage::Loop() {
|
|
||||||
log("BrowserPage::Loop(). GL thread: %i", GetCurrentThreadId());
|
|
||||||
|
|
||||||
mOpenGLES.MakeCurrent(mRenderSurface);
|
|
||||||
|
|
||||||
EGLint panelWidth = 0;
|
|
||||||
EGLint panelHeight = 0;
|
|
||||||
mOpenGLES.GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
|
||||||
glViewport(0, 0, panelWidth, panelHeight);
|
|
||||||
|
|
||||||
if (mServo == nullptr) {
|
|
||||||
log("Entering loop");
|
|
||||||
ServoDelegate *sd = static_cast<ServoDelegate *>(this);
|
|
||||||
mServo = std::make_unique<Servo>(panelWidth, panelHeight, *sd);
|
|
||||||
} else {
|
|
||||||
// FIXME: this will fail since create_task didn't pick the thread
|
|
||||||
// where Servo was running initially.
|
|
||||||
throw winrt::hresult_error(E_FAIL, L"Recovering loop unimplemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
mServo->SetBatchMode(true);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
EnterCriticalSection(&mGLLock);
|
|
||||||
while (mTasks.size() == 0 && !mAnimating && mLooping) {
|
|
||||||
SleepConditionVariableCS(&mGLCondVar, &mGLLock, INFINITE);
|
|
||||||
}
|
|
||||||
if (!mLooping) {
|
|
||||||
LeaveCriticalSection(&mGLLock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (auto &&task : mTasks) {
|
|
||||||
task();
|
|
||||||
}
|
|
||||||
mTasks.clear();
|
|
||||||
LeaveCriticalSection(&mGLLock);
|
|
||||||
mServo->PerformUpdates();
|
|
||||||
}
|
|
||||||
mServo->DeInit();
|
|
||||||
cancel_current_task();
|
|
||||||
} // namespace winrt::ServoApp::implementation
|
|
||||||
|
|
||||||
void BrowserPage::StartRenderLoop() {
|
|
||||||
if (mLooping) {
|
|
||||||
#if defined _DEBUG
|
|
||||||
throw winrt::hresult_error(E_FAIL, L"GL thread is already looping");
|
|
||||||
#else
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
mLooping = true;
|
|
||||||
log("BrowserPage::StartRenderLoop(). UI thread: %i", GetCurrentThreadId());
|
|
||||||
auto task = Concurrency::create_task([=] { Loop(); });
|
|
||||||
mLoopTask = std::make_unique<Concurrency::task<void>>(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::StopRenderLoop() {
|
|
||||||
if (mLooping) {
|
|
||||||
EnterCriticalSection(&mGLLock);
|
|
||||||
mLooping = false;
|
|
||||||
LeaveCriticalSection(&mGLLock);
|
|
||||||
WakeConditionVariable(&mGLCondVar);
|
|
||||||
mLoopTask->wait();
|
|
||||||
mLoopTask.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**** SERVO CALLBACKS ****/
|
|
||||||
|
|
||||||
void BrowserPage::OnLoadStarted() {
|
|
||||||
RunOnUIThread([=] {
|
|
||||||
reloadButton().IsEnabled(false);
|
reloadButton().IsEnabled(false);
|
||||||
stopButton().IsEnabled(true);
|
stopButton().IsEnabled(true);
|
||||||
});
|
});
|
||||||
}
|
servoControl().OnLoadEnded([=] {
|
||||||
|
|
||||||
void BrowserPage::OnLoadEnded() {
|
|
||||||
RunOnUIThread([=] {
|
|
||||||
reloadButton().IsEnabled(true);
|
reloadButton().IsEnabled(true);
|
||||||
stopButton().IsEnabled(false);
|
stopButton().IsEnabled(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserPage::OnHistoryChanged(bool back, bool forward) {
|
void BrowserPage::Shutdown() {
|
||||||
RunOnUIThread([=] {
|
servoControl().Shutdown();
|
||||||
backButton().IsEnabled(back);
|
|
||||||
forwardButton().IsEnabled(forward);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::OnShutdownComplete() {
|
|
||||||
EnterCriticalSection(&mGLLock);
|
|
||||||
mLooping = false;
|
|
||||||
LeaveCriticalSection(&mGLLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::OnAlert(std::wstring message) {
|
|
||||||
// FIXME: make this sync
|
|
||||||
RunOnUIThread([=] {
|
|
||||||
Windows::UI::Popups::MessageDialog msg{message};
|
|
||||||
msg.ShowAsync();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::OnTitleChanged(std::wstring title) {
|
|
||||||
RunOnUIThread([=] { ApplicationView::GetForCurrentView().Title(title); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::OnURLChanged(std::wstring url) {
|
|
||||||
RunOnUIThread([=] { urlTextbox().Text(url); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::Flush() {
|
|
||||||
if (mOpenGLES.SwapBuffers(mRenderSurface) != GL_TRUE) {
|
|
||||||
// The call to eglSwapBuffers might not be successful (i.e. due to Device
|
|
||||||
// Lost) If the call fails, then we must reinitialize EGL and the GL
|
|
||||||
// resources.
|
|
||||||
RunOnUIThread([=] { RecoverFromLostDevice(); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::MakeCurrent() { mOpenGLES.MakeCurrent(mRenderSurface); }
|
|
||||||
|
|
||||||
void BrowserPage::WakeUp() {
|
|
||||||
RunOnGLThread([=] { });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BrowserPage::OnAllowNavigation(std::wstring) { return true; }
|
|
||||||
|
|
||||||
void BrowserPage::OnAnimatingChanged(bool animating) {
|
|
||||||
EnterCriticalSection(&mGLLock);
|
|
||||||
mAnimating = animating;
|
|
||||||
LeaveCriticalSection(&mGLLock);
|
|
||||||
WakeConditionVariable(&mGLCondVar);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Callable> void BrowserPage::RunOnUIThread(Callable cb) {
|
|
||||||
swapChainPanel().Dispatcher().RunAsync(
|
|
||||||
Windows::UI::Core::CoreDispatcherPriority::High, cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**** USER INTERACTIONS WITH UI ****/
|
/**** USER INTERACTIONS WITH UI ****/
|
||||||
|
|
||||||
void BrowserPage::OnBackButtonClicked(IInspectable const &,
|
void BrowserPage::OnBackButtonClicked(IInspectable const &,
|
||||||
RoutedEventArgs const &) {
|
RoutedEventArgs const &) {
|
||||||
RunOnGLThread([=] { mServo->GoBack(); });
|
servoControl().GoBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserPage::OnForwardButtonClicked(IInspectable const &,
|
void BrowserPage::OnForwardButtonClicked(IInspectable const &,
|
||||||
RoutedEventArgs const &) {
|
RoutedEventArgs const &) {
|
||||||
RunOnGLThread([=] { mServo->GoForward(); });
|
servoControl().GoForward();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserPage::OnReloadButtonClicked(IInspectable const &,
|
void BrowserPage::OnReloadButtonClicked(IInspectable const &,
|
||||||
RoutedEventArgs const &) {
|
RoutedEventArgs const &) {
|
||||||
RunOnGLThread([=] { mServo->Reload(); });
|
servoControl().Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserPage::OnStopButtonClicked(IInspectable const &,
|
void BrowserPage::OnStopButtonClicked(IInspectable const &,
|
||||||
RoutedEventArgs const &) {
|
RoutedEventArgs const &) {
|
||||||
RunOnGLThread([=] { mServo->Stop(); });
|
servoControl().Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrowserPage::OnURLEdited(IInspectable const &sender,
|
||||||
|
Input::KeyRoutedEventArgs const &e) {
|
||||||
|
if (e.Key() == Windows::System::VirtualKey::Enter) {
|
||||||
|
servoControl().Focus(FocusState::Programmatic);
|
||||||
|
auto input = urlTextbox().Text();
|
||||||
|
auto uri = servoControl().LoadURIOrSearch(input);
|
||||||
|
urlTextbox().Text(uri.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserPage::OnImmersiveButtonClicked(IInspectable const &,
|
void BrowserPage::OnImmersiveButtonClicked(IInspectable const &,
|
||||||
RoutedEventArgs const &) {
|
RoutedEventArgs const &) {
|
||||||
if (HolographicSpace::IsAvailable()) {
|
if (HolographicSpace::IsAvailable()) {
|
||||||
log("Holographic space available");
|
log("Holographic space available");
|
||||||
auto v =
|
auto v = CoreApplication::CreateNewView(mImmersiveViewSource);
|
||||||
winrt::Windows::ApplicationModel::Core::CoreApplication::CreateNewView(
|
|
||||||
mImmersiveViewSource);
|
|
||||||
auto parentId = ApplicationView::GetForCurrentView().Id();
|
auto parentId = ApplicationView::GetForCurrentView().Id();
|
||||||
v.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [=] {
|
v.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [=] {
|
||||||
auto winId = ApplicationView::GetForCurrentView().Id();
|
auto winId = ApplicationView::GetForCurrentView().Id();
|
||||||
|
@ -273,30 +91,4 @@ void BrowserPage::OnImmersiveButtonClicked(IInspectable const &,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserPage::OnSurfaceManipulationDelta(
|
|
||||||
IInspectable const &, Input::ManipulationDeltaRoutedEventArgs const &e) {
|
|
||||||
auto x = e.Position().X;
|
|
||||||
auto y = e.Position().Y;
|
|
||||||
auto dx = e.Delta().Translation.X;
|
|
||||||
auto dy = e.Delta().Translation.Y;
|
|
||||||
RunOnGLThread([=] { mServo->Scroll(dx, dy, x, y); });
|
|
||||||
e.Handled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::OnSurfaceClicked(IInspectable const &,
|
|
||||||
Input::PointerRoutedEventArgs const &e) {
|
|
||||||
auto coords = e.GetCurrentPoint(swapChainPanel());
|
|
||||||
auto x = coords.Position().X;
|
|
||||||
auto y = coords.Position().Y;
|
|
||||||
RunOnGLThread([=] { mServo->Click(x, y); });
|
|
||||||
e.Handled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrowserPage::RunOnGLThread(std::function<void()> task) {
|
|
||||||
EnterCriticalSection(&mGLLock);
|
|
||||||
mTasks.push_back(task);
|
|
||||||
LeaveCriticalSection(&mGLLock);
|
|
||||||
WakeConditionVariable(&mGLCondVar);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace winrt::ServoApp::implementation
|
} // namespace winrt::ServoApp::implementation
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
|
|
||||||
#include "BrowserPage.g.h"
|
#include "BrowserPage.g.h"
|
||||||
#include "ImmersiveView.h"
|
#include "ImmersiveView.h"
|
||||||
#include "OpenGLES.h"
|
#include "ServoControl.h"
|
||||||
#include "Servo.h"
|
|
||||||
|
|
||||||
namespace winrt::ServoApp::implementation {
|
namespace winrt::ServoApp::implementation {
|
||||||
|
|
||||||
struct BrowserPage : BrowserPageT<BrowserPage>,
|
struct BrowserPage : BrowserPageT<BrowserPage> {
|
||||||
public servo::ServoDelegate {
|
|
||||||
public:
|
public:
|
||||||
BrowserPage();
|
BrowserPage();
|
||||||
|
|
||||||
|
@ -26,59 +25,13 @@ public:
|
||||||
Windows::UI::Xaml::RoutedEventArgs const &);
|
Windows::UI::Xaml::RoutedEventArgs const &);
|
||||||
void OnStopButtonClicked(Windows::Foundation::IInspectable const &,
|
void OnStopButtonClicked(Windows::Foundation::IInspectable const &,
|
||||||
Windows::UI::Xaml::RoutedEventArgs const &);
|
Windows::UI::Xaml::RoutedEventArgs const &);
|
||||||
void
|
void OnURLEdited(Windows::Foundation::IInspectable const &,
|
||||||
OnSurfaceClicked(Windows::Foundation::IInspectable const &,
|
Windows::UI::Xaml::Input::KeyRoutedEventArgs const &);
|
||||||
Windows::UI::Xaml::Input::PointerRoutedEventArgs const &);
|
|
||||||
|
|
||||||
void BrowserPage::OnSurfaceManipulationDelta(
|
|
||||||
IInspectable const &,
|
|
||||||
Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs const &e);
|
|
||||||
|
|
||||||
template <typename Callable> void RunOnUIThread(Callable);
|
|
||||||
void RunOnGLThread(std::function<void()>);
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
virtual void WakeUp();
|
|
||||||
virtual void OnLoadStarted();
|
|
||||||
virtual void OnLoadEnded();
|
|
||||||
virtual void OnHistoryChanged(bool, bool);
|
|
||||||
virtual void OnShutdownComplete();
|
|
||||||
virtual void OnTitleChanged(std::wstring);
|
|
||||||
virtual void OnAlert(std::wstring);
|
|
||||||
virtual void OnURLChanged(std::wstring);
|
|
||||||
virtual void Flush();
|
|
||||||
virtual void MakeCurrent();
|
|
||||||
virtual bool OnAllowNavigation(std::wstring);
|
|
||||||
virtual void OnAnimatingChanged(bool);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnVisibilityChanged(
|
|
||||||
Windows::UI::Core::CoreWindow const &,
|
|
||||||
Windows::UI::Core::VisibilityChangedEventArgs const &args);
|
|
||||||
void OnPageLoaded(Windows::Foundation::IInspectable const &,
|
|
||||||
Windows::UI::Xaml::RoutedEventArgs const &);
|
|
||||||
void CreateRenderSurface();
|
|
||||||
void DestroyRenderSurface();
|
|
||||||
void RecoverFromLostDevice();
|
|
||||||
|
|
||||||
void StartRenderLoop();
|
|
||||||
void StopRenderLoop();
|
|
||||||
void Loop();
|
|
||||||
|
|
||||||
std::unique_ptr<Concurrency::task<void>> mLoopTask;
|
|
||||||
winrt::ServoApp::ImmersiveViewSource mImmersiveViewSource;
|
winrt::ServoApp::ImmersiveViewSource mImmersiveViewSource;
|
||||||
EGLSurface mRenderSurface{EGL_NO_SURFACE};
|
void BindServoEvents();
|
||||||
std::unique_ptr<servo::Servo> mServo;
|
|
||||||
|
|
||||||
std::vector<std::function<void()>> mTasks;
|
|
||||||
|
|
||||||
CRITICAL_SECTION mGLLock;
|
|
||||||
CONDITION_VARIABLE mGLCondVar;
|
|
||||||
|
|
||||||
bool mAnimating = false;
|
|
||||||
bool mLooping = false;
|
|
||||||
|
|
||||||
OpenGLES mOpenGLES; // FIXME: shared pointer
|
|
||||||
};
|
};
|
||||||
} // namespace winrt::ServoApp::implementation
|
} // namespace winrt::ServoApp::implementation
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,16 @@
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel Orientation="Horizontal" Grid.Column="0">
|
<StackPanel Orientation="Horizontal" Grid.Column="0">
|
||||||
<Button x:Name="backButton" IsEnabled="false" Content="Back" Click="OnBackButtonClicked"/>
|
<Button x:Name="backButton" IsTabStop="true" IsEnabled="false" Content="Back" Click="OnBackButtonClicked"/>
|
||||||
<Button x:Name="forwardButton" IsEnabled="false" Content="Forward" Click="OnForwardButtonClicked"/>
|
<Button x:Name="forwardButton" IsTabStop="true" IsEnabled="false" Content="Forward" Click="OnForwardButtonClicked"/>
|
||||||
<Button x:Name="reloadButton" IsEnabled="false" Content="reload" Click="OnReloadButtonClicked"/>
|
<Button x:Name="reloadButton" IsTabStop="true" IsEnabled="false" Content="reload" Click="OnReloadButtonClicked"/>
|
||||||
<Button x:Name="stopButton" IsEnabled="false" Content="stop" Click="OnStopButtonClicked"/>
|
<Button x:Name="stopButton" IsTabStop="true" IsEnabled="false" Content="stop" Click="OnStopButtonClicked"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBox Text="" AcceptsReturn="True" PlaceholderText="Type a URL" x:Name="urlTextbox" Grid.Column="1" IsReadOnly="True"/>
|
<TextBox Text="" IsTabStop="true" PlaceholderText="Type a URL" x:Name="urlTextbox" Grid.Column="1" KeyUp="OnURLEdited"/>
|
||||||
<StackPanel Orientation="Horizontal" Grid.Column="2">
|
<StackPanel Orientation="Horizontal" Grid.Column="2">
|
||||||
<Button x:Name="immersiveButton" Click="OnImmersiveButtonClicked">Run Immersive</Button>
|
<Button x:Name="immersiveButton" Click="OnImmersiveButtonClicked">Run Immersive</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<SwapChainPanel x:Name="swapChainPanel" MinHeight="200" MinWidth="200" Grid.Row="1" ManipulationMode="All">
|
<local:ServoControl TabIndex="0" x:Name="servoControl" Grid.Row="1"/>
|
||||||
</SwapChainPanel>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "Servo.h"
|
#include "Servo.h"
|
||||||
|
|
||||||
namespace servo {
|
namespace winrt::servo {
|
||||||
|
|
||||||
void on_load_started() { sServo->Delegate().OnLoadStarted(); }
|
void on_load_started() { sServo->Delegate().OnServoLoadStarted(); }
|
||||||
void on_load_ended() { sServo->Delegate().OnLoadEnded(); }
|
void on_load_ended() { sServo->Delegate().OnServoLoadEnded(); }
|
||||||
void on_history_changed(bool back, bool forward) {
|
void on_history_changed(bool back, bool forward) {
|
||||||
sServo->Delegate().OnHistoryChanged(back, forward);
|
sServo->Delegate().OnServoHistoryChanged(back, forward);
|
||||||
}
|
}
|
||||||
void on_shutdown_complete() { sServo->Delegate().OnShutdownComplete(); }
|
void on_shutdown_complete() { sServo->Delegate().OnServoShutdownComplete(); }
|
||||||
void on_alert(const char *message) {
|
void on_alert(const char *message) {
|
||||||
sServo->Delegate().OnAlert(char2w(message));
|
sServo->Delegate().OnServoAlert(char2hstring(message));
|
||||||
}
|
}
|
||||||
void on_title_changed(const char *title) {
|
void on_title_changed(const char *title) {
|
||||||
sServo->Delegate().OnTitleChanged(char2w(title));
|
sServo->Delegate().OnServoTitleChanged(char2hstring(title));
|
||||||
}
|
}
|
||||||
void on_url_changed(const char *url) {
|
void on_url_changed(const char *url) {
|
||||||
sServo->Delegate().OnURLChanged(char2w(url));
|
sServo->Delegate().OnServoURLChanged(char2hstring(url));
|
||||||
}
|
}
|
||||||
void flush() { sServo->Delegate().Flush(); }
|
void flush() { sServo->Delegate().Flush(); }
|
||||||
void make_current() { sServo->Delegate().MakeCurrent(); }
|
void make_current() { sServo->Delegate().MakeCurrent(); }
|
||||||
void wakeup() { sServo->Delegate().WakeUp(); }
|
void wakeup() { sServo->Delegate().WakeUp(); }
|
||||||
bool on_allow_navigation(const char *url) {
|
bool on_allow_navigation(const char *url) {
|
||||||
return sServo->Delegate().OnAllowNavigation(char2w(url));
|
return sServo->Delegate().OnServoAllowNavigation(char2hstring(url));
|
||||||
};
|
};
|
||||||
void on_animating_changed(bool aAnimating) {
|
void on_animating_changed(bool aAnimating) {
|
||||||
sServo->Delegate().OnAnimatingChanged(aAnimating);
|
sServo->Delegate().OnServoAnimatingChanged(aAnimating);
|
||||||
}
|
}
|
||||||
|
|
||||||
Servo::Servo(GLsizei width, GLsizei height, ServoDelegate &aDelegate)
|
Servo::Servo(GLsizei width, GLsizei height, ServoDelegate &aDelegate)
|
||||||
|
@ -60,14 +60,14 @@ Servo::Servo(GLsizei width, GLsizei height, ServoDelegate &aDelegate)
|
||||||
|
|
||||||
Servo::~Servo() { sServo = nullptr; }
|
Servo::~Servo() { sServo = nullptr; }
|
||||||
|
|
||||||
std::wstring char2w(const char *c_str) {
|
winrt::hstring char2hstring(const char *c_str) {
|
||||||
|
// FIXME: any better way of doing this?
|
||||||
auto str = std::string(c_str);
|
auto str = std::string(c_str);
|
||||||
int size_needed =
|
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
|
||||||
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
|
|
||||||
std::wstring str2(size_needed, 0);
|
std::wstring str2(size_needed, 0);
|
||||||
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &str2[0],
|
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &str2[0], size_needed);
|
||||||
size_needed);
|
winrt::hstring str3 {str2};
|
||||||
return str2;
|
return str3;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace servo
|
} // namespace servo
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "logs.h"
|
#include "logs.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
namespace servo {
|
namespace winrt::servo {
|
||||||
|
|
||||||
namespace capi {
|
namespace capi {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -20,17 +21,17 @@ public:
|
||||||
// Called from any thread
|
// Called from any thread
|
||||||
virtual void WakeUp() = 0;
|
virtual void WakeUp() = 0;
|
||||||
// Called from GL thread
|
// Called from GL thread
|
||||||
virtual void OnLoadStarted() = 0;
|
virtual void OnServoLoadStarted() = 0;
|
||||||
virtual void OnLoadEnded() = 0;
|
virtual void OnServoLoadEnded() = 0;
|
||||||
virtual void OnHistoryChanged(bool, bool) = 0;
|
virtual void OnServoHistoryChanged(bool, bool) = 0;
|
||||||
virtual void OnShutdownComplete() = 0;
|
virtual void OnServoShutdownComplete() = 0;
|
||||||
virtual void OnTitleChanged(std::wstring) = 0;
|
virtual void OnServoTitleChanged(hstring) = 0;
|
||||||
virtual void OnAlert(std::wstring) = 0;
|
virtual void OnServoAlert(hstring) = 0;
|
||||||
virtual void OnURLChanged(std::wstring) = 0;
|
virtual void OnServoURLChanged(hstring) = 0;
|
||||||
|
virtual bool OnServoAllowNavigation(hstring) = 0;
|
||||||
|
virtual void OnServoAnimatingChanged(bool) = 0;
|
||||||
virtual void Flush() = 0;
|
virtual void Flush() = 0;
|
||||||
virtual void MakeCurrent() = 0;
|
virtual void MakeCurrent() = 0;
|
||||||
virtual bool OnAllowNavigation(std::wstring) = 0;
|
|
||||||
virtual void OnAnimatingChanged(bool) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~ServoDelegate(){};
|
virtual ~ServoDelegate(){};
|
||||||
|
@ -51,6 +52,14 @@ public:
|
||||||
void Click(float x, float y) { capi::click(x, y); }
|
void Click(float x, float y) { capi::click(x, y); }
|
||||||
void Reload() { capi::reload(); }
|
void Reload() { capi::reload(); }
|
||||||
void Stop() { capi::stop(); }
|
void Stop() { capi::stop(); }
|
||||||
|
void LoadUri(hstring uri) {
|
||||||
|
const wchar_t* wc = uri.c_str();
|
||||||
|
size_t size = uri.size() + 1;
|
||||||
|
char* str = new char[size];
|
||||||
|
size_t converted = 0;
|
||||||
|
wcstombs_s(&converted, str, size, wc, uri.size());
|
||||||
|
capi::load_uri(str);
|
||||||
|
}
|
||||||
void Scroll(float dx, float dy, float x, float y) {
|
void Scroll(float dx, float dy, float x, float y) {
|
||||||
capi::scroll(dx, dy, x, y);
|
capi::scroll(dx, dy, x, y);
|
||||||
}
|
}
|
||||||
|
@ -73,6 +82,6 @@ private:
|
||||||
// the Servo instance. See https://github.com/servo/servo/issues/22967
|
// the Servo instance. See https://github.com/servo/servo/issues/22967
|
||||||
static Servo *sServo = nullptr;
|
static Servo *sServo = nullptr;
|
||||||
|
|
||||||
std::wstring char2w(const char *c_str);
|
hstring char2hstring(const char *c_str);
|
||||||
|
|
||||||
} // namespace servo
|
} // namespace servo
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
<DependentUpon>BrowserPage.xaml</DependentUpon>
|
<DependentUpon>BrowserPage.xaml</DependentUpon>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Servo.h" />
|
<ClInclude Include="Servo.h" />
|
||||||
|
<ClInclude Include="ServoControl.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ApplicationDefinition Include="App.xaml">
|
<ApplicationDefinition Include="App.xaml">
|
||||||
|
@ -168,6 +169,9 @@
|
||||||
<Page Include="BrowserPage.xaml">
|
<Page Include="BrowserPage.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Themes\Generic.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AppxManifest Include="Package.appxmanifest">
|
<AppxManifest Include="Package.appxmanifest">
|
||||||
|
@ -307,6 +311,7 @@
|
||||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||||
<ClCompile Include="logs.cpp" />
|
<ClCompile Include="logs.cpp" />
|
||||||
<ClCompile Include="Servo.cpp" />
|
<ClCompile Include="Servo.cpp" />
|
||||||
|
<ClCompile Include="ServoControl.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Midl Include="App.idl">
|
<Midl Include="App.idl">
|
||||||
|
@ -315,6 +320,7 @@
|
||||||
<Midl Include="BrowserPage.idl">
|
<Midl Include="BrowserPage.idl">
|
||||||
<DependentUpon>BrowserPage.xaml</DependentUpon>
|
<DependentUpon>BrowserPage.xaml</DependentUpon>
|
||||||
</Midl>
|
</Midl>
|
||||||
|
<Midl Include="ServoControl.idl" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Midl Include="BrowserPage.idl" />
|
<Midl Include="BrowserPage.idl" />
|
||||||
<Midl Include="App.idl" />
|
<Midl Include="App.idl" />
|
||||||
|
<Midl Include="ServoControl.idl">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</Midl>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="pch.cpp" />
|
<ClCompile Include="pch.cpp" />
|
||||||
|
@ -10,8 +13,6 @@
|
||||||
<ClCompile Include="logs.cpp" />
|
<ClCompile Include="logs.cpp" />
|
||||||
<ClCompile Include="ImmersiveView.cpp" />
|
<ClCompile Include="ImmersiveView.cpp" />
|
||||||
<ClCompile Include="BrowserPage.cpp" />
|
<ClCompile Include="BrowserPage.cpp" />
|
||||||
<ClCompile Include="Servo.cpp" />
|
|
||||||
<ClCompile Include="OpenGLES.cpp" />
|
|
||||||
<ClCompile Include="App.cpp" />
|
<ClCompile Include="App.cpp" />
|
||||||
<ClCompile Include="Common\CameraResources.cpp">
|
<ClCompile Include="Common\CameraResources.cpp">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
|
@ -26,14 +27,21 @@
|
||||||
<Filter>Content</Filter>
|
<Filter>Content</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="ImmersiveMain.cpp" />
|
<ClCompile Include="ImmersiveMain.cpp" />
|
||||||
|
<ClCompile Include="ServoControl.cpp">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Servo.cpp">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="OpenGLES.cpp">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="logs.h" />
|
<ClInclude Include="logs.h" />
|
||||||
<ClInclude Include="ImmersiveView.h" />
|
<ClInclude Include="ImmersiveView.h" />
|
||||||
<ClInclude Include="BrowserPage.h" />
|
<ClInclude Include="BrowserPage.h" />
|
||||||
<ClInclude Include="Servo.h" />
|
|
||||||
<ClInclude Include="OpenGLES.h" />
|
|
||||||
<ClInclude Include="App.h" />
|
<ClInclude Include="App.h" />
|
||||||
<ClInclude Include="Common\CameraResources.h">
|
<ClInclude Include="Common\CameraResources.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
|
@ -57,6 +65,15 @@
|
||||||
<Filter>Content</Filter>
|
<Filter>Content</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="ImmersiveMain.h" />
|
<ClInclude Include="ImmersiveMain.h" />
|
||||||
|
<ClInclude Include="ServoControl.h">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Servo.h">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="OpenGLES.h">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Image Include="Assets\Wide310x150Logo.scale-200.png">
|
<Image Include="Assets\Wide310x150Logo.scale-200.png">
|
||||||
|
@ -191,12 +208,18 @@
|
||||||
<Filter Include="ReleaseARM64ServoDLLs">
|
<Filter Include="ReleaseARM64ServoDLLs">
|
||||||
<UniqueIdentifier>{384b4019-d076-4301-994d-a891969a3036}</UniqueIdentifier>
|
<UniqueIdentifier>{384b4019-d076-4301-994d-a891969a3036}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="ServoControl">
|
||||||
|
<UniqueIdentifier>{d21a959c-19d1-4a54-b942-692c27e5b3a6}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="PropertySheet.props" />
|
<None Include="PropertySheet.props" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Include="BrowserPage.xaml" />
|
<Page Include="BrowserPage.xaml" />
|
||||||
|
<Page Include="Themes\Generic.xaml">
|
||||||
|
<Filter>ServoControl</Filter>
|
||||||
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FxCompile Include="Content\GeometryShader.hlsl">
|
<FxCompile Include="Content\GeometryShader.hlsl">
|
||||||
|
|
257
support/hololens/ServoApp/ServoControl.cpp
Normal file
257
support/hololens/ServoApp/ServoControl.cpp
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
#include "pch.h"
|
||||||
|
#include "ServoControl.h"
|
||||||
|
#include "ServoControl.g.cpp"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
using namespace std::placeholders;
|
||||||
|
using namespace winrt::Windows::UI::Xaml;
|
||||||
|
using namespace winrt::Windows::UI::Core;
|
||||||
|
using namespace winrt::Windows::Foundation;
|
||||||
|
using namespace concurrency;
|
||||||
|
using namespace winrt::servo;
|
||||||
|
|
||||||
|
namespace winrt::ServoApp::implementation {
|
||||||
|
|
||||||
|
ServoControl::ServoControl() {
|
||||||
|
DefaultStyleKey(winrt::box_value(L"ServoApp.ServoControl"));
|
||||||
|
Loaded(std::bind(&ServoControl::OnLoaded, this, _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::Shutdown() {
|
||||||
|
if (mServo != nullptr) {
|
||||||
|
if (!mLooping) {
|
||||||
|
// FIXME: this should not happen. In that case, we can't send the
|
||||||
|
// shutdown event to Servo.
|
||||||
|
} else {
|
||||||
|
RunOnGLThread([=] { mServo->RequestShutdown(); });
|
||||||
|
mLoopTask->wait();
|
||||||
|
mLoopTask.reset();
|
||||||
|
mServo.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnLoaded(IInspectable const &, RoutedEventArgs const &) {
|
||||||
|
Panel().PointerReleased(
|
||||||
|
std::bind(&ServoControl::OnSurfaceClicked, this, _1, _2));
|
||||||
|
Panel().ManipulationDelta(
|
||||||
|
std::bind(&ServoControl::OnSurfaceManipulationDelta, this, _1, _2));
|
||||||
|
InitializeConditionVariable(&mGLCondVar);
|
||||||
|
InitializeCriticalSection(&mGLLock);
|
||||||
|
CreateRenderSurface();
|
||||||
|
StartRenderLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Controls::SwapChainPanel ServoControl::Panel() {
|
||||||
|
// FIXME: is there a better way of doing this?
|
||||||
|
return GetTemplateChild(L"swapChainPanel")
|
||||||
|
.as<Controls::SwapChainPanel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::CreateRenderSurface() {
|
||||||
|
if (mRenderSurface == EGL_NO_SURFACE) {
|
||||||
|
mRenderSurface = mOpenGLES.CreateSurface(Panel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::DestroyRenderSurface() {
|
||||||
|
mOpenGLES.DestroySurface(mRenderSurface);
|
||||||
|
mRenderSurface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::RecoverFromLostDevice() {
|
||||||
|
StopRenderLoop();
|
||||||
|
DestroyRenderSurface();
|
||||||
|
mOpenGLES.Reset();
|
||||||
|
CreateRenderSurface();
|
||||||
|
StartRenderLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnSurfaceManipulationDelta(
|
||||||
|
IInspectable const &, Input::ManipulationDeltaRoutedEventArgs const &e) {
|
||||||
|
auto x = e.Position().X;
|
||||||
|
auto y = e.Position().Y;
|
||||||
|
auto dx = e.Delta().Translation.X;
|
||||||
|
auto dy = e.Delta().Translation.Y;
|
||||||
|
RunOnGLThread([=] { mServo->Scroll(dx, dy, x, y); });
|
||||||
|
e.Handled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnSurfaceClicked(IInspectable const &,
|
||||||
|
Input::PointerRoutedEventArgs const &e) {
|
||||||
|
auto coords = e.GetCurrentPoint(Panel());
|
||||||
|
auto x = coords.Position().X;
|
||||||
|
auto y = coords.Position().Y;
|
||||||
|
RunOnGLThread([=] { mServo->Click(x, y); });
|
||||||
|
e.Handled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::GoBack() {
|
||||||
|
RunOnGLThread([=] { mServo->GoBack(); });
|
||||||
|
}
|
||||||
|
void ServoControl::GoForward() {
|
||||||
|
RunOnGLThread([=] { mServo->GoForward(); });
|
||||||
|
}
|
||||||
|
void ServoControl::Reload() {
|
||||||
|
RunOnGLThread([=] { mServo->Reload(); });
|
||||||
|
}
|
||||||
|
void ServoControl::Stop() {
|
||||||
|
RunOnGLThread([=] { mServo->Stop(); });
|
||||||
|
}
|
||||||
|
Uri ServoControl::LoadURIOrSearch(hstring input) {
|
||||||
|
auto uri = TryParseURI(input);
|
||||||
|
if (uri == std::nullopt) {
|
||||||
|
bool has_dot = wcsstr(input.c_str(), L".") != nullptr;
|
||||||
|
hstring input2 = L"https://" + input;
|
||||||
|
uri = TryParseURI(input2);
|
||||||
|
if (uri == std::nullopt || !has_dot) {
|
||||||
|
hstring input3 = L"https://duckduckgo.com/html/?q=" + Uri::EscapeComponent(input);
|
||||||
|
uri = TryParseURI(input3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto finalUri = uri.value();
|
||||||
|
RunOnGLThread([=] { mServo->LoadUri(finalUri.ToString()); });
|
||||||
|
return finalUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::RunOnGLThread(std::function<void()> task) {
|
||||||
|
EnterCriticalSection(&mGLLock);
|
||||||
|
mTasks.push_back(task);
|
||||||
|
LeaveCriticalSection(&mGLLock);
|
||||||
|
WakeConditionVariable(&mGLCondVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** GL THREAD LOOP ****/
|
||||||
|
|
||||||
|
void ServoControl::Loop() {
|
||||||
|
log("BrowserPage::Loop(). GL thread: %i", GetCurrentThreadId());
|
||||||
|
|
||||||
|
mOpenGLES.MakeCurrent(mRenderSurface);
|
||||||
|
|
||||||
|
EGLint panelWidth = 0;
|
||||||
|
EGLint panelHeight = 0;
|
||||||
|
mOpenGLES.GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
glViewport(0, 0, panelWidth, panelHeight);
|
||||||
|
|
||||||
|
if (mServo == nullptr) {
|
||||||
|
log("Entering loop");
|
||||||
|
ServoDelegate *sd = static_cast<ServoDelegate *>(this);
|
||||||
|
mServo = std::make_unique<Servo>(panelWidth, panelHeight, *sd);
|
||||||
|
} else {
|
||||||
|
// FIXME: this will fail since create_task didn't pick the thread
|
||||||
|
// where Servo was running initially.
|
||||||
|
throw winrt::hresult_error(E_FAIL, L"Recovering loop unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
mServo->SetBatchMode(true);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
EnterCriticalSection(&mGLLock);
|
||||||
|
while (mTasks.size() == 0 && !mAnimating && mLooping) {
|
||||||
|
SleepConditionVariableCS(&mGLCondVar, &mGLLock, INFINITE);
|
||||||
|
}
|
||||||
|
if (!mLooping) {
|
||||||
|
LeaveCriticalSection(&mGLLock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (auto &&task : mTasks) {
|
||||||
|
task();
|
||||||
|
}
|
||||||
|
mTasks.clear();
|
||||||
|
LeaveCriticalSection(&mGLLock);
|
||||||
|
mServo->PerformUpdates();
|
||||||
|
}
|
||||||
|
mServo->DeInit();
|
||||||
|
cancel_current_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::StartRenderLoop() {
|
||||||
|
if (mLooping) {
|
||||||
|
#if defined _DEBUG
|
||||||
|
throw winrt::hresult_error(E_FAIL, L"GL thread is already looping");
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
mLooping = true;
|
||||||
|
log("BrowserPage::StartRenderLoop(). UI thread: %i", GetCurrentThreadId());
|
||||||
|
auto task = Concurrency::create_task([=] { Loop(); });
|
||||||
|
mLoopTask = std::make_unique<Concurrency::task<void>>(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::StopRenderLoop() {
|
||||||
|
if (mLooping) {
|
||||||
|
EnterCriticalSection(&mGLLock);
|
||||||
|
mLooping = false;
|
||||||
|
LeaveCriticalSection(&mGLLock);
|
||||||
|
WakeConditionVariable(&mGLCondVar);
|
||||||
|
mLoopTask->wait();
|
||||||
|
mLoopTask.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** SERVO CALLBACKS ****/
|
||||||
|
|
||||||
|
void ServoControl::OnServoLoadStarted() {
|
||||||
|
RunOnUIThread([=] { mOnLoadStartedEvent(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnServoLoadEnded() {
|
||||||
|
RunOnUIThread([=] { mOnLoadEndedEvent(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnServoHistoryChanged(bool back, bool forward) {
|
||||||
|
RunOnUIThread([=] { mOnHistoryChangedEvent(back, forward); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnServoShutdownComplete() {
|
||||||
|
EnterCriticalSection(&mGLLock);
|
||||||
|
mLooping = false;
|
||||||
|
LeaveCriticalSection(&mGLLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnServoAlert(hstring message) {
|
||||||
|
// FIXME: make this sync
|
||||||
|
RunOnUIThread([=] {
|
||||||
|
Windows::UI::Popups::MessageDialog msg{message};
|
||||||
|
msg.ShowAsync();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnServoTitleChanged(hstring title) {
|
||||||
|
RunOnUIThread([=] { mOnTitleChangedEvent(*this, title); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::OnServoURLChanged(hstring url) {
|
||||||
|
RunOnUIThread([=] { mOnURLChangedEvent(*this, url); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::Flush() {
|
||||||
|
if (mOpenGLES.SwapBuffers(mRenderSurface) != GL_TRUE) {
|
||||||
|
// The call to eglSwapBuffers might not be successful (i.e. due to Device
|
||||||
|
// Lost) If the call fails, then we must reinitialize EGL and the GL
|
||||||
|
// resources.
|
||||||
|
RunOnUIThread([=] { RecoverFromLostDevice(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServoControl::MakeCurrent() { mOpenGLES.MakeCurrent(mRenderSurface); }
|
||||||
|
|
||||||
|
void ServoControl::WakeUp() {
|
||||||
|
RunOnGLThread([=] {});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServoControl::OnServoAllowNavigation(hstring) { return true; }
|
||||||
|
|
||||||
|
void ServoControl::OnServoAnimatingChanged(bool animating) {
|
||||||
|
EnterCriticalSection(&mGLLock);
|
||||||
|
mAnimating = animating;
|
||||||
|
LeaveCriticalSection(&mGLLock);
|
||||||
|
WakeConditionVariable(&mGLCondVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callable> void ServoControl::RunOnUIThread(Callable cb) {
|
||||||
|
Dispatcher().RunAsync(CoreDispatcherPriority::High, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace winrt::ServoApp::implementation
|
110
support/hololens/ServoApp/ServoControl.h
Normal file
110
support/hololens/ServoApp/ServoControl.h
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#pragma once
|
||||||
|
#include "ServoControl.g.h"
|
||||||
|
#include "OpenGLES.h"
|
||||||
|
#include "Servo.h"
|
||||||
|
|
||||||
|
namespace winrt::ServoApp::implementation {
|
||||||
|
struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
|
||||||
|
|
||||||
|
ServoControl();
|
||||||
|
|
||||||
|
void GoBack();
|
||||||
|
void GoForward();
|
||||||
|
void Reload();
|
||||||
|
void Stop();
|
||||||
|
void Shutdown();
|
||||||
|
Windows::Foundation::Uri LoadURIOrSearch(hstring);
|
||||||
|
|
||||||
|
void OnLoaded(IInspectable const &, Windows::UI::Xaml::RoutedEventArgs const &);
|
||||||
|
|
||||||
|
winrt::event_token
|
||||||
|
OnURLChanged(Windows::Foundation::EventHandler<hstring> const &handler){
|
||||||
|
return mOnURLChangedEvent.add(handler);
|
||||||
|
};
|
||||||
|
void OnURLChanged(winrt::event_token const& token) noexcept { mOnURLChangedEvent.remove(token); }
|
||||||
|
|
||||||
|
winrt::event_token
|
||||||
|
OnTitleChanged(Windows::Foundation::EventHandler<hstring> const &handler){
|
||||||
|
return mOnTitleChangedEvent.add(handler);
|
||||||
|
};
|
||||||
|
void OnTitleChanged(winrt::event_token const& token) noexcept { mOnTitleChangedEvent.remove(token); }
|
||||||
|
|
||||||
|
winrt::event_token OnHistoryChanged(HistoryChangedDelegate const &handler){
|
||||||
|
return mOnHistoryChangedEvent.add(handler);
|
||||||
|
};
|
||||||
|
void OnHistoryChanged(winrt::event_token const& token) noexcept { mOnHistoryChangedEvent.remove(token); }
|
||||||
|
|
||||||
|
winrt::event_token OnLoadStarted(LoadStatusChangedDelegate const &handler){
|
||||||
|
return mOnLoadStartedEvent.add(handler);
|
||||||
|
};
|
||||||
|
void OnLoadStarted(winrt::event_token const& token) noexcept { mOnLoadStartedEvent.remove(token); }
|
||||||
|
|
||||||
|
winrt::event_token OnLoadEnded(LoadStatusChangedDelegate const &handler){
|
||||||
|
return mOnLoadEndedEvent.add(handler);
|
||||||
|
};
|
||||||
|
void OnLoadEnded(winrt::event_token const& token) noexcept { mOnLoadEndedEvent.remove(token); }
|
||||||
|
|
||||||
|
virtual void WakeUp();
|
||||||
|
virtual void OnServoLoadStarted();
|
||||||
|
virtual void OnServoLoadEnded();
|
||||||
|
virtual void OnServoHistoryChanged(bool, bool);
|
||||||
|
virtual void OnServoShutdownComplete();
|
||||||
|
virtual void OnServoTitleChanged(winrt::hstring);
|
||||||
|
virtual void OnServoAlert(winrt::hstring);
|
||||||
|
virtual void OnServoURLChanged(winrt::hstring);
|
||||||
|
virtual void Flush();
|
||||||
|
virtual void MakeCurrent();
|
||||||
|
virtual bool OnServoAllowNavigation(winrt::hstring);
|
||||||
|
virtual void OnServoAnimatingChanged(bool);
|
||||||
|
|
||||||
|
private:
|
||||||
|
winrt::event<Windows::Foundation::EventHandler<hstring>> mOnURLChangedEvent;
|
||||||
|
winrt::event<Windows::Foundation::EventHandler<hstring>> mOnTitleChangedEvent;
|
||||||
|
winrt::event<HistoryChangedDelegate> mOnHistoryChangedEvent;
|
||||||
|
winrt::event<LoadStatusChangedDelegate> mOnLoadStartedEvent;
|
||||||
|
winrt::event<LoadStatusChangedDelegate> mOnLoadEndedEvent;
|
||||||
|
|
||||||
|
Windows::UI::Xaml::Controls::SwapChainPanel ServoControl::Panel();
|
||||||
|
void CreateRenderSurface();
|
||||||
|
void DestroyRenderSurface();
|
||||||
|
void RecoverFromLostDevice();
|
||||||
|
|
||||||
|
void StartRenderLoop();
|
||||||
|
void StopRenderLoop();
|
||||||
|
void Loop();
|
||||||
|
|
||||||
|
std::optional<Windows::Foundation::Uri> TryParseURI(hstring input) {
|
||||||
|
try {
|
||||||
|
return Windows::Foundation::Uri(input);
|
||||||
|
} catch (hresult_invalid_argument const &e) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OnSurfaceClicked(IInspectable const &,
|
||||||
|
Windows::UI::Xaml::Input::PointerRoutedEventArgs const &);
|
||||||
|
|
||||||
|
void OnSurfaceManipulationDelta(
|
||||||
|
IInspectable const &,
|
||||||
|
Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs const &e);
|
||||||
|
|
||||||
|
template <typename Callable> void RunOnUIThread(Callable);
|
||||||
|
void RunOnGLThread(std::function<void()>);
|
||||||
|
|
||||||
|
std::unique_ptr<servo::Servo> mServo;
|
||||||
|
EGLSurface mRenderSurface{EGL_NO_SURFACE};
|
||||||
|
OpenGLES mOpenGLES;
|
||||||
|
bool mAnimating = false;
|
||||||
|
bool mLooping = false;
|
||||||
|
std::vector<std::function<void()>> mTasks;
|
||||||
|
CRITICAL_SECTION mGLLock;
|
||||||
|
CONDITION_VARIABLE mGLCondVar;
|
||||||
|
std::unique_ptr<Concurrency::task<void>> mLoopTask;
|
||||||
|
};
|
||||||
|
} // namespace winrt::ServoApp::implementation
|
||||||
|
|
||||||
|
namespace winrt::ServoApp::factory_implementation {
|
||||||
|
struct ServoControl
|
||||||
|
: ServoControlT<ServoControl, implementation::ServoControl> {};
|
||||||
|
} // namespace winrt::ServoApp::factory_implementation
|
20
support/hololens/ServoApp/ServoControl.idl
Normal file
20
support/hololens/ServoApp/ServoControl.idl
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
namespace ServoApp {
|
||||||
|
|
||||||
|
delegate void LoadStatusChangedDelegate();
|
||||||
|
delegate void HistoryChangedDelegate(Boolean back, Boolean forward);
|
||||||
|
|
||||||
|
runtimeclass ServoControl : Windows.UI.Xaml.Controls.Control {
|
||||||
|
ServoControl();
|
||||||
|
void GoBack();
|
||||||
|
void GoForward();
|
||||||
|
void Reload();
|
||||||
|
void Stop();
|
||||||
|
Windows.Foundation.Uri LoadURIOrSearch(String url);
|
||||||
|
void Shutdown();
|
||||||
|
event LoadStatusChangedDelegate OnLoadStarted;
|
||||||
|
event LoadStatusChangedDelegate OnLoadEnded;
|
||||||
|
event HistoryChangedDelegate OnHistoryChanged;
|
||||||
|
event Windows.Foundation.EventHandler<String> OnTitleChanged;
|
||||||
|
event Windows.Foundation.EventHandler<String> OnURLChanged;
|
||||||
|
}
|
||||||
|
} // namespace ServoApp
|
19
support/hololens/ServoApp/Themes/Generic.xaml
Normal file
19
support/hololens/ServoApp/Themes/Generic.xaml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<!-- \Themes\Generic.xaml -->
|
||||||
|
<ResourceDictionary
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:ServoApp">
|
||||||
|
|
||||||
|
<Style TargetType="local:ServoControl" >
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="local:ServoControl">
|
||||||
|
<Grid>
|
||||||
|
<SwapChainPanel x:Name="swapChainPanel" MinHeight="200" MinWidth="200" ManipulationMode="All">
|
||||||
|
</SwapChainPanel>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
Loading…
Add table
Add a link
Reference in a new issue