aboutsummaryrefslogtreecommitdiff
path: root/backends/x11/x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backends/x11/x11.cpp')
-rw-r--r--backends/x11/x11.cpp990
1 files changed, 990 insertions, 0 deletions
diff --git a/backends/x11/x11.cpp b/backends/x11/x11.cpp
new file mode 100644
index 0000000000..2ebbe96193
--- /dev/null
+++ b/backends/x11/x11.cpp
@@ -0,0 +1,990 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001/2002 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+/* The bare pure X11 port done by Lionel 'BBrox' Ulmer */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "mididrv.h"
+#include "gameDetector.h"
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+#ifdef USE_XV_SCALING
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+#endif
+#include <linux/soundcard.h>
+
+#include <sched.h>
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+class OSystem_X11:public OSystem {
+public:
+ // Set colors of the palette
+ void set_palette(const byte *colors, uint start, uint num);
+
+ // Set the size of the video bitmap.
+ // Typically, 320x200
+ void init_size(uint w, uint h);
+
+ // Draw a bitmap to screen.
+ // The screen will not be updated to reflect the new bitmap
+ void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h);
+
+ // Update the dirty areas of the screen
+ void update_screen();
+
+ // Either show or hide the mouse cursor
+ bool show_mouse(bool visible);
+
+ // Set the position of the mouse cursor
+ void set_mouse_pos(int x, int y);
+
+ // Set the bitmap that's used when drawing the cursor.
+ void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y);
+
+ // Shaking is used in SCUMM. Set current shake position.
+ void set_shake_pos(int shake_pos);
+
+ // Get the number of milliseconds since the program was started.
+ uint32 get_msecs();
+
+ // Delay for a specified amount of milliseconds
+ void delay_msecs(uint msecs);
+
+ // Create a thread
+ void *create_thread(ThreadProc *proc, void *param);
+
+ // Get the next event.
+ // Returns true if an event was retrieved.
+ bool poll_event(Event *event);
+
+ // Set function that generates samples
+ bool set_sound_proc(void *param, SoundProc *proc, byte sound);
+
+ // Poll cdrom status
+ // Returns true if cd audio is playing
+ bool poll_cdrom();
+
+ // Play cdrom audio track
+ void play_cdrom(int track, int num_loops, int start_frame, int end_frame);
+
+ // Stop cdrom audio track
+ void stop_cdrom();
+
+ // Update cdrom audio status
+ void update_cdrom();
+
+ // Quit
+ void quit();
+
+ // Set a parameter
+ uint32 property(int param, Property *value);
+
+ // Add a callback timer
+ void set_timer(int timer, int (*callback) (int));
+
+ // Mutex handling
+ void *create_mutex(void);
+ void lock_mutex(void *mutex);
+ void unlock_mutex(void *mutex);
+ void delete_mutex(void *mutex);
+
+ static OSystem *create(int gfx_mode, bool full_screen);
+
+private:
+ OSystem_X11();
+
+ typedef struct {
+ int x, y, w, h;
+ } dirty_square;
+
+ void create_empty_cursor();
+ void undraw_mouse();
+ void draw_mouse();
+ void update_screen_helper(const dirty_square * d, dirty_square * dout);
+
+ unsigned char *local_fb;
+
+ int window_width, window_height;
+ int fb_width, fb_height;
+ int scumm_x, scumm_y;
+
+#ifdef USE_XV_SCALING
+ unsigned int *palette;
+#else
+ unsigned short *palette;
+#endif
+ bool _palette_changed;
+ Display *display;
+ int screen;
+ Window window;
+ GC black_gc;
+#ifdef USE_XV_SCALING
+ XvImage *image;
+#else
+ XImage *image;
+#endif
+ pthread_t sound_thread;
+
+ int fake_right_mouse;
+ int report_presses;
+ int current_shake_pos;
+ int new_shake_pos;
+ struct timeval start_time;
+
+ enum {
+ MAX_NUMBER_OF_DIRTY_SQUARES = 32,
+ BAK_WIDTH = 40,
+ BAK_HEIGHT = 40
+ };
+ dirty_square ds[MAX_NUMBER_OF_DIRTY_SQUARES];
+ int num_of_dirty_square;
+
+ typedef struct {
+ int x, y;
+ int w, h;
+ int hot_x, hot_y;
+ } mouse_state;
+ mouse_state old_state, cur_state;
+ const byte *_ms_buf;
+ byte _ms_backup[BAK_WIDTH * BAK_HEIGHT];
+ bool _mouse_drawn;
+ bool _mouse_visible;
+
+ unsigned int _timer_duration, _timer_next_expiry;
+ bool _timer_active;
+ int (*_timer_callback) (int);
+};
+
+typedef struct {
+ OSystem::SoundProc *sound_proc;
+ void *param;
+ byte format;
+} THREAD_PARAM;
+
+#undef CAPTURE_SOUND
+
+#define FRAG_SIZE 4096
+static void *sound_and_music_thread(void *params)
+{
+ /* Init sound */
+ int sound_fd, param, frag_size;
+ unsigned char sound_buffer[FRAG_SIZE];
+ OSystem::SoundProc *sound_proc = ((THREAD_PARAM *) params)->sound_proc;
+ void *proc_param = ((THREAD_PARAM *) params)->param;
+
+#ifdef CAPTURE_SOUND
+ FILE *f = fopen("sound.raw", "wb");
+#endif
+
+ sound_fd = open("/dev/dsp", O_WRONLY);
+ audio_buf_info info;
+ if (sound_fd < 0) {
+ error("Error opening sound device !\n");
+ exit(1);
+ }
+ param = 0;
+ frag_size = FRAG_SIZE /* audio fragment size */ ;
+ while (frag_size) {
+ frag_size >>= 1;
+ param++;
+ }
+ param--;
+ param |= /* audio_fragment_num */ 3 << 16;
+ if (ioctl(sound_fd, SNDCTL_DSP_SETFRAGMENT, &param) != 0) {
+ error("Error in the SNDCTL_DSP_SETFRAGMENT ioctl !\n");
+ exit(1);
+ }
+ param = AFMT_S16_LE;
+ if (ioctl(sound_fd, SNDCTL_DSP_SETFMT, &param) == -1) {
+ perror("Error in the SNDCTL_DSP_SETFMT ioctl !\n");
+ exit(1);
+ }
+ if (param != AFMT_S16_LE) {
+ error("AFMT_S16_LE not supported !\n");
+ exit(1);
+ }
+ param = 2;
+ if (ioctl(sound_fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
+ error("Error in the SNDCTL_DSP_CHANNELS ioctl !\n");
+ exit(1);
+ }
+ if (param != 2) {
+ error("Stereo mode not supported !\n");
+ exit(1);
+ }
+ param = 22050;
+ if (ioctl(sound_fd, SNDCTL_DSP_SPEED, &param) == -1) {
+ perror("Error in the SNDCTL_DSP_SPEED ioctl !\n");
+ exit(1);
+ }
+ if (param != 22050) {
+ error("22050 kHz not supported !\n");
+ exit(1);
+ }
+ if (ioctl(sound_fd, SNDCTL_DSP_GETOSPACE, &info) != 0) {
+ perror("SNDCTL_DSP_GETOSPACE");
+ exit(-1);
+ }
+
+ sched_yield();
+ while (1) {
+ unsigned char *buf = (unsigned char *)sound_buffer;
+ int size, written;
+
+ sound_proc(proc_param, (byte *)sound_buffer, FRAG_SIZE);
+#ifdef CAPTURE_SOUND
+ fwrite(buf, 2, FRAG_SIZE >> 1, f);
+ fflush(f);
+#endif
+ size = FRAG_SIZE;
+ while (size > 0) {
+ written = write(sound_fd, buf, size);
+ buf += written;
+ size -= written;
+ }
+ }
+
+ return NULL;
+}
+
+/* Function used to hide the mouse cursor */
+void OSystem_X11::create_empty_cursor()
+{
+ XColor bg;
+ Pixmap pixmapBits;
+ Cursor cursor = None;
+ static const char data[] = { 0 };
+
+ bg.red = bg.green = bg.blue = 0x0000;
+ pixmapBits = XCreateBitmapFromData(display, XRootWindow(display, screen), data, 1, 1);
+ if (pixmapBits) {
+ cursor = XCreatePixmapCursor(display, pixmapBits, pixmapBits, &bg, &bg, 0, 0);
+ XFreePixmap(display, pixmapBits);
+ }
+ XDefineCursor(display, window, cursor);
+}
+
+OSystem *OSystem_X11_create(void)
+{
+ return OSystem_X11::create(0, 0);
+}
+
+OSystem *OSystem_X11::create(int gfx_mode, bool full_screen)
+{
+ OSystem_X11 *syst = new OSystem_X11();
+ return syst;
+}
+
+OSystem_X11::OSystem_X11()
+{
+ char buf[512];
+ XWMHints *wm_hints;
+ XGCValues values;
+ XTextProperty window_name;
+ char *name = (char *)&buf;
+
+ /* Some members initialization */
+ fake_right_mouse = 0;
+ report_presses = 1;
+ current_shake_pos = 0;
+ new_shake_pos = 0;
+ _palette_changed = false;
+ num_of_dirty_square = MAX_NUMBER_OF_DIRTY_SQUARES;
+
+ /* For the window title */
+ sprintf(buf, "ScummVM");
+
+ display = XOpenDisplay(NULL);
+ if (display == NULL) {
+ error("Could not open display !\n");
+ exit(1);
+ }
+ screen = DefaultScreen(display);
+
+ window_width = 320;
+ window_height = 200;
+ scumm_x = 0;
+ scumm_y = 0;
+ window = XCreateSimpleWindow(display, XRootWindow(display, screen), 0, 0, 320, 200, 0, 0, 0);
+ wm_hints = XAllocWMHints();
+ if (wm_hints == NULL) {
+ error("Not enough memory to allocate Hints !\n");
+ exit(1);
+ }
+ wm_hints->flags = InputHint | StateHint;
+ wm_hints->input = True;
+ wm_hints->initial_state = NormalState;
+ XStringListToTextProperty(&name, 1, &window_name);
+ XSetWMProperties(display, window, &window_name, &window_name,
+ NULL /* argv */ , 0 /* argc */ , NULL /* size hints */ ,
+ wm_hints, NULL /* class hints */ );
+ XFree(wm_hints);
+
+ XSelectInput(display, window,
+ ExposureMask | KeyPressMask | KeyReleaseMask |
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
+
+ values.foreground = BlackPixel(display, screen);
+ black_gc = XCreateGC(display, window, GCForeground, &values);
+
+ XMapWindow(display, window);
+ XFlush(display);
+
+ while (1) {
+ XEvent event;
+ XNextEvent(display, &event);
+ switch (event.type) {
+ case Expose:
+ goto out_of_loop;
+ }
+ }
+out_of_loop:
+ create_empty_cursor();
+
+ /* Initialize the timer routines */
+ _timer_active = false;
+
+ /* And finally start the local timer */
+ gettimeofday(&start_time, NULL);
+}
+
+uint32 OSystem_X11::get_msecs()
+{
+ struct timeval current_time;
+ gettimeofday(&current_time, NULL);
+ return (uint32)(((current_time.tv_sec - start_time.tv_sec) * 1000) +
+ ((current_time.tv_usec - start_time.tv_usec) / 1000));
+}
+
+void OSystem_X11::init_size(uint w, uint h)
+{
+ static XShmSegmentInfo shminfo;
+
+ fb_width = w;
+ fb_height = h;
+
+ if ((fb_width != 320) || (fb_height != 200)) {
+ /* We need to change the size of the X11 window */
+ XWindowChanges new_values;
+
+ new_values.width = fb_width;
+ new_values.height = fb_height;
+
+ XConfigureWindow(display, window, CWWidth | CWHeight, &new_values);
+ }
+#ifdef USE_XV_SCALING
+ image = XvShmCreateImage(display, 65, 0x03, 0, fb_width, fb_height, &shminfo);
+ shminfo.shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0700);
+#else
+ image =
+ XShmCreateImage(display, DefaultVisual(display, screen), 16, ZPixmap, NULL, &shminfo, fb_width,
+ fb_height);
+ shminfo.shmid = shmget(IPC_PRIVATE, fb_width * fb_height * 2, IPC_CREAT | 0700);
+#endif
+ shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0);
+ image->data = shminfo.shmaddr;
+ shminfo.readOnly = False;
+ if (XShmAttach(display, &shminfo) == 0) {
+ error("Could not attach shared memory segment !\n");
+ exit(1);
+ }
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+
+ /* Initialize the 'local' frame buffer and the palette */
+ local_fb = (unsigned char *)calloc(fb_width * fb_height, sizeof(unsigned char));
+#ifdef USE_XV_SCALING
+ palette = (unsigned int *)calloc(256, sizeof(unsigned int));
+#else
+ palette = (unsigned short *)calloc(256, sizeof(unsigned short));
+#endif
+}
+
+bool OSystem_X11::set_sound_proc(void *param, SoundProc *proc, byte format)
+{
+ static THREAD_PARAM thread_param;
+
+ /* And finally start the music thread */
+ thread_param.param = param;
+ thread_param.sound_proc = proc;
+ thread_param.format = format;
+
+ if (format == SOUND_16BIT)
+ pthread_create(&sound_thread, NULL, sound_and_music_thread, (void *)&thread_param);
+ else
+ warning("Only support 16 bit sound for now. Disabling sound ");
+
+ return true;
+}
+
+void OSystem_X11::set_palette(const byte *colors, uint start, uint num)
+{
+ const byte *data = colors;
+#ifdef USE_XV_SCALING
+ unsigned int *pal = &(palette[start]);
+#else
+ unsigned short *pal = &(palette[start]);
+#endif
+
+ do {
+#ifdef USE_XV_SCALING
+ *pal++ = (data[0] << 16) | (data[1] << 8) | data[2];
+#else
+ *pal++ = ((data[0] & 0xF8) << 8) | ((data[1] & 0xFC) << 3) | (data[2] >> 3);
+#endif
+ data += 4;
+ num--;
+ } while (num > 0);
+
+ _palette_changed = true;
+}
+
+#define AddDirtyRec(xi,yi,wi,hi) \
+ if (num_of_dirty_square < MAX_NUMBER_OF_DIRTY_SQUARES) { \
+ ds[num_of_dirty_square].x = xi; \
+ ds[num_of_dirty_square].y = yi; \
+ ds[num_of_dirty_square].w = wi; \
+ ds[num_of_dirty_square].h = hi; \
+ num_of_dirty_square++; \
+ }
+
+void OSystem_X11::copy_rect(const byte *buf, int pitch, int x, int y, int w, int h)
+{
+ unsigned char *dst;
+
+ if (y < 0) {
+ h += y;
+ buf -= y * pitch;
+ y = 0;
+ }
+ if (h > (fb_height - y)) {
+ h = fb_height - y;
+ }
+
+ dst = local_fb + fb_width * y + x;
+
+ if (h <= 0)
+ return;
+
+ if (_mouse_drawn)
+ undraw_mouse();
+
+ AddDirtyRec(x, y, w, h);
+ while (h-- > 0) {
+ memcpy(dst, buf, w);
+ dst += fb_width;
+ buf += pitch;
+ }
+}
+
+void OSystem_X11::update_screen_helper(const dirty_square * d, dirty_square * dout)
+{
+ int x, y;
+ unsigned char *ptr_src = local_fb + (fb_width * d->y) + d->x;
+#ifdef USE_XV_SCALING
+ unsigned int *ptr_dst = ((unsigned int *)image->data) + (fb_width * d->y) + d->x;
+#else
+ unsigned short *ptr_dst = ((unsigned short *)image->data) + (fb_width * d->y) + d->x;
+#endif
+
+ for (y = 0; y < d->h; y++) {
+ for (x = 0; x < d->w; x++) {
+ *ptr_dst++ = palette[*ptr_src++];
+ }
+ ptr_dst += fb_width - d->w;
+ ptr_src += fb_width - d->w;
+ }
+ if (d->x < dout->x)
+ dout->x = d->x;
+ if (d->y < dout->y)
+ dout->y = d->y;
+ if ((d->x + d->w) > dout->w)
+ dout->w = d->x + d->w;
+ if ((d->y + d->h) > dout->h)
+ dout->h = d->y + d->h;
+}
+
+void OSystem_X11::update_screen()
+{
+ bool full_redraw = false;
+ bool need_redraw = false;
+ static const dirty_square ds_full = { 0, 0, fb_width, fb_height };
+ dirty_square dout = { fb_width, fb_height, 0, 0 };
+
+ /* First make sure the mouse is drawn, if it should be drawn. */
+ draw_mouse();
+
+ if (_palette_changed) {
+ full_redraw = true;
+ num_of_dirty_square = 0;
+ _palette_changed = false;
+ } else if (num_of_dirty_square >= MAX_NUMBER_OF_DIRTY_SQUARES) {
+ full_redraw = true;
+ num_of_dirty_square = 0;
+ }
+
+ if (full_redraw) {
+ update_screen_helper(&ds_full, &dout);
+ need_redraw = true;
+ } else if (num_of_dirty_square > 0) {
+ need_redraw = true;
+ while (num_of_dirty_square > 0) {
+ num_of_dirty_square--;
+ update_screen_helper(&(ds[num_of_dirty_square]), &dout);
+ }
+ }
+
+ if (current_shake_pos != new_shake_pos) {
+ /* Redraw first the 'black borders' in case of resize */
+ if (current_shake_pos < new_shake_pos)
+ XFillRectangle(display, window, black_gc, 0, current_shake_pos, window_width, new_shake_pos);
+ else
+ XFillRectangle(display, window, black_gc, 0, window_height - current_shake_pos,
+ window_width, window_height - new_shake_pos);
+#ifndef USE_XV_SCALING
+ XShmPutImage(display, window, DefaultGC(display, screen), image,
+ 0, 0, scumm_x, scumm_y + new_shake_pos, fb_width, fb_height, 0);
+#endif
+ current_shake_pos = new_shake_pos;
+ } else if (need_redraw == true) {
+#ifdef USE_XV_SCALING
+ XvShmPutImage(display, 65, window, DefaultGC(display, screen), image,
+ 0, 0, fb_width, fb_height, 0, 0, window_width, window_height, 0);
+#else
+ XShmPutImage(display, window, DefaultGC(display, screen), image,
+ dout.x, dout.y, scumm_x + dout.x, scumm_y + dout.y + current_shake_pos,
+ dout.w - dout.x, dout.h - dout.y, 0);
+#endif
+ XFlush(display);
+ }
+}
+
+bool OSystem_X11::show_mouse(bool visible)
+{
+ if (_mouse_visible == visible)
+ return visible;
+
+ bool last = _mouse_visible;
+ _mouse_visible = visible;
+
+ if (visible)
+ draw_mouse();
+ else
+ undraw_mouse();
+
+ return last;
+}
+
+void OSystem_X11::quit()
+{
+ exit(1);
+}
+
+void OSystem_X11::draw_mouse()
+{
+ if (_mouse_drawn || !_mouse_visible)
+ return;
+ _mouse_drawn = true;
+
+ int xdraw = cur_state.x - cur_state.hot_x;
+ int ydraw = cur_state.y - cur_state.hot_y;
+ int w = cur_state.w;
+ int h = cur_state.h;
+ int real_w;
+ int real_h;
+ int real_h_2;
+
+ byte *dst;
+ byte *dst2;
+ const byte *buf = _ms_buf;
+ byte *bak = _ms_backup;
+
+ assert(w <= BAK_WIDTH && h <= BAK_HEIGHT);
+
+ if (ydraw < 0) {
+ real_h = h + ydraw;
+ buf += (-ydraw) * w;
+ ydraw = 0;
+ } else {
+ real_h = (ydraw + h) > fb_height ? (fb_height - ydraw) : h;
+ }
+ if (xdraw < 0) {
+ real_w = w + xdraw;
+ buf += (-xdraw);
+ xdraw = 0;
+ } else {
+ real_w = (xdraw + w) > fb_width ? (fb_width - xdraw) : w;
+ }
+
+ dst = local_fb + (ydraw * fb_width) + xdraw;
+ dst2 = dst;
+
+ if ((real_h == 0) || (real_w == 0)) {
+ _mouse_drawn = false;
+ return;
+ }
+
+ AddDirtyRec(xdraw, ydraw, real_w, real_h);
+ old_state.x = xdraw;
+ old_state.y = ydraw;
+ old_state.w = real_w;
+ old_state.h = real_h;
+
+ real_h_2 = real_h;
+ while (real_h_2 > 0) {
+ memcpy(bak, dst, real_w);
+ bak += BAK_WIDTH;
+ dst += fb_width;
+ real_h_2--;
+ }
+ while (real_h > 0) {
+ int width = real_w;
+ while (width > 0) {
+ byte color = *buf;
+ if (color != 0xFF) {
+ *dst2 = color;
+ }
+ buf++;
+ dst2++;
+ width--;
+ }
+ buf += w - real_w;
+ dst2 += fb_width - real_w;
+ real_h--;
+ }
+}
+
+void OSystem_X11::undraw_mouse()
+{
+ if (!_mouse_drawn)
+ return;
+ _mouse_drawn = false;
+
+ int old_h = old_state.h;
+
+ AddDirtyRec(old_state.x, old_state.y, old_state.w, old_state.h);
+
+ byte *dst = local_fb + (old_state.y * fb_width) + old_state.x;
+ byte *bak = _ms_backup;
+
+ while (old_h > 0) {
+ memcpy(dst, bak, old_state.w);
+ bak += BAK_WIDTH;
+ dst += fb_width;
+ old_h--;
+ }
+}
+
+void OSystem_X11::set_mouse_pos(int x, int y)
+{
+ if ((x != cur_state.x) || (y != cur_state.y)) {
+ cur_state.x = x;
+ cur_state.y = y;
+ undraw_mouse();
+ }
+}
+
+void OSystem_X11::set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y)
+{
+ cur_state.w = w;
+ cur_state.h = h;
+ cur_state.hot_x = hotspot_x;
+ cur_state.hot_y = hotspot_y;
+ _ms_buf = (byte *)buf;
+
+ undraw_mouse();
+}
+
+void OSystem_X11::set_shake_pos(int shake_pos)
+{
+ new_shake_pos = shake_pos;
+}
+
+void *OSystem_X11::create_thread(ThreadProc *proc, void *param)
+{
+ pthread_t *thread = (pthread_t *) malloc(sizeof(pthread_t));
+ if (pthread_create(thread, NULL, (void *(*)(void *))proc, param))
+ return NULL;
+ else
+ return thread;
+}
+
+uint32 OSystem_X11::property(int param, Property *value)
+{
+ switch (param) {
+ case PROP_GET_SAMPLE_RATE:
+ return 22050;
+ case PROP_GET_FULLSCREEN:
+ return 0;
+ }
+ warning("Property not implemented yet (%d) ", param);
+ return 0;
+}
+
+bool OSystem_X11::poll_cdrom()
+{
+ return false;
+}
+
+void OSystem_X11::play_cdrom(int track, int num_loops, int start_frame, int end_frame)
+{
+}
+
+void OSystem_X11::stop_cdrom()
+{
+}
+
+void OSystem_X11::update_cdrom()
+{
+}
+
+void OSystem_X11::delay_msecs(uint msecs)
+{
+ usleep(msecs * 1000);
+}
+
+bool OSystem_X11::poll_event(Event *scumm_event)
+{
+ /* First, handle timers */
+ uint32 current_msecs = get_msecs();
+
+ if (_timer_active && (current_msecs >= _timer_next_expiry)) {
+ _timer_duration = _timer_callback(_timer_duration);
+ _timer_next_expiry = current_msecs + _timer_duration;
+ }
+
+ while (XPending(display)) {
+ XEvent event;
+
+ XNextEvent(display, &event);
+ switch (event.type) {
+ case Expose:{
+ int real_w, real_h;
+ int real_x, real_y;
+ real_x = event.xexpose.x;
+ real_y = event.xexpose.y;
+ real_w = event.xexpose.width;
+ real_h = event.xexpose.height;
+ if (real_x < scumm_x) {
+ real_w -= scumm_x - real_x;
+ real_x = 0;
+ } else {
+ real_x -= scumm_x;
+ }
+ if (real_y < scumm_y) {
+ real_h -= scumm_y - real_y;
+ real_y = 0;
+ } else {
+ real_y -= scumm_y;
+ }
+ if ((real_h <= 0) || (real_w <= 0))
+ break;
+ if ((real_x >= fb_width) || (real_y >= fb_height))
+ break;
+
+ if ((real_x + real_w) >= fb_width) {
+ real_w = fb_width - real_x;
+ }
+ if ((real_y + real_h) >= fb_height) {
+ real_h = fb_height - real_y;
+ }
+
+ /* Compute the intersection of the expose event with the real ScummVM display zone */
+ AddDirtyRec(real_x, real_y, real_w, real_h);
+ }
+ break;
+
+ case KeyPress:
+ switch (event.xkey.keycode) {
+ case 132:
+ report_presses = 0;
+ break;
+
+ case 133:
+ fake_right_mouse = 1;
+ break;
+ }
+ break;
+
+ case KeyRelease:{
+ /* I am using keycodes here and NOT keysyms to be sure that even if the user
+ remaps his iPAQ's keyboard, it will still work.
+ */
+ int keycode = -1;
+ int ascii = -1;
+ byte mode = 0;
+
+ if (event.xkey.state & 0x01)
+ mode |= KBD_SHIFT;
+ if (event.xkey.state & 0x04)
+ mode |= KBD_CTRL;
+ if (event.xkey.state & 0x08)
+ mode |= KBD_ALT;
+ switch (event.xkey.keycode) {
+ case 9: /* Escape on my PC */
+ case 130: /* Calendar on the iPAQ */
+ keycode = 27;
+ break;
+
+ case 71: /* F5 on my PC */
+ case 128: /* Record on the iPAQ */
+ keycode = 319;
+ break;
+
+ case 65: /* Space on my PC */
+ case 131: /* Schedule on the iPAQ */
+ keycode = 32;
+ break;
+
+ case 132: /* 'Q' on the iPAQ */
+ report_presses = 1;
+ break;
+
+ case 133: /* Arrow on the iPAQ */
+ fake_right_mouse = 0;
+ break;
+
+ default:{
+ KeySym xsym;
+ xsym = XKeycodeToKeysym(display, event.xkey.keycode, 0);
+ keycode = xsym;
+ if ((xsym >= 'a') && (xsym <= 'z') && (event.xkey.state & 0x01))
+ xsym &= ~0x20; /* Handle shifted keys */
+ ascii = xsym;
+ }
+ }
+ if (keycode != -1) {
+ scumm_event->event_code = EVENT_KEYDOWN;
+ scumm_event->kbd.keycode = keycode;
+ scumm_event->kbd.ascii = (ascii != -1 ? ascii : keycode);
+ scumm_event->kbd.flags = mode;
+ return true;
+ }
+ }
+ break;
+
+ case ButtonPress:
+ if (report_presses != 0) {
+ if (event.xbutton.button == 1) {
+ if (fake_right_mouse == 0) {
+ scumm_event->event_code = EVENT_LBUTTONDOWN;
+ } else {
+ scumm_event->event_code = EVENT_RBUTTONDOWN;
+ }
+ } else if (event.xbutton.button == 3)
+ scumm_event->event_code = EVENT_RBUTTONDOWN;
+ scumm_event->mouse.x = event.xbutton.x - scumm_x;
+ scumm_event->mouse.y = event.xbutton.y - scumm_y;
+ return true;
+ }
+ break;
+
+ case ButtonRelease:
+ if (report_presses != 0) {
+ if (event.xbutton.button == 1) {
+ if (fake_right_mouse == 0) {
+ scumm_event->event_code = EVENT_LBUTTONUP;
+ } else {
+ scumm_event->event_code = EVENT_RBUTTONUP;
+ }
+ } else if (event.xbutton.button == 3)
+ scumm_event->event_code = EVENT_RBUTTONUP;
+ scumm_event->mouse.x = event.xbutton.x - scumm_x;
+ scumm_event->mouse.y = event.xbutton.y - scumm_y;
+ return true;
+ }
+ break;
+
+ case MotionNotify:
+ scumm_event->event_code = EVENT_MOUSEMOVE;
+ scumm_event->mouse.x = event.xmotion.x - scumm_x;
+ scumm_event->mouse.y = event.xmotion.y - scumm_y;
+ return true;
+
+ case ConfigureNotify:{
+ if ((window_width != event.xconfigure.width) || (window_height != event.xconfigure.height)) {
+ window_width = event.xconfigure.width;
+ window_height = event.xconfigure.height;
+ scumm_x = (window_width - fb_width) / 2;
+ scumm_y = (window_height - fb_height) / 2;
+ XFillRectangle(display, window, black_gc, 0, 0, window_width, window_height);
+ }
+ }
+ break;
+
+ default:
+ printf("Unhandled event : %d\n", event.type);
+ break;
+ }
+ }
+
+ return false;
+}
+
+void OSystem_X11::set_timer(int timer, int (*callback) (int))
+{
+ if (callback != NULL) {
+ _timer_duration = timer;
+ _timer_next_expiry = get_msecs() + timer;
+ _timer_callback = callback;
+ _timer_active = true;
+ } else {
+ _timer_active = false;
+ }
+}
+
+void *OSystem_X11::create_mutex(void)
+{
+ pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+ pthread_mutex_init(mutex, NULL);
+ return (void *)mutex;
+}
+
+void OSystem_X11::lock_mutex(void *mutex)
+{
+ pthread_mutex_lock((pthread_mutex_t *) mutex);
+}
+
+void OSystem_X11::unlock_mutex(void *mutex)
+{
+ pthread_mutex_unlock((pthread_mutex_t *) mutex);
+}
+
+void OSystem_X11::delete_mutex(void *mutex)
+{
+ pthread_mutex_destroy((pthread_mutex_t *) mutex);
+ free(mutex);
+}