diff options
Diffstat (limited to 'backends/x11/x11.cpp')
-rw-r--r-- | backends/x11/x11.cpp | 990 |
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, ¶m) != 0) { + error("Error in the SNDCTL_DSP_SETFRAGMENT ioctl !\n"); + exit(1); + } + param = AFMT_S16_LE; + if (ioctl(sound_fd, SNDCTL_DSP_SETFMT, ¶m) == -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, ¶m) == -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, ¶m) == -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(¤t_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); +} |