Support for dynamically changing window size

* Beginning of support for fullscreen mode
    * Fullscreen depends on "fuzzing" the graphics
This commit is contained in:
Aaron Culliney 2014-01-04 14:24:55 -08:00
parent b5023f88f4
commit 12f6c9704e
5 changed files with 217 additions and 97 deletions

View File

@ -735,6 +735,7 @@ typedef enum interface_enum_t {
OPT_PATH,
//OPT_MODE,
OPT_COLOR,
OPT_VIDEO,
OPT_VOLUME,
OPT_JOYSTICK,
OPT_CALIBRATE,
@ -750,6 +751,7 @@ static const char *options[] =
" Path : ",
//" Mode : ",
" Color : ",
" Video : ",
" Volume : ",
" Joystick : ",
" Calibrate Joystick...",
@ -864,6 +866,10 @@ void c_interface_parameters()
(color_mode == COLOR_INTERP) ? "Interpolated" : "Black/White ");
break;
case OPT_VIDEO:
sprintf(temp, "%s", (a2_video_mode == VIDEO_1X) ? "1X " : (a2_video_mode == VIDEO_2X) ? "2X " : "Fullscreen");
break;
case OPT_VOLUME:
if (sound_volume == 0)
{
@ -1031,6 +1037,18 @@ void c_interface_parameters()
}
break;
case OPT_VIDEO:
if (a2_video_mode == 1)
{
a2_video_mode = NUM_VIDOPTS-1;
}
else
{
--a2_video_mode;
}
video_set_mode(a2_video_mode);
break;
case OPT_VOLUME:
if (sound_volume > 0)
{
@ -1124,6 +1142,18 @@ void c_interface_parameters()
}
break;
case OPT_VIDEO:
if (a2_video_mode == NUM_VIDOPTS-1)
{
a2_video_mode = 1;
}
else
{
++a2_video_mode;
}
video_set_mode(a2_video_mode);
break;
case OPT_VOLUME:
sound_volume++;
if (sound_volume > 10)

View File

@ -37,6 +37,7 @@
#define PRM_HIRES_COLOR 4
#define PRM_VOLUME 5
#define PRM_JOY_INPUT 6
#define PRM_VIDEO_MODE 7
#define PRM_JOY_PC_CALIBRATE 10
#define PRM_JOY_KPAD_CALIBRATE 11
#define PRM_ROM_PATH 12
@ -48,6 +49,7 @@ char disk_path[DISKSIZE];
int apple_mode;
int sound_volume;
color_mode_t color_mode;
a2_video_mode_t a2_video_mode;
joystick_mode_t joy_mode;
static char *config_filename = NULL;
@ -68,6 +70,7 @@ static const struct match_table prefs_table[] =
{ "disk_path", PRM_DISK_PATH },
{ "path", PRM_DISK_PATH },
{ "color", PRM_HIRES_COLOR },
{ "video", PRM_VIDEO_MODE },
{ "volume", PRM_VOLUME },
{ "joystick", PRM_JOY_INPUT },
{ "pc joystick parms", PRM_JOY_PC_CALIBRATE },
@ -99,6 +102,14 @@ static const struct match_table color_table[] =
{ 0, COLOR }
};
static const struct match_table video_table[] =
{
{ "1X", VIDEO_1X },
{ "2X", VIDEO_2X },
{ "Fullscreen", VIDEO_FULLSCREEN },
{ 0, VIDEO_1X }
};
static const struct match_table volume_table[] =
{
{ "0", 0 },
@ -274,6 +285,10 @@ void load_settings(void)
color_mode = match(color_table, argument);
break;
case PRM_VIDEO_MODE:
a2_video_mode = match(video_table, argument);
break;
case PRM_VOLUME:
sound_volume = match(volume_table, argument);
break;
@ -388,6 +403,7 @@ bool save_settings(void)
"mode = %s\n"
"disk path = %s\n"
"color = %s\n"
"video = %s\n"
"volume = %s\n"
"joystick = %s\n"
"system path = %s\n",
@ -396,6 +412,7 @@ bool save_settings(void)
reverse_match(modes_table, apple_mode),
disk_path,
reverse_match(color_table, color_mode),
reverse_match(video_table, a2_video_mode),
reverse_match(volume_table, sound_volume),
reverse_match(joy_input_table, joy_mode),
system_path);

