From b68e37b39d7ed69139913953b61eee6b65f43655 Mon Sep 17 00:00:00 2001 From: pingkai Date: Fri, 5 Jun 2020 11:09:25 +0800 Subject: [PATCH] feat(cmdline): support set native window and sdl window to sdl render Signed-off-by: pingkai --- cmdline/CMakeLists.txt | 7 ++- cmdline/SDLEventReceiver.cpp | 62 +++++++++++--------- cmdline/SDLEventReceiver.h | 10 +++- cmdline/nativeWindow/CocoaWindow.m | 91 +++++++++++++++++++++++++++++ cmdline/nativeWindow/X11Window.c | 44 ++++++++++++++ cmdline/nativeWindow/nativeWindow.h | 51 ++++++++++++++++ 6 files changed, 235 insertions(+), 30 deletions(-) create mode 100644 cmdline/nativeWindow/CocoaWindow.m create mode 100644 cmdline/nativeWindow/X11Window.c create mode 100644 cmdline/nativeWindow/nativeWindow.h diff --git a/cmdline/CMakeLists.txt b/cmdline/CMakeLists.txt index f6e06457f..0c55ca52c 100644 --- a/cmdline/CMakeLists.txt +++ b/cmdline/CMakeLists.txt @@ -30,7 +30,8 @@ if (ENABLE_SDL) list(APPEND SRC_FILE SDLEventReceiver.cpp SDLEventReceiver.h - ) + nativeWindow/CocoaWindow.m + nativeWindow/X11Window.c) endif () add_executable(cicadaPlayer @@ -120,6 +121,10 @@ else () add_subdirectory(example) endif () +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(cicadaPlayer PUBLIC X11) +endif() + if(MSVC AND NOT CMAKE_SIZEOF_VOID_P EQUAL 8) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") diff --git a/cmdline/SDLEventReceiver.cpp b/cmdline/SDLEventReceiver.cpp index d4dd8a9ba..9a9394b97 100644 --- a/cmdline/SDLEventReceiver.cpp +++ b/cmdline/SDLEventReceiver.cpp @@ -3,6 +3,7 @@ // #include "SDLEventReceiver.h" +#include "nativeWindow/nativeWindow.h" #include #include #include @@ -18,28 +19,30 @@ void SDLEventReceiver::poll(bool &exit) { if (UserEvent) { switch (UserEvent->getType()) { case IEvent::TYPE_SET_VIEW: { - if (window == nullptr) { - if (SDL_WasInit(SDL_INIT_VIDEO) != SDL_INIT_VIDEO) { - SDL_Init(SDL_INIT_VIDEO); - } - Uint32 flags = 0; - flags |= SDL_WINDOW_ALLOW_HIGHDPI; - flags |= SDL_WINDOW_RESIZABLE; - window = SDL_CreateWindow("playerDemo", 0, 0, 1280, 720, flags); - } - SDL_SysWMinfo wminfo; - SDL_VERSION(&wminfo.version) - SDL_GetWindowWMInfo(window, &wminfo); - void* window_id = nullptr; - #if defined(SDL_VIDEO_DRIVER_WINDOWS) - window_id = wminfo.info.win.window; - #elif defined(SDL_VIDEO_DRIVER_X11) - window_id = wminfo.info.x11.window; - #elif defined(SDL_VIDEO_DRIVER_COCOA) - window_id = wminfo.info.cocoa.window; - #endif - mListener.onSetView(window_id); - break; + if (SDL_WasInit(SDL_INIT_VIDEO) != SDL_INIT_VIDEO) { + SDL_Init(SDL_INIT_VIDEO); + } + if (mView.view == nullptr) { +#if USE_NATIVE_WINDOW + if (getNativeFactor() != nullptr) { + mView.view = (getNativeFactor()->CreateNativeWindow(1280, 720)); + if (mView.view) { + mView.type = CicadaSDLViewType_NATIVE_WINDOW; + } + } + +#endif + if (mView.view == nullptr) { + Uint32 flags = 0; + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + flags |= SDL_WINDOW_RESIZABLE; + SDL_Renderer *renderer; + SDL_CreateWindowAndRenderer(1280, 720, flags, reinterpret_cast(&mView.view), &renderer); + mView.type = CicadaSDLViewType_SDL_WINDOW; + } + } + mListener.onSetView(&mView); + break; } case IEvent::TYPE_EXIT: mListener.onExit(); @@ -100,13 +103,13 @@ void SDLEventReceiver::poll(bool &exit) { } case SDL_MOUSEBUTTONDOWN: { - if (event.button.button == SDL_BUTTON_LEFT) { + if (event.button.button == SDL_BUTTON_LEFT && mView.type == CicadaSDLViewType_SDL_WINDOW) { static int64_t last_mouse_left_click = 0; static bool is_full_screen = false; if (af_gettime_relative() - last_mouse_left_click <= 500000) { is_full_screen = !is_full_screen; - if (window) { - SDL_SetWindowFullscreen(window, is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + if (mView.view) { + SDL_SetWindowFullscreen((SDL_Window *) mView.view, is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); } mListener.onFullScreen(is_full_screen); last_mouse_left_click = 0; @@ -121,9 +124,12 @@ void SDLEventReceiver::poll(bool &exit) { break; } if (exit){ - if (window != nullptr) { - SDL_DestroyWindow(window); - window = nullptr; + if (mView.view != nullptr) { + if (mView.type == CicadaSDLViewType_NATIVE_WINDOW) { + getNativeFactor()->DestroyNativeWindow(mView.view); + } else + SDL_DestroyWindow((SDL_Window *) mView.view); + mView.view = nullptr; } } } diff --git a/cmdline/SDLEventReceiver.h b/cmdline/SDLEventReceiver.h index 08c9e3e33..dcebaca0a 100644 --- a/cmdline/SDLEventReceiver.h +++ b/cmdline/SDLEventReceiver.h @@ -8,6 +8,14 @@ #include #endif #include "IEventReceiver.h" +#define USE_NATIVE_WINDOW 0 + +enum CicadaSDLViewType { CicadaSDLViewType_SDL_WINDOW, CicadaSDLViewType_NATIVE_WINDOW }; + +typedef struct CicadaSDLView_t { + void *view; + CicadaSDLViewType type; +} CicadaSDLView; class SDLEventReceiver : public IEventReceiver { @@ -20,7 +28,7 @@ class SDLEventReceiver : public IEventReceiver { private: #ifdef ENABLE_SDL SDL_Event event{}; - SDL_Window *window = nullptr; + CicadaSDLView mView{}; #endif }; diff --git a/cmdline/nativeWindow/CocoaWindow.m b/cmdline/nativeWindow/CocoaWindow.m new file mode 100644 index 000000000..4f502804a --- /dev/null +++ b/cmdline/nativeWindow/CocoaWindow.m @@ -0,0 +1,91 @@ + +#include "nativeWindow.h" + +#ifdef TEST_NATIVE_COCOA + +#include + +static void *CreateWindowCocoa(int w, int h); +static void DestroyWindowCocoa(void *window); + +NativeWindowFactory CocoaWindowFactory = {"cocoa", CreateWindowCocoa, DestroyWindowCocoa}; + +static void *CreateWindowCocoa(int w, int h) +{ + NSAutoreleasePool *pool; + NSWindow *nswindow; + NSRect rect; + unsigned int style; + NSArray *screens = [NSScreen screens]; + + pool = [[NSAutoreleasePool alloc] init]; + + rect.origin.x = 0; + rect.origin.y = 0; + rect.size.width = w; + rect.size.height = h; + rect.origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - rect.origin.y - rect.size.height; + + style = (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable); + // NSRect viewport = [contentView bounds]; + // if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) { + // viewport = [contentView convertRectToBacking:viewport]; + // } + // rect.size.width = viewport.size.width; + // rect.size.height = viewport.size.height; + + /* Figure out which screen to place this window */ + NSScreen *screen = nil; + for (NSScreen *candidate in screens) { + NSRect screenRect = [candidate frame]; + if (rect.origin.x >= screenRect.origin.x && rect.origin.x < screenRect.origin.x + screenRect.size.width && + rect.origin.y >= screenRect.origin.y && rect.origin.y < screenRect.origin.y + screenRect.size.height) { + screen = candidate; + rect.origin.x -= screenRect.origin.x; + rect.origin.y -= screenRect.origin.y; + } + } + + nswindow = [[NSWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:FALSE screen:screen]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 /* Added in the 10.12.0 SDK. */ + /* By default, don't allow users to make our window tabbed in 10.12 or later */ + if ([nswindow respondsToSelector:@selector(setTabbingMode:)]) { + [nswindow setTabbingMode:NSWindowTabbingModeDisallowed]; + } +#endif + [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + rect = [nswindow contentRectForFrameRect:[nswindow frame]]; + NSView *contentView = [[NSView alloc] initWithFrame:rect]; +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { + // BOOL highdpi = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; + [contentView setWantsBestResolutionOpenGLSurface:YES]; + } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + + [nswindow makeKeyAndOrderFront:nil]; + [nswindow setContentView:contentView]; + [contentView release]; + + [pool release]; + + return nswindow; +} + +static void DestroyWindowCocoa(void *window) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSWindow *nswindow = (NSWindow *) window; + + [nswindow close]; + [pool release]; +} + +#endif diff --git a/cmdline/nativeWindow/X11Window.c b/cmdline/nativeWindow/X11Window.c new file mode 100644 index 000000000..939851b3e --- /dev/null +++ b/cmdline/nativeWindow/X11Window.c @@ -0,0 +1,44 @@ +// +// Created by moqi on 2020/6/4. +// +#include "nativeWindow.h" +#ifdef TEST_NATIVE_X11 + +static void *CreateWindowX11(int w, int h); +static void DestroyWindowX11(void *window); + +NativeWindowFactory X11WindowFactory = { + "x11", + CreateWindowX11, + DestroyWindowX11 +}; + +static Display *dpy; + +static void * +CreateWindowX11(int w, int h) +{ + Window window = 0; + + dpy = XOpenDisplay(NULL); + if (dpy) { + window = + XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, w, h, 0, 0, + 0); + XMapRaised(dpy, window); + XSync(dpy, False); + } + return (void *) window; +} + +static void +DestroyWindowX11(void *window) +{ + if (dpy) { + XDestroyWindow(dpy, (Window) window); + XCloseDisplay(dpy); + } +} + +#endif + diff --git a/cmdline/nativeWindow/nativeWindow.h b/cmdline/nativeWindow/nativeWindow.h new file mode 100644 index 000000000..53bcf9421 --- /dev/null +++ b/cmdline/nativeWindow/nativeWindow.h @@ -0,0 +1,51 @@ +// +// Created by moqi on 2020/6/4. +// + +#ifndef CICADAMEDIA_NATIVEWINDOW_H +#define CICADAMEDIA_NATIVEWINDOW_H +#include +#include + +typedef struct { + const char *tag; + void *(*CreateNativeWindow)(int w, int h); + void (*DestroyNativeWindow)(void *window); +} NativeWindowFactory; + +#ifdef SDL_VIDEO_DRIVER_WINDOWS +#define TEST_NATIVE_WINDOWS +extern NativeWindowFactory WindowsWindowFactory; +#endif + +#ifdef SDL_VIDEO_DRIVER_X11 +#define TEST_NATIVE_X11 +extern NativeWindowFactory X11WindowFactory; +#endif + +#ifdef SDL_VIDEO_DRIVER_COCOA +/* Actually, we don't really do this, since it involves adding Objective C + support to the build system, which is a little tricky. You can uncomment + it manually though and link testnativecocoa.m into the test application. +*/ +#define TEST_NATIVE_COCOA +extern NativeWindowFactory CocoaWindowFactory; +#endif + +static NativeWindowFactory *getNativeFactor() +{ +#ifdef SDL_VIDEO_DRIVER_COCOA + return &CocoaWindowFactory; +#endif + +#ifdef SDL_VIDEO_DRIVER_WINDOWS + return &WindowsWindowFactory; +#endif +#ifdef SDL_VIDEO_DRIVER_X11 + return &X11WindowFactory; +#endif + return NULL; +} + + +#endif//CICADAMEDIA_NATIVEWINDOW_H