ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/video_x.cpp
(Generate patch)

Comparing SheepShaver/src/Unix/video_x.cpp (file contents):
Revision 1.1.1.1 by cebix, 2002-02-04T16:58:13Z vs.
Revision 1.12 by gbeauche, 2004-01-14T23:15:41Z

# Line 1 | Line 1
1   /*
2   *  video_x.cpp - Video/graphics emulation, X11 specific stuff
3   *
4 < *  SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer
4 > *  SheepShaver (C) 1997-2004 Marc Hellwig and Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 18 | Line 18
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   */
20  
21 + #include "sysdeps.h"
22 +
23   #include <X11/Xlib.h>
24   #include <X11/Xutil.h>
25   #include <X11/keysym.h>
26   #include <X11/extensions/XShm.h>
27   #include <sys/ipc.h>
28   #include <sys/shm.h>
29 + #include <errno.h>
30   #include <pthread.h>
31  
32 < #include "sysdeps.h"
32 > #ifdef ENABLE_XF86_DGA
33 > #include <X11/extensions/xf86dga.h>
34 > #endif
35 >
36 > #ifdef ENABLE_XF86_VIDMODE
37 > # include <X11/extensions/xf86vmode.h>
38 > #endif
39 >
40   #include "main.h"
41   #include "adb.h"
42   #include "prefs.h"
# Line 38 | Line 48
48   #define DEBUG 0
49   #include "debug.h"
50  
41 #ifdef ENABLE_XF86_DGA
42 #include <X11/extensions/xf86dga.h>
43 #endif
44
45 #ifdef ENABLE_XF86_VIDMODE
46 #include <X11/extensions/xf86vmode.h>
47 #endif
51  
52 + // Constants
53 + const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes";
54  
55   // Global variables
56   static int32 frame_skip;
57 + static int16 mouse_wheel_mode;
58 + static int16 mouse_wheel_lines;
59   static bool redraw_thread_active = false;       // Flag: Redraw thread installed
60   static pthread_t redraw_thread;                         // Redraw thread
61  
62 + static bool local_X11;                                          // Flag: X server running on local machine?
63   static volatile bool thread_stop_req = false;
64   static volatile bool thread_stop_ack = false;   // Acknowledge for thread_stop_req
65  
66   static bool has_dga = false;                            // Flag: Video DGA capable
67   static bool has_vidmode = false;                        // Flag: VidMode extension available
68  
69 + #ifdef ENABLE_VOSF
70 + static bool use_vosf = true;                            // Flag: VOSF enabled
71 + #else
72 + static const bool use_vosf = false;                     // VOSF not possible
73 + #endif
74 +
75   static bool palette_changed = false;            // Flag: Palette changed, redraw thread must update palette
76   static bool ctrl_down = false;                          // Flag: Ctrl key pressed
77   static bool quit_full_screen = false;           // Flag: DGA close requested from redraw thread
# Line 67 | Line 81 | static bool emerg_quit = false;                                // Fl
81   static bool emul_suspended = false;                     // Flag: emulator suspended
82   static Window suspend_win;                                      // "Suspend" window
83   static void *fb_save = NULL;                            // Saved frame buffer for suspend
84 + static bool use_keycodes = false;                       // Flag: Use keycodes rather than keysyms
85 + static int keycode_table[256];                          // X keycode -> Mac keycode translation table
86  
87   // X11 variables
88   static int screen;                                                      // Screen number
# Line 92 | Line 108 | static Cursor mac_cursor;
108   static GC cursor_gc, cursor_mask_gc;
109   static bool cursor_changed = false;                     // Flag: Cursor changed, window_func must update cursor
110   static bool have_shm = false;                           // Flag: SHM present and usable
111 < static uint8 *the_buffer;                                       // Pointer to Mac frame buffer
111 > static uint8 *the_buffer = NULL;                        // Pointer to Mac frame buffer
112   static uint8 *the_buffer_copy = NULL;           // Copy of Mac frame buffer
113 + static uint32 the_buffer_size;                          // Size of allocated the_buffer
114  
115   // Variables for DGA mode
116   static char *dga_screen_base;
# Line 111 | Line 128 | static int num_x_video_modes;
128   static void *redraw_func(void *arg);
129  
130  
131 < // From main_linux.cpp
131 > // From main_unix.cpp
132 > extern char *x_display_name;
133   extern Display *x_display;
134  
135   // From sys_unix.cpp
136   extern void SysMountFirstFloppy(void);
137  
138 + // From clip_unix.cpp
139 + extern void ClipboardSelectionClear(XSelectionClearEvent *);
140 + extern void ClipboardSelectionRequest(XSelectionRequestEvent *);
141 +
142 +
143 + // Video acceleration through SIGSEGV
144 + #ifdef ENABLE_VOSF
145 + # include "video_vosf.h"
146 + #endif
147 +
148  
149   /*
150   *  Open display (window or fullscreen)
# Line 138 | Line 166 | static int error_handler(Display *d, XEr
166   // Open window
167   static bool open_window(int width, int height)
168   {
169 +        int aligned_width = (width + 15) & ~15;
170 +        int aligned_height = (height + 15) & ~15;
171 +
172          // Set absolute mouse mode
173          ADBSetRelMouseMode(false);
174  
144        // Read frame skip prefs
145        frame_skip = PrefsFindInt32("frameskip");
146        if (frame_skip == 0)
147                frame_skip = 1;
148
175          // Create window
176          XSetWindowAttributes wattr;
177          wattr.event_mask = eventmask = win_eventmask;
# Line 179 | Line 205 | static bool open_window(int width, int h
205                  XFree((char *)hints);
206          }
207  
208 +        // 1-bit mode is big-endian; if the X server is little-endian, we can't
209 +        // use SHM because that doesn't allow changing the image byte order
210 +        bool need_msb_image = (depth == 1 && XImageByteOrder(x_display) == LSBFirst);
211 +
212          // Try to create and attach SHM image
213          have_shm = false;
214 <        if (depth != 1 && XShmQueryExtension(x_display)) {
214 >        if (local_X11 && !need_msb_image && XShmQueryExtension(x_display)) {
215  
216                  // Create SHM image ("height + 2" for safety)
217 <                img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
217 >                img = XShmCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
218                  shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
219 <                screen_base = (uint32)shmat(shminfo.shmid, 0, 0);
220 <                the_buffer = (uint8 *)screen_base;
191 <                shminfo.shmaddr = img->data = (char *)screen_base;
219 >                the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
220 >                shminfo.shmaddr = img->data = (char *)the_buffer_copy;
221                  shminfo.readOnly = False;
222  
223                  // Try to attach SHM image, catching errors
# Line 209 | Line 238 | static bool open_window(int width, int h
238  
239          // Create normal X image if SHM doesn't work ("height + 2" for safety)
240          if (!have_shm) {
241 <                int bytes_per_row = width;
241 >                int bytes_per_row = aligned_width;
242                  switch (depth) {
243                          case 1:
244                                  bytes_per_row /= 8;
# Line 223 | Line 252 | static bool open_window(int width, int h
252                                  bytes_per_row *= 4;
253                                  break;
254                  }
255 <                screen_base = (uint32)malloc((height + 2) * bytes_per_row);
256 <                the_buffer = (uint8 *)screen_base;
228 <                img = XCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)screen_base, width, height, 32, bytes_per_row);
255 >                the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
256 >                img = XCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row);
257          }
258  
259          // 1-Bit mode is big-endian
# Line 234 | Line 262 | static bool open_window(int width, int h
262          img->bitmap_bit_order = MSBFirst;
263      }
264  
265 <        // Allocate memory for frame buffer copy
266 <        the_buffer_copy = (uint8 *)malloc((height + 2) * img->bytes_per_line);
265 > #ifdef ENABLE_VOSF
266 >        use_vosf = true;
267 >        // Allocate memory for frame buffer (SIZE is extended to page-boundary)
268 >        the_host_buffer = the_buffer_copy;
269 >        the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
270 >        the_buffer = (uint8 *)vm_acquire(the_buffer_size);
271 >        the_buffer_copy = (uint8 *)malloc(the_buffer_size);
272 >        D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
273 > #else
274 >        // Allocate memory for frame buffer
275 >        the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
276 >        D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
277 > #endif
278 >        screen_base = (uint32)the_buffer;
279  
280          // Create GC
281          the_gc = XCreateGC(x_display, the_win, 0, 0);
# Line 255 | Line 295 | static bool open_window(int width, int h
295          mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0);
296          cursor_changed = false;
297  
298 +        // Init blitting routines
299 +        bool native_byte_order;
300 + #ifdef WORDS_BIGENDIAN
301 +        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
302 + #else
303 +        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
304 + #endif
305 + #ifdef ENABLE_VOSF
306 +        Screen_blitter_init(&visualInfo, native_byte_order, depth);
307 + #endif
308 +
309          // Set bytes per row
310          VModes[cur_mode].viRowBytes = img->bytes_per_line;
311          XSync(x_display, false);
# Line 289 | Line 340 | static bool open_dga(int width, int heig
340          XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
341          XF86DGASetViewPort(x_display, screen, 0, 0);
342          XF86DGASetVidPage(x_display, screen, 0);
292        screen_base = (uint32)dga_screen_base;
343  
344          // Set colormap
345          if (depth == 8)
# Line 307 | Line 357 | static bool open_dga(int width, int heig
357                          bytes_per_row *= 4;
358                          break;
359          }
360 +
361 + #if ENABLE_VOSF
362 +        bool native_byte_order;
363 + #ifdef WORDS_BIGENDIAN
364 +        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
365 + #else
366 +        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
367 + #endif
368 + #if REAL_ADDRESSING || DIRECT_ADDRESSING
369 +        // Screen_blitter_init() returns TRUE if VOSF is mandatory
370 +        // i.e. the framebuffer update function is not Blit_Copy_Raw
371 +        use_vosf = Screen_blitter_init(&visualInfo, native_byte_order, depth);
372 +        
373 +        if (use_vosf) {
374 +          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
375 +          the_host_buffer = the_buffer;
376 +          the_buffer_size = page_extend((height + 2) * bytes_per_row);
377 +          the_buffer_copy = (uint8 *)malloc(the_buffer_size);
378 +          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
379 +        }
380 + #else
381 +        use_vosf = false;
382 +        the_buffer = dga_screen_base;
383 + #endif
384 + #endif
385 +        screen_base = (uint32)the_buffer;
386 +
387          VModes[cur_mode].viRowBytes = bytes_per_row;
388          XSync(x_display, false);
389          return true;
# Line 333 | Line 410 | static bool open_display(void)
410                          depth = 8;
411                          break;
412                  case APPLE_16_BIT:
413 <                        depth = 16;
413 >                        depth = xdepth == 15 ? 15 : 16;
414                          break;
415                  case APPLE_32_BIT:
416                          depth = 32;
417                          break;
418          }
419 +
420 +        bool display_open = false;
421          if (display_type == DIS_SCREEN)
422 <                return open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
422 >                display_open = open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
423          else if (display_type == DIS_WINDOW)
424 <                return open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
425 <        else
426 <                return false;
424 >                display_open = open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
425 >
426 > #ifdef ENABLE_VOSF
427 >        if (use_vosf) {
428 >                // Initialize the VOSF system
429 >                if (!video_vosf_init()) {
430 >                        ErrorAlert(GetString(STR_VOSF_INIT_ERR));
431 >                        return false;
432 >                }
433 >        }
434 > #endif
435 >        
436 >        return display_open;
437   }
438  
439  
# Line 355 | Line 444 | static bool open_display(void)
444   // Close window
445   static void close_window(void)
446   {
447 +        if (have_shm) {
448 +                XShmDetach(x_display, &shminfo);
449 + #ifdef ENABLE_VOSF
450 +                the_host_buffer = NULL; // don't free() in driver_base dtor
451 + #else
452 +                the_buffer_copy = NULL; // don't free() in driver_base dtor
453 + #endif
454 +        }
455 +        if (img) {
456 +                if (!have_shm)
457 +                        img->data = NULL;
458 +                XDestroyImage(img);
459 +        }
460 +        if (have_shm) {
461 +                shmdt(shminfo.shmaddr);
462 +                shmctl(shminfo.shmid, IPC_RMID, 0);
463 +        }
464 +        if (the_gc)
465 +                XFreeGC(x_display, the_gc);
466 +
467          // Close window
468          XDestroyWindow(x_display, the_win);
360
361        // Close frame buffer copy
362        if (the_buffer_copy) {
363                free(the_buffer_copy);
364                the_buffer_copy = NULL;
365        }
469   }
470  
471   // Close DGA mode
# Line 378 | Line 481 | static void close_dga(void)
481          if (has_vidmode)
482                  XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]);
483   #endif
484 +
485 +        if (!use_vosf) {
486 +                // don't free() the screen buffer in driver_base dtor
487 +                the_buffer = NULL;
488 +        }
489 + #ifdef ENABLE_VOSF
490 +        else {
491 +                // don't free() the screen buffer in driver_base dtor
492 +                the_host_buffer = NULL;
493 +        }
494 + #endif
495   }
496  
497   static void close_display(void)
# Line 386 | Line 500 | static void close_display(void)
500                  close_dga();
501          else if (display_type == DIS_WINDOW)
502                  close_window();
503 +
504 + #ifdef ENABLE_VOSF
505 +        if (use_vosf) {
506 +                // Deinitialize VOSF
507 +                video_vosf_exit();
508 +        }
509 + #endif
510 +
511 +        // Free frame buffer(s)
512 +        if (!use_vosf) {
513 +                if (the_buffer_copy) {
514 +                        free(the_buffer_copy);
515 +                        the_buffer_copy = NULL;
516 +                }
517 +        }
518 + #ifdef ENABLE_VOSF
519 +        else {
520 +                // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will
521 +                if (the_buffer != VM_MAP_FAILED) {
522 +                        D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
523 +                        vm_release(the_buffer, the_buffer_size);
524 +                        the_buffer = NULL;
525 +                }
526 +                if (the_host_buffer) {
527 +                        D(bug(" freeing the_host_buffer at %p\n", the_host_buffer));
528 +                        free(the_host_buffer);
529 +                        the_host_buffer = NULL;
530 +                }
531 +                if (the_buffer_copy) {
532 +                        D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
533 +                        free(the_buffer_copy);
534 +                        the_buffer_copy = NULL;
535 +                }
536 +        }
537 + #endif
538   }
539  
540  
# Line 393 | Line 542 | static void close_display(void)
542   *  Initialization
543   */
544  
545 + // Init keycode translation table
546 + static void keycode_init(void)
547 + {
548 +        bool use_kc = PrefsFindBool("keycodes");
549 +        if (use_kc) {
550 +
551 +                // Get keycode file path from preferences
552 +                const char *kc_path = PrefsFindString("keycodefile");
553 +
554 +                // Open keycode table
555 +                FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r");
556 +                if (f == NULL) {
557 +                        char str[256];
558 +                        sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno));
559 +                        WarningAlert(str);
560 +                        return;
561 +                }
562 +
563 +                // Default translation table
564 +                for (int i=0; i<256; i++)
565 +                        keycode_table[i] = -1;
566 +
567 +                // Search for server vendor string, then read keycodes
568 +                const char *vendor = ServerVendor(x_display);
569 +                bool vendor_found = false;
570 +                char line[256];
571 +                while (fgets(line, 255, f)) {
572 +                        // Read line
573 +                        int len = strlen(line);
574 +                        if (len == 0)
575 +                                continue;
576 +                        line[len-1] = 0;
577 +
578 +                        // Comments begin with "#" or ";"
579 +                        if (line[0] == '#' || line[0] == ';' || line[0] == 0)
580 +                                continue;
581 +
582 +                        if (vendor_found) {
583 +                                // Read keycode
584 +                                int x_code, mac_code;
585 +                                if (sscanf(line, "%d %d", &x_code, &mac_code) == 2)
586 +                                        keycode_table[x_code & 0xff] = mac_code;
587 +                                else
588 +                                        break;
589 +                        } else {
590 +                                // Search for vendor string
591 +                                if (strstr(vendor, line) == vendor)
592 +                                        vendor_found = true;
593 +                        }
594 +                }
595 +
596 +                // Keycode file completely read
597 +                fclose(f);
598 +                use_keycodes = vendor_found;
599 +
600 +                // Vendor not found? Then display warning
601 +                if (!vendor_found) {
602 +                        char str[256];
603 +                        sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), vendor, kc_path ? kc_path : KEYCODE_FILE_NAME);
604 +                        WarningAlert(str);
605 +                        return;
606 +                }
607 +        }
608 + }
609 +
610   static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type)
611   {
612          if (allow & test) {
# Line 456 | Line 670 | static bool has_mode(int x, int y)
670  
671   bool VideoInit(void)
672   {
673 + #ifdef ENABLE_VOSF
674 +        // Zero the mainBuffer structure
675 +        mainBuffer.dirtyPages = NULL;
676 +        mainBuffer.pageInfo = NULL;
677 + #endif
678 +        
679 +        // Check if X server runs on local machine
680 +        local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0)
681 +                 || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0);
682 +    
683 +        // Init keycode translation
684 +        keycode_init();
685 +
686 +        // Read frame skip prefs
687 +        frame_skip = PrefsFindInt32("frameskip");
688 +        if (frame_skip == 0)
689 +                frame_skip = 1;
690 +
691 +        // Read mouse wheel prefs
692 +        mouse_wheel_mode = PrefsFindInt32("mousewheelmode");
693 +        mouse_wheel_lines = PrefsFindInt32("mousewheellines");
694 +
695          // Init variables
696          private_data = NULL;
697          cur_mode = 0;   // Window 640x480
# Line 471 | Line 707 | bool VideoInit(void)
707   #ifdef ENABLE_XF86_DGA
708          // DGA available?
709      int event_base, error_base;
710 <    if (XF86DGAQueryExtension(x_display, &event_base, &error_base)) {
710 >    if (local_X11 && XF86DGAQueryExtension(x_display, &event_base, &error_base)) {
711                  int dga_flags = 0;
712                  XF86DGAQueryDirectVideo(x_display, screen, &dga_flags);
713                  has_dga = dga_flags & XF86DGADirectPresent;
# Line 652 | Line 888 | void VideoExit(void)
888                  redraw_thread_active = false;
889          }
890  
891 + #ifdef ENABLE_VOSF
892 +        if (use_vosf) {
893 +                // Deinitialize VOSF
894 +                video_vosf_exit();
895 +        }
896 + #endif
897 +
898          // Close window and server connection
899          if (x_display != NULL) {
900                  XSync(x_display, false);
# Line 725 | Line 968 | static void resume_emul(void)
968          // Reopen full screen display
969          XGrabKeyboard(x_display, rootwin, 1, GrabModeAsync, GrabModeAsync, CurrentTime);
970          XGrabPointer(x_display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
971 + #ifdef ENABLE_XF86_DGA
972          XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
973          XF86DGASetViewPort(x_display, screen, 0, 0);
974 + #endif
975          XSync(x_display, false);
976  
977 +        // the_buffer already contains the data to restore. i.e. since a temporary
978 +        // frame buffer is used when VOSF is actually used, fb_save is therefore
979 +        // not necessary.
980 + #ifdef ENABLE_VOSF
981 +        if (use_vosf) {
982 +                LOCK_VOSF;
983 +                PFLAG_SET_ALL;
984 +                UNLOCK_VOSF;
985 +                memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
986 +        }
987 + #endif
988 +        
989          // Restore frame buffer
990          if (fb_save) {
991 + #ifdef ENABLE_VOSF
992 +                // Don't copy fb_save to the temporary frame buffer in VOSF mode
993 +                if (!use_vosf)
994 + #endif
995                  memcpy((void *)screen_base, fb_save, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes);
996                  free(fb_save);
997                  fb_save = NULL;
# Line 904 | Line 1165 | static int kc_decode(KeySym ks)
1165          return -1;
1166   }
1167  
1168 < static int event2keycode(XKeyEvent *ev)
1168 > static int event2keycode(XKeyEvent &ev)
1169   {
1170          KeySym ks;
1171          int as;
1172          int i = 0;
1173  
1174          do {
1175 <                ks = XLookupKeysym(ev, i++);
1175 >                ks = XLookupKeysym(&ev, i++);
1176                  as = kc_decode(ks);
1177                  if (as != -1)
1178                          return as;
# Line 926 | Line 1187 | static void handle_events(void)
1187          for (;;) {
1188                  XEvent event;
1189  
1190 <                if (!XCheckMaskEvent(x_display, eventmask, &event))
1190 >                XDisplayLock();
1191 >                if (!XCheckMaskEvent(x_display, eventmask, &event)) {
1192 >                        // Handle clipboard events
1193 >                        if (XCheckTypedEvent(x_display, SelectionRequest, &event))
1194 >                                ClipboardSelectionRequest(&event.xselectionrequest);
1195 >                        else if (XCheckTypedEvent(x_display, SelectionClear, &event))
1196 >                                ClipboardSelectionClear(&event.xselectionclear);
1197 >
1198 >                        XDisplayUnlock();
1199                          break;
1200 +                }
1201 +                XDisplayUnlock();
1202  
1203                  switch (event.type) {
1204                          // Mouse button
# Line 935 | Line 1206 | static void handle_events(void)
1206                                  unsigned int button = ((XButtonEvent *)&event)->button;
1207                                  if (button < 4)
1208                                          ADBMouseDown(button - 1);
1209 +                                else if (button < 6) {  // Wheel mouse
1210 +                                        if (mouse_wheel_mode == 0) {
1211 +                                                int key = (button == 5) ? 0x79 : 0x74;  // Page up/down
1212 +                                                ADBKeyDown(key);
1213 +                                                ADBKeyUp(key);
1214 +                                        } else {
1215 +                                                int key = (button == 5) ? 0x3d : 0x3e;  // Cursor up/down
1216 +                                                for(int i=0; i<mouse_wheel_lines; i++) {
1217 +                                                        ADBKeyDown(key);
1218 +                                                        ADBKeyUp(key);
1219 +                                                }
1220 +                                        }
1221 +                                }
1222                                  break;
1223                          }
1224                          case ButtonRelease: {
# Line 954 | Line 1238 | static void handle_events(void)
1238  
1239                          // Keyboard
1240                          case KeyPress: {
1241 <                                int code;
1242 <                                if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1241 >                                int code = event2keycode(event.xkey);
1242 >                                if (use_keycodes && code != -1)
1243 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1244 >                                if (code != -1) {
1245                                          if (!emul_suspended) {
1246                                                  ADBKeyDown(code);
1247                                                  if (code == 0x36)
# Line 968 | Line 1254 | static void handle_events(void)
1254                                  break;
1255                          }
1256                          case KeyRelease: {
1257 <                                int code;
1258 <                                if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1257 >                                int code = event2keycode(event.xkey);
1258 >                                if (use_keycodes && code != 1)
1259 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1260 >                                if (code != -1) {
1261                                          ADBKeyUp(code);
1262                                          if (code == 0x36)
1263                                                  ctrl_down = false;
# Line 979 | Line 1267 | static void handle_events(void)
1267  
1268                          // Hidden parts exposed, force complete refresh
1269                          case Expose:
1270 + #ifdef ENABLE_VOSF
1271 +                                if (use_vosf) {                 // VOSF refresh
1272 +                                        LOCK_VOSF;
1273 +                                        PFLAG_SET_ALL;
1274 +                                        UNLOCK_VOSF;
1275 +                                }
1276 + #endif
1277                                  memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
1278                                  break;
1279                  }
# Line 1330 | Line 1625 | static void update_display(void)
1625  
1626          // Refresh display
1627          if (high && wide) {
1628 +                XDisplayLock();
1629                  if (have_shm)
1630                          XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high, 0);
1631                  else
1632                          XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high);
1633 +                XDisplayUnlock();
1634          }
1635   }
1636  
1637 + const int VIDEO_REFRESH_HZ = 60;
1638 + const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
1639 +
1640   static void *redraw_func(void *arg)
1641   {
1642 <        int tick_counter = 0;
1343 <        struct timespec req = {0, 16666667};
1642 >        int fd = ConnectionNumber(x_display);
1643  
1644 <        for (;;) {
1644 >        uint64 start = GetTicks_usec();
1645 >        int64 ticks = 0;
1646 >        uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY;
1647  
1648 <                // Wait
1348 <                nanosleep(&req, NULL);
1648 >        for (;;) {
1649  
1650                  // Pause if requested (during video mode switches)
1651                  while (thread_stop_req)
1652                          thread_stop_ack = true;
1653  
1654 <                // Handle X11 events
1655 <                handle_events();
1654 >                int64 delay = next - GetTicks_usec();
1655 >                if (delay < -VIDEO_REFRESH_DELAY) {
1656 >
1657 >                        // We are lagging far behind, so we reset the delay mechanism
1658 >                        next = GetTicks_usec();
1659  
1660 <                // Quit DGA mode if requested
1661 <                if (quit_full_screen) {
1662 <                        quit_full_screen = false;
1663 <                        if (display_type == DIS_SCREEN) {
1660 >                } else if (delay <= 0) {
1661 >
1662 >                        // Delay expired, refresh display
1663 >                        next += VIDEO_REFRESH_DELAY;
1664 >                        ticks++;
1665 >
1666 >                        // Handle X11 events
1667 >                        handle_events();
1668 >
1669 >                        // Quit DGA mode if requested
1670 >                        if (quit_full_screen) {
1671 >                                quit_full_screen = false;
1672 >                                if (display_type == DIS_SCREEN) {
1673 >                                        XDisplayLock();
1674   #ifdef ENABLE_XF86_DGA
1675 <                                XF86DGADirectVideo(x_display, screen, 0);
1676 <                                XUngrabPointer(x_display, CurrentTime);
1677 <                                XUngrabKeyboard(x_display, CurrentTime);
1678 < #endif
1679 <                                XSync(x_display, false);
1680 <                                quit_full_screen_ack = true;
1681 <                                return NULL;
1675 >                                        XF86DGADirectVideo(x_display, screen, 0);
1676 >                                        XUngrabPointer(x_display, CurrentTime);
1677 >                                        XUngrabKeyboard(x_display, CurrentTime);
1678 > #endif
1679 >                                        XSync(x_display, false);
1680 >                                        XDisplayUnlock();
1681 >                                        quit_full_screen_ack = true;
1682 >                                        return NULL;
1683 >                                }
1684                          }
1370                }
1685  
1686 <                // Refresh display and set cursor image in window mode
1687 <                if (display_type == DIS_WINDOW) {
1688 <                        tick_counter++;
1689 <                        if (tick_counter >= frame_skip) {
1690 <                                tick_counter = 0;
1691 <
1692 <                                // Update display
1693 <                                update_display();
1694 <
1695 <                                // Set new cursor image if it was changed
1696 <                                if (cursor_changed) {
1697 <                                        cursor_changed = false;
1698 <                                        memcpy(cursor_image->data, MacCursor + 4, 32);
1699 <                                        memcpy(cursor_mask_image->data, MacCursor + 36, 32);
1700 <                                        XFreeCursor(x_display, mac_cursor);
1701 <                                        XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);
1702 <                                        XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16);
1703 <                                        mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]);
1704 <                                        XDefineCursor(x_display, the_win, mac_cursor);
1686 >                        // Refresh display and set cursor image in window mode
1687 >                        static int tick_counter = 0;
1688 >                        if (display_type == DIS_WINDOW) {
1689 >                                tick_counter++;
1690 >                                if (tick_counter >= frame_skip) {
1691 >                                        tick_counter = 0;
1692 >
1693 >                                        // Update display
1694 > #ifdef ENABLE_VOSF
1695 >                                        if (use_vosf) {
1696 >                                                XDisplayLock();
1697 >                                                if (mainBuffer.dirty) {
1698 >                                                        LOCK_VOSF;
1699 >                                                        update_display_window_vosf();
1700 >                                                        UNLOCK_VOSF;
1701 >                                                        XSync(x_display, false); // Let the server catch up
1702 >                                                }
1703 >                                                XDisplayUnlock();
1704 >                                        }
1705 >                                        else
1706 > #endif
1707 >                                                update_display();
1708 >
1709 >                                        // Set new cursor image if it was changed
1710 >                                        if (cursor_changed) {
1711 >                                                cursor_changed = false;
1712 >                                                memcpy(cursor_image->data, MacCursor + 4, 32);
1713 >                                                memcpy(cursor_mask_image->data, MacCursor + 36, 32);
1714 >                                                XDisplayLock();
1715 >                                                XFreeCursor(x_display, mac_cursor);
1716 >                                                XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);
1717 >                                                XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16);
1718 >                                                mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]);
1719 >                                                XDefineCursor(x_display, the_win, mac_cursor);
1720 >                                                XDisplayUnlock();
1721 >                                        }
1722                                  }
1723                          }
1724 <                }
1725 <
1726 <                // Set new palette if it was changed
1727 <                if (palette_changed && !emul_suspended) {
1728 <                        palette_changed = false;
1729 <                        XColor c[256];
1730 <                        for (int i=0; i<256; i++) {
1731 <                                c[i].pixel = i;
1732 <                                c[i].red = mac_pal[i].red * 0x0101;
1733 <                                c[i].green = mac_pal[i].green * 0x0101;
1734 <                                c[i].blue = mac_pal[i].blue * 0x0101;
1404 <                                c[i].flags = DoRed | DoGreen | DoBlue;
1724 > #ifdef ENABLE_VOSF
1725 >                        else if (use_vosf) {
1726 >                                // Update display (VOSF variant)
1727 >                                if (++tick_counter >= frame_skip) {
1728 >                                        tick_counter = 0;
1729 >                                        if (mainBuffer.dirty) {
1730 >                                                LOCK_VOSF;
1731 >                                                update_display_dga_vosf();
1732 >                                                UNLOCK_VOSF;
1733 >                                        }
1734 >                                }
1735                          }
1736 <                        if (depth == 8) {
1737 <                                XStoreColors(x_display, cmap[0], c, 256);
1738 <                                XStoreColors(x_display, cmap[1], c, 256);
1739 < #ifdef ENABLE_XF86_DGA
1740 <                                if (display_type == DIS_SCREEN) {
1741 <                                        current_dga_cmap ^= 1;
1742 <                                        XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1736 > #endif
1737 >
1738 >                        // Set new palette if it was changed
1739 >                        if (palette_changed && !emul_suspended) {
1740 >                                palette_changed = false;
1741 >                                XColor c[256];
1742 >                                for (int i=0; i<256; i++) {
1743 >                                        c[i].pixel = i;
1744 >                                        c[i].red = mac_pal[i].red * 0x0101;
1745 >                                        c[i].green = mac_pal[i].green * 0x0101;
1746 >                                        c[i].blue = mac_pal[i].blue * 0x0101;
1747 >                                        c[i].flags = DoRed | DoGreen | DoBlue;
1748                                  }
1749 +                                if (depth == 8) {
1750 +                                        XDisplayLock();
1751 +                                        XStoreColors(x_display, cmap[0], c, 256);
1752 +                                        XStoreColors(x_display, cmap[1], c, 256);
1753 + #ifdef ENABLE_XF86_DGA
1754 +                                        if (display_type == DIS_SCREEN) {
1755 +                                                current_dga_cmap ^= 1;
1756 +                                                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1757 +                                        }
1758   #endif
1759 +                                        XDisplayUnlock();
1760 +                                }
1761                          }
1762 +
1763 +                } else {
1764 +
1765 +                        // No display refresh pending, check for X events
1766 +                        fd_set readfds;
1767 +                        FD_ZERO(&readfds);
1768 +                        FD_SET(fd, &readfds);
1769 +                        struct timeval timeout;
1770 +                        timeout.tv_sec = 0;
1771 +                        timeout.tv_usec = delay;
1772 +                        if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
1773 +                                handle_events();
1774                  }
1775          }
1776          return NULL;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines