Index: src/views/sdl/SkOSWindow_SDL.cpp |
diff --git a/src/views/sdl/SkOSWindow_SDL.cpp b/src/views/sdl/SkOSWindow_SDL.cpp |
index 45beaee53e8d97795538e92b9f7eb0f0c4bb15f3..c39a4fdfef8a64cc4453f8df0b739b7cee5ae047 100644 |
--- a/src/views/sdl/SkOSWindow_SDL.cpp |
+++ b/src/views/sdl/SkOSWindow_SDL.cpp |
@@ -15,72 +15,39 @@ |
#include <gl.h> |
#endif |
-const int SCREEN_WIDTH = 640; |
-const int SCREEN_HEIGHT = 480; |
+const int kInitialWindowWidth = 640; |
+const int kInitialWindowHeight = 480; |
+static SkOSWindow* gCurrentWindow; |
-static void handle_error() { |
+static void report_sdl_error(const char* failure) { |
const char* error = SDL_GetError(); |
- SkDebugf("SDL Error: %s\n", error); |
+ SkASSERT(error); // Called only to check SDL error. |
+ SkDebugf("%s SDL Error: %s.\n", failure, error); |
SDL_ClearError(); |
} |
+SkOSWindow::SkOSWindow(void*) |
+ : fWindow(nullptr) |
+ , fGLContext(nullptr) |
+ , fWindowMSAASampleCount(0) { |
-SkOSWindow::SkOSWindow(void* screen) : fQuit(false) , fGLContext(nullptr) { |
-#if defined(SK_BUILD_FOR_ANDROID) |
- // TODO we should try and get a 3.0 context first |
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); |
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); |
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); |
- fWindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | |
- SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN_DESKTOP | |
- SDL_WINDOW_ALLOW_HIGHDPI; |
-#else |
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); |
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); |
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); |
- SDL_StartTextInput(); |
- |
- fWindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; |
-#endif |
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); |
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); |
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); |
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); |
- SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); |
- |
- SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); |
- |
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { |
- handle_error(); |
- return; |
- } |
- |
- SDL_DisplayMode dm; |
- if (SDL_GetDesktopDisplayMode(0, &dm) != 0) { |
- handle_error(); |
- return; |
- } |
+ SkASSERT(!gCurrentWindow); |
+ gCurrentWindow = this; |
- fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, |
- dm.w, dm.h, fWindowFlags); |
- |
- if (!fWindow) { |
- handle_error(); |
- return; |
- } |
- this->resize(dm.w, dm.h); |
+ this->createWindow(0); |
} |
SkOSWindow::~SkOSWindow() { |
- if (fGLContext) { |
- SDL_GL_DeleteContext(fGLContext); |
- } |
- |
- //Destroy window |
- SDL_DestroyWindow(fWindow); |
+ this->destroyWindow(); |
+ gCurrentWindow = nullptr; |
+} |
- //Quit SDL subsystems |
- SDL_Quit(); |
+SkOSWindow* SkOSWindow::GetInstanceForWindowID(Uint32 windowID) { |
+ if (gCurrentWindow && |
+ gCurrentWindow->fWindow && |
+ SDL_GetWindowID(gCurrentWindow->fWindow) == windowID) { |
+ return gCurrentWindow; |
+ } |
+ return nullptr; |
} |
void SkOSWindow::detach() { |
@@ -88,67 +55,67 @@ void SkOSWindow::detach() { |
SDL_GL_DeleteContext(fGLContext); |
fGLContext = nullptr; |
} |
- |
-#if defined(SK_BUILD_FOR_ANDROID) |
- if (fWindow) { |
- // Destroy window |
- // Not totally sure why, but we have to do this or swapbuffers will hang |
- SDL_DestroyWindow(fWindow); |
- fWindow = nullptr; |
- } |
-#endif |
} |
bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info) { |
+ this->createWindow(msaaSampleCount); |
if (!fWindow) { |
- fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, |
- SCREEN_WIDTH, SCREEN_HEIGHT, |
- fWindowFlags); |
- } |
- |
- if (msaaSampleCount > 0) { |
- SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); |
- SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaaSampleCount); |
+ return false; |
} |
- |
- info->fSampleCount = msaaSampleCount; |
- info->fStencilBits = 8; |
- |
- fGLContext = SDL_GL_CreateContext(fWindow); |
if (!fGLContext) { |
- handle_error(); |
- return false; |
+ fGLContext = SDL_GL_CreateContext(fWindow); |
+ if (!fGLContext) { |
+ report_sdl_error("Failed to create SDL GL context."); |
+ return false; |
+ } |
+ glClearColor(0, 0, 0, 0); |
+ glClearStencil(0); |
+ glStencilMask(0xffffffff); |
+ glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
} |
- int success = SDL_GL_MakeCurrent(fWindow, fGLContext); |
- if (success != 0) { |
- handle_error(); |
+ if (SDL_GL_MakeCurrent(fWindow, fGLContext) != 0) { |
+ report_sdl_error("Failed to make SDL GL context current."); |
+ this->detach(); |
return false; |
} |
- glViewport(0, 0, SkScalarFloorToInt(this->width()), SkScalarFloorToInt(this->height())); |
- glClearColor(1, 1, 1, 1); |
- glClearStencil(0); |
- glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
+ info->fSampleCount = msaaSampleCount; |
+ info->fStencilBits = 8; |
+ glViewport(0, 0, SkScalarRoundToInt(this->width()), SkScalarRoundToInt(this->height())); |
return true; |
} |
void SkOSWindow::present() { |
+ if (!fWindow) { |
+ return; |
+ } |
SDL_GL_SwapWindow(fWindow); |
} |
bool SkOSWindow::makeFullscreen() { |
- SDL_SetWindowFullscreen(fWindow, SDL_WINDOW_FULLSCREEN); |
+ if (!fWindow) { |
+ return false; |
+ } |
+ SDL_SetWindowFullscreen(fWindow, SDL_WINDOW_FULLSCREEN_DESKTOP); |
return true; |
} |
void SkOSWindow::setVsync(bool vsync) { |
+ if (!fWindow) { |
+ return; |
+ } |
SDL_GL_SetSwapInterval(vsync ? 1 : 0); |
} |
void SkOSWindow::closeWindow() { |
- fQuit = true; |
+ this->destroyWindow(); |
+ |
+ // Currently closing the window causes the app to quit. |
+ SDL_Event event; |
+ event.type = SDL_QUIT; |
+ SDL_PushEvent(&event); |
} |
static SkKey convert_sdlkey_to_skkey(SDL_Keycode src) { |
@@ -194,59 +161,200 @@ static SkKey convert_sdlkey_to_skkey(SDL_Keycode src) { |
} |
} |
-void SkOSWindow::handleEvents() { |
- SkEvent::ServiceQueueTimer(); |
- SkEvent::ProcessEvent(); |
+void SkOSWindow::createWindow(int msaaSampleCount) { |
+ if (fWindowMSAASampleCount != msaaSampleCount) { |
+ this->destroyWindow(); |
+ } |
+ if (fWindow) { |
+ return; |
+ } |
+ uint32_t windowFlags = |
+#if defined(SK_BUILD_FOR_ANDROID) |
+ SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN_DESKTOP | |
+ SDL_WINDOW_ALLOW_HIGHDPI | |
+#endif |
+ SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; |
- SDL_Event event; |
- while(SDL_PollEvent(&event)) { |
- switch (event.type) { |
- case SDL_MOUSEMOTION: |
+ // GL settings are part of SDL_WINDOW_OPENGL window creation arguments. |
+#if defined(SK_BUILD_FOR_ANDROID) |
+ // TODO we should try and get a 3.0 context first |
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); |
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); |
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); |
+#else |
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); |
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); |
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); |
+#endif |
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); |
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); |
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); |
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); |
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); |
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); |
+#if defined(SK_BUILD_FOR_UNIX) |
+ // Apparently MSAA request matches "slow caveat". Make SDL not set anything for caveat for MSAA |
+ // by setting -1 for ACCELERATED_VISUAL. For non-MSAA, set ACCELERATED_VISUAL to 1 just for |
+ // compatiblity with other platforms. |
+ SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, msaaSampleCount > 0 ? -1 : 1); |
+#else |
+ SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); |
+#endif |
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, msaaSampleCount > 0 ? 1 : 0); |
+ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaaSampleCount); |
+ |
+ // This is an approximation for sizing purposes. |
+ bool isInitialWindow = this->width() == 0 && this->height() == 0; |
+ SkScalar windowWidth = isInitialWindow ? kInitialWindowWidth : this->width(); |
+ SkScalar windowHeight = isInitialWindow ? kInitialWindowHeight : this->height(); |
+ |
+ fWindow = SDL_CreateWindow(this->getTitle(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, |
+ windowWidth, windowHeight, windowFlags); |
+ if (!fWindow) { |
+ report_sdl_error("Failed to create SDL window."); |
+ return; |
+ } |
+ fWindowMSAASampleCount = msaaSampleCount; |
+} |
+ |
+void SkOSWindow::destroyWindow() { |
+ this->detach(); |
+ if (fWindow) { |
+ SDL_DestroyWindow(fWindow); |
+ fWindow = nullptr; |
+ fWindowMSAASampleCount = 0; |
+ } |
+} |
+ |
+bool SkOSWindow::HasDirtyWindows() { |
+ if (gCurrentWindow && gCurrentWindow->fWindow) { |
+ return gCurrentWindow->isDirty(); |
+ } |
+ return false; |
+} |
+ |
+void SkOSWindow::UpdateDirtyWindows() { |
+ if (gCurrentWindow && gCurrentWindow->fWindow) { |
+ if (gCurrentWindow->isDirty()) { |
+ // This will call present. |
+ gCurrentWindow->update(nullptr); |
+ } |
+ } |
+} |
+ |
+void SkOSWindow::HandleEvent(const SDL_Event& event) { |
+ switch (event.type) { |
+ case SDL_MOUSEMOTION: |
+ if (SkOSWindow* window = GetInstanceForWindowID(event.motion.windowID)) { |
if (event.motion.state == SDL_PRESSED) { |
- this->handleClick(event.motion.x, event.motion.y, |
- SkView::Click::kMoved_State, nullptr); |
+ window->handleClick(event.motion.x, event.motion.y, |
+ SkView::Click::kMoved_State, nullptr); |
} |
- break; |
- case SDL_MOUSEBUTTONDOWN: |
- case SDL_MOUSEBUTTONUP: |
- this->handleClick(event.button.x, event.button.y, |
- event.button.state == SDL_PRESSED ? |
- SkView::Click::kDown_State : |
- SkView::Click::kUp_State, nullptr); |
- break; |
- case SDL_KEYDOWN: { |
+ } |
+ break; |
+ case SDL_MOUSEBUTTONDOWN: |
+ case SDL_MOUSEBUTTONUP: |
+ if (SkOSWindow* window = GetInstanceForWindowID(event.button.windowID)) { |
+ window->handleClick(event.button.x, event.button.y, |
+ event.button.state == SDL_PRESSED ? |
+ SkView::Click::kDown_State : |
+ SkView::Click::kUp_State, nullptr); |
+ } |
+ break; |
+ case SDL_KEYDOWN: |
+ if (SkOSWindow* window = GetInstanceForWindowID(event.key.windowID)) { |
SDL_Keycode key = event.key.keysym.sym; |
SkKey sk = convert_sdlkey_to_skkey(key); |
if (kNONE_SkKey != sk) { |
if (event.key.state == SDL_PRESSED) { |
- this->handleKey(sk); |
+ window->handleKey(sk); |
} else { |
- this->handleKeyUp(sk); |
+ window->handleKeyUp(sk); |
} |
} else if (key == SDLK_ESCAPE) { |
- fQuit = true; |
+ window->closeWindow(); |
} |
- break; |
} |
- case SDL_TEXTINPUT: { |
+ break; |
+ case SDL_TEXTINPUT: |
+ if (SkOSWindow* window = GetInstanceForWindowID(event.text.windowID)) { |
size_t len = strlen(event.text.text); |
for (size_t i = 0; i < len; i++) { |
- this->handleChar((SkUnichar)event.text.text[i]); |
+ window->handleChar((SkUnichar)event.text.text[i]); |
} |
- break; |
} |
- case SDL_QUIT: |
- fQuit = true; |
- break; |
- default: |
- break; |
- } |
+ break; |
+ case SDL_WINDOWEVENT: |
+ switch (event.window.event) { |
+ case SDL_WINDOWEVENT_SHOWN: |
+ // For initialization purposes, we resize upon first show. |
+ // Fallthrough. |
+ case SDL_WINDOWEVENT_SIZE_CHANGED: |
+ if (SkOSWindow* window = GetInstanceForWindowID(event.window.windowID)) { |
+ int w = 0; |
+ int h = 0; |
+ SDL_GetWindowSize(window->fWindow, &w, &h); |
+ window->resize(w, h); |
+ } |
+ break; |
+ case SDL_WINDOWEVENT_FOCUS_GAINED: |
+ if (GetInstanceForWindowID(event.text.windowID)) { |
+ SDL_StartTextInput(); |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+ break; |
+ default: |
+ break; |
} |
} |
+SkMSec gTimerDelay; |
+ |
+void SkOSWindow::RunEventLoop() { |
+ for (;;) { |
+ SkEvent::ServiceQueueTimer(); |
+ bool hasMoreSkEvents = SkEvent::ProcessEvent(); |
+ |
+ SDL_Event event; |
+ bool hasSDLEvents = SDL_PollEvent(&event) == 1; |
+ |
+ // Invalidations do not post to event loop, rather we just go through the |
+ // windows for each event loop iteration. |
+ bool hasDirtyWindows = HasDirtyWindows(); |
+ |
+ if (!hasSDLEvents && !hasMoreSkEvents && !hasDirtyWindows) { |
+ // If there is no SDL events, SkOSWindow updates or SkEvents |
+ // to be done, wait for the SDL events. |
+ if (gTimerDelay > 0) { |
+ hasSDLEvents = SDL_WaitEventTimeout(&event, gTimerDelay) == 1; |
+ } else { |
+ hasSDLEvents = SDL_WaitEvent(&event) == 1; |
+ } |
+ } |
+ while (hasSDLEvents) { |
+ if (event.type == SDL_QUIT) { |
+ return; |
+ } |
+ HandleEvent(event); |
+ hasSDLEvents = SDL_PollEvent(&event); |
+ } |
+ UpdateDirtyWindows(); |
+ } |
+} |
void SkOSWindow::onSetTitle(const char title[]) { |
- SDL_SetWindowTitle(fWindow, title); |
+ if (!fWindow) { |
+ return; |
+ } |
+ this->updateWindowTitle(); |
+} |
+ |
+void SkOSWindow::updateWindowTitle() { |
+ SDL_SetWindowTitle(fWindow, this->getTitle()); |
} |
/////////////////////////////////////////////////////////////////////////////////////// |
@@ -255,13 +363,7 @@ void SkEvent::SignalNonEmptyQueue() { |
} |
void SkEvent::SignalQueueTimer(SkMSec delay) { |
- // just need to record the delay time. We handle waking up for it in |
-} |
- |
-void SkOSWindow::onHandleInval(const SkIRect& rect) { |
-} |
- |
-void SkOSWindow::onPDFSaved(const char title[], const char desc[], const char path[]) { |
+ gTimerDelay = delay; |
} |
////////////////////////////////////////////////////////////////////////////////////////////// |
@@ -275,17 +377,24 @@ int SDL_main(int argc, char** argv) { |
#else |
int main(int argc, char** argv) { |
#endif |
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { |
+ report_sdl_error("Failed to init SDL."); |
+ return -1; |
+ } |
+ |
+ application_init(); |
+ |
SkOSWindow* window = create_sk_window(nullptr, argc, argv); |
// drain any events that occurred before |window| was assigned. |
while (SkEvent::ProcessEvent()); |
- // Start normal Skia sequence |
- application_init(); |
- |
- window->loop(); |
+ SkOSWindow::RunEventLoop(); |
delete window; |
application_term(); |
+ |
+ SDL_Quit(); |
+ |
return 0; |
} |