/* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup GHOST */ #include "GHOST_WindowSDL.h" #include "SDL_mouse.h" #include "GHOST_ContextSDL.h" #include GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system, const char *title, int32_t left, int32_t top, uint32_t width, uint32_t height, GHOST_TWindowState state, GHOST_TDrawingContextType type, const bool stereoVisual, const bool exclusive, const GHOST_IWindow * /*parentWindow*/) : GHOST_Window(width, height, state, stereoVisual, exclusive), m_system(system), m_valid_setup(false), m_invalid_window(false), m_sdl_custom_cursor(nullptr) { /* creating the window _must_ come after setting attributes */ m_sdl_win = SDL_CreateWindow(title, left, top, width, height, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); /* now set up the rendering context. */ if (setDrawingContextType(type) == GHOST_kSuccess) { m_valid_setup = true; GHOST_PRINT("Created window\n"); } if (exclusive) { SDL_RaiseWindow(m_sdl_win); } setTitle(title); } GHOST_WindowSDL::~GHOST_WindowSDL() { if (m_sdl_custom_cursor) { SDL_FreeCursor(m_sdl_custom_cursor); } releaseNativeHandles(); SDL_DestroyWindow(m_sdl_win); } GHOST_Context *GHOST_WindowSDL::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { GHOST_Context *context = new GHOST_ContextSDL(m_wantStereoVisual, m_sdl_win, 0, // profile bit 3, 3, GHOST_OPENGL_SDL_CONTEXT_FLAGS, GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY); if (context->initializeDrawingContext()) { return context; } delete context; } return nullptr; } GHOST_TSuccess GHOST_WindowSDL::invalidate() { if (m_invalid_window == false) { m_system->addDirtyWindow(this); m_invalid_window = true; } return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowSDL::setState(GHOST_TWindowState state) { switch (state) { case GHOST_kWindowStateNormal: SDL_SetWindowFullscreen(m_sdl_win, SDL_FALSE); SDL_RestoreWindow(m_sdl_win); break; case GHOST_kWindowStateMaximized: SDL_SetWindowFullscreen(m_sdl_win, SDL_FALSE); SDL_MaximizeWindow(m_sdl_win); break; case GHOST_kWindowStateMinimized: SDL_MinimizeWindow(m_sdl_win); break; case GHOST_kWindowStateFullScreen: SDL_SetWindowFullscreen(m_sdl_win, SDL_TRUE); break; default: break; } return GHOST_kSuccess; } GHOST_TWindowState GHOST_WindowSDL::getState() const { Uint32 flags = SDL_GetWindowFlags(m_sdl_win); if (flags & SDL_WINDOW_FULLSCREEN) { return GHOST_kWindowStateFullScreen; } if (flags & SDL_WINDOW_MAXIMIZED) { return GHOST_kWindowStateMaximized; } if (flags & SDL_WINDOW_MINIMIZED) { return GHOST_kWindowStateMinimized; } return GHOST_kWindowStateNormal; } bool GHOST_WindowSDL::getValid() const { return GHOST_Window::getValid() && m_valid_setup; } void GHOST_WindowSDL::setTitle(const char *title) { SDL_SetWindowTitle(m_sdl_win, title); } std::string GHOST_WindowSDL::getTitle() const { return SDL_GetWindowTitle(m_sdl_win); } void GHOST_WindowSDL::getWindowBounds(GHOST_Rect &bounds) const { getClientBounds(bounds); } void GHOST_WindowSDL::getClientBounds(GHOST_Rect &bounds) const { int x, y, w, h; SDL_GetWindowSize(m_sdl_win, &w, &h); SDL_GetWindowPosition(m_sdl_win, &x, &y); bounds.m_l = x; bounds.m_r = x + w; bounds.m_t = y; bounds.m_b = y + h; } GHOST_TSuccess GHOST_WindowSDL::setClientWidth(uint32_t width) { int height; SDL_GetWindowSize(m_sdl_win, nullptr, &height); SDL_SetWindowSize(m_sdl_win, width, height); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowSDL::setClientHeight(uint32_t height) { int width; SDL_GetWindowSize(m_sdl_win, &width, nullptr); SDL_SetWindowSize(m_sdl_win, width, height); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowSDL::setClientSize(uint32_t width, uint32_t height) { SDL_SetWindowSize(m_sdl_win, width, height); return GHOST_kSuccess; } void GHOST_WindowSDL::screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const { /* XXXSDL_WEAK_ABS_COORDS */ int x_win, y_win; SDL_GetWindowPosition(m_sdl_win, &x_win, &y_win); outX = inX - x_win; outY = inY - y_win; } void GHOST_WindowSDL::clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const { /* XXXSDL_WEAK_ABS_COORDS */ int x_win, y_win; SDL_GetWindowPosition(m_sdl_win, &x_win, &y_win); outX = inX + x_win; outY = inY + y_win; } /* mouse cursor */ static uchar sdl_std_cursor_mask_xterm[] = { 0xef, 0x01, 0xff, 0x01, 0xff, 0x01, 0x7c, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7c, 0x00, 0xff, 0x01, 0xff, 0x01, 0xef, 0x01, }; static uchar sdl_std_cursor_xterm[] = { 0x00, 0x77, 0x00, 0x1c, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_xterm 9 #define sdl_std_cursor_HEIGHT_xterm 16 #define sdl_std_cursor_HOT_X_xterm -3 #define sdl_std_cursor_HOT_Y_xterm -7 static uchar sdl_std_cursor_mask_watch[] = { 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, 0xfe, 0x1f, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x1f, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, }; static uchar sdl_std_cursor_watch[] = { 0xf8, 0x07, 0xf8, 0x07, 0xf8, 0x07, 0xfc, 0x0f, 0x86, 0x18, 0x83, 0x30, 0x81, 0xe0, 0xc1, 0xe1, 0xc1, 0xe1, 0x21, 0xe0, 0x13, 0x30, 0x06, 0x18, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8, 0x07, }; #define sdl_std_cursor_WIDTH_watch 16 #define sdl_std_cursor_HEIGHT_watch 16 #define sdl_std_cursor_HOT_X_watch -15 #define sdl_std_cursor_HOT_Y_watch -7 static uchar sdl_std_cursor_mask_umbrella[] = { 0xe8, 0x76, 0xfb, 0xdf, 0xfd, 0x3f, 0xfe, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xcf, 0x79, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0x80, 0x03, }; static uchar sdl_std_cursor_umbrella[] = { 0x88, 0x04, 0x20, 0x0a, 0xc9, 0x32, 0xf2, 0x09, 0x4c, 0x06, 0x43, 0x18, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_umbrella 16 #define sdl_std_cursor_HEIGHT_umbrella 16 #define sdl_std_cursor_HOT_X_umbrella -7 #define sdl_std_cursor_HOT_Y_umbrella -12 static uchar sdl_std_cursor_mask_top_side[] = { 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xdc, 0x1d, 0xcc, 0x19, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, }; static uchar sdl_std_cursor_top_side[] = { 0xff, 0x1f, 0xff, 0x1f, 0x00, 0x00, 0x40, 0x00, 0xe0, 0x00, 0x50, 0x01, 0x48, 0x02, 0x44, 0x04, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_top_side 15 #define sdl_std_cursor_HEIGHT_top_side 16 #define sdl_std_cursor_HOT_X_top_side -6 #define sdl_std_cursor_HOT_Y_top_side -14 static uchar sdl_std_cursor_mask_top_right_corner[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xfc, 0xf7, 0xfc, 0xf7, 0xfc, 0xf7, 0xc0, 0xf7, 0xe0, 0xf7, 0x70, 0xf7, 0x38, 0xf7, 0x1c, 0xf7, 0x0c, 0xf7, 0x00, 0xf0, 0x00, 0xf0, }; static uchar sdl_std_cursor_top_right_corner[] = { 0xff, 0x3f, 0xff, 0x3f, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0xfc, 0x31, 0x80, 0x31, 0x40, 0x31, 0x20, 0x31, 0x10, 0x31, 0x08, 0x31, 0x04, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_top_right_corner 16 #define sdl_std_cursor_HEIGHT_top_right_corner 16 #define sdl_std_cursor_HOT_X_top_right_corner -13 #define sdl_std_cursor_HOT_Y_top_right_corner -14 static uchar sdl_std_cursor_mask_top_left_corner[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xef, 0x3f, 0xef, 0x3f, 0xef, 0x3f, 0xef, 0x03, 0xef, 0x07, 0xef, 0x0e, 0xef, 0x1c, 0xef, 0x38, 0xef, 0x30, 0x0f, 0x00, 0x0f, 0x00, }; static uchar sdl_std_cursor_top_left_corner[] = { 0xff, 0x3f, 0xff, 0x3f, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0xe3, 0x0f, 0x63, 0x00, 0xa3, 0x00, 0x23, 0x01, 0x23, 0x02, 0x23, 0x04, 0x23, 0x08, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_top_left_corner 16 #define sdl_std_cursor_HEIGHT_top_left_corner 16 #define sdl_std_cursor_HOT_X_top_left_corner 0 #define sdl_std_cursor_HOT_Y_top_left_corner -14 static uchar sdl_std_cursor_mask_sb_v_double_arrow[] = { 0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00, 0xff, 0x01, 0xff, 0x01, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0xff, 0x01, 0xff, 0x01, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, }; static uchar sdl_std_cursor_sb_v_double_arrow[] = { 0x10, 0x00, 0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00, }; #define sdl_std_cursor_WIDTH_sb_v_double_arrow 9 #define sdl_std_cursor_HEIGHT_sb_v_double_arrow 15 #define sdl_std_cursor_HOT_X_sb_v_double_arrow -3 #define sdl_std_cursor_HOT_Y_sb_v_double_arrow -8 static uchar sdl_std_cursor_mask_sb_h_double_arrow[] = { 0x18, 0x0c, 0x1c, 0x1c, 0xfe, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x3f, 0x1c, 0x1c, 0x18, 0x0c, }; static uchar sdl_std_cursor_sb_h_double_arrow[] = { 0x00, 0x00, 0x08, 0x08, 0x0c, 0x18, 0xfe, 0x3f, 0x0f, 0x78, 0xfe, 0x3f, 0x0c, 0x18, 0x08, 0x08, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_sb_h_double_arrow 15 #define sdl_std_cursor_HEIGHT_sb_h_double_arrow 9 #define sdl_std_cursor_HOT_X_sb_h_double_arrow -7 #define sdl_std_cursor_HOT_Y_sb_h_double_arrow -4 static uchar sdl_std_cursor_mask_right_side[] = { 0x00, 0xf0, 0x00, 0xf0, 0xc0, 0xf0, 0xc0, 0xf1, 0x80, 0xf3, 0x00, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf7, 0x80, 0xf3, 0xc0, 0xf1, 0xc0, 0xf0, 0x00, 0xf0, 0x00, 0xf0, }; static uchar sdl_std_cursor_right_side[] = { 0x00, 0x30, 0x00, 0x30, 0x40, 0x30, 0x80, 0x30, 0x00, 0x31, 0x00, 0x32, 0xff, 0x37, 0x00, 0x32, 0x00, 0x31, 0x80, 0x30, 0x40, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_right_side 16 #define sdl_std_cursor_HEIGHT_right_side 15 #define sdl_std_cursor_HOT_X_right_side -13 #define sdl_std_cursor_HOT_Y_right_side -7 static uchar sdl_std_cursor_mask_right_ptr[] = { 0x00, 0x03, 0x80, 0x03, 0xc0, 0x03, 0xe0, 0x03, 0xf0, 0x03, 0xf8, 0x03, 0xfc, 0x03, 0xfe, 0x03, 0xff, 0x03, 0xff, 0x03, 0xf8, 0x03, 0xbc, 0x03, 0x3c, 0x03, 0x1e, 0x00, 0x1e, 0x00, 0x0c, 0x00, }; static uchar sdl_std_cursor_right_ptr[] = { 0x00, 0x80, 0x00, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf8, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0xff, 0x00, 0xf8, 0x00, 0xd8, 0x00, 0x8c, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_right_ptr 10 #define sdl_std_cursor_HEIGHT_right_ptr 16 #define sdl_std_cursor_HOT_X_right_ptr -7 #define sdl_std_cursor_HOT_Y_right_ptr -14 static uchar sdl_std_cursor_mask_question_arrow[] = { 0xf8, 0x00, 0xfc, 0x01, 0xfe, 0x03, 0xff, 0x07, 0x8f, 0x07, 0x9f, 0x07, 0xde, 0x07, 0xfc, 0x03, 0xf8, 0x01, 0xf8, 0x00, 0xf8, 0x00, 0xfc, 0x01, 0xfe, 0x03, 0xfc, 0x01, 0xf8, 0x00, 0x70, 0x00, }; static uchar sdl_std_cursor_question_arrow[] = { 0x7c, 0x00, 0xfe, 0x00, 0xc7, 0x01, 0x83, 0x01, 0x87, 0x01, 0xc6, 0x01, 0xe0, 0x00, 0x78, 0x00, 0x38, 0x00, 0x28, 0x00, 0x28, 0x00, 0xee, 0x00, 0x6c, 0x00, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_question_arrow 11 #define sdl_std_cursor_HEIGHT_question_arrow 16 #define sdl_std_cursor_HOT_X_question_arrow -4 #define sdl_std_cursor_HOT_Y_question_arrow -8 static uchar sdl_std_cursor_mask_pirate[] = { 0xf0, 0x03, 0xf8, 0x07, 0xfc, 0x0f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf1, 0x83, 0xf1, 0xe3, 0xf3, 0xf3, 0xef, 0x39, 0x1e, 0x1e, 0xe0, 0x01, 0xfe, 0xc7, 0xff, 0xff, 0x0f, 0x7c, }; static uchar sdl_std_cursor_pirate[] = { 0xe0, 0x01, 0xf0, 0x03, 0xf8, 0x07, 0xcc, 0x0c, 0xcc, 0x0c, 0xf8, 0x07, 0xf0, 0x03, 0xe0, 0x01, 0xe1, 0x21, 0xe1, 0x61, 0xc2, 0x10, 0x1c, 0x0e, 0xe0, 0x01, 0xf8, 0x47, 0x0f, 0x7c, 0x01, 0x20, }; #define sdl_std_cursor_WIDTH_pirate 16 #define sdl_std_cursor_HEIGHT_pirate 16 #define sdl_std_cursor_HOT_X_pirate -7 #define sdl_std_cursor_HOT_Y_pirate -4 static uchar sdl_std_cursor_mask_left_side[] = { 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x03, 0x8f, 0x03, 0xcf, 0x01, 0xef, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x00, 0xcf, 0x01, 0x8f, 0x03, 0x0f, 0x03, 0x0f, 0x00, 0x0f, 0x00, }; static uchar sdl_std_cursor_left_side[] = { 0x03, 0x00, 0x03, 0x00, 0x83, 0x00, 0x43, 0x00, 0x23, 0x00, 0x13, 0x00, 0xfb, 0x3f, 0x13, 0x00, 0x23, 0x00, 0x43, 0x00, 0x83, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_left_side 16 #define sdl_std_cursor_HEIGHT_left_side 15 #define sdl_std_cursor_HOT_X_left_side 0 #define sdl_std_cursor_HOT_Y_left_side -7 static uchar sdl_std_cursor_mask_left_ptr[] = { 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x3f, 0x00, 0x7f, 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x03, 0x7f, 0x00, 0xf7, 0x00, 0xf3, 0x00, 0xe0, 0x01, 0xe0, 0x01, 0xc0, 0x00, }; static uchar sdl_std_cursor_left_ptr[] = { 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x3e, 0x00, 0x7e, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x3e, 0x00, 0x36, 0x00, 0x62, 0x00, 0x60, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_left_ptr 10 #define sdl_std_cursor_HEIGHT_left_ptr 16 #define sdl_std_cursor_HOT_X_left_ptr -8 #define sdl_std_cursor_HOT_Y_left_ptr -14 static uchar sdl_std_cursor_mask_crosshair[] = { 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, }; static uchar sdl_std_cursor_crosshair[] = { 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x7f, 0xff, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_crosshair 16 #define sdl_std_cursor_HEIGHT_crosshair 16 #define sdl_std_cursor_HOT_X_crosshair -7 #define sdl_std_cursor_HOT_Y_crosshair -8 static uchar sdl_std_cursor_mask_bottom_side[] = { 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xcc, 0x19, 0xdc, 0x1d, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, }; static uchar sdl_std_cursor_bottom_side[] = { 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x44, 0x04, 0x48, 0x02, 0x50, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x1f, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_bottom_side 15 #define sdl_std_cursor_HEIGHT_bottom_side 16 #define sdl_std_cursor_HOT_X_bottom_side -6 #define sdl_std_cursor_HOT_Y_bottom_side -1 static uchar sdl_std_cursor_mask_bottom_right_corner[] = { 0x00, 0xf0, 0x00, 0xf0, 0x0c, 0xf7, 0x1c, 0xf7, 0x38, 0xf7, 0x70, 0xf7, 0xe0, 0xf7, 0xc0, 0xf7, 0xfc, 0xf7, 0xfc, 0xf7, 0xfc, 0xf7, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; static uchar sdl_std_cursor_bottom_right_corner[] = { 0x00, 0x30, 0x00, 0x30, 0x04, 0x31, 0x08, 0x31, 0x10, 0x31, 0x20, 0x31, 0x40, 0x31, 0x80, 0x31, 0xfc, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0xff, 0x3f, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_bottom_right_corner 16 #define sdl_std_cursor_HEIGHT_bottom_right_corner 16 #define sdl_std_cursor_HOT_X_bottom_right_corner -13 #define sdl_std_cursor_HOT_Y_bottom_right_corner -1 static uchar sdl_std_cursor_mask_bottom_left_corner[] = { 0x0f, 0x00, 0x0f, 0x00, 0xef, 0x30, 0xef, 0x38, 0xef, 0x1c, 0xef, 0x0e, 0xef, 0x07, 0xef, 0x03, 0xef, 0x3f, 0xef, 0x3f, 0xef, 0x3f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; static uchar sdl_std_cursor_bottom_left_corner[] = { 0x03, 0x00, 0x03, 0x00, 0x23, 0x08, 0x23, 0x04, 0x23, 0x02, 0x23, 0x01, 0xa3, 0x00, 0x63, 0x00, 0xe3, 0x0f, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0xff, 0x3f, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_bottom_left_corner 16 #define sdl_std_cursor_HEIGHT_bottom_left_corner 16 #define sdl_std_cursor_HOT_X_bottom_left_corner 0 #define sdl_std_cursor_HOT_Y_bottom_left_corner -1 static uchar sdl_std_cursor_mask_arrow[] = { 0x00, 0xe0, 0x00, 0xf8, 0x00, 0xfe, 0x80, 0x7f, 0xe0, 0x7f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc, 0x1f, 0xe0, 0x1f, 0xf0, 0x0f, 0xf8, 0x0f, 0x7c, 0x07, 0x3e, 0x07, 0x1f, 0x02, 0x0e, 0x00, 0x04, 0x00, }; static uchar sdl_std_cursor_arrow[] = { 0x00, 0x30, 0x00, 0x3c, 0x00, 0x1f, 0xc0, 0x1f, 0xf0, 0x0f, 0xfc, 0x0f, 0xc0, 0x07, 0xe0, 0x07, 0x70, 0x03, 0x38, 0x03, 0x1c, 0x01, 0x0e, 0x01, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define sdl_std_cursor_WIDTH_arrow 16 #define sdl_std_cursor_HEIGHT_arrow 16 #define sdl_std_cursor_HOT_X_arrow -13 #define sdl_std_cursor_HOT_Y_arrow -14 /* end cursor data */ static SDL_Cursor *sdl_std_cursor_array[int(GHOST_kStandardCursorNumCursors)] = {nullptr}; /* utility function mostly a copy of SDL_CreateCursor but allows us to change * color and supports blenders flipped bits */ static SDL_Cursor *sdl_ghost_CreateCursor( const Uint8 *data, const Uint8 *mask, int w, int h, int hot_x, int hot_y) { SDL_Surface *surface; SDL_Cursor *cursor; int x, y; Uint32 *pixel; Uint8 datab = 0, maskb = 0; const Uint32 black = 0xFF000000; const Uint32 white = 0xFFFFFFFF; const Uint32 transparent = 0x00000000; /* Make sure the width is a multiple of 8 */ w = ((w + 7) & ~7); /* Create the surface from a bitmap */ surface = SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); if (!surface) { return nullptr; } for (y = 0; y < h; ++y) { pixel = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch); for (x = 0; x < w; ++x) { if ((x % 8) == 0) { datab = *data++; maskb = *mask++; /* reverse bit order */ datab = (datab * 0x0202020202ULL & 0x010884422010ULL) % 1023; maskb = (maskb * 0x0202020202ULL & 0x010884422010ULL) % 1023; } if (maskb & 0x80) { *pixel++ = (datab & 0x80) ? white : black; } else { *pixel++ = (datab & 0x80) ? white : transparent; } datab <<= 1; maskb <<= 1; } } cursor = SDL_CreateColorCursor(surface, hot_x, hot_y); SDL_FreeSurface(surface); return cursor; } /* TODO: this is currently never freed but it won't leak either. */ static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape) { if (sdl_std_cursor_array[0] == nullptr) { #define DEF_CURSOR(name, ind) \ { \ sdl_std_cursor_array[int(ind)] = sdl_ghost_CreateCursor( \ sdl_std_cursor_##name, \ sdl_std_cursor_mask_##name, \ sdl_std_cursor_WIDTH_##name, \ sdl_std_cursor_HEIGHT_##name, \ (sdl_std_cursor_WIDTH_##name + (sdl_std_cursor_HOT_X_##name)) - 1, \ (sdl_std_cursor_HEIGHT_##name + (sdl_std_cursor_HOT_Y_##name)) - 1); \ assert(sdl_std_cursor_array[int(ind)] != nullptr); \ } \ (void)0 DEF_CURSOR(left_ptr, GHOST_kStandardCursorDefault); DEF_CURSOR(right_ptr, GHOST_kStandardCursorRightArrow); DEF_CURSOR(left_ptr, GHOST_kStandardCursorLeftArrow); DEF_CURSOR(umbrella, GHOST_kStandardCursorInfo); /* TODO: replace this one. */ DEF_CURSOR(pirate, GHOST_kStandardCursorDestroy); DEF_CURSOR(question_arrow, GHOST_kStandardCursorHelp); DEF_CURSOR(watch, GHOST_kStandardCursorWait); DEF_CURSOR(xterm, GHOST_kStandardCursorText); DEF_CURSOR(crosshair, GHOST_kStandardCursorCrosshair); DEF_CURSOR(sb_v_double_arrow, GHOST_kStandardCursorUpDown); DEF_CURSOR(sb_h_double_arrow, GHOST_kStandardCursorLeftRight); DEF_CURSOR(top_side, GHOST_kStandardCursorTopSide); DEF_CURSOR(bottom_side, GHOST_kStandardCursorBottomSide); DEF_CURSOR(left_side, GHOST_kStandardCursorLeftSide); DEF_CURSOR(right_side, GHOST_kStandardCursorRightSide); DEF_CURSOR(top_left_corner, GHOST_kStandardCursorTopLeftCorner); DEF_CURSOR(top_right_corner, GHOST_kStandardCursorTopRightCorner); DEF_CURSOR(bottom_right_corner, GHOST_kStandardCursorBottomRightCorner); DEF_CURSOR(bottom_left_corner, GHOST_kStandardCursorBottomLeftCorner); DEF_CURSOR(arrow, GHOST_kStandardCursorCopy); // DEF_CURSOR(arrow, GHOST_kStandardCursorCustom); DEF_CURSOR(arrow, GHOST_kStandardCursorPencil); #undef DEF_CURSOR } return sdl_std_cursor_array[int(shape)]; } GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/) { return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowSDL::setWindowCursorShape(GHOST_TStandardCursor shape) { SDL_Cursor *cursor = getStandardCursorShape(shape); if (cursor == nullptr) { cursor = getStandardCursorShape(GHOST_kStandardCursorDefault); } SDL_SetCursor(cursor); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowSDL::hasCursorShape(GHOST_TStandardCursor shape) { return (getStandardCursorShape(shape)) ? GHOST_kSuccess : GHOST_kFailure; } GHOST_TSuccess GHOST_WindowSDL::setWindowCustomCursorShape(uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool /*canInvertColor*/) { if (m_sdl_custom_cursor) { SDL_FreeCursor(m_sdl_custom_cursor); } m_sdl_custom_cursor = sdl_ghost_CreateCursor( (const Uint8 *)bitmap, (const Uint8 *)mask, sizex, sizey, hotX, hotY); SDL_SetCursor(m_sdl_custom_cursor); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowSDL::setWindowCursorVisibility(bool visible) { SDL_ShowCursor(visible); return GHOST_kSuccess; } uint16_t GHOST_WindowSDL::getDPIHint() { int displayIndex = SDL_GetWindowDisplayIndex(m_sdl_win); if (displayIndex < 0) { return 96; } float ddpi; if (SDL_GetDisplayDPI(displayIndex, &ddpi, nullptr, nullptr) != 0) { return 96; } return int(ddpi); }