--- SheepShaver/src/Unix/video_x.cpp 2003/05/22 22:12:05 1.3 +++ SheepShaver/src/Unix/video_x.cpp 2004/01/12 15:37:22 1.11 @@ -1,7 +1,7 @@ /* * video_x.cpp - Video/graphics emulation, X11 specific stuff * - * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * SheepShaver (C) 1997-2004 Marc Hellwig and Christian Bauer * * 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 @@ -18,15 +18,25 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "sysdeps.h" + #include #include #include #include #include #include +#include #include -#include "sysdeps.h" +#ifdef ENABLE_XF86_DGA +#include +#endif + +#ifdef ENABLE_XF86_VIDMODE +# include +#endif + #include "main.h" #include "adb.h" #include "prefs.h" @@ -38,20 +48,18 @@ #define DEBUG 0 #include "debug.h" -#ifdef ENABLE_XF86_DGA -#include -#endif - -#ifdef ENABLE_XF86_VIDMODE -#include -#endif +// Constants +const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes"; // Global variables static int32 frame_skip; +static int16 mouse_wheel_mode; +static int16 mouse_wheel_lines; static bool redraw_thread_active = false; // Flag: Redraw thread installed static pthread_t redraw_thread; // Redraw thread +static bool local_X11; // Flag: X server running on local machine? static volatile bool thread_stop_req = false; static volatile bool thread_stop_ack = false; // Acknowledge for thread_stop_req @@ -73,6 +81,8 @@ static bool emerg_quit = false; // Fl static bool emul_suspended = false; // Flag: emulator suspended static Window suspend_win; // "Suspend" window static void *fb_save = NULL; // Saved frame buffer for suspend +static bool use_keycodes = false; // Flag: Use keycodes rather than keysyms +static int keycode_table[256]; // X keycode -> Mac keycode translation table // X11 variables static int screen; // Screen number @@ -118,12 +128,17 @@ static int num_x_video_modes; static void *redraw_func(void *arg); -// From main_linux.cpp +// From main_unix.cpp +extern char *x_display_name; extern Display *x_display; // From sys_unix.cpp extern void SysMountFirstFloppy(void); +// From clip_unix.cpp +extern void ClipboardSelectionClear(XSelectionClearEvent *); +extern void ClipboardSelectionRequest(XSelectionRequestEvent *); + // Video acceleration through SIGSEGV #ifdef ENABLE_VOSF @@ -157,11 +172,6 @@ static bool open_window(int width, int h // Set absolute mouse mode ADBSetRelMouseMode(false); - // Read frame skip prefs - frame_skip = PrefsFindInt32("frameskip"); - if (frame_skip == 0) - frame_skip = 1; - // Create window XSetWindowAttributes wattr; wattr.event_mask = eventmask = win_eventmask; @@ -195,12 +205,16 @@ static bool open_window(int width, int h XFree((char *)hints); } + // 1-bit mode is big-endian; if the X server is little-endian, we can't + // use SHM because that doesn't allow changing the image byte order + bool need_msb_image = (depth == 1 && XImageByteOrder(x_display) == LSBFirst); + // Try to create and attach SHM image have_shm = false; - if (depth != 1 && XShmQueryExtension(x_display)) { + if (local_X11 && !need_msb_image && XShmQueryExtension(x_display)) { // Create SHM image ("height + 2" for safety) - img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height); + img = XShmCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height); shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777); the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0); shminfo.shmaddr = img->data = (char *)the_buffer_copy; @@ -528,6 +542,71 @@ static void close_display(void) * Initialization */ +// Init keycode translation table +static void keycode_init(void) +{ + bool use_kc = PrefsFindBool("keycodes"); + if (use_kc) { + + // Get keycode file path from preferences + const char *kc_path = PrefsFindString("keycodefile"); + + // Open keycode table + FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r"); + if (f == NULL) { + char str[256]; + sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno)); + WarningAlert(str); + return; + } + + // Default translation table + for (int i=0; i<256; i++) + keycode_table[i] = -1; + + // Search for server vendor string, then read keycodes + const char *vendor = ServerVendor(x_display); + bool vendor_found = false; + char line[256]; + while (fgets(line, 255, f)) { + // Read line + int len = strlen(line); + if (len == 0) + continue; + line[len-1] = 0; + + // Comments begin with "#" or ";" + if (line[0] == '#' || line[0] == ';' || line[0] == 0) + continue; + + if (vendor_found) { + // Read keycode + int x_code, mac_code; + if (sscanf(line, "%d %d", &x_code, &mac_code) == 2) + keycode_table[x_code & 0xff] = mac_code; + else + break; + } else { + // Search for vendor string + if (strstr(vendor, line) == vendor) + vendor_found = true; + } + } + + // Keycode file completely read + fclose(f); + use_keycodes = vendor_found; + + // Vendor not found? Then display warning + if (!vendor_found) { + char str[256]; + sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), vendor, kc_path ? kc_path : KEYCODE_FILE_NAME); + WarningAlert(str); + return; + } + } +} + static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type) { if (allow & test) { @@ -597,6 +676,22 @@ bool VideoInit(void) mainBuffer.pageInfo = NULL; #endif + // Check if X server runs on local machine + local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0) + || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0); + + // Init keycode translation + keycode_init(); + + // Read frame skip prefs + frame_skip = PrefsFindInt32("frameskip"); + if (frame_skip == 0) + frame_skip = 1; + + // Read mouse wheel prefs + mouse_wheel_mode = PrefsFindInt32("mousewheelmode"); + mouse_wheel_lines = PrefsFindInt32("mousewheellines"); + // Init variables private_data = NULL; cur_mode = 0; // Window 640x480 @@ -612,7 +707,7 @@ bool VideoInit(void) #ifdef ENABLE_XF86_DGA // DGA available? int event_base, error_base; - if (XF86DGAQueryExtension(x_display, &event_base, &error_base)) { + if (local_X11 && XF86DGAQueryExtension(x_display, &event_base, &error_base)) { int dga_flags = 0; XF86DGAQueryDirectVideo(x_display, screen, &dga_flags); has_dga = dga_flags & XF86DGADirectPresent; @@ -1068,14 +1163,14 @@ static int kc_decode(KeySym ks) return -1; } -static int event2keycode(XKeyEvent *ev) +static int event2keycode(XKeyEvent &ev) { KeySym ks; int as; int i = 0; do { - ks = XLookupKeysym(ev, i++); + ks = XLookupKeysym(&ev, i++); as = kc_decode(ks); if (as != -1) return as; @@ -1090,8 +1185,18 @@ static void handle_events(void) for (;;) { XEvent event; - if (!XCheckMaskEvent(x_display, eventmask, &event)) + XDisplayLock(); + if (!XCheckMaskEvent(x_display, eventmask, &event)) { + // Handle clipboard events + if (XCheckTypedEvent(x_display, SelectionRequest, &event)) + ClipboardSelectionRequest(&event.xselectionrequest); + else if (XCheckTypedEvent(x_display, SelectionClear, &event)) + ClipboardSelectionClear(&event.xselectionclear); + + XDisplayUnlock(); break; + } + XDisplayUnlock(); switch (event.type) { // Mouse button @@ -1099,6 +1204,19 @@ static void handle_events(void) unsigned int button = ((XButtonEvent *)&event)->button; if (button < 4) ADBMouseDown(button - 1); + else if (button < 6) { // Wheel mouse + if (mouse_wheel_mode == 0) { + int key = (button == 5) ? 0x79 : 0x74; // Page up/down + ADBKeyDown(key); + ADBKeyUp(key); + } else { + int key = (button == 5) ? 0x3d : 0x3e; // Cursor up/down + for(int i=0; i= frame_skip) { - tick_counter = 0; + // Refresh display and set cursor image in window mode + static int tick_counter = 0; + if (display_type == DIS_WINDOW) { + tick_counter++; + if (tick_counter >= frame_skip) { + tick_counter = 0; - // Update display + // Update display #ifdef ENABLE_VOSF - if (use_vosf) { - if (mainBuffer.dirty) { - LOCK_VOSF; - update_display_window_vosf(); - UNLOCK_VOSF; - XSync(x_display, false); // Let the server catch up + if (use_vosf) { + XDisplayLock(); + if (mainBuffer.dirty) { + LOCK_VOSF; + update_display_window_vosf(); + UNLOCK_VOSF; + XSync(x_display, false); // Let the server catch up + } + XDisplayUnlock(); } - } - else + else #endif - update_display(); + update_display(); - // Set new cursor image if it was changed - if (cursor_changed) { - cursor_changed = false; - memcpy(cursor_image->data, MacCursor + 4, 32); - memcpy(cursor_mask_image->data, MacCursor + 36, 32); - XFreeCursor(x_display, mac_cursor); - XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16); - XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16); - mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]); - XDefineCursor(x_display, the_win, mac_cursor); + // Set new cursor image if it was changed + if (cursor_changed) { + cursor_changed = false; + memcpy(cursor_image->data, MacCursor + 4, 32); + memcpy(cursor_mask_image->data, MacCursor + 36, 32); + XDisplayLock(); + XFreeCursor(x_display, mac_cursor); + XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16); + XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16); + mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]); + XDefineCursor(x_display, the_win, mac_cursor); + XDisplayUnlock(); + } } } - } #ifdef ENABLE_VOSF - else if (use_vosf) { - // Update display (VOSF variant) - static int tick_counter = 0; - if (++tick_counter >= frame_skip) { - tick_counter = 0; - if (mainBuffer.dirty) { - LOCK_VOSF; - update_display_dga_vosf(); - UNLOCK_VOSF; + else if (use_vosf) { + // Update display (VOSF variant) + if (++tick_counter >= frame_skip) { + tick_counter = 0; + if (mainBuffer.dirty) { + LOCK_VOSF; + update_display_dga_vosf(); + UNLOCK_VOSF; + } } } - } #endif - // Set new palette if it was changed - if (palette_changed && !emul_suspended) { - palette_changed = false; - XColor c[256]; - for (int i=0; i<256; i++) { - c[i].pixel = i; - c[i].red = mac_pal[i].red * 0x0101; - c[i].green = mac_pal[i].green * 0x0101; - c[i].blue = mac_pal[i].blue * 0x0101; - c[i].flags = DoRed | DoGreen | DoBlue; - } - if (depth == 8) { - XStoreColors(x_display, cmap[0], c, 256); - XStoreColors(x_display, cmap[1], c, 256); -#ifdef ENABLE_XF86_DGA - if (display_type == DIS_SCREEN) { - current_dga_cmap ^= 1; - XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); + // Set new palette if it was changed + if (palette_changed && !emul_suspended) { + palette_changed = false; + XColor c[256]; + for (int i=0; i<256; i++) { + c[i].pixel = i; + c[i].red = mac_pal[i].red * 0x0101; + c[i].green = mac_pal[i].green * 0x0101; + c[i].blue = mac_pal[i].blue * 0x0101; + c[i].flags = DoRed | DoGreen | DoBlue; } + if (depth == 8) { + XDisplayLock(); + XStoreColors(x_display, cmap[0], c, 256); + XStoreColors(x_display, cmap[1], c, 256); +#ifdef ENABLE_XF86_DGA + if (display_type == DIS_SCREEN) { + current_dga_cmap ^= 1; + XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); + } #endif + XDisplayUnlock(); + } } + + } else { + + // No display refresh pending, check for X events + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = delay; + if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0) + handle_events(); } } return NULL;