#include "fbdev.h"
+#define PFX "fbdev: "
+
struct vout_fbdev {
int fd;
void *mem;
int fb_size;
int buffer_count;
int top_border, bottom_border;
+ void *mem_saved;
+ size_t mem_saved_size;
};
void *vout_fbdev_flip(struct vout_fbdev *fbdev)
{
if (fbdev->fbvar_new.bits_per_pixel != bpp ||
w != fbdev->fbvar_new.xres || h != fbdev->fbvar_new.yres)
- printf(" switching to %dx%d@%d\n", w, h, bpp);
+ printf(PFX "switching to %dx%d@%d\n", w, h, bpp);
fbdev->fbvar_new.xres = w;
fbdev->fbvar_new.yres = h;
fbdev->fbvar_new.yres_virtual = h_total;
ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
if (ret == -1) {
- perror("FBIOPUT_VSCREENINFO ioctl");
+ perror(PFX "FBIOPUT_VSCREENINFO ioctl");
return NULL;
}
fbdev->buffer_count = 1;
fbdev->buffer_write = 0;
- fprintf(stderr, "Warning: failed to increase virtual resolution, "
+ fprintf(stderr, PFX "Warning: failed to increase virtual resolution, "
"multibuffering disabled\n");
}
fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
if (fbdev->mem == MAP_FAILED && fbdev->buffer_count > 1) {
- fprintf(stderr, "Warning: can't map %zd bytes, doublebuffering disabled\n", mem_size);
+ fprintf(stderr, PFX "Warning: can't map %zd bytes, doublebuffering disabled\n", mem_size);
fbdev->buffer_count = 1;
fbdev->buffer_write = 0;
mem_size = fbdev->fb_size;
if (fbdev->mem == MAP_FAILED) {
fbdev->mem = NULL;
fbdev->mem_size = 0;
- perror("mmap framebuffer");
+ perror(PFX "mmap framebuffer");
return NULL;
}
fbdev->fd = open(fbdev_name, O_RDWR);
if (fbdev->fd == -1) {
- fprintf(stderr, "%s: ", fbdev_name);
+ fprintf(stderr, PFX "%s: ", fbdev_name);
perror("open");
goto fail_open;
}
ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old);
if (ret == -1) {
- perror("FBIOGET_VSCREENINFO ioctl");
+ perror(PFX "FBIOGET_VSCREENINFO ioctl");
goto fail;
}
if (pret == NULL)
goto fail;
- printf("%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_new.xres, fbdev->fbvar_new.yres,
- fbdev->fbvar_new.bits_per_pixel);
+ printf(PFX "%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_new.xres,
+ fbdev->fbvar_new.yres, fbdev->fbvar_new.bits_per_pixel);
*w = fbdev->fbvar_new.xres;
*h = fbdev->fbvar_new.yres;
ret = 0;
ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret);
if (ret != 0)
- fprintf(stderr, "Warning: vsync doesn't seem to be supported\n");
+ fprintf(stderr, PFX "Warning: vsync doesn't seem to be supported\n");
if (fbdev->buffer_count > 1) {
fbdev->buffer_write = 0;
ret = ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
if (ret != 0) {
fbdev->buffer_count = 1;
- fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n");
+ fprintf(stderr, PFX "Warning: can't pan display, doublebuffering disabled\n");
}
}
return NULL;
}
-void vout_fbdev_finish(struct vout_fbdev *fbdev)
+static void vout_fbdev_release(struct vout_fbdev *fbdev)
{
ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_old);
if (fbdev->mem != MAP_FAILED)
munmap(fbdev->mem, fbdev->mem_size);
+ fbdev->mem = NULL;
+}
+
+int vout_fbdev_save(struct vout_fbdev *fbdev)
+{
+ void *tmp;
+
+ if (fbdev == NULL || fbdev->mem == NULL || fbdev->mem == MAP_FAILED) {
+ fprintf(stderr, PFX "bad args for save\n");
+ return -1;
+ }
+
+ if (fbdev->mem_saved_size < fbdev->mem_size) {
+ tmp = realloc(fbdev->mem_saved, fbdev->mem_size);
+ if (tmp == NULL)
+ return -1;
+ fbdev->mem_saved = tmp;
+ }
+ memcpy(fbdev->mem_saved, fbdev->mem, fbdev->mem_size);
+ fbdev->mem_saved_size = fbdev->mem_size;
+
+ vout_fbdev_release(fbdev);
+ return 0;
+}
+
+int vout_fbdev_restore(struct vout_fbdev *fbdev)
+{
+ int ret;
+
+ if (fbdev == NULL || fbdev->mem != NULL) {
+ fprintf(stderr, PFX "bad args/state for restore\n");
+ return -1;
+ }
+
+ fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
+ if (fbdev->mem == MAP_FAILED) {
+ perror(PFX "restore: memory restore failed");
+ return -1;
+ }
+ memcpy(fbdev->mem, fbdev->mem_saved, fbdev->mem_size);
+
+ ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
+ if (ret == -1) {
+ perror(PFX "restore: FBIOPUT_VSCREENINFO");
+ return -1;
+ }
+
+ return 0;
+}
+
+void vout_fbdev_finish(struct vout_fbdev *fbdev)
+{
+ vout_fbdev_release(fbdev);
if (fbdev->fd >= 0)
close(fbdev->fd);
- fbdev->mem = NULL;
fbdev->fd = -1;
free(fbdev);
}
void vout_fbdev_clear(struct vout_fbdev *fbdev);
void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count);
int vout_fbdev_get_fd(struct vout_fbdev *fbdev);
+int vout_fbdev_save(struct vout_fbdev *fbdev);
+int vout_fbdev_restore(struct vout_fbdev *fbdev);
void vout_fbdev_finish(struct vout_fbdev *fbdev);
#include <termios.h>
#include <linux/kd.h>
+#include "xenv.h"
+
#define PFX "xenv: "
#define FPTR(f) typeof(f) * p##f
return cursor;
}
-static int x11h_init(const char *window_title)
+static int x11h_init(int *xenv_flags, const char *window_title)
{
unsigned int display_width, display_height;
Display *display;
XSetWindowAttributes attributes;
Window win;
Visual *visual;
+ long evt_mask;
void *x11lib;
int screen;
attributes.cursor = transparent_cursor(&g_xstuff, display, win);
g_xstuff.pXChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes);
- g_xstuff.pXStoreName(display, win, window_title);
- g_xstuff.pXSelectInput(display, win,
- ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask);
+ if (window_title != NULL)
+ g_xstuff.pXStoreName(display, win, window_title);
+ evt_mask = ExposureMask | FocusChangeMask | PropertyChangeMask;
+ if (xenv_flags && (*xenv_flags & XENV_CAP_KEYS))
+ evt_mask |= KeyPressMask | KeyReleaseMask;
+ if (xenv_flags && (*xenv_flags & XENV_CAP_MOUSE))
+ evt_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
+ g_xstuff.pXSelectInput(display, win, evt_mask);
g_xstuff.pXMapWindow(display, win);
g_xstuff.pXGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
g_xstuff.pXkbSetDetectableAutoRepeat(display, 1, NULL);
return -1;
}
-static int x11h_update(int *is_down)
+static void x11h_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed),
+ int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed),
+ int (*mousem_cb)(void *cb_arg, int x, int y),
+ void *cb_arg)
{
XEvent evt;
+ int keysym;
while (g_xstuff.pXPending(g_xstuff.display))
{
g_xstuff.pXNextEvent(g_xstuff.display, &evt);
switch (evt.type)
{
- case Expose:
- while (g_xstuff.pXCheckTypedEvent(g_xstuff.display, Expose, &evt))
- ;
- default:
- // printf("event %d\n", evt.type);
- break;
-
- case KeyPress:
- *is_down = 1;
- return g_xstuff.pXLookupKeysym(&evt.xkey, 0);
-
- case KeyRelease:
- *is_down = 0;
- return g_xstuff.pXLookupKeysym(&evt.xkey, 0);
- // printf("press %d\n", evt.xkey.keycode);
+ case Expose:
+ while (g_xstuff.pXCheckTypedEvent(g_xstuff.display, Expose, &evt))
+ ;
+ break;
+
+ case KeyPress:
+ keysym = g_xstuff.pXLookupKeysym(&evt.xkey, 0);
+ if (key_cb != NULL)
+ key_cb(cb_arg, keysym, 1);
+ break;
+
+ case KeyRelease:
+ keysym = g_xstuff.pXLookupKeysym(&evt.xkey, 0);
+ if (key_cb != NULL)
+ key_cb(cb_arg, keysym, 0);
+ break;
+
+ case ButtonPress:
+ if (mouseb_cb != NULL)
+ mouseb_cb(cb_arg, evt.xbutton.x, evt.xbutton.y,
+ evt.xbutton.button, 1);
+ break;
+
+ case ButtonRelease:
+ if (mouseb_cb != NULL)
+ mouseb_cb(cb_arg, evt.xbutton.x, evt.xbutton.y,
+ evt.xbutton.button, 0);
+ break;
+
+ case MotionNotify:
+ if (mousem_cb != NULL)
+ mousem_cb(cb_arg, evt.xmotion.x, evt.xmotion.y);
+ break;
}
}
-
- return NoSymbol;
}
static void x11h_wait_vmstate(void)
usleep(200000);
}
- printf("timeout waiting for wm_state change\n");
+ fprintf(stderr, PFX "timeout waiting for wm_state change\n");
}
static int x11h_minimize(void)
g_kbdfd = -1;
}
-int xenv_init(const char *window_title)
+int xenv_init(int *xenv_flags, const char *window_title)
{
int ret;
- ret = x11h_init(window_title);
+ ret = x11h_init(xenv_flags, window_title);
if (ret == 0)
- return 0;
+ goto out;
+ if (xenv_flags != NULL)
+ *xenv_flags &= ~(XENV_CAP_KEYS | XENV_CAP_MOUSE); /* TODO? */
ret = tty_init();
if (ret == 0)
- return 0;
+ goto out;
fprintf(stderr, PFX "error: both x11h_init and tty_init failed\n");
- return -1;
+ ret = -1;
+out:
+ return ret;
}
-int xenv_update(int *is_down)
+int xenv_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed),
+ int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed),
+ int (*mousem_cb)(void *cb_arg, int x, int y),
+ void *cb_arg)
{
- if (g_xstuff.display)
- return x11h_update(is_down);
+ if (g_xstuff.display) {
+ x11h_update(key_cb, mouseb_cb, mousem_cb, cb_arg);
+ return 0;
+ }
// TODO: read tty?
return -1;
}
-/* blocking minimize until user maximazes again */
+/* blocking minimize until user maximizes again */
int xenv_minimize(void)
{
- int ret, dummy;
+ int ret;
if (g_xstuff.display) {
- xenv_update(&dummy);
+ xenv_update(NULL, NULL, NULL, NULL);
ret = x11h_minimize();
- xenv_update(&dummy);
+ xenv_update(NULL, NULL, NULL, NULL);
return ret;
}
-int xenv_init(const char *window_title);
-int xenv_update(int *is_down);
+#define XENV_CAP_KEYS (1<<0)
+#define XENV_CAP_MOUSE (1<<1)
+
+/* xenv_flags specify if we need keys and mouse,
+ * on return, flag is removed if input is not available */
+int xenv_init(int *xenv_flags, const char *window_title);
+
+/* read events from X, calling key_cb for key, mouseb_cb for mouse button
+ * and mousem_cb for mouse motion events */
+int xenv_update(int (*key_cb)(void *cb_arg, int kc, int is_pressed),
+ int (*mouseb_cb)(void *cb_arg, int x, int y, int button, int is_pressed),
+ int (*mousem_cb)(void *cb_arg, int x, int y),
+ void *cb_arg);
+
int xenv_minimize(void);
void xenv_finish(void);
void plat_video_menu_enter(int is_rom_loaded)
{
- int dummy;
-
g_menuscreen_ptr = vout_fbdev_resize(main_fb,
g_menuscreen_w, g_menuscreen_h, 16, 0, 0, 0, 0, 3);
if (g_menuscreen_ptr == NULL)
fprintf(stderr, "warning: vout_fbdev_resize failed\n");
- // hmh
- xenv_update(&dummy);
+ xenv_update(NULL, NULL, NULL, NULL);
}
void plat_video_menu_begin(void)
exit(1);
}
- xenv_init("PCSX-ReARMed");
+ xenv_init(NULL, "PCSX-ReARMed");
w = h = 0;
main_fb = vout_fbdev_init(main_fb_name, &w, &h, 16, 2);