View File

@ -41,6 +41,13 @@ typedef enum color_mode_t {
NUM_COLOROPTS
} color_mode_t;
typedef enum a2_video_mode_t {
VIDEO_FULLSCREEN = 0,
VIDEO_1X,
VIDEO_2X,
NUM_VIDOPTS
} a2_video_mode_t;
#define SYSSIZE 4096
extern char system_path[SYSSIZE];
#define DISKSIZE 4096
@ -49,6 +56,7 @@ extern char disk_path[DISKSIZE];
extern int apple_mode; /* undocumented instructions or //e mode */
extern int sound_volume;
extern color_mode_t color_mode;
extern a2_video_mode_t a2_video_mode;
/* generic joystick settings */
extern joystick_mode_t joy_mode;

View File

@ -19,6 +19,8 @@
#ifndef __ASSEMBLER__
#include "prefs.h"
/* Prepare the video system, converting console to graphics mode, or
* opening X window, or whatever. This is called only once when the
* emulator is run
@ -104,13 +106,7 @@ void video_plotchar(int row, int col, int color, unsigned char code);
*/
void video_sync(int block);
typedef enum A2_VIDSCALE {
VIDEO_FULL_SCREEN = 0,
VIDEO_SCALE_1,
VIDEO_SCALE_2
} A2_VIDSCALE;
void video_setscale();
void video_set_mode(a2_video_mode_t mode);
#endif /* !__ASSEMBLER__ */

View File

