diff options
Diffstat (limited to 'src/osd/sdl/window.cpp')
-rw-r--r-- | src/osd/sdl/window.cpp | 792 |
1 files changed, 498 insertions, 294 deletions
diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp index 875e06a7b3d..59be82238d0 100644 --- a/src/osd/sdl/window.cpp +++ b/src/osd/sdl/window.cpp @@ -8,40 +8,38 @@ // //============================================================ -#ifdef SDLMAME_WIN32 -#include <windows.h> -#endif - -// standard SDL headers -#include <SDL2/SDL.h> - -// standard C headers -#include <math.h> -#ifndef _MSC_VER -#include <unistd.h> -#endif -#include <list> -#include <memory> - // MAME headers - #include "emu.h" #include "emuopts.h" #include "render.h" +#include "screen.h" +#include "uiinput.h" #include "ui/uimain.h" // OSD headers - -#include "window.h" -#include "osdsdl.h" -#include "modules/render/drawbgfx.h" -#include "modules/render/drawsdl.h" -#include "modules/render/draw13.h" #include "modules/monitor/monitor_common.h" -#if (USE_OPENGL) -#include "modules/render/drawogl.h" +#include "osdsdl.h" +#include "window.h" + +// standard SDL headers +#include <SDL2/SDL_syswm.h> + +// standard C headers +#include <algorithm> +#include <cassert> +#include <cmath> +#include <list> +#include <memory> + +#ifndef _MSC_VER +#include <unistd.h> +#endif + +#ifdef SDLMAME_WIN32 +#include <windows.h> #endif + //============================================================ // PARAMETERS //============================================================ @@ -66,19 +64,6 @@ #define SDL_VERSION_EQUALS(v1, vnum2) (SDL_VERSIONNUM(v1.major, v1.minor, v1.patch) == vnum2) -class SDL_DM_Wrapper -{ -public: - SDL_DisplayMode mode; -}; - -// debugger -//static int in_background; - - -//============================================================ -// PROTOTYPES -//============================================================ //============================================================ @@ -90,30 +75,10 @@ bool sdl_osd_interface::window_init() { osd_printf_verbose("Enter sdlwindow_init\n"); - // initialize the drawers - - switch (video_config.mode) - { - case VIDEO_MODE_BGFX: - renderer_bgfx::init(machine()); - break; -#if (USE_OPENGL) - case VIDEO_MODE_OPENGL: - renderer_ogl::init(machine()); - break; -#endif - case VIDEO_MODE_SDL2ACCEL: - renderer_sdl2::init(machine()); - break; - case VIDEO_MODE_SOFT: - renderer_sdl1::init(machine()); - break; - } - - /* We may want to set a number of the hints SDL2 provides. - * The code below will document which hints were set. - */ - const char * hints[] = { SDL_HINT_FRAMEBUFFER_ACCELERATION, + // We may want to set a number of the hints SDL2 provides. + // The code below will document which hints were set. + char const *const hints[] = { + SDL_HINT_FRAMEBUFFER_ACCELERATION, SDL_HINT_RENDER_DRIVER, SDL_HINT_RENDER_OPENGL_SHADERS, SDL_HINT_RENDER_SCALE_QUALITY, SDL_HINT_RENDER_VSYNC, @@ -124,23 +89,21 @@ bool sdl_osd_interface::window_init() SDL_HINT_XINPUT_ENABLED, SDL_HINT_GAMECONTROLLERCONFIG, SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, SDL_HINT_ALLOW_TOPMOST, SDL_HINT_TIMER_RESOLUTION, -#if SDL_VERSION_ATLEAST(2, 0, 2) SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_HINT_VIDEO_ALLOW_SCREENSAVER, SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, SDL_HINT_VIDEO_WIN_D3DCOMPILER, SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, SDL_HINT_MOUSE_RELATIVE_MODE_WARP, -#endif -#if SDL_VERSION_ATLEAST(2, 0, 3) SDL_HINT_RENDER_DIRECT3D11_DEBUG, SDL_HINT_VIDEO_HIGHDPI_DISABLED, SDL_HINT_WINRT_PRIVACY_POLICY_URL, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL, SDL_HINT_WINRT_HANDLE_BACK_BUTTON, -#endif - nullptr - }; + }; osd_printf_verbose("\nHints:\n"); - for (int i = 0; hints[i] != nullptr; i++) - osd_printf_verbose("\t%-40s %s\n", hints[i], SDL_GetHint(hints[i])); + for (auto const hintname : hints) + { + char const *const hintvalue(SDL_GetHint(hintname)); + osd_printf_verbose("\t%-40s %s\n", hintname, hintvalue ? hintvalue : "(NULL)"); + } // set up the window list osd_printf_verbose("Leave sdlwindow_init\n"); @@ -148,30 +111,6 @@ bool sdl_osd_interface::window_init() } -void sdl_osd_interface::update_slider_list() -{ - for (auto window : osd_common_t::s_window_list) - { - // check if any window has dirty sliders - if (window->renderer().sliders_dirty()) - { - build_slider_list(); - return; - } - } -} - -void sdl_osd_interface::build_slider_list() -{ - m_sliders.clear(); - - for (auto window : osd_common_t::s_window_list) - { - std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list(); - m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end()); - } -} - //============================================================ // sdlwindow_exit // (main thread) @@ -182,33 +121,14 @@ void sdl_osd_interface::window_exit() osd_printf_verbose("Enter sdlwindow_exit\n"); // free all the windows + m_focus_window = nullptr; while (!osd_common_t::s_window_list.empty()) { - auto window = osd_common_t::s_window_list.front(); - - // Part of destroy removes the window from the list + auto window = std::move(osd_common_t::s_window_list.back()); + s_window_list.pop_back(); window->destroy(); } - switch(video_config.mode) - { - case VIDEO_MODE_SDL2ACCEL: - renderer_sdl1::exit(); - break; - case VIDEO_MODE_SOFT: - renderer_sdl1::exit(); - break; - case VIDEO_MODE_BGFX: - renderer_bgfx::exit(); - break; -#if (USE_OPENGL) - case VIDEO_MODE_OPENGL: - renderer_ogl::exit(); - break; -#endif - default: - break; - } osd_printf_verbose("Leave sdlwindow_exit\n"); } @@ -293,8 +213,6 @@ void sdl_window_info::toggle_full_screen() m_windowed_dim = get_size(); } - // reset UI to main menu - machine().ui().menu_reset(); // kill off the drawers renderer_reset(); bool is_osx = false; @@ -304,17 +222,14 @@ void sdl_window_info::toggle_full_screen() #endif if (fullscreen() && (video_config.switchres || is_osx)) { - SDL_SetWindowFullscreen(platform_window(), 0); // Try to set mode - SDL_SetWindowDisplayMode(platform_window(), &m_original_mode->mode); // Try to set mode - SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode + SDL_SetWindowFullscreen(platform_window(), 0); + SDL_SetWindowDisplayMode(platform_window(), &m_original_mode); + SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); } SDL_DestroyWindow(platform_window()); set_platform_window(nullptr); - downcast<sdl_osd_interface &>(machine().osd()).release_keys(); - set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this())); - // toggle the window mode set_fullscreen(!fullscreen()); @@ -325,7 +240,7 @@ void sdl_window_info::modify_prescale(int dir) { int new_prescale = prescale(); - if (dir > 0 && prescale() < 3) + if (dir > 0 && prescale() < 20) new_prescale = prescale() + 1; if (dir < 0 && prescale() > 1) new_prescale = prescale() - 1; @@ -342,11 +257,11 @@ void sdl_window_info::modify_prescale(int dir) } else { - notify_changed(); m_prescale = new_prescale; + notify_changed(); } - machine().ui().popup_time(1, "Prescale %d", prescale()); } + machine().ui().popup_time(1, "Prescale %d", prescale()); } //============================================================ @@ -393,6 +308,291 @@ int sdl_window_info::xy_to_render_target(int x, int y, int *xt, int *yt) return renderer().xy_to_render_target(x, y, xt, yt); } +void sdl_window_info::mouse_entered(unsigned device) +{ + m_mouse_inside = true; +} + +void sdl_window_info::mouse_left(unsigned device) +{ + m_mouse_inside = false; + + auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), SDL_FingerID(-1), &sdl_pointer_info::compare)); + if ((m_active_pointers.end() == info) || (info->finger != SDL_FingerID(-1))) + return; + + // leaving implicitly releases buttons, so check hold/drag if necessary + if (BIT(info->buttons, 0) && (0 < info->clickcnt)) + { + auto const now(std::chrono::steady_clock::now()); + auto const exp(std::chrono::milliseconds(250) + info->pressed); + int const dx(info->x - info->pressedx); + int const dy(info->y - info->pressedy); + int const distance((dx * dx) + (dy * dy)); + if ((exp < now) || (CLICK_DISTANCE < distance)) + info->clickcnt = -info->clickcnt; + } + + // push to UI manager + machine().ui_input().push_pointer_leave( + target(), + osd::ui_event_handler::pointer::MOUSE, + info->index, + device, + info->x, info->y, + info->buttons, info->clickcnt); + + // dump pointer data + m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index); + if (info->index < m_next_pointer) + m_next_pointer = info->index; + m_active_pointers.erase(info); +} + +void sdl_window_info::mouse_down(unsigned device, int x, int y, unsigned button) +{ + if (!m_mouse_inside) + return; + + auto const info(map_pointer(SDL_FingerID(-1), device)); + if (m_active_pointers.end() == info) + return; + + if ((x == info->x) && (y == info->y) && BIT(info->buttons, button)) + return; + + // detect multi-click actions + if (0 == button) + { + info->primary_down( + x, + y, + std::chrono::milliseconds(250), + CLICK_DISTANCE, + false, + m_ptrdev_info); + } + + // update info and push to UI manager + auto const pressed(decltype(info->buttons)(1) << button); + info->x = x; + info->y = y; + info->buttons |= pressed; + machine().ui_input().push_pointer_update( + target(), + osd::ui_event_handler::pointer::MOUSE, + info->index, + device, + x, y, + info->buttons, pressed, 0, info->clickcnt); +} + +void sdl_window_info::mouse_up(unsigned device, int x, int y, unsigned button) +{ + if (!m_mouse_inside) + return; + + auto const info(map_pointer(SDL_FingerID(-1), device)); + if (m_active_pointers.end() == info) + return; + + if ((x == info->x) && (y == info->y) && !BIT(info->buttons, button)) + return; + + // detect multi-click actions + if (0 == button) + { + info->check_primary_hold_drag( + x, + y, + std::chrono::milliseconds(250), + CLICK_DISTANCE); + } + + // update info and push to UI manager + auto const released(decltype(info->buttons)(1) << button); + info->x = x; + info->y = y; + info->buttons &= ~released; + machine().ui_input().push_pointer_update( + target(), + osd::ui_event_handler::pointer::MOUSE, + info->index, + device, + x, y, + info->buttons, 0, released, info->clickcnt); +} + +void sdl_window_info::mouse_moved(unsigned device, int x, int y) +{ + if (!m_mouse_inside) + return; + + auto const info(map_pointer(SDL_FingerID(-1), device)); + if (m_active_pointers.end() == info) + return; + + // detect multi-click actions + if (BIT(info->buttons, 0)) + { + info->check_primary_hold_drag( + x, + y, + std::chrono::milliseconds(250), + CLICK_DISTANCE); + } + + // update info and push to UI manager + info->x = x; + info->y = y; + machine().ui_input().push_pointer_update( + target(), + osd::ui_event_handler::pointer::MOUSE, + info->index, + device, + x, y, + info->buttons, 0, 0, info->clickcnt); +} + +void sdl_window_info::mouse_wheel(unsigned device, int y) +{ + if (!m_mouse_inside) + return; + + auto const info(map_pointer(SDL_FingerID(-1), device)); + if (m_active_pointers.end() == info) + return; + + // push to UI manager + machine().ui_input().push_mouse_wheel_event(target(), info->x, info->y, y, 3); +} + +void sdl_window_info::finger_down(SDL_FingerID finger, unsigned device, int x, int y) +{ + auto const info(map_pointer(finger, device)); + if (m_active_pointers.end() == info) + return; + + assert(!info->buttons); + + // detect multi-click actions + info->primary_down( + x, + y, + std::chrono::milliseconds(250), + TAP_DISTANCE, + true, + m_ptrdev_info); + + // update info and push to UI manager + info->x = x; + info->y = y; + info->buttons = 1; + machine().ui_input().push_pointer_update( + target(), + osd::ui_event_handler::pointer::TOUCH, + info->index, + device, + x, y, + 1, 1, 0, info->clickcnt); +} + +void sdl_window_info::finger_up(SDL_FingerID finger, unsigned device, int x, int y) +{ + auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare)); + if ((m_active_pointers.end() == info) || (info->finger != finger)) + return; + + assert(1 == info->buttons); + + // check for conversion to a (multi-)click-and-hold/drag + info->check_primary_hold_drag( + x, + y, + std::chrono::milliseconds(250), + TAP_DISTANCE); + + // need to remember touches to recognise multi-tap gestures + if (0 < info->clickcnt) + { + auto const now(std::chrono::steady_clock::now()); + auto const time = std::chrono::milliseconds(250); + if ((time + info->pressed) >= now) + { + try + { + unsigned i(0); + if (m_ptrdev_info.size() > device) + i = m_ptrdev_info[device].clear_expired_touches(now, time); + else + m_ptrdev_info.resize(device + 1); + + if (std::size(m_ptrdev_info[device].touches) > i) + { + m_ptrdev_info[device].touches[i].when = info->pressed; + m_ptrdev_info[device].touches[i].x = info->pressedx; + m_ptrdev_info[device].touches[i].y = info->pressedy; + m_ptrdev_info[device].touches[i].cnt = info->clickcnt; + } + } + catch (std::bad_alloc const &) + { + osd_printf_error("win_window_info: error allocating pointer data\n"); + } + } + } + + // push to UI manager + machine().ui_input().push_pointer_update( + target(), + osd::ui_event_handler::pointer::TOUCH, + info->index, + device, + x, y, + 0, 0, 1, info->clickcnt); + machine().ui_input().push_pointer_leave( + target(), + osd::ui_event_handler::pointer::TOUCH, + info->index, + device, + x, y, + 0, info->clickcnt); + + // dump pointer data + m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index); + if (info->index < m_next_pointer) + m_next_pointer = info->index; + m_active_pointers.erase(info); +} + +void sdl_window_info::finger_moved(SDL_FingerID finger, unsigned device, int x, int y) +{ + auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare)); + if ((m_active_pointers.end() == info) || (info->finger != finger)) + + assert(1 == info->buttons); + + if ((x != info->x) || (y != info->y)) + { + info->check_primary_hold_drag( + x, + y, + std::chrono::milliseconds(250), + TAP_DISTANCE); + + // update info and push to UI manager + info->x = x; + info->y = y; + machine().ui_input().push_pointer_update( + target(), + osd::ui_event_handler::pointer::TOUCH, + info->index, + device, + x, y, + 1, 0, 0, info->clickcnt); + } +} + //============================================================ // sdlwindow_video_window_create // (main thread) @@ -400,31 +600,13 @@ int sdl_window_info::xy_to_render_target(int x, int y, int *xt, int *yt) int sdl_window_info::window_init() { - int result; - // set the initial maximized state // FIXME: Does not belong here - sdl_options &options = downcast<sdl_options &>(m_machine.options()); - m_startmaximized = options.maximize(); - - // add us to the list - osd_common_t::s_window_list.push_back(std::static_pointer_cast<sdl_window_info>(shared_from_this())); + m_startmaximized = downcast<sdl_options &>(machine().options()).maximize(); - set_renderer(osd_renderer::make_for_type(video_config.mode, static_cast<osd_window*>(this)->shared_from_this())); - - // load the layout - m_target = m_machine.render().target_alloc(); - - // set the specific view - set_starting_view(m_index, options.view(), options.view(m_index)); - - // make the window title - if (video_config.numscreens == 1) - sprintf(m_title, "%s: %s [%s]", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name); - else - sprintf(m_title, "%s: %s [%s] - Screen %d", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name, m_index); + create_target(); - result = complete_create(); + int result = complete_create(); // handle error conditions if (result == 1) @@ -450,31 +632,17 @@ void sdl_window_info::complete_destroy() if (fullscreen() && video_config.switchres) { - SDL_SetWindowFullscreen(platform_window(), 0); // Try to set mode - SDL_SetWindowDisplayMode(platform_window(), &m_original_mode->mode); // Try to set mode - SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode + SDL_SetWindowFullscreen(platform_window(), 0); + SDL_SetWindowDisplayMode(platform_window(), &m_original_mode); + SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); } + renderer_reset(); SDL_DestroyWindow(platform_window()); - // release all keys ... + set_platform_window(nullptr); downcast<sdl_osd_interface &>(machine().osd()).release_keys(); } -void sdl_window_info::destroy() -{ - //osd_event_wait(window->rendered_event, osd_ticks_per_second()*10); - - // remove us from the list - osd_common_t::s_window_list.remove(std::static_pointer_cast<sdl_window_info>(shared_from_this())); - - // free the textures etc - complete_destroy(); - - // free the render target, after the textures! - machine().render().target_free(m_target); - -} - //============================================================ // pick_best_mode @@ -489,7 +657,7 @@ osd_dim sdl_window_info::pick_best_mode() osd_dim ret(0,0); // determine the minimum width/height for the selected target - m_target->compute_minimum_size(minimum_width, minimum_height); + target()->compute_minimum_size(minimum_width, minimum_height); // use those as the target for now target_width = minimum_width * std::max(1, prescale()); @@ -502,7 +670,7 @@ osd_dim sdl_window_info::pick_best_mode() } // FIXME: this should be provided by monitor ! - num = SDL_GetNumDisplayModes(m_monitor->oshandle()); + num = SDL_GetNumDisplayModes(monitor()->oshandle()); if (num == 0) { @@ -514,7 +682,7 @@ osd_dim sdl_window_info::pick_best_mode() for (i = 0; i < num; ++i) { SDL_DisplayMode mode; - SDL_GetDisplayMode(m_monitor->oshandle(), i, &mode); + SDL_GetDisplayMode(monitor()->oshandle(), i, &mode); // compute initial score based on difference between target and current size_score = 1.0f / (1.0f + abs((int32_t)mode.w - target_width) + abs((int32_t)mode.h - target_height)); @@ -556,20 +724,16 @@ osd_dim sdl_window_info::pick_best_mode() void sdl_window_info::update() { - osd_ticks_t event_wait_ticks; - // adjust the cursor state - //sdlwindow_update_cursor_state(machine, window); - update_cursor_state(); // if we're visible and running and not in the middle of a resize, draw - if (m_target != nullptr) + if (target() != nullptr) { int tempwidth, tempheight; // see if the games video mode has changed - m_target->compute_minimum_size(tempwidth, tempheight); + target()->compute_minimum_size(tempwidth, tempheight); if (osd_dim(tempwidth, tempheight) != m_minimum_dim) { m_minimum_dim = osd_dim(tempwidth, tempheight); @@ -586,6 +750,7 @@ void sdl_window_info::update() } } + osd_ticks_t event_wait_ticks; if (video_config.waitvsync && video_config.syncrefresh) event_wait_ticks = osd_ticks_per_second(); // block at most a second else @@ -601,13 +766,10 @@ void sdl_window_info::update() // and redraw now - // Some configurations require events to be polled in the worker thread - downcast< sdl_osd_interface& >(machine().osd()).process_events_buf(); - // Check whether window has vector screens { - const screen_device *screen = screen_device_iterator(machine().root_device()).byindex(m_index); + const screen_device *screen = screen_device_enumerator(machine().root_device()).byindex(index()); if ((screen != nullptr) && (screen->screen_type() == SCREEN_TYPE_VECTOR)) renderer().set_flags(osd_renderer::FLAG_HAS_VECTOR_SCREEN); else @@ -616,20 +778,20 @@ void sdl_window_info::update() m_primlist = &primlist; - // if no bitmap, just fill if (m_primlist == nullptr) { + // if no bitmap, just fill } - // otherwise, render with our drawing system else { - if( video_config.perftest ) + // otherwise, render with our drawing system + if (video_config.perftest) measure_fps(update); else renderer().draw(update); } - /* all done, ready for next */ + // all done, ready for next m_rendered_event.set(); } } @@ -637,27 +799,6 @@ void sdl_window_info::update() //============================================================ -// set_starting_view -// (main thread) -//============================================================ - -void sdl_window_info::set_starting_view(int index, const char *defview, const char *view) -{ - int viewindex; - - // choose non-auto over auto - if (strcmp(view, "auto") == 0 && strcmp(defview, "auto") != 0) - view = defview; - - // query the video system to help us pick a view - viewindex = target()->configured_view(view, index, video_config.numscreens); - - // set the view - target()->set_view(viewindex); -} - - -//============================================================ // complete_create //============================================================ @@ -681,9 +822,13 @@ int sdl_window_info::complete_create() temp = m_windowed_dim; } else if (m_startmaximized) - temp = get_max_bounds(video_config.keepaspect ); + { + temp = get_max_bounds(keepaspect()); + } else - temp = get_min_bounds(video_config.keepaspect ); + { + temp = get_min_bounds(keepaspect()); + } // create the window ..... @@ -694,50 +839,20 @@ int sdl_window_info::complete_create() * */ osd_printf_verbose("Enter sdl_info::create\n"); - if (renderer().has_flags(osd_renderer::FLAG_NEEDS_OPENGL) && !video_config.novideo) + if (renderer_sdl_needs_opengl()) { SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); - - /* FIXME: A reminder that gamma is wrong throughout MAME. Currently, SDL2.0 doesn't seem to - * support the following attribute although my hardware lists GL_ARB_framebuffer_sRGB as an extension. - * - * SDL_GL_SetAttribute( SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1 ); - * - */ m_extra_flags = SDL_WINDOW_OPENGL; } else - m_extra_flags = 0; - -#ifdef SDLMAME_MACOSX - /* FIMXE: On OSX, SDL_WINDOW_FULLSCREEN_DESKTOP seems to be more reliable. - * It however creates issues with white borders, i.e. the screen clear - * does not work. This happens both with opengl and accel. - */ -#endif - - // We need to workaround an issue in SDL 2.0.4 for OS X where setting the - // relative mode on the mouse in fullscreen mode makes mouse events stop - // It is fixed in the latest revisions so we'll assume it'll be fixed - // in the next public SDL release as well -#if defined(SDLMAME_MACOSX) && SDL_VERSION_ATLEAST(2, 0, 2) // SDL_HINT_MOUSE_RELATIVE_MODE_WARP is introduced in 2.0.2 - SDL_version linked; - SDL_GetVersion(&linked); - int revision = SDL_GetRevisionNumber(); - - // If we're running the exact version of SDL 2.0.4 (revision 10001) from the - // SDL web site, we need to work around this issue and send the warp mode hint - if (SDL_VERSION_EQUALS(linked, SDL_VERSIONNUM(2, 0, 4)) && revision == 10001) { - osd_printf_verbose("Using warp mode for relative mouse in OS X SDL 2.0.4\n"); - SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); + m_extra_flags = 0; } -#endif // create the SDL window // soft driver also used | SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_MOUSE_FOCUS m_extra_flags |= (fullscreen() ? - SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE); + SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE); #if defined(SDLMAME_WIN32) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); @@ -746,17 +861,74 @@ int sdl_window_info::complete_create() // get monitor work area for centering osd_rect work = monitor()->usuable_position_size(); - // create the SDL window - auto sdlwindow = SDL_CreateWindow(m_title, + // create or attach to an existing window + SDL_Window *sdlwindow; +#ifdef SDLMAME_X11 + const char *attach_window = downcast<sdl_options &>(machine().options()).attach_window(); +#else + const char *attach_window = nullptr; +#endif + if (attach_window && *attach_window) + { + // we're attaching to an existing window; parse the argument + unsigned long long attach_window_value; + try + { + attach_window_value = std::stoull(attach_window, nullptr, 0); + } + catch (std::invalid_argument &) + { + osd_printf_error("Invalid -attach_window value: %s\n", attach_window); + return 1; + } + + // and attach to it + sdlwindow = SDL_CreateWindowFrom((void *)attach_window_value); + if (!sdlwindow) + { + osd_printf_error("Failed to attach to window \"%s\": %s\n", attach_window, SDL_GetError()); + return 1; + } + + // perform SDL subsystem-specific tasks + SDL_SysWMinfo swmi; + SDL_VERSION(&swmi.version); + if (SDL_GetWindowWMInfo(sdlwindow, &swmi)) + { + switch (swmi.subsystem) + { +#ifdef SDLMAME_X11 + case SDL_SYSWM_X11: + // by default, SDL_CreateWindowFrom() doesn't ensure that we're getting the events that we + // expect + XSelectInput(swmi.info.x11.display, swmi.info.x11.window, + FocusChangeMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + ExposureMask | KeymapStateMask); + break; +#endif // SDLMAME_X11 + + default: + break; + } + } + } + else + { + // create the SDL window + sdlwindow = SDL_CreateWindow(title().c_str(), work.left() + (work.width() - temp.width()) / 2, work.top() + (work.height() - temp.height()) / 2, temp.width(), temp.height(), m_extra_flags); + } + //window().sdl_window() = SDL_CreateWindow(window().m_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, // width, height, m_extra_flags); if (sdlwindow == nullptr ) { - if (renderer().has_flags(osd_renderer::FLAG_NEEDS_OPENGL)) + if (renderer_sdl_needs_opengl()) osd_printf_error("OpenGL not supported on this driver: %s\n", SDL_GetError()); else osd_printf_error("Window creation failed: %s\n", SDL_GetError()); @@ -764,13 +936,14 @@ int sdl_window_info::complete_create() } set_platform_window(sdlwindow); + renderer_create(); if (fullscreen() && video_config.switchres) { SDL_DisplayMode mode; //SDL_GetCurrentDisplayMode(window().monitor()->handle, &mode); SDL_GetWindowDisplayMode(platform_window(), &mode); - m_original_mode->mode = mode; + m_original_mode = mode; mode.w = temp.width(); mode.h = temp.height(); if (m_win_config.refresh) @@ -802,24 +975,6 @@ int sdl_window_info::complete_create() SDL_SetWindowGrab(platform_window(), SDL_TRUE); #endif - // set main window - if (m_index > 0) - { - for (auto w : osd_common_t::s_window_list) - { - if (w->m_index == 0) - { - set_main_window(std::dynamic_pointer_cast<osd_window>(w)); - break; - } - } - } - else - { - // We must be the main window - set_main_window(shared_from_this()); - } - // update monitor resolution after mode change to ensure proper pixel aspect monitor()->refresh(); if (fullscreen() && video_config.switchres) @@ -830,8 +985,8 @@ int sdl_window_info::complete_create() return 1; // Make sure we have a consistent state - SDL_ShowCursor(0); - SDL_ShowCursor(1); + SDL_ShowCursor(SDL_DISABLE); + SDL_ShowCursor(SDL_ENABLE); return 0; } @@ -910,14 +1065,9 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad int32_t viswidth, visheight; int32_t adjwidth, adjheight; float pixel_aspect; - std::shared_ptr<osd_monitor_info> monitor = m_monitor; - - // do not constrain aspect ratio for integer scaled views - if (m_target->scale_mode() != SCALE_FRACTIONAL) - return rect; // get the pixel aspect ratio for the target monitor - pixel_aspect = monitor->pixel_aspect(); + pixel_aspect = monitor()->pixel_aspect(); // determine the proposed width/height propwidth = rect.width() - extrawidth; @@ -929,21 +1079,21 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad { case WMSZ_BOTTOM: case WMSZ_TOP: - m_target->compute_visible_area(10000, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight); + target()->compute_visible_area(10000, propheight, pixel_aspect, target()->orientation(), propwidth, propheight); break; case WMSZ_LEFT: case WMSZ_RIGHT: - m_target->compute_visible_area(propwidth, 10000, pixel_aspect, m_target->orientation(), propwidth, propheight); + target()->compute_visible_area(propwidth, 10000, pixel_aspect, target()->orientation(), propwidth, propheight); break; default: - m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight); + target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), propwidth, propheight); break; } // get the minimum width/height for the current layout - m_target->compute_minimum_size(minwidth, minheight); + target()->compute_minimum_size(minwidth, minheight); // clamp against the absolute minimum propwidth = std::max(propwidth, MIN_WINDOW_DIM); @@ -956,13 +1106,13 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad // clamp against the maximum (fit on one screen for full screen mode) if (m_fullscreen) { - maxwidth = monitor->position_size().width() - extrawidth; - maxheight = monitor->position_size().height() - extraheight; + maxwidth = monitor()->position_size().width() - extrawidth; + maxheight = monitor()->position_size().height() - extraheight; } else { - maxwidth = monitor->usuable_position_size().width() - extrawidth; - maxheight = monitor->usuable_position_size().height() - extraheight; + maxwidth = monitor()->usuable_position_size().width() - extrawidth; + maxheight = monitor()->usuable_position_size().height() - extraheight; // further clamp to the maximum width/height in the window if (m_win_config.width != 0) @@ -976,7 +1126,11 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad propheight = std::min(propheight, maxheight); // compute the visible area based on the proposed rectangle - m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), viswidth, visheight); + target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), viswidth, visheight); + + // clamp visable area to the proposed rectangle + viswidth = std::min(viswidth, propwidth); + visheight = std::min(visheight, propheight); // compute the adjustments we need to make adjwidth = (viswidth + extrawidth) - rect.width(); @@ -1024,7 +1178,13 @@ osd_dim sdl_window_info::get_min_bounds(int constrain) //assert(GetCurrentThreadId() == window_threadid); // get the minimum target size - m_target->compute_minimum_size(minwidth, minheight); + target()->compute_minimum_size(minwidth, minheight); + + // check if visible area is bigger + int32_t viswidth, visheight; + target()->compute_visible_area(minwidth, minheight, monitor()->aspect(), target()->orientation(), viswidth, visheight); + minwidth = std::max(viswidth, minwidth); + minheight = std::max(visheight, minheight); // expand to our minimum dimensions if (minwidth < MIN_WINDOW_DIM) @@ -1037,7 +1197,7 @@ osd_dim sdl_window_info::get_min_bounds(int constrain) minheight += wnd_extra_height(); // if we want it constrained, figure out which one is larger - if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL) + if (constrain) { // first constrain with no height limit osd_rect test1(0,0,minwidth,10000); @@ -1089,8 +1249,8 @@ osd_dim sdl_window_info::get_max_bounds(int constrain) //assert(GetCurrentThreadId() == window_threadid); // compute the maximum client area - // m_monitor->refresh(); - osd_rect maximum = m_monitor->usuable_position_size(); + // monitor()->refresh(); + osd_rect maximum = monitor()->usuable_position_size(); // clamp to the window's max int tempw = maximum.width(); @@ -1111,7 +1271,7 @@ osd_dim sdl_window_info::get_max_bounds(int constrain) maximum = maximum.resize(tempw, temph); // constrain to fit - if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL) + if (constrain) maximum = constrain_to_aspect_ratio(maximum, WMSZ_BOTTOMRIGHT); // remove extra window stuff @@ -1120,43 +1280,87 @@ osd_dim sdl_window_info::get_max_bounds(int constrain) return maximum.dim(); } + +std::vector<sdl_window_info::sdl_pointer_info>::iterator sdl_window_info::map_pointer(SDL_FingerID finger, unsigned device) +{ + auto found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare)); + if ((m_active_pointers.end() != found) && (found->finger == finger)) + return found; + + if ((sizeof(m_next_pointer) * 8) <= m_next_pointer) + { + assert(~decltype(m_pointer_mask)(0) == m_pointer_mask); + osd_printf_warning("sdl_window_info: exceeded maximum number of active pointers\n"); + return m_active_pointers.end(); + } + assert(!BIT(m_pointer_mask, m_next_pointer)); + + try + { + found = m_active_pointers.emplace( + found, + sdl_pointer_info(finger, m_next_pointer, device)); + m_pointer_mask |= decltype(m_pointer_mask)(1) << m_next_pointer; + do + { + ++m_next_pointer; + } + while (((sizeof(m_next_pointer) * 8) > m_next_pointer) && BIT(m_pointer_mask, m_next_pointer)); + + return found; + } + catch (std::bad_alloc const &) + { + osd_printf_error("sdl_window_info: error allocating pointer data\n"); + return m_active_pointers.end(); + } +} + + +inline sdl_window_info::sdl_pointer_info::sdl_pointer_info(SDL_FingerID f, unsigned i, unsigned d) + : pointer_info(i, d) + , finger(f) +{ +} + + + + //============================================================ // construction and destruction //============================================================ sdl_window_info::sdl_window_info( running_machine &a_machine, + render_module &renderprovider, int index, - std::shared_ptr<osd_monitor_info> a_monitor, + const std::shared_ptr<osd_monitor_info> &a_monitor, const osd_window_config *config) - : osd_window_t(*config) - , m_next(nullptr) + : osd_window_t(a_machine, renderprovider, index, std::move(a_monitor), *config) , m_startmaximized(0) // Following three are used by input code to defer resizes , m_minimum_dim(0, 0) , m_windowed_dim(0, 0) , m_rendered_event(0, 1) - , m_target(nullptr) , m_extra_flags(0) - , m_machine(a_machine) - , m_monitor(a_monitor) - , m_fullscreen(0) , m_mouse_captured(false) , m_mouse_hidden(false) + , m_pointer_mask(0) + , m_next_pointer(0) + , m_mouse_inside(false) { - m_index = index; - //FIXME: these should be per_window in config-> or even better a bit set m_fullscreen = !video_config.windowed; m_prescale = video_config.prescale; m_windowed_dim = osd_dim(config->width, config->height); - m_original_mode = global_alloc(SDL_DM_Wrapper); + + m_ptrdev_info.reserve(1); + m_active_pointers.reserve(16); } sdl_window_info::~sdl_window_info() { - global_free(m_original_mode); } |