Skip to content

Latest commit

 

History

History
469 lines (407 loc) · 18.1 KB

SDL_winrtapp.cpp

File metadata and controls

469 lines (407 loc) · 18.1 KB
 
Aug 27, 2013
Aug 27, 2013
2
/* Standard C++11 includes */
Aug 26, 2013
Aug 26, 2013
3
#include <functional>
4
5
#include <string>
#include <sstream>
Aug 27, 2013
Aug 27, 2013
6
7
using namespace std;
Aug 27, 2013
Aug 27, 2013
9
/* Windows includes */
10
#include "ppltasks.h"
Aug 27, 2013
Aug 27, 2013
11
12
13
14
15
16
17
18
19
20
21
using namespace concurrency;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Devices::Input;
using namespace Windows::Graphics::Display;
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
Aug 27, 2013
Aug 27, 2013
23
/* SDL includes */
24
25
26
27
28
extern "C" {
#include "SDL_assert.h"
#include "SDL_events.h"
#include "SDL_hints.h"
#include "SDL_log.h"
Aug 14, 2013
Aug 14, 2013
29
#include "SDL_main.h"
30
31
#include "SDL_stdinc.h"
#include "SDL_render.h"
Aug 21, 2013
Aug 21, 2013
32
#include "../../video/SDL_sysvideo.h"
Aug 14, 2013
Aug 14, 2013
33
//#include "../../SDL_hints_c.h"
34
35
36
37
38
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_windowevents_c.h"
#include "../../render/SDL_sysrender.h"
}
Aug 26, 2013
Aug 26, 2013
39
#include "../../video/winrt/SDL_winrtevents_c.h"
Aug 21, 2013
Aug 21, 2013
40
#include "SDL_winrtapp.h"
Aug 27, 2013
Aug 27, 2013
42
extern SDL_Window * WINRT_GlobalSDLWindow;
Aug 27, 2013
Aug 27, 2013
43
extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice;
Aug 27, 2013
Aug 27, 2013
44
extern SDL_DisplayMode WINRT_CalcDisplayModeUsingNativeWindow();
Aug 27, 2013
Aug 27, 2013
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Compile-time debugging options:
// To enable, uncomment; to disable, comment them out.
//#define LOG_POINTER_EVENTS 1
//#define LOG_WINDOW_EVENTS 1
//#define LOG_ORIENTATION_EVENTS 1
// HACK, DLudwig: The C-style main() will get loaded via the app's
// WinRT-styled main(), which is part of SDLmain_for_WinRT.cpp.
// This seems wrong on some level, but does seem to work.
typedef int (*SDL_WinRT_MainFunction)(int, char **);
static SDL_WinRT_MainFunction SDL_WinRT_main = nullptr;
Aug 27, 2013
Aug 27, 2013
60
// HACK, DLudwig: record a reference to the global, WinRT 'app'/view.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// SDL/WinRT will use this throughout its code.
//
// TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
// non-global, such as something created inside
// SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
// SDL_CreateWindow().
SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
{
public:
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
};
IFrameworkView^ SDLApplicationSource::CreateView()
{
// TODO, WinRT: see if this function (CreateView) can ever get called
// more than once. For now, just prevent it from ever assigning
// SDL_WinRTGlobalApp more than once.
SDL_assert(!SDL_WinRTGlobalApp);
SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
if (!SDL_WinRTGlobalApp)
{
SDL_WinRTGlobalApp = app;
}
return app;
}
__declspec(dllexport) int SDL_WinRT_RunApplication(SDL_WinRT_MainFunction mainFunction)
{
SDL_WinRT_main = mainFunction;
auto direct3DApplicationSource = ref new SDLApplicationSource();
CoreApplication::Run(direct3DApplicationSource);
return 0;
}
Aug 14, 2013
Aug 14, 2013
97
static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
98
99
100
101
102
103
{
SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0);
// Start with no orientation flags, then add each in as they're parsed
// from newValue.
unsigned int orientationFlags = 0;
Aug 14, 2013
Aug 14, 2013
104
105
106
107
108
109
110
111
112
113
114
115
116
117
if (newValue) {
std::istringstream tokenizer(newValue);
while (!tokenizer.eof()) {
std::string orientationName;
std::getline(tokenizer, orientationName, ' ');
if (orientationName == "LandscapeLeft") {
orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped;
} else if (orientationName == "LandscapeRight") {
orientationFlags |= (unsigned int) DisplayOrientations::Landscape;
} else if (orientationName == "Portrait") {
orientationFlags |= (unsigned int) DisplayOrientations::Portrait;
} else if (orientationName == "PortraitUpsideDown") {
orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped;
}
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
}
}
// If no valid orientation flags were specified, use a reasonable set of defaults:
if (!orientationFlags) {
// TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s).
orientationFlags = (unsigned int) ( \
DisplayOrientations::Landscape |
DisplayOrientations::LandscapeFlipped |
DisplayOrientations::Portrait |
DisplayOrientations::PortraitFlipped);
}
// Set the orientation/rotation preferences. Please note that this does
// not constitute a 100%-certain lock of a given set of possible
Aug 27, 2013
Aug 27, 2013
133
// orientations. According to Microsoft's documentation on WinRT [1]
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// when a device is not capable of being rotated, Windows may ignore
// the orientation preferences, and stick to what the device is capable of
// displaying.
//
// [1] Documentation on the 'InitialRotationPreference' setting for a
// Windows app's manifest file describes how some orientation/rotation
// preferences may be ignored. See
// http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx
// for details. Microsoft's "Display orientation sample" also gives an
// outline of how Windows treats device rotation
// (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93).
DisplayProperties::AutoRotationPreferences = (DisplayOrientations) orientationFlags;
}
SDL_WinRTApp::SDL_WinRTApp() :
m_windowClosed(false),
Aug 27, 2013
Aug 27, 2013
150
m_windowVisible(true)
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
{
}
void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
{
applicationView->Activated +=
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated);
CoreApplication::Suspending +=
ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
CoreApplication::Resuming +=
ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
DisplayProperties::OrientationChanged +=
ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
// Register the hint, SDL_HINT_ORIENTATIONS, with SDL. This needs to be
// done before the hint's callback is registered (as of Feb 22, 2013),
// otherwise the hint callback won't get registered.
//
Aug 27, 2013
Aug 27, 2013
172
// TODO, WinRT: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly.
Aug 14, 2013
Aug 14, 2013
173
174
//SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown"); // DavidL: this is no longer needed (for SDL_AddHintCallback)
SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL);
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
}
void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
{
#if LOG_ORIENTATION_EVENTS==1
CoreWindow^ window = CoreWindow::GetForCurrentThread();
if (window) {
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n",
__FUNCTION__,
(int)DisplayProperties::CurrentOrientation,
(int)DisplayProperties::NativeOrientation,
(int)DisplayProperties::AutoRotationPreferences,
window->Bounds.Width,
window->Bounds.Height);
} else {
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
__FUNCTION__,
(int)DisplayProperties::CurrentOrientation,
(int)DisplayProperties::NativeOrientation,
(int)DisplayProperties::AutoRotationPreferences);
}
#endif
}
void SDL_WinRTApp::SetWindow(CoreWindow^ window)
{
#if LOG_WINDOW_EVENTS==1
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n",
__FUNCTION__,
(int)DisplayProperties::CurrentOrientation,
(int)DisplayProperties::NativeOrientation,
(int)DisplayProperties::AutoRotationPreferences,
window->Bounds.Width,
window->Bounds.Height);
#endif
window->SizeChanged +=
ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
window->VisibilityChanged +=
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
window->Closed +=
ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
#endif
window->PointerPressed +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
window->PointerReleased +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
window->PointerWheelChanged +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged);
window->PointerMoved +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
// Retrieves relative-only mouse movements:
Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
#endif
window->KeyDown +=
ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
window->KeyUp +=
ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
}
void SDL_WinRTApp::Load(Platform::String^ entryPoint)
{
}
void SDL_WinRTApp::Run()
{
Aug 14, 2013
Aug 14, 2013
255
SDL_SetMainReady();
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
if (SDL_WinRT_main)
{
// TODO, WinRT: pass the C-style main() a reasonably realistic
// representation of command line arguments.
int argc = 0;
char **argv = NULL;
SDL_WinRT_main(argc, argv);
}
}
void SDL_WinRTApp::PumpEvents()
{
if (!m_windowClosed)
{
if (m_windowVisible)
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
}
else
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
void SDL_WinRTApp::Uninitialize()
{
}
void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
#if LOG_WINDOW_EVENTS==1
Aug 27, 2013
Aug 27, 2013
288
SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
289
290
291
292
293
__FUNCTION__,
args->Size.Width, args->Size.Height,
(int)DisplayProperties::CurrentOrientation,
(int)DisplayProperties::NativeOrientation,
(int)DisplayProperties::AutoRotationPreferences,
Aug 27, 2013
Aug 27, 2013
294
(WINRT_GlobalSDLWindow ? "yes" : "no"));
Aug 27, 2013
Aug 27, 2013
297
if (WINRT_GlobalSDLWindow) {
298
// Make the new window size be the one true fullscreen mode.
Aug 27, 2013
Aug 27, 2013
299
300
// This change was initially done, in part, to allow the Direct3D 11.1
// renderer to receive window-resize events as a device rotates.
301
302
303
304
305
306
307
308
// Before, rotating a device from landscape, to portrait, and then
// back to landscape would cause the Direct3D 11.1 swap buffer to
// not get resized appropriately. SDL would, on the rotation from
// landscape to portrait, re-resize the SDL window to it's initial
// size (landscape). On the subsequent rotation, SDL would drop the
// window-resize event as it appeared the SDL window didn't change
// size, and the Direct3D 11.1 renderer wouldn't resize its swap
// chain.
Aug 27, 2013
Aug 27, 2013
309
SDL_DisplayMode resizedDisplayMode = WINRT_CalcDisplayModeUsingNativeWindow();
Aug 27, 2013
Aug 27, 2013
310
311
312
WINRT_GlobalSDLVideoDevice->displays[0].current_mode = resizedDisplayMode;
WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = resizedDisplayMode;
WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0] = resizedDisplayMode;
Aug 27, 2013
Aug 27, 2013
313
314
315
316
317
// Send the window-resize event to the rest of SDL, and to apps:
const int windowWidth = (int) ceil(args->Size.Width);
const int windowHeight = (int) ceil(args->Size.Height);
SDL_SendWindowEvent(
Aug 27, 2013
Aug 27, 2013
318
WINRT_GlobalSDLWindow,
319
320
321
322
323
324
325
326
327
SDL_WINDOWEVENT_RESIZED,
windowWidth,
windowHeight);
}
}
void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
#if LOG_WINDOW_EVENTS==1
Aug 27, 2013
Aug 27, 2013
328
SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n",
329
330
__FUNCTION__,
(args->Visible ? "yes" : "no"),
Aug 27, 2013
Aug 27, 2013
331
(WINRT_GlobalSDLWindow ? "yes" : "no"));
332
333
334
#endif
m_windowVisible = args->Visible;
Aug 27, 2013
Aug 27, 2013
335
336
if (WINRT_GlobalSDLWindow) {
SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
337
338
if (args->Visible) {
Aug 27, 2013
Aug 27, 2013
339
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
Aug 27, 2013
Aug 27, 2013
341
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
342
343
344
345
346
347
348
349
}
// HACK: Prevent SDL's window-hide handling code, which currently
// triggers a fake window resize (possibly erronously), from
// marking the SDL window's surface as invalid.
//
// A better solution to this probably involves figuring out if the
// fake window resize can be prevented.
Aug 27, 2013
Aug 27, 2013
350
WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid;
351
352
353
354
355
356
357
358
359
360
361
362
363
}
}
void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
#if LOG_WINDOW_EVENTS==1
SDL_Log("%s\n", __FUNCTION__);
#endif
m_windowClosed = true;
}
void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
{
Aug 27, 2013
Aug 27, 2013
364
WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args);
365
366
367
368
}
void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
{
Aug 27, 2013
Aug 27, 2013
369
WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args);
370
371
372
373
}
void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
{
Aug 27, 2013
Aug 27, 2013
374
WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args);
375
376
377
378
}
void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
{
Aug 27, 2013
Aug 27, 2013
379
WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args);
380
381
382
383
}
void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
{
Aug 27, 2013
Aug 27, 2013
384
WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args);
385
386
387
388
}
void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
{
Aug 26, 2013
Aug 26, 2013
389
WINRT_ProcessKeyDownEvent(args);
390
391
392
393
}
void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
{
Aug 26, 2013
Aug 26, 2013
394
WINRT_ProcessKeyUpEvent(args);
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
}
void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
CoreWindow::GetForCurrentThread()->Activate();
}
static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event)
{
if (event->type == SDL_WINDOWEVENT)
{
switch (event->window.event)
{
case SDL_WINDOWEVENT_MINIMIZED:
case SDL_WINDOWEVENT_RESTORED:
// Return 0 to indicate that the event should be removed from the
// event queue:
return 0;
default:
break;
}
}
// Return 1 to indicate that the event should stay in the event queue:
return 1;
}
void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
// Save app state asynchronously after requesting a deferral. Holding a deferral
// indicates that the application is busy performing suspending operations. Be
// aware that a deferral may not be held indefinitely. After about five seconds,
// the app will be forced to exit.
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
create_task([this, deferral]()
{
// Send a window-minimized event immediately to observers.
// CoreDispatcher::ProcessEvents, which is the backbone on which
// SDL_WinRTApp::PumpEvents is built, will not return to its caller
// once it sends out a suspend event. Any events posted to SDL's
// event queue won't get received until the WinRT app is resumed.
// SDL_AddEventWatch() may be used to receive app-suspend events on
// WinRT.
//
// In order to prevent app-suspend events from being received twice:
// first via a callback passed to SDL_AddEventWatch, and second via
// SDL's event queue, the event will be sent to SDL, then immediately
// removed from the queue.
Aug 27, 2013
Aug 27, 2013
443
if (WINRT_GlobalSDLWindow)
Aug 27, 2013
Aug 27, 2013
445
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
446
447
448
449
450
451
452
453
454
455
456
SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
}
deferral->Complete();
});
}
void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
// Restore any data or state that was unloaded on suspend. By default, data
// and state are persisted when resuming from suspend. Note that this event
// does not occur if the app was previously terminated.
Aug 27, 2013
Aug 27, 2013
457
if (WINRT_GlobalSDLWindow)
Aug 27, 2013
Aug 27, 2013
459
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
460
461
462
463
464
465
466
467
468
469
// Remove the app-resume event from the queue, as is done with the
// app-suspend event.
//
// TODO, WinRT: consider posting this event to the queue even though
// its counterpart, the app-suspend event, effectively has to be
// processed immediately.
SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
}
}