@ -42,24 +42,39 @@ static Display *display;
static Window win;
static GC gc;
static unsigned int width, height; /* window size */
static A2_VIDSCALE scale = VIDEO_SCALE_1;
static unsigned int scale = 1;
static int screen_num;
static XVisualInfo visualinfo;
static XColor colors[256];
XImage *image;
static XImage *image=NULL;
static Colormap cmap;
XEvent xevent;
static XEvent xevent;
static XSizeHints *size_hints=NULL;
static XWMHints *wm_hints=NULL;
static XClassHint *class_hints=NULL;
static XTextProperty windowName, iconName;
static uint32_t red_shift;
static uint32_t green_shift;
static uint32_t blue_shift;
static uint32_t alpha_shift;
int doShm = 1; /* assume true */
XShmSegmentInfo xshminfo;
int xshmeventtype;
static int doShm = 1; /* assume true */
static XShmSegmentInfo xshminfo;
static int xshmeventtype;
// pad pixels to uint32_t boundaries
static int bitmap_pad = sizeof(uint32_t);
typedef struct {
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
} FullScreenHints;
/* -------------------------------------------------------------------------
video_setpage(p): Switch to screen page p
@ -462,7 +477,7 @@ static void post_image() {
((uint32_t)(colors[index].blue) << blue_shift) |
((uint32_t)0xff /* alpha */ << alpha_shift)
);
if (scale == VIDEO_SCALE_2)
if (scale > 1)
{
j+=4;
@ -637,13 +652,137 @@ static void parseArgs() {
{
doShm=0;
}
else if (strstr(argv[i], "-2"))
}
}
static void _destroy_image() {
if (doShm)
{
// Detach from X server
if (!XShmDetach(display, &xshminfo))
{
scale=VIDEO_SCALE_2;
fprintf(stderr,"XShmDetach() failed in video_shutdown()\n");
}
XDestroyImage(image);
// Release shared memory.
shmdt(xshminfo.shmaddr);
shmctl(xshminfo.shmid, IPC_RMID, 0);
}
else
{
XDestroyImage(image);
//free(image->data);
}
}
static void _create_image() {
int pixel_buffer_size = width*height*bitmap_pad;
if (doShm) {
image = XShmCreateImage(display, visualinfo.visual, visualinfo.depth, ZPixmap, NULL, &xshminfo, width, height);
if (!image) {
ERRQUIT("XShmCreateImage failed");
}
LOG("Allocating shared memory: bytes_per_line:%ds height:x%d (depth:%d) bitmap_pad:%d",
image->bytes_per_line, image->height, visualinfo.depth, bitmap_pad);
getshm(pixel_buffer_size);
/* get the X server to attach to it */
if (!XShmAttach(display, &xshminfo)) {
ERRQUIT("XShmAttach() failed");
}
} else {
void *data = malloc(pixel_buffer_size);
if (!data) {
ERRQUIT("no memory for image data!");
}
LOG("Creating regular XImage");
image = XCreateImage(display, visualinfo.visual, visualinfo.depth, ZPixmap, 0 /*offset*/, data, width, height, 8, width*bitmap_pad /*bytes_per_line*/);
if (!image) {
ERRQUIT("XCreateImage failed");
}
}
}
static void _size_hints_set_fixed() {
size_hints->flags = PPosition | PSize | PMinSize | PMaxSize;
size_hints->min_width = width;
size_hints->min_height = height;
size_hints->max_width = XDisplayWidth(display, 0);
size_hints->max_height = XDisplayHeight(display, 0);
}
static void _size_hints_set_resize() {
size_hints->flags = USPosition | USSize | PMinSize | PMaxSize;
size_hints->min_width = width;
size_hints->min_height = height;
size_hints->max_width = XDisplayWidth(display, 0);
size_hints->max_height = XDisplayHeight(display, 0);
}
void video_set_mode(a2_video_mode_t mode) {
_destroy_image();
scale = mode;
if (mode == VIDEO_FULLSCREEN) {
scale = 1; // HACK FIXME for now ................
}
width = SCANWIDTH*scale;
height = SCANHEIGHT*scale;
_size_hints_set_resize();
//XResizeWindow(display, win, width, height);
XSetWMProperties(display, win, &windowName, &iconName,
argv, argc, size_hints, wm_hints,
class_hints);
#if 0
// TODO ...
// Fullscreen mode really should "fuzz" the graphics like AppleWin does when emulating NTSC.
// Also will need to verify the canonical way to switch to fullscreen in X11
// http://www.tonyobryan.com/index.php?article=9
if (mode == VIDEO_FULLSCREEN) {
FullScreenHints hints = { .flags=2, .decorations=0 };
Atom property = XInternAtom(display, "_MOTIF_WM_HINTS", True);
XChangeProperty(display, win, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
/*
int modecount_return = 0;
XF86VidModeModeInfo *modesinfo = NULL;
XF86VidModeGetAllModeLines(display, DefaultScreen(display), &modecount_return, &modesinfo);
XF86VidModeSwitchToMode(display, DefaultScreen(display), video_mode);
XF86VidModeSetViewPort(display, DefaultScreen(display), 0, 0);
*/
int display_w = XDisplayWidth(display, 0);
int display_h = XDisplayHeight(display, 0);
LOG("Fullscreen : %d x %d", display_w, display_h);
XMoveResizeWindow(display, win, 0, 0, display_w, display_h);
XMapRaised(display, win);
XGrabPointer(display, win, True, 0, GrabModeAsync, GrabModeAsync, win, 0L, CurrentTime);
XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
}
#endif
XWindowChanges changes = { .width=width, .height=height };
XConfigureWindow(display, win, CWWidth|CWHeight, &changes);
_create_image();
_size_hints_set_fixed();
}
void video_init() {
XSetWindowAttributes attribs;
unsigned long attribmask;
@ -652,12 +791,8 @@ void video_init() {
//unsigned int display_width, display_height;
XGCValues xgcvalues;
int valuemask;
char *window_name = "Apple ][";
char *window_name = "Apple //ix";
char *icon_name = window_name;
XSizeHints *size_hints;
XWMHints *wm_hints;
XClassHint *class_hints;
XTextProperty windowName, iconName;
//GC gc;
char *progname; /* name this program was invoked by */
char *displayname = NULL;
@ -728,7 +863,7 @@ void video_init() {
unsigned int shift = 0;
for (unsigned int i=0; i<4; i++)
{
if ((((uint32_t)visualinfo.red_mask >>shift) & 0xff) == (uint32_t)0xff)
if ((((uint32_t)visualinfo.red_mask >>shift) & 0xff) == (uint32_t)0xff)
{
red_shift = shift;
}
@ -757,6 +892,11 @@ void video_init() {
fprintf(stderr, "red mask:%08x green mask:%08x blue mask:%08x\n", (uint32_t)visualinfo.red_mask, (uint32_t)visualinfo.blue_mask, (uint32_t)visualinfo.green_mask);
fprintf(stderr, "redshift:%08d greenshift:%08d blueshift:%08d alphashift:%08d\n", red_shift, blue_shift, green_shift, alpha_shift);
scale = a2_video_mode;
if (a2_video_mode == VIDEO_FULLSCREEN) {
scale = 1; // HACK FIXME FOR NOW ...
}
/* Note that in a real Xlib application, x and y would default to 0
* but would be settable from the command line or resource database.
*/
@ -811,16 +951,6 @@ void video_init() {
attribmask,
&attribs);
/* set size hints for window manager. We don't want the user to
* dynamically allocate window size since we won't do the right
* scaling in response. Whaddya want, performance or a snazzy gui?
*/
size_hints->flags = PPosition | PSize | PMinSize | PMaxSize;
size_hints->min_width = width;
size_hints->min_height = height;
size_hints->max_width = width;
size_hints->max_height = height;
/* store window_name and icon_name for niceity. */
if (XStringListToTextProperty(&window_name, 1, &windowName) == 0)
{
@ -842,6 +972,7 @@ void video_init() {
class_hints->res_name = progname;
class_hints->res_class = "Apple2";
_size_hints_set_fixed();
XSetWMProperties(display, win, &windowName, &iconName,
argv, argc, size_hints, wm_hints,
class_hints);
@ -868,53 +999,9 @@ void video_init() {
}
}
// pad pixels to uint32_t boundaries
int bitmap_pad = sizeof(uint32_t);
int pixel_buffer_size = width*height*bitmap_pad;
xshmeventtype = XShmGetEventBase(display) + ShmCompletion;
/* create the image */
if (doShm)
{
image = XShmCreateImage(display, visualinfo.visual, visualinfo.depth, ZPixmap, NULL, &xshminfo, width, height);
if (!image)
{
fprintf(stderr, "XShmCreateImage failed\n");
exit(1);
}
printf("Allocating shared memory: bytes_per_line:%ds height:x%d (depth:%d) bitmap_pad:%d\n",
image->bytes_per_line, image->height, visualinfo.depth, bitmap_pad);
getshm(pixel_buffer_size);
/* get the X server to attach to it */
if (!XShmAttach(display, &xshminfo))
{
fprintf(stderr, "XShmAttach() failed in InitGraphics()\n");
exit(1);
}
}
else
{
void *data = malloc(pixel_buffer_size); // pad to uint32_t
if (!data)
{
fprintf(stderr, "no memory for image data!\n");
exit(1);
}
printf("Creating regular XImage\n");
image = XCreateImage(display, visualinfo.visual, visualinfo.depth, ZPixmap, 0 /*offset*/, data, width, height, 8, width*bitmap_pad /*bytes_per_line*/);
if (!image)
{
fprintf(stderr, "XCreateImage failed\n");
exit(1);
}
}
_create_image();
video__fb1 = vga_mem_page_0;
video__fb2 = vga_mem_page_1;
@ -936,25 +1023,7 @@ void video_init() {
void video_shutdown(void)
{
if (doShm)
{
// Detach from X server
if (!XShmDetach(display, &xshminfo))
{
fprintf(stderr,"XShmDetach() failed in video_shutdown()\n");
}
// Release shared memory.
shmdt(xshminfo.shmaddr);
shmctl(xshminfo.shmid, IPC_RMID, 0);
// Paranoia.
image->data = NULL;
}
else
{
free(image->data);
}
_destroy_image();
exit(0);
}