mirror of
https://github.com/holub/mame
synced 2025-05-19 20:29:09 +03:00

- Added sdlmisc_<targetos>.c again. This was necessary since certain tools create stubs for e.g. osd_break_into_debugger. If we do not have this in a separate file, the link stage may break. - Applied OS/2 patch [Credit: KO Myung-Hun] - Cleaned up #includes. Removed stdlib.h were possible. - More malloc to osd_malloc rename. - SDL monitor modes are read now when they are needed. This is now consistent across platforms.
1396 lines
37 KiB
C
1396 lines
37 KiB
C
//============================================================
|
|
//
|
|
// window.c - SDL window handling
|
|
//
|
|
// Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team.
|
|
// Visit http://mamedev.org for licensing and usage restrictions.
|
|
//
|
|
// SDLMAME by Olivier Galibert and R. Belmont
|
|
//
|
|
//============================================================
|
|
|
|
// standard SDL headers
|
|
#include <SDL/SDL.h>
|
|
#include <SDL/SDL_syswm.h>
|
|
#include <SDL/SDL_thread.h>
|
|
|
|
// standard C headers
|
|
#include <math.h>
|
|
#include <unistd.h>
|
|
|
|
// MAME headers
|
|
|
|
#include "emu.h"
|
|
#include "emuopts.h"
|
|
#include "ui.h"
|
|
|
|
|
|
// OSD headers
|
|
|
|
#include "window.h"
|
|
#include "input.h"
|
|
#include "osdsdl.h"
|
|
|
|
#ifdef MESS
|
|
#include "menu.h"
|
|
#endif /* MESS */
|
|
|
|
//============================================================
|
|
// PARAMETERS
|
|
//============================================================
|
|
|
|
// these are arbitrary values since AFAIK there's no way to make X/SDL tell you
|
|
#define WINDOW_DECORATION_WIDTH (8) // should be more than plenty
|
|
#define WINDOW_DECORATION_HEIGHT (48) // title bar + bottom drag region
|
|
|
|
#ifdef MAME_DEBUG
|
|
//#define ASSERT_USE(x) do { printf("%x %x\n", (int) SDL_ThreadID(), x); assert_always(SDL_ThreadID() == x, "Wrong Thread"); } while (0)
|
|
#define ASSERT_USE(x) do { SDL_threadID _thid = SDL_ThreadID(); assert_always( _thid == x, "Wrong Thread"); } while (0)
|
|
#else
|
|
#define ASSERT_USE(x) do {} while (0)
|
|
//#define ASSERT_USE(x) assert(SDL_ThreadID() == x)
|
|
#endif
|
|
|
|
#define ASSERT_REDRAW_THREAD() ASSERT_USE(window_threadid)
|
|
#define ASSERT_WINDOW_THREAD() ASSERT_USE(window_threadid)
|
|
#define ASSERT_MAIN_THREAD() ASSERT_USE(main_threadid)
|
|
|
|
#define OSDWORK_CALLBACK(name) void *name(void *param, ATTR_UNUSED int threadid)
|
|
|
|
// minimum window dimension
|
|
#define MIN_WINDOW_DIM 200
|
|
|
|
#ifndef SDLMAME_WIN32
|
|
#define WMSZ_TOP (0)
|
|
#define WMSZ_BOTTOM (1)
|
|
#define WMSZ_BOTTOMLEFT (2)
|
|
#define WMSZ_BOTTOMRIGHT (3)
|
|
#define WMSZ_LEFT (4)
|
|
#define WMSZ_TOPLEFT (5)
|
|
#define WMSZ_TOPRIGHT (6)
|
|
#define WMSZ_RIGHT (7)
|
|
#endif
|
|
|
|
//============================================================
|
|
// GLOBAL VARIABLES
|
|
//============================================================
|
|
|
|
sdl_window_info *sdl_window_list;
|
|
|
|
|
|
//============================================================
|
|
// LOCAL VARIABLES
|
|
//============================================================
|
|
|
|
static sdl_window_info **last_window_ptr;
|
|
|
|
// event handling
|
|
static int multithreading_enabled;
|
|
static osd_work_queue *work_queue;
|
|
|
|
#if !(SDL_VERSION_ATLEAST(1,3,0))
|
|
typedef int SDL_threadID;
|
|
#endif
|
|
|
|
static SDL_threadID main_threadid;
|
|
static SDL_threadID window_threadid;
|
|
|
|
// debugger
|
|
//static int in_background;
|
|
|
|
static sdl_draw_info draw;
|
|
|
|
typedef struct _worker_param worker_param;
|
|
struct _worker_param {
|
|
sdl_window_info *window;
|
|
const render_primitive_list *list;
|
|
running_machine *machine;
|
|
int resize_new_width;
|
|
int resize_new_height;
|
|
};
|
|
|
|
|
|
//============================================================
|
|
// PROTOTYPES
|
|
//============================================================
|
|
|
|
static void sdlwindow_exit(running_machine *machine);
|
|
static void sdlwindow_video_window_destroy(running_machine *machine, sdl_window_info *window);
|
|
static OSDWORK_CALLBACK( draw_video_contents_wt );
|
|
static OSDWORK_CALLBACK( sdlwindow_video_window_destroy_wt );
|
|
static OSDWORK_CALLBACK( sdlwindow_resize_wt );
|
|
static OSDWORK_CALLBACK( sdlwindow_toggle_full_screen_wt );
|
|
static void sdlwindow_update_cursor_state(running_machine *machine, sdl_window_info *window);
|
|
static void sdlwindow_sync(void);
|
|
|
|
static void get_min_bounds(sdl_window_info *window, int *window_width, int *window_height, int constrain);
|
|
static void get_max_bounds(sdl_window_info *window, int *window_width, int *window_height, int constrain);
|
|
|
|
static void *complete_create_wt(void *param, int threadid);
|
|
static void set_starting_view(running_machine *machine, int index, sdl_window_info *window, const char *view);
|
|
|
|
//============================================================
|
|
// clear the worker_param structure, inline - faster than memset
|
|
//============================================================
|
|
|
|
INLINE void clear_worker_param(worker_param *wp)
|
|
{
|
|
wp->window=NULL;
|
|
wp->list=NULL;
|
|
wp->machine=NULL;
|
|
wp->resize_new_width=0;
|
|
wp->resize_new_height=0;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// execute_async
|
|
//============================================================
|
|
|
|
|
|
INLINE void execute_async(osd_work_callback callback, worker_param *wp)
|
|
{
|
|
worker_param *wp_temp = NULL;
|
|
|
|
if (wp)
|
|
{
|
|
wp_temp = (worker_param *) osd_malloc(sizeof(worker_param));
|
|
*wp_temp = *wp;
|
|
}
|
|
if (multithreading_enabled)
|
|
{
|
|
osd_work_item_queue(work_queue, callback, (void *) wp_temp, WORK_ITEM_FLAG_AUTO_RELEASE);
|
|
} else
|
|
callback((void *) wp_temp, 0);
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// execute_async_wait
|
|
//============================================================
|
|
|
|
INLINE void execute_async_wait(osd_work_callback callback, worker_param *wp)
|
|
{
|
|
execute_async(callback, wp);
|
|
sdlwindow_sync();
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_thread_id
|
|
// (window thread)
|
|
//============================================================
|
|
|
|
static OSDWORK_CALLBACK(sdlwindow_thread_id)
|
|
{
|
|
window_threadid = SDL_ThreadID();
|
|
|
|
if (SDLMAME_INIT_IN_WORKER_THREAD)
|
|
{
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
if (SDL_InitSubSystem(SDL_INIT_TIMER|SDL_INIT_AUDIO| SDL_INIT_VIDEO| SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE))
|
|
#else
|
|
if (SDL_Init(SDL_INIT_TIMER|SDL_INIT_AUDIO| SDL_INIT_VIDEO| SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE))
|
|
#endif
|
|
{
|
|
mame_printf_error("Could not initialize SDL: %s.\n", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// win_init_window
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
int sdlwindow_init(running_machine *machine)
|
|
{
|
|
mame_printf_verbose("Enter sdlwindow_init\n");
|
|
// determine if we are using multithreading or not
|
|
multithreading_enabled = options_get_bool(mame_options(), SDLOPTION_MULTITHREADING);
|
|
|
|
// get the main thread ID before anything else
|
|
main_threadid = SDL_ThreadID();
|
|
|
|
// ensure we get called on the way out
|
|
add_exit_callback(machine, sdlwindow_exit);
|
|
|
|
// if multithreading, create a thread to run the windows
|
|
if (multithreading_enabled)
|
|
{
|
|
// create a thread to run the windows from
|
|
work_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_IO);
|
|
if (work_queue == NULL)
|
|
return 1;
|
|
osd_work_item_queue(work_queue, &sdlwindow_thread_id, NULL, WORK_ITEM_FLAG_AUTO_RELEASE);
|
|
}
|
|
else
|
|
{
|
|
// otherwise, treat the window thread as the main thread
|
|
//window_threadid = main_threadid;
|
|
sdlwindow_thread_id(NULL, 0);
|
|
}
|
|
|
|
// initialize the drawers
|
|
#if USE_OPENGL
|
|
if (video_config.mode == VIDEO_MODE_OPENGL)
|
|
{
|
|
if (drawogl_init(&draw))
|
|
video_config.mode = VIDEO_MODE_SOFT;
|
|
}
|
|
#endif
|
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
|
if (video_config.mode == VIDEO_MODE_SDL13)
|
|
{
|
|
if (draw13_init(&draw))
|
|
video_config.mode = VIDEO_MODE_SOFT;
|
|
}
|
|
#endif
|
|
if (video_config.mode == VIDEO_MODE_SOFT)
|
|
{
|
|
if (drawsdl_init(&draw))
|
|
return 1;
|
|
}
|
|
|
|
// set up the window list
|
|
last_window_ptr = &sdl_window_list;
|
|
mame_printf_verbose("Leave sdlwindow_init\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_sync
|
|
//============================================================
|
|
|
|
static void sdlwindow_sync(void)
|
|
{
|
|
if (multithreading_enabled)
|
|
{
|
|
// Fallback
|
|
while (!osd_work_queue_wait(work_queue, osd_ticks_per_second()*10))
|
|
{
|
|
mame_printf_warning("sdlwindow_sync: Sleeping...\n");
|
|
osd_sleep(100000);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_exit
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
static OSDWORK_CALLBACK( sdlwindow_exit_wt )
|
|
{
|
|
if (SDLMAME_INIT_IN_WORKER_THREAD)
|
|
SDL_Quit();
|
|
|
|
if (param)
|
|
osd_free(param);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void sdlwindow_exit(running_machine *machine)
|
|
{
|
|
ASSERT_MAIN_THREAD();
|
|
|
|
mame_printf_verbose("Enter sdlwindow_exit\n");
|
|
|
|
// free all the windows
|
|
while (sdl_window_list != NULL)
|
|
{
|
|
sdl_window_info *temp = sdl_window_list;
|
|
sdl_window_list = temp->next;
|
|
sdlwindow_video_window_destroy(machine, temp);
|
|
}
|
|
|
|
// if we're multithreaded, clean up the window thread
|
|
if (multithreading_enabled)
|
|
{
|
|
sdlwindow_sync();
|
|
}
|
|
|
|
// kill the drawers
|
|
(*draw.exit)();
|
|
|
|
execute_async_wait(&sdlwindow_exit_wt, NULL);
|
|
|
|
if (multithreading_enabled)
|
|
{
|
|
osd_work_queue_wait(work_queue, 1000000);
|
|
osd_work_queue_free(work_queue);
|
|
}
|
|
mame_printf_verbose("Leave sdlwindow_exit\n");
|
|
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_blit_surface_size
|
|
//============================================================
|
|
|
|
INLINE int better_mode(int width0, int height0, int width1, int height1, float desired_aspect)
|
|
{
|
|
float aspect0 = (float)width0 / (float)height0;
|
|
float aspect1 = (float)width1 / (float)height1;
|
|
return (fabs(desired_aspect - aspect0) < fabs(desired_aspect - aspect1)) ? 0 : 1;
|
|
}
|
|
|
|
void sdlwindow_blit_surface_size(sdl_window_info *window, int window_width, int window_height)
|
|
{
|
|
INT32 newwidth, newheight;
|
|
int xscale = 1, yscale = 1;
|
|
float desired_aspect = 1.0f;
|
|
INT32 target_width = window_width;
|
|
INT32 target_height = window_height;
|
|
|
|
// start with the minimum size
|
|
render_target_get_minimum_size(window->target, &newwidth, &newheight);
|
|
|
|
// compute the appropriate visible area if we're trying to keepaspect
|
|
if (video_config.keepaspect)
|
|
{
|
|
// make sure the monitor is up-to-date
|
|
sdlvideo_monitor_refresh(window->monitor);
|
|
render_target_compute_visible_area(window->target, target_width, target_height, sdlvideo_monitor_get_aspect(window->monitor), render_target_get_orientation(window->target), &target_width, &target_height);
|
|
desired_aspect = (float)target_width / (float)target_height;
|
|
}
|
|
|
|
// non-integer scaling - often gives more pleasing results in full screen
|
|
if (!video_config.fullstretch)
|
|
{
|
|
// compute maximum integral scaling to fit the window
|
|
xscale = (target_width + 2) / newwidth;
|
|
yscale = (target_height + 2) / newheight;
|
|
|
|
// try a little harder to keep the aspect ratio if desired
|
|
if (video_config.keepaspect)
|
|
{
|
|
// if we could stretch more in the X direction, and that makes a better fit, bump the xscale
|
|
while (newwidth * (xscale + 1) <= window_width &&
|
|
better_mode(newwidth * xscale, newheight * yscale, newwidth * (xscale + 1), newheight * yscale, desired_aspect))
|
|
xscale++;
|
|
|
|
// if we could stretch more in the Y direction, and that makes a better fit, bump the yscale
|
|
while (newheight * (yscale + 1) <= window_height &&
|
|
better_mode(newwidth * xscale, newheight * yscale, newwidth * xscale, newheight * (yscale + 1), desired_aspect))
|
|
yscale++;
|
|
|
|
// now that we've maxed out, see if backing off the maximally stretched one makes a better fit
|
|
if (window_width - newwidth * xscale < window_height - newheight * yscale)
|
|
{
|
|
while (better_mode(newwidth * xscale, newheight * yscale, newwidth * (xscale - 1), newheight * yscale, desired_aspect) && (xscale >= 0))
|
|
xscale--;
|
|
}
|
|
else
|
|
{
|
|
while (better_mode(newwidth * xscale, newheight * yscale, newwidth * xscale, newheight * (yscale - 1), desired_aspect) && (yscale >= 0))
|
|
yscale--;
|
|
}
|
|
}
|
|
|
|
// ensure at least a scale factor of 1
|
|
if (xscale <= 0) xscale = 1;
|
|
if (yscale <= 0) yscale = 1;
|
|
|
|
// apply the final scale
|
|
newwidth *= xscale;
|
|
newheight *= yscale;
|
|
}
|
|
else
|
|
{
|
|
newwidth = target_width;
|
|
newheight = target_height;
|
|
}
|
|
|
|
//FIXME: really necessary to distinguish for yuv_modes ?
|
|
if ((render_target_get_layer_config(window->target) & LAYER_CONFIG_ZOOM_TO_SCREEN)
|
|
&& (window->scale_mode == VIDEO_SCALE_MODE_NONE ))
|
|
newwidth = window_width;
|
|
|
|
if ((window->blitwidth != newwidth) || (window->blitheight != newheight))
|
|
sdlwindow_clear(window);
|
|
|
|
window->blitwidth = newwidth;
|
|
window->blitheight = newheight;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_resize
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
static OSDWORK_CALLBACK( sdlwindow_resize_wt )
|
|
{
|
|
worker_param * wp = (worker_param *) param;
|
|
sdl_window_info * window = wp->window;
|
|
|
|
ASSERT_WINDOW_THREAD();
|
|
|
|
window->destroy_all_textures(window);
|
|
window->resize(window, wp->resize_new_width, wp->resize_new_height);
|
|
|
|
sdlwindow_blit_surface_size(window, wp->resize_new_width, wp->resize_new_height);
|
|
|
|
sdlwindow_clear(window);
|
|
|
|
osd_free(wp);
|
|
return NULL;
|
|
}
|
|
|
|
void sdlwindow_resize(sdl_window_info *window, INT32 width, INT32 height)
|
|
{
|
|
worker_param wp;
|
|
|
|
ASSERT_MAIN_THREAD();
|
|
|
|
if (width == window->width && height == window->height)
|
|
return;
|
|
|
|
clear_worker_param(&wp);
|
|
wp.resize_new_width = width;
|
|
wp.resize_new_height = height;
|
|
wp.window = window;
|
|
|
|
execute_async_wait(&sdlwindow_resize_wt, &wp);
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_clear_surface
|
|
// (window thread)
|
|
//============================================================
|
|
|
|
static OSDWORK_CALLBACK( sdlwindow_clear_surface_wt )
|
|
{
|
|
worker_param *wp = (worker_param *) param;
|
|
sdl_window_info *window = wp->window;
|
|
|
|
ASSERT_WINDOW_THREAD();
|
|
|
|
window->clear(window);
|
|
osd_free(wp);
|
|
return NULL;
|
|
}
|
|
|
|
void sdlwindow_clear(sdl_window_info *window)
|
|
{
|
|
worker_param *wp = (worker_param *) osd_malloc(sizeof(worker_param));
|
|
|
|
clear_worker_param(wp);
|
|
wp->window = window;
|
|
|
|
if (SDL_ThreadID() == main_threadid)
|
|
{
|
|
execute_async_wait(&sdlwindow_clear_surface_wt, wp);
|
|
osd_free(wp);
|
|
}
|
|
else
|
|
sdlwindow_clear_surface_wt( (void *) wp, 0);
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_toggle_full_screen
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
static OSDWORK_CALLBACK( sdlwindow_toggle_full_screen_wt )
|
|
{
|
|
worker_param *wp = (worker_param *) param;
|
|
sdl_window_info *window = wp->window;
|
|
|
|
ASSERT_WINDOW_THREAD();
|
|
|
|
// if we are in debug mode, never go full screen
|
|
if (options_get_bool(mame_options(), OPTION_DEBUG))
|
|
return NULL;
|
|
|
|
// If we are going fullscreen (leaving windowed) remember our windowed size
|
|
if (!window->fullscreen)
|
|
{
|
|
window->windowed_width = window->width;
|
|
window->windowed_height = window->height;
|
|
}
|
|
|
|
window->destroy(window);
|
|
sdlinput_release_keys(wp->machine);
|
|
|
|
// toggle the window mode
|
|
window->fullscreen = !window->fullscreen;
|
|
|
|
complete_create_wt(param, 0);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void sdlwindow_toggle_full_screen(running_machine *machine, sdl_window_info *window)
|
|
{
|
|
worker_param wp;
|
|
|
|
ASSERT_MAIN_THREAD();
|
|
|
|
clear_worker_param(&wp);
|
|
wp.window = window;
|
|
wp.machine = machine;
|
|
|
|
execute_async_wait(&sdlwindow_toggle_full_screen_wt, &wp);
|
|
}
|
|
|
|
static OSDWORK_CALLBACK( destroy_all_textures_wt )
|
|
{
|
|
worker_param *wp = (worker_param *) param;
|
|
|
|
sdl_window_info *window = wp->window;
|
|
|
|
window->destroy_all_textures(window);
|
|
|
|
osd_free(wp);
|
|
return NULL;
|
|
}
|
|
|
|
void sdlwindow_modify_prescale(running_machine *machine, sdl_window_info *window, int dir)
|
|
{
|
|
worker_param wp;
|
|
int new_prescale = window->prescale;
|
|
|
|
clear_worker_param(&wp);
|
|
|
|
wp.window = window;
|
|
wp.machine = machine;
|
|
|
|
if (dir > 0 && window->prescale < 3)
|
|
new_prescale = window->prescale + 1;
|
|
if (dir < 0 && window->prescale > 1)
|
|
new_prescale = window->prescale - 1;
|
|
|
|
if (new_prescale != window->prescale)
|
|
{
|
|
if (window->fullscreen && video_config.switchres)
|
|
{
|
|
execute_async_wait(&sdlwindow_video_window_destroy_wt, &wp);
|
|
|
|
window->prescale = new_prescale;
|
|
|
|
execute_async_wait(&complete_create_wt, &wp);
|
|
|
|
}
|
|
else
|
|
{
|
|
execute_async_wait(destroy_all_textures_wt, &wp);
|
|
window->prescale = new_prescale;
|
|
}
|
|
ui_popup_time(1, "Prescale %d", window->prescale);
|
|
}
|
|
}
|
|
|
|
void sdlwindow_toggle_draw(running_machine *machine, sdl_window_info *window)
|
|
{
|
|
#if USE_OPENGL
|
|
//FIXME: Not yet working in 1.3
|
|
#if (!SDL_VERSION_ATLEAST(1,3,0))
|
|
worker_param wp;
|
|
|
|
// If we are not fullscreen (windowed) remember our windowed size
|
|
if (!window->fullscreen)
|
|
{
|
|
window->windowed_width = window->width;
|
|
window->windowed_height = window->height;
|
|
}
|
|
|
|
clear_worker_param(&wp);
|
|
|
|
wp.window = window;
|
|
wp.machine = machine;
|
|
execute_async_wait(&sdlwindow_video_window_destroy_wt, &wp);
|
|
|
|
window->scale_mode = VIDEO_SCALE_MODE_NONE;
|
|
|
|
if (video_config.mode == VIDEO_MODE_OPENGL)
|
|
{
|
|
video_config.mode = VIDEO_MODE_SOFT;
|
|
drawsdl_init(&draw);
|
|
ui_popup_time(1, "Using software rendering");
|
|
}
|
|
else
|
|
{
|
|
video_config.mode = VIDEO_MODE_OPENGL;
|
|
drawogl_init(&draw);
|
|
ui_popup_time(1, "Using OpenGL rendering");
|
|
}
|
|
|
|
execute_async_wait(&complete_create_wt, &wp);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_update_cursor_state
|
|
// (main or window thread)
|
|
//============================================================
|
|
|
|
static void sdlwindow_update_cursor_state(running_machine *machine, sdl_window_info *window)
|
|
{
|
|
#if (SDL_VERSION_ATLEAST(1,3,0))
|
|
// do not do mouse capture if the debugger's enabled to avoid
|
|
// the possibility of losing control
|
|
if (!options_get_bool(mame_options(), OPTION_DEBUG))
|
|
{
|
|
//FIXME: SDL1.3: really broken: the whole SDL code
|
|
// will only work correct with relative mouse movements ...
|
|
//SDL_SetRelativeMouseMode
|
|
if (!window->fullscreen && !sdlinput_should_hide_mouse(machine))
|
|
{
|
|
SDL_ShowCursor(SDL_ENABLE);
|
|
if (SDL_GetWindowGrab(window->window_id ))
|
|
SDL_SetWindowGrab(window->window_id, 0);
|
|
}
|
|
else
|
|
{
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
if (!SDL_GetWindowGrab(window->window_id))
|
|
SDL_SetWindowGrab(window->window_id, 1);
|
|
}
|
|
SDL_SetCursor(NULL); // Force an update in case the underlying driver has changed visibility
|
|
}
|
|
|
|
#else
|
|
// do not do mouse capture if the debugger's enabled to avoid
|
|
// the possibility of losing control
|
|
if (!options_get_bool(mame_options(), OPTION_DEBUG))
|
|
{
|
|
if ( window->fullscreen || sdlinput_should_hide_mouse(machine) )
|
|
{
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
if (!SDL_WM_GrabInput(SDL_GRAB_QUERY))
|
|
{
|
|
SDL_WM_GrabInput(SDL_GRAB_ON);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SDL_ShowCursor(SDL_ENABLE);
|
|
if (SDL_WM_GrabInput(SDL_GRAB_QUERY))
|
|
{
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_video_window_create
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
int sdlwindow_video_window_create(running_machine *machine, int index, sdl_monitor_info *monitor, const sdl_window_config *config)
|
|
{
|
|
sdl_window_info *window;
|
|
worker_param *wp = (worker_param *) osd_malloc(sizeof(worker_param));
|
|
char option[20];
|
|
int result;
|
|
|
|
ASSERT_MAIN_THREAD();
|
|
|
|
clear_worker_param(wp);
|
|
|
|
// allocate a new window object
|
|
window = global_alloc_clear(sdl_window_info);
|
|
window->maxwidth = config->width;
|
|
window->maxheight = config->height;
|
|
window->depth = config->depth;
|
|
window->refresh = config->refresh;
|
|
window->monitor = monitor;
|
|
window->machine = machine;
|
|
window->index = index;
|
|
|
|
//FIXME: these should be per_window in config-> or even better a bit set
|
|
window->fullscreen = !video_config.windowed;
|
|
window->prescale = video_config.prescale;
|
|
window->scale_mode = video_config.scale_mode;
|
|
|
|
// set the initial maximized state
|
|
// FIXME: Does not belong here
|
|
window->startmaximized = options_get_bool(mame_options(), SDLOPTION_MAXIMIZE);
|
|
|
|
if (!window->fullscreen)
|
|
{
|
|
window->windowed_width = config->width;
|
|
window->windowed_height = config->height;
|
|
}
|
|
window->totalColors = config->totalColors;
|
|
|
|
// add us to the list
|
|
*last_window_ptr = window;
|
|
last_window_ptr = &window->next;
|
|
|
|
draw.attach(&draw, window);
|
|
|
|
// create an event that we can use to skip blitting
|
|
window->rendered_event = osd_event_alloc(FALSE, TRUE);
|
|
|
|
// load the layout
|
|
window->target = render_target_alloc(machine, NULL, FALSE);
|
|
if (window->target == NULL)
|
|
goto error;
|
|
|
|
// set the specific view
|
|
sprintf(option, SDLOPTION_VIEW("%d"), index);
|
|
set_starting_view(machine, index, window, options_get_string(mame_options(), option));
|
|
|
|
// make the window title
|
|
if (video_config.numscreens == 1)
|
|
sprintf(window->title, APPNAME ": %s [%s]", machine->gamedrv->description, machine->gamedrv->name);
|
|
else
|
|
sprintf(window->title, APPNAME ": %s [%s] - Screen %d", machine->gamedrv->description, machine->gamedrv->name, index);
|
|
|
|
wp->window = window;
|
|
|
|
if (multithreading_enabled)
|
|
{
|
|
osd_work_item *wi;
|
|
|
|
wi = osd_work_item_queue(work_queue, &complete_create_wt, (void *) wp, 0);
|
|
sdlwindow_sync();
|
|
result = *((int *) (osd_work_item_result)(wi));
|
|
osd_work_item_release(wi);
|
|
}
|
|
else
|
|
result = *((int *) complete_create_wt((void *) wp, 0));
|
|
|
|
// handle error conditions
|
|
if (result == 1)
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
sdlwindow_video_window_destroy(machine, window);
|
|
return 1;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// sdlwindow_video_window_destroy
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
static OSDWORK_CALLBACK( sdlwindow_video_window_destroy_wt )
|
|
{
|
|
worker_param * wp = (worker_param *) param;
|
|
sdl_window_info * window = wp->window;
|
|
|
|
ASSERT_WINDOW_THREAD();
|
|
|
|
// free the textures etc
|
|
window->destroy(window);
|
|
|
|
// release all keys ...
|
|
sdlinput_release_keys(wp->machine);
|
|
|
|
|
|
osd_free(wp);
|
|
return NULL;
|
|
}
|
|
|
|
static void sdlwindow_video_window_destroy(running_machine *machine, sdl_window_info *window)
|
|
{
|
|
sdl_window_info **prevptr;
|
|
worker_param wp;
|
|
|
|
ASSERT_MAIN_THREAD();
|
|
if (multithreading_enabled)
|
|
{
|
|
sdlwindow_sync();
|
|
}
|
|
|
|
//osd_event_wait(window->rendered_event, osd_ticks_per_second()*10);
|
|
|
|
// remove us from the list
|
|
for (prevptr = &sdl_window_list; *prevptr != NULL; prevptr = &(*prevptr)->next)
|
|
if (*prevptr == window)
|
|
{
|
|
*prevptr = window->next;
|
|
break;
|
|
}
|
|
|
|
// free the textures etc
|
|
clear_worker_param(&wp);
|
|
wp.window = window;
|
|
wp.machine = machine;
|
|
execute_async_wait(&sdlwindow_video_window_destroy_wt, &wp);
|
|
|
|
// free the render target, after the textures!
|
|
if (window->target != NULL)
|
|
render_target_free(window->target);
|
|
|
|
// free the event
|
|
osd_event_free(window->rendered_event);
|
|
|
|
// free the window itself
|
|
global_free(window);
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// pick_best_mode
|
|
//============================================================
|
|
|
|
#if SDL_VERSION_ATLEAST(1,3,0)
|
|
static void pick_best_mode(sdl_window_info *window, int *fswidth, int *fsheight)
|
|
{
|
|
int minimum_width, minimum_height, target_width, target_height;
|
|
int i;
|
|
int num;
|
|
float size_score, best_score = 0.0f;
|
|
|
|
// determine the minimum width/height for the selected target
|
|
render_target_get_minimum_size(window->target, &minimum_width, &minimum_height);
|
|
|
|
// use those as the target for now
|
|
target_width = minimum_width * MAX(1, window->prescale);
|
|
target_height = minimum_height * MAX(1, window->prescale);
|
|
|
|
// if we're not stretching, allow some slop on the minimum since we can handle it
|
|
{
|
|
minimum_width -= 4;
|
|
minimum_height -= 4;
|
|
}
|
|
|
|
num = SDL_GetNumDisplayModes();
|
|
|
|
if (num == 0)
|
|
{
|
|
mame_printf_error("SDL: No modes available?!\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < num; ++i)
|
|
{
|
|
SDL_DisplayMode mode;
|
|
SDL_GetDisplayMode(i, &mode);
|
|
|
|
// compute initial score based on difference between target and current
|
|
size_score = 1.0f / (1.0f + fabsf((INT32)mode.w - target_width) + fabsf((INT32)mode.h - target_height));
|
|
|
|
// if the mode is too small, give a big penalty
|
|
if (mode.w < minimum_width || mode.h < minimum_height)
|
|
size_score *= 0.01f;
|
|
|
|
// if mode is smaller than we'd like, it only scores up to 0.1
|
|
if (mode.w < target_width || mode.h < target_height)
|
|
size_score *= 0.1f;
|
|
|
|
// if we're looking for a particular mode, that's a winner
|
|
if (mode.w == window->maxwidth && mode.h == window->maxheight)
|
|
size_score = 2.0f;
|
|
|
|
// refresh adds some points
|
|
if (window->refresh)
|
|
size_score *= 1.0f / (1.0f + fabsf(window->refresh - mode.refresh_rate) / 10.0f);
|
|
|
|
mame_printf_verbose("%4dx%4d@%2d -> %f\n", (int)mode.w, (int)mode.h, (int) mode.refresh_rate, size_score);
|
|
|
|
// best so far?
|
|
if (size_score > best_score)
|
|
{
|
|
best_score = size_score;
|
|
*fswidth = mode.w;
|
|
*fsheight = mode.h;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
static void pick_best_mode(sdl_window_info *window, int *fswidth, int *fsheight)
|
|
{
|
|
int minimum_width, minimum_height, target_width, target_height;
|
|
int i;
|
|
float size_score, best_score = 0.0f;
|
|
SDL_Rect **modes;
|
|
|
|
// determine the minimum width/height for the selected target
|
|
render_target_get_minimum_size(window->target, &minimum_width, &minimum_height);
|
|
|
|
// use those as the target for now
|
|
target_width = minimum_width * MAX(1, window->prescale);
|
|
target_height = minimum_height * MAX(1, window->prescale);
|
|
|
|
// if we're not stretching, allow some slop on the minimum since we can handle it
|
|
{
|
|
minimum_width -= 4;
|
|
minimum_height -= 4;
|
|
}
|
|
|
|
#if 1 // defined(SDLMAME_WIN32)
|
|
/*
|
|
* We need to do this here. If SDL_ListModes is
|
|
* called in init_monitors, the call will crash
|
|
* on win32
|
|
*/
|
|
modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_DOUBLEBUF);
|
|
#else
|
|
modes = window->monitor->modes;
|
|
#endif
|
|
|
|
if (modes == (SDL_Rect **)0)
|
|
{
|
|
mame_printf_error("SDL: No modes available?!\n");
|
|
exit(-1);
|
|
}
|
|
else if (modes == (SDL_Rect **)-1) // all modes are possible
|
|
{
|
|
*fswidth = window->maxwidth;
|
|
*fsheight = window->maxheight;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; modes[i]; ++i)
|
|
{
|
|
// compute initial score based on difference between target and current
|
|
size_score = 1.0f / (1.0f + fabsf((INT32)modes[i]->w - target_width) + fabsf((INT32)modes[i]->h - target_height));
|
|
|
|
// if the mode is too small, give a big penalty
|
|
if (modes[i]->w < minimum_width || modes[i]->h < minimum_height)
|
|
size_score *= 0.01f;
|
|
|
|
// if mode is smaller than we'd like, it only scores up to 0.1
|
|
if (modes[i]->w < target_width || modes[i]->h < target_height)
|
|
size_score *= 0.1f;
|
|
|
|
// if we're looking for a particular mode, that's a winner
|
|
if (modes[i]->w == window->maxwidth && modes[i]->h == window->maxheight)
|
|
size_score = 2.0f;
|
|
|
|
mame_printf_verbose("%4dx%4d -> %f\n", (int)modes[i]->w, (int)modes[i]->h, size_score);
|
|
|
|
// best so far?
|
|
if (size_score > best_score)
|
|
{
|
|
best_score = size_score;
|
|
*fswidth = modes[i]->w;
|
|
*fsheight = modes[i]->h;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//============================================================
|
|
// sdlwindow_video_window_update
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
void sdlwindow_video_window_update(running_machine *machine, sdl_window_info *window)
|
|
{
|
|
|
|
ASSERT_MAIN_THREAD();
|
|
|
|
// adjust the cursor state
|
|
sdlwindow_update_cursor_state(machine, window);
|
|
|
|
// if we're visible and running and not in the middle of a resize, draw
|
|
if (window->target != NULL)
|
|
{
|
|
int tempwidth, tempheight;
|
|
|
|
// see if the games video mode has changed
|
|
render_target_get_minimum_size(window->target, &tempwidth, &tempheight);
|
|
if (tempwidth != window->minwidth || tempheight != window->minheight)
|
|
{
|
|
window->minwidth = tempwidth;
|
|
window->minheight = tempheight;
|
|
if (!window->fullscreen)
|
|
{
|
|
sdlwindow_blit_surface_size(window, window->width, window->height);
|
|
sdlwindow_resize(window, window->blitwidth, window->blitheight);
|
|
}
|
|
else if (video_config.switchres)
|
|
{
|
|
pick_best_mode(window, &tempwidth, &tempheight);
|
|
sdlwindow_resize(window, tempwidth, tempheight);
|
|
}
|
|
}
|
|
|
|
// only render if we have been signalled
|
|
if (osd_event_wait(window->rendered_event, 0))
|
|
{
|
|
worker_param wp;
|
|
const render_primitive_list *primlist;
|
|
|
|
clear_worker_param(&wp);
|
|
|
|
// ensure the target bounds are up-to-date, and then get the primitives
|
|
primlist = window->get_primitives(window);
|
|
|
|
// and redraw now
|
|
|
|
wp.list = primlist;
|
|
wp.window = window;
|
|
wp.machine = machine;
|
|
|
|
execute_async(&draw_video_contents_wt, &wp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// set_starting_view
|
|
// (main thread)
|
|
//============================================================
|
|
|
|
static void set_starting_view(running_machine *machine, int index, sdl_window_info *window, const char *view)
|
|
{
|
|
const char *defview = options_get_string(mame_options(), SDLOPTION_VIEW( ));
|
|
int viewindex;
|
|
|
|
ASSERT_MAIN_THREAD();
|
|
|
|
// 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 = video_get_view_for_target(machine, window->target, view, index, video_config.numscreens);
|
|
|
|
// set the view
|
|
render_target_set_view(window->target, viewindex);
|
|
window->start_viewscreen=viewindex;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// complete_create
|
|
// (window thread)
|
|
//============================================================
|
|
|
|
static OSDWORK_CALLBACK( complete_create_wt )
|
|
{
|
|
worker_param * wp = (worker_param *) param;
|
|
sdl_window_info * window = wp->window;
|
|
|
|
int tempwidth, tempheight;
|
|
static int result[2] = {0,1};
|
|
|
|
ASSERT_WINDOW_THREAD();
|
|
osd_free(wp);
|
|
|
|
if (window->fullscreen)
|
|
{
|
|
// default to the current mode exactly
|
|
tempwidth = window->monitor->monitor_width;
|
|
tempheight = window->monitor->monitor_height;
|
|
|
|
// if we're allowed to switch resolutions, override with something better
|
|
if (video_config.switchres)
|
|
pick_best_mode(window, &tempwidth, &tempheight);
|
|
}
|
|
else if (window->windowed_width)
|
|
{
|
|
// if we have a remembered size force the new window size to it
|
|
tempwidth = window->windowed_width;
|
|
tempheight = window->windowed_height;
|
|
}
|
|
else
|
|
{
|
|
if (window->startmaximized)
|
|
{
|
|
tempwidth = tempheight = 0;
|
|
get_max_bounds(window, &tempwidth, &tempheight, video_config.keepaspect );
|
|
}
|
|
else
|
|
{
|
|
/* Create the window directly with the correct aspect
|
|
instead of letting sdlwindow_blit_surface_size() resize it
|
|
this stops the window from "flashing" from the wrong aspect
|
|
size to the right one at startup. */
|
|
tempwidth = (window->maxwidth != 0) ? window->maxwidth : 640;
|
|
tempheight = (window->maxheight != 0) ? window->maxheight : 480;
|
|
|
|
get_min_bounds(window, &tempwidth, &tempheight, video_config.keepaspect );
|
|
}
|
|
}
|
|
|
|
// initialize the drawing backend
|
|
if (window->create(window, tempwidth, tempheight))
|
|
return (void *) &result[1];
|
|
|
|
// Make sure we have a consistent state
|
|
SDL_ShowCursor(0);
|
|
SDL_ShowCursor(1);
|
|
|
|
return (void *) &result[0];
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// draw_video_contents
|
|
// (window thread)
|
|
//============================================================
|
|
|
|
static void measure_fps(sdl_window_info *window, UINT32 dc, int update)
|
|
{
|
|
const unsigned long frames_skip4fps = 100;
|
|
static int64_t lastTime=0, sumdt=0, startTime=0;
|
|
static unsigned long frames = 0;
|
|
int64_t currentTime, t0;
|
|
double dt;
|
|
double tps;
|
|
osd_ticks_t tps_t;
|
|
|
|
tps_t = osd_ticks_per_second();
|
|
tps = (double) tps_t;
|
|
|
|
t0 = osd_ticks();
|
|
|
|
window->draw(window, dc, update);
|
|
|
|
frames++;
|
|
currentTime = osd_ticks();
|
|
if(startTime==0||frames==frames_skip4fps)
|
|
startTime=currentTime;
|
|
if( frames>=frames_skip4fps )
|
|
sumdt+=currentTime-t0;
|
|
if( (currentTime-lastTime)>1L*osd_ticks_per_second() && frames>frames_skip4fps )
|
|
{
|
|
dt = (double) (currentTime-startTime) / tps; // in decimale sec.
|
|
mame_printf_info("%6.2lfs, %4lu F, "
|
|
"avrg game: %5.2lf FPS %.2lf ms/f, "
|
|
"avrg video: %5.2lf FPS %.2lf ms/f, "
|
|
"last video: %5.2lf FPS %.2lf ms/f\n",
|
|
dt, frames-frames_skip4fps,
|
|
(double)(frames-frames_skip4fps)/dt, // avrg game fps
|
|
( (currentTime-startTime) / ((frames-frames_skip4fps)) ) * 1000.0 / osd_ticks_per_second(),
|
|
(double)(frames-frames_skip4fps)/((double)(sumdt) / tps), // avrg vid fps
|
|
( sumdt / ((frames-frames_skip4fps)) ) * 1000.0 / tps,
|
|
1.0/((currentTime-t0) / osd_ticks_per_second()), // this vid fps
|
|
(currentTime-t0) * 1000.0 / tps
|
|
);
|
|
lastTime = currentTime;
|
|
}
|
|
}
|
|
|
|
static OSDWORK_CALLBACK( draw_video_contents_wt )
|
|
{
|
|
UINT32 dc = 0;
|
|
int update = 1;
|
|
worker_param *wp = (worker_param *) param;
|
|
sdl_window_info *window = wp->window;
|
|
|
|
ASSERT_REDRAW_THREAD();
|
|
|
|
// Some configurations require events to be polled in the worker thread
|
|
sdlinput_process_events_buf(wp->machine);
|
|
|
|
window->primlist = wp->list;
|
|
|
|
// if no bitmap, just fill
|
|
if (window->primlist == NULL)
|
|
{
|
|
}
|
|
// otherwise, render with our drawing system
|
|
else
|
|
{
|
|
if( video_config.perftest )
|
|
measure_fps(window, dc, update);
|
|
else
|
|
window->draw(window, dc, update);
|
|
}
|
|
|
|
/* all done, ready for next */
|
|
osd_event_set(window->rendered_event);
|
|
osd_free(wp);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// constrain_to_aspect_ratio
|
|
// (window thread)
|
|
//============================================================
|
|
|
|
static void constrain_to_aspect_ratio(sdl_window_info *window, int *window_width, int *window_height, int adjustment)
|
|
{
|
|
INT32 extrawidth = 0;
|
|
INT32 extraheight = 0;
|
|
INT32 propwidth, propheight;
|
|
INT32 minwidth, minheight;
|
|
INT32 maxwidth, maxheight;
|
|
INT32 viswidth, visheight;
|
|
float pixel_aspect;
|
|
|
|
// make sure the monitor is up-to-date
|
|
sdlvideo_monitor_refresh(window->monitor);
|
|
|
|
// get the pixel aspect ratio for the target monitor
|
|
pixel_aspect = sdlvideo_monitor_get_aspect(window->monitor);
|
|
|
|
// determine the proposed width/height
|
|
propwidth = *window_width - extrawidth;
|
|
propheight = *window_height - extraheight;
|
|
|
|
// based on which edge we are adjusting, take either the width, height, or both as gospel
|
|
// and scale to fit using that as our parameter
|
|
switch (adjustment)
|
|
{
|
|
case WMSZ_BOTTOM:
|
|
case WMSZ_TOP:
|
|
render_target_compute_visible_area(window->target, 10000, propheight, pixel_aspect, render_target_get_orientation(window->target), &propwidth, &propheight);
|
|
break;
|
|
|
|
case WMSZ_LEFT:
|
|
case WMSZ_RIGHT:
|
|
render_target_compute_visible_area(window->target, propwidth, 10000, pixel_aspect, render_target_get_orientation(window->target), &propwidth, &propheight);
|
|
break;
|
|
|
|
default:
|
|
render_target_compute_visible_area(window->target, propwidth, propheight, pixel_aspect, render_target_get_orientation(window->target), &propwidth, &propheight);
|
|
break;
|
|
}
|
|
|
|
// get the minimum width/height for the current layout
|
|
render_target_get_minimum_size(window->target, &minwidth, &minheight);
|
|
|
|
// clamp against the absolute minimum
|
|
propwidth = MAX(propwidth, MIN_WINDOW_DIM);
|
|
propheight = MAX(propheight, MIN_WINDOW_DIM);
|
|
|
|
// clamp against the minimum width and height
|
|
propwidth = MAX(propwidth, minwidth);
|
|
propheight = MAX(propheight, minheight);
|
|
|
|
// clamp against the maximum (fit on one screen for full screen mode)
|
|
if (window->fullscreen)
|
|
{
|
|
maxwidth = window->monitor->center_width - extrawidth;
|
|
maxheight = window->monitor->center_height - extraheight;
|
|
}
|
|
else
|
|
{
|
|
maxwidth = window->monitor->center_width - extrawidth;
|
|
maxheight = window->monitor->center_height - extraheight;
|
|
|
|
// further clamp to the maximum width/height in the window
|
|
if (window->maxwidth != 0)
|
|
maxwidth = MIN(maxwidth, window->maxwidth + extrawidth);
|
|
if (window->maxheight != 0)
|
|
maxheight = MIN(maxheight, window->maxheight + extraheight);
|
|
}
|
|
|
|
// clamp to the maximum
|
|
propwidth = MIN(propwidth, maxwidth);
|
|
propheight = MIN(propheight, maxheight);
|
|
|
|
// compute the visible area based on the proposed rectangle
|
|
render_target_compute_visible_area(window->target, propwidth, propheight, pixel_aspect, render_target_get_orientation(window->target), &viswidth, &visheight);
|
|
|
|
*window_width = viswidth;
|
|
*window_height = visheight;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// get_min_bounds
|
|
// (window thread)
|
|
//============================================================
|
|
|
|
static void get_min_bounds(sdl_window_info *window, int *window_width, int *window_height, int constrain)
|
|
{
|
|
INT32 minwidth, minheight;
|
|
|
|
// get the minimum target size
|
|
render_target_get_minimum_size(window->target, &minwidth, &minheight);
|
|
|
|
// expand to our minimum dimensions
|
|
if (minwidth < MIN_WINDOW_DIM)
|
|
minwidth = MIN_WINDOW_DIM;
|
|
if (minheight < MIN_WINDOW_DIM)
|
|
minheight = MIN_WINDOW_DIM;
|
|
|
|
// if we want it constrained, figure out which one is larger
|
|
if (constrain)
|
|
{
|
|
int test1w, test1h;
|
|
int test2w, test2h;
|
|
|
|
// first constrain with no height limit
|
|
test1w = minwidth; test1h = 10000;
|
|
constrain_to_aspect_ratio(window, &test1w, &test1h, WMSZ_BOTTOMRIGHT);
|
|
|
|
// then constrain with no width limit
|
|
test2w = 10000; test2h = minheight;
|
|
constrain_to_aspect_ratio(window, &test2w, &test2h, WMSZ_BOTTOMRIGHT);
|
|
|
|
// pick the larger
|
|
if ( test1w > test2w )
|
|
{
|
|
minwidth = test1w;
|
|
minheight = test1h;
|
|
}
|
|
else
|
|
{
|
|
minwidth = test2w;
|
|
minheight = test2h;
|
|
}
|
|
}
|
|
|
|
*window_width = minwidth;
|
|
*window_height = minheight;
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// get_max_bounds
|
|
// (window thread)
|
|
//============================================================
|
|
|
|
static void get_max_bounds(sdl_window_info *window, int *window_width, int *window_height, int constrain)
|
|
{
|
|
INT32 maxwidth, maxheight;
|
|
|
|
// compute the maximum client area
|
|
maxwidth = window->monitor->center_width;
|
|
maxheight = window->monitor->center_height;
|
|
|
|
// clamp to the window's max
|
|
if (window->maxwidth != 0)
|
|
{
|
|
int temp = window->maxwidth + WINDOW_DECORATION_WIDTH;
|
|
if (temp < maxwidth)
|
|
maxwidth = temp;
|
|
}
|
|
if (window->maxheight != 0)
|
|
{
|
|
int temp = window->maxheight + WINDOW_DECORATION_HEIGHT;
|
|
if (temp < maxheight)
|
|
maxheight = temp;
|
|
}
|
|
|
|
// constrain to fit
|
|
if (constrain)
|
|
constrain_to_aspect_ratio(window, &maxwidth, &maxheight, WMSZ_BOTTOMRIGHT);
|
|
//else
|
|
{
|
|
maxwidth -= WINDOW_DECORATION_WIDTH;
|
|
maxheight -= WINDOW_DECORATION_HEIGHT;
|
|
*window_width = maxwidth;
|
|
*window_height = maxheight;
|
|
}
|
|
}
|
|
|