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

Comparing BasiliskII/src/Unix/video_x.cpp (file contents):
Revision 1.50 by cebix, 2001-07-01T21:09:29Z vs.
Revision 1.61 by cebix, 2001-07-14T15:02:47Z

# Line 24 | Line 24
24   *      Ctrl-Tab = suspend DGA mode
25   *      Ctrl-Esc = emergency quit
26   *      Ctrl-F1 = mount floppy
27 + *      Ctrl-F5 = grab mouse (in windowed mode)
28   */
29  
30   #include "sysdeps.h"
# Line 36 | Line 37
37   #include <sys/shm.h>
38   #include <errno.h>
39  
40 + #include <algorithm>
41 +
42 + #ifndef NO_STD_NAMESPACE
43 + using std::sort;
44 + #endif
45 +
46   #ifdef HAVE_PTHREADS
47   # include <pthread.h>
48   #endif
# Line 86 | Line 93 | static int display_type = DISPLAY_WINDOW
93   static bool local_X11;                                                          // Flag: X server running on local machine?
94   static uint8 *the_buffer = NULL;                                        // Mac frame buffer (where MacOS draws into)
95   static uint8 *the_buffer_copy = NULL;                           // Copy of Mac frame buffer (for refreshed modes)
96 + static uint32 the_buffer_size;                                          // Size of allocated the_buffer
97  
98   static bool redraw_thread_active = false;                       // Flag: Redraw thread installed
99   #ifdef HAVE_PTHREADS
# Line 115 | Line 123 | static int keycode_table[256];                                         // X
123  
124   // X11 variables
125   static int screen;                                                                      // Screen number
118 static int xdepth;                                                                      // Depth of X screen
126   static Window rootwin;                                                          // Root window and our window
127 < static XVisualInfo visualInfo;
128 < static Visual *vis;
122 < static Colormap cmap[2] = {0, 0};                                       // Colormaps for indexed modes (DGA needs two of them)
127 > static int num_depths = 0;                                                      // Number of available X depths
128 > static int *avail_depths = NULL;                                        // List of available X depths
129   static XColor black, white;
130   static unsigned long black_pixel, white_pixel;
131   static int eventmask;
132  
133 + static int xdepth;                                                                      // Depth of X screen
134 + static XVisualInfo visualInfo;
135 + static Visual *vis;
136 + static int color_class;
137 +
138   static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes
139  
140 + static Colormap cmap[2] = {0, 0};                                       // Colormaps for indexed modes (DGA needs two of them)
141 +
142   static XColor palette[256];                                                     // Color palette to be used as CLUT and gamma table
143   static bool palette_changed = false;                            // Flag: Palette changed, redraw thread must set new colors
144  
# Line 171 | Line 184 | static void (*video_refresh)(void);
184  
185   // Prototypes
186   static void *redraw_func(void *arg);
174 static int event2keycode(XKeyEvent &ev);
187  
188   // From main_unix.cpp
189   extern char *x_display_name;
# Line 191 | Line 203 | static inline uint32 map_rgb(uint8 red,
203          return ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift);
204   }
205  
206 + // Do we have a visual for handling the specified Mac depth? If so, set the
207 + // global variables "xdepth", "visualInfo", "vis" and "color_class".
208 + static bool find_visual_for_depth(video_depth depth)
209 + {
210 +        D(bug("have_visual_for_depth(%d)\n", 1 << depth));
211 +
212 +        // 1-bit works always and uses default visual
213 +        if (depth == VDEPTH_1BIT) {
214 +                vis = DefaultVisual(x_display, screen);
215 +                visualInfo.visualid = XVisualIDFromVisual(vis);
216 +                int num = 0;
217 +                XVisualInfo *vi = XGetVisualInfo(x_display, VisualIDMask, &visualInfo, &num);
218 +                visualInfo = vi[0];
219 +                XFree(vi);
220 +                xdepth = visualInfo.depth;
221 +                color_class = visualInfo.c_class;
222 +                D(bug(" found visual ID 0x%02x, depth %d\n", visualInfo.visualid, xdepth));
223 +                return true;
224 +        }
225 +
226 +        // Calculate minimum and maximum supported X depth
227 +        int min_depth = 1, max_depth = 32;
228 +        switch (depth) {
229 + #ifdef ENABLE_VOSF
230 +                case VDEPTH_2BIT:
231 +                case VDEPTH_4BIT:       // VOSF blitters can convert 2/4/8-bit -> 8/16/32-bit
232 +                case VDEPTH_8BIT:
233 +                        min_depth = 8;
234 +                        max_depth = 32;
235 +                        break;
236 + #else
237 +                case VDEPTH_2BIT:
238 +                case VDEPTH_4BIT:       // 2/4-bit requires VOSF blitters
239 +                        return false;
240 +                case VDEPTH_8BIT:       // 8-bit without VOSF requires an 8-bit visual
241 +                        min_depth = 8;
242 +                        max_depth = 8;
243 +                        break;
244 + #endif
245 +                case VDEPTH_16BIT:      // 16-bit requires a 15/16-bit visual
246 +                        min_depth = 15;
247 +                        max_depth = 16;
248 +                        break;
249 +                case VDEPTH_32BIT:      // 32-bit requires a 24/32-bit visual
250 +                        min_depth = 24;
251 +                        max_depth = 32;
252 +                        break;
253 +        }
254 +        D(bug(" minimum required X depth is %d, maximum supported X depth is %d\n", min_depth, max_depth));
255 +
256 +        // Try to find a visual for one of the color depths
257 +        bool visual_found = false;
258 +        for (int i=0; i<num_depths && !visual_found; i++) {
259 +
260 +                xdepth = avail_depths[i];
261 +                D(bug(" trying to find visual for depth %d\n", xdepth));
262 +                if (xdepth < min_depth || xdepth > max_depth)
263 +                        continue;
264 +
265 +                // Determine best color class for this depth
266 +                switch (xdepth) {
267 +                        case 1: // Try StaticGray or StaticColor
268 +                                if (XMatchVisualInfo(x_display, screen, xdepth, StaticGray, &visualInfo)
269 +                                 || XMatchVisualInfo(x_display, screen, xdepth, StaticColor, &visualInfo))
270 +                                        visual_found = true;
271 +                                break;
272 +                        case 8: // Need PseudoColor
273 +                                if (XMatchVisualInfo(x_display, screen, xdepth, PseudoColor, &visualInfo))
274 +                                        visual_found = true;
275 +                                break;
276 +                        case 15:
277 +                        case 16:
278 +                        case 24:
279 +                        case 32: // Try DirectColor first, as this will allow gamma correction
280 +                                if (XMatchVisualInfo(x_display, screen, xdepth, DirectColor, &visualInfo)
281 +                                 || XMatchVisualInfo(x_display, screen, xdepth, TrueColor, &visualInfo))
282 +                                        visual_found = true;
283 +                                break;
284 +                        default:
285 +                                D(bug("  not a supported depth\n"));
286 +                                break;
287 +                }
288 +        }
289 +        if (!visual_found)
290 +                return false;
291 +
292 +        // Visual was found
293 +        vis = visualInfo.visual;
294 +        color_class = visualInfo.c_class;
295 +        D(bug(" found visual ID 0x%02x, depth %d, class ", visualInfo.visualid, xdepth));
296 + #if DEBUG
297 +        switch (color_class) {
298 +                case StaticGray: D(bug("StaticGray\n")); break;
299 +                case GrayScale: D(bug("GrayScale\n")); break;
300 +                case StaticColor: D(bug("StaticColor\n")); break;
301 +                case PseudoColor: D(bug("PseudoColor\n")); break;
302 +                case TrueColor: D(bug("TrueColor\n")); break;
303 +                case DirectColor: D(bug("DirectColor\n")); break;
304 +        }
305 + #endif
306 +        return true;
307 + }
308 +
309   // Add mode to list of supported modes
310   static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth)
311   {
# Line 236 | Line 351 | static void set_mac_frame_buffer(video_d
351          InitFrameBufferMapping();
352   #else
353          VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer);
239        D(bug("Host frame buffer = %p, ", the_buffer));
354   #endif
355          D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base));
356   }
# Line 322 | Line 436 | public:
436          virtual void update_palette(void);
437          virtual void suspend(void) {}
438          virtual void resume(void) {}
439 +        virtual void toggle_mouse_grab(void) {}
440 +        virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); }
441 +
442 +        void disable_mouse_accel(void);
443 +        void restore_mouse_accel(void);
444 +
445 +        virtual void grab_mouse(void) {}
446 +        virtual void ungrab_mouse(void) {}
447  
448   public:
449          bool init_ok;   // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer)
450          Window w;               // The window we draw into
451 +
452 +        int orig_accel_numer, orig_accel_denom, orig_threshold; // Original mouse acceleration
453   };
454  
455   class driver_window;
# Line 342 | Line 466 | public:
466          driver_window(const video_mode &mode);
467          ~driver_window();
468  
469 +        void toggle_mouse_grab(void);
470 +        void mouse_moved(int x, int y);
471 +
472 +        void grab_mouse(void);
473 +        void ungrab_mouse(void);
474 +
475   private:
476          GC gc;
477          XImage *img;
478 <        bool have_shm;                          // Flag: SHM extensions available
478 >        bool have_shm;                                  // Flag: SHM extensions available
479          XShmSegmentInfo shminfo;
480          Cursor mac_cursor;
481 +        bool mouse_grabbed;                             // Flag: mouse pointer grabbed, using relative mouse mode
482 +        int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode)
483   };
484  
485   static driver_base *drv = NULL; // Pointer to currently used driver object
# Line 361 | Line 493 | driver_base::driver_base()
493   {
494          the_buffer = NULL;
495          the_buffer_copy = NULL;
496 +        XGetPointerControl(x_display, &orig_accel_numer, &orig_accel_denom, &orig_threshold);
497   }
498  
499   driver_base::~driver_base()
500   {
501 +        ungrab_mouse();
502 +        restore_mouse_accel();
503 +
504          if (w) {
505                  XUnmapWindow(x_display, w);
506                  wait_unmapped(w);
# Line 387 | Line 523 | driver_base::~driver_base()
523          }
524   #ifdef ENABLE_VOSF
525          else {
526 <                if (the_buffer != (uint8 *)VM_MAP_FAILED) {
527 <                        vm_release(the_buffer, the_buffer_size);
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) {
532 >                        D(bug(" freeing the_buffer at %p\n", the_buffer));
533 >                        free(the_buffer);
534                          the_buffer = NULL;
535                  }
536 <                if (the_buffer_copy != (uint8 *)VM_MAP_FAILED) {
537 <                        vm_release(the_buffer_copy, the_buffer_size);
536 >                if (the_buffer_copy) {
537 >                        D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
538 >                        free(the_buffer_copy);
539                          the_buffer_copy = NULL;
540                  }
541          }
# Line 402 | Line 545 | driver_base::~driver_base()
545   // Palette has changed
546   void driver_base::update_palette(void)
547   {
548 <        if (cmap[0] && cmap[1]) {
549 <                int num = 256;
550 <                if (IsDirectMode(VideoMonitor.mode))
408 <                        num = vis->map_entries; // Palette is gamma table
409 <                else if (vis->c_class == DirectColor)
548 >        if (color_class == PseudoColor || color_class == DirectColor) {
549 >                int num = vis->map_entries;
550 >                if (!IsDirectMode(VideoMonitor.mode) && color_class == DirectColor)
551                          return; // Indexed mode on true color screen, don't set CLUT
552                  XStoreColors(x_display, cmap[0], palette, num);
553                  XStoreColors(x_display, cmap[1], palette, num);
# Line 414 | Line 555 | void driver_base::update_palette(void)
555          XSync(x_display, false);
556   }
557  
558 + // Disable mouse acceleration
559 + void driver_base::disable_mouse_accel(void)
560 + {
561 +        XChangePointerControl(x_display, True, False, 1, 1, 0);
562 + }
563 +
564 + // Restore mouse acceleration to original value
565 + void driver_base::restore_mouse_accel(void)
566 + {
567 +        XChangePointerControl(x_display, True, True, orig_accel_numer, orig_accel_denom, orig_threshold);
568 + }
569 +
570  
571   /*
572   *  Windowed display driver
# Line 421 | Line 574 | void driver_base::update_palette(void)
574  
575   // Open display
576   driver_window::driver_window(const video_mode &mode)
577 < : gc(0), img(NULL), have_shm(false), mac_cursor(0)
577 > : gc(0), img(NULL), have_shm(false), mac_cursor(0), mouse_grabbed(false)
578   {
579          int width = mode.x, height = mode.y;
580          int aligned_width = (width + 15) & ~15;
581          int aligned_height = (height + 15) & ~15;
582  
583          // Set absolute mouse mode
584 <        ADBSetRelMouseMode(false);
584 >        ADBSetRelMouseMode(mouse_grabbed);
585  
586 <        // Create window
586 >        // Create window (setting backround_pixel, border_pixel and colormap is
587 >        // mandatory when using a non-default visual; in 1-bit mode we use the
588 >        // default visual, so we can also use the default colormap)
589          XSetWindowAttributes wattr;
590          wattr.event_mask = eventmask = win_eventmask;
591 <        wattr.background_pixel = black_pixel;
592 <        wattr.colormap = (mode.depth == VDEPTH_1BIT && vis->c_class == PseudoColor ? DefaultColormap(x_display, screen) : cmap[0]);
591 >        wattr.background_pixel = (vis == DefaultVisual(x_display, screen) ? black_pixel : 0);
592 >        wattr.border_pixel = 0;
593 >        wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]);
594          w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
595 <                InputOutput, vis, CWEventMask | CWBackPixel | (vis->c_class == PseudoColor || vis->c_class == DirectColor ? CWColormap : 0), &wattr);
595 >                InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWColormap, &wattr);
596 >        D(bug(" window created\n"));
597  
598          // Set window name/class
599          set_window_name(w, STR_WINDOW_TITLE);
# Line 460 | Line 617 | driver_window::driver_window(const video
617                          XFree(hints);
618                  }
619          }
620 +        D(bug(" window attributes set\n"));
621          
622          // Show window
623          XMapWindow(x_display, w);
624          wait_mapped(w);
625 +        D(bug(" window mapped\n"));
626  
627          // 1-bit mode is big-endian; if the X server is little-endian, we can't
628          // use SHM because that doesn't allow changing the image byte order
# Line 474 | Line 633 | driver_window::driver_window(const video
633  
634                  // Create SHM image ("height + 2" for safety)
635                  img = XShmCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
636 +                D(bug(" shm image created\n"));
637                  shminfo.shmid = shmget(IPC_PRIVATE, (aligned_height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
638                  the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
639                  shminfo.shmaddr = img->data = (char *)the_buffer_copy;
# Line 488 | Line 648 | driver_window::driver_window(const video
648                  if (shm_error) {
649                          shmdt(shminfo.shmaddr);
650                          XDestroyImage(img);
651 +                        img = NULL;
652                          shminfo.shmid = -1;
653                  } else {
654                          have_shm = true;
655                          shmctl(shminfo.shmid, IPC_RMID, 0);
656                  }
657 +                D(bug(" shm image attached\n"));
658          }
659          
660          // Create normal X image if SHM doesn't work ("height + 2" for safety)
# Line 500 | Line 662 | driver_window::driver_window(const video
662                  int bytes_per_row = (mode.depth == VDEPTH_1BIT ? aligned_width/8 : TrivialBytesPerRow(aligned_width, DepthModeForPixelDepth(xdepth)));
663                  the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
664                  img = XCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row);
665 +                D(bug(" X image created\n"));
666          }
667  
668          if (need_msb_image) {
# Line 508 | Line 671 | driver_window::driver_window(const video
671          }
672  
673   #ifdef ENABLE_VOSF
674 +        use_vosf = true;
675          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
676          the_host_buffer = the_buffer_copy;
677          the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
678          the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
679          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
680 +        D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
681   #else
682          // Allocate memory for frame buffer
683          the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
684 +        D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
685   #endif
686  
687          // Create GC
# Line 551 | Line 717 | driver_window::driver_window(const video
717   // Close display
718   driver_window::~driver_window()
719   {
554        if (img)
555                XDestroyImage(img);
720          if (have_shm) {
721                  XShmDetach(x_display, &shminfo);
722 + #ifdef ENABLE_VOSF
723 +                the_host_buffer = NULL; // don't free() in driver_base dtor
724 + #else
725                  the_buffer_copy = NULL; // don't free() in driver_base dtor
726 + #endif
727 +        }
728 + #ifdef ENABLE_VOSF
729 +        if (use_vosf) {
730 +                // don't free() memory mapped buffers in driver_base dtor
731 +                if (the_buffer != VM_MAP_FAILED) {
732 +                        D(bug(" releasing the_buffer at %p\n", the_buffer));
733 +                        vm_release(the_buffer, the_buffer_size);
734 +                        the_buffer = NULL;
735 +                }
736 +                if (the_buffer_copy != VM_MAP_FAILED) {
737 +                        D(bug(" releasing the_buffer_copy at %p\n", the_buffer_copy));
738 +                        vm_release(the_buffer_copy, the_buffer_size);
739 +                        the_buffer_copy = NULL;
740 +                }
741 +        }
742 + #endif
743 +        if (img) {
744 +                if (!have_shm)
745 +                        img->data = NULL;
746 +                XDestroyImage(img);
747 +        }
748 +        if (have_shm) {
749 +                shmdt(shminfo.shmaddr);
750 +                shmctl(shminfo.shmid, IPC_RMID, 0);
751          }
752          if (gc)
753                  XFreeGC(x_display, gc);
754   }
755  
756 + // Toggle mouse grab
757 + void driver_window::toggle_mouse_grab(void)
758 + {
759 +        if (mouse_grabbed)
760 +                ungrab_mouse();
761 +        else
762 +                grab_mouse();
763 + }
764 +
765 + // Grab mouse, switch to relative mouse mode
766 + void driver_window::grab_mouse(void)
767 + {
768 +        int result;
769 +        for (int i=0; i<10; i++) {
770 +                result = XGrabPointer(x_display, w, True, 0,
771 +                        GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
772 +                if (result != AlreadyGrabbed)
773 +                        break;
774 +                Delay_usec(100000);
775 +        }
776 +        if (result == GrabSuccess) {
777 +                XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED));
778 +                ADBSetRelMouseMode(mouse_grabbed = true);
779 +                disable_mouse_accel();
780 +        }
781 + }
782 +
783 + // Ungrab mouse, switch to absolute mouse mode
784 + void driver_window::ungrab_mouse(void)
785 + {
786 +        if (mouse_grabbed) {
787 +                XUngrabPointer(x_display, CurrentTime);
788 +                XStoreName(x_display, w, GetString(STR_WINDOW_TITLE));
789 +                ADBSetRelMouseMode(mouse_grabbed = false);
790 +                restore_mouse_accel();
791 +        }
792 + }
793 +
794 + // Mouse moved
795 + void driver_window::mouse_moved(int x, int y)
796 + {
797 +        if (!mouse_grabbed) {
798 +                mouse_last_x = x; mouse_last_y = y;
799 +                ADBMouseMoved(x, y);
800 +                return;
801 +        }
802 +
803 +        // Warped mouse motion (this code is taken from SDL)
804 +
805 +        // Post first mouse event
806 +        int width = VideoMonitor.mode.x, height = VideoMonitor.mode.y;
807 +        int delta_x = x - mouse_last_x, delta_y = y - mouse_last_y;
808 +        mouse_last_x = x; mouse_last_y = y;
809 +        ADBMouseMoved(delta_x, delta_y);
810 +
811 +        // Only warp the pointer when it has reached the edge
812 +        const int MOUSE_FUDGE_FACTOR = 8;
813 +        if (x < MOUSE_FUDGE_FACTOR || x > (width - MOUSE_FUDGE_FACTOR)
814 +         || y < MOUSE_FUDGE_FACTOR || y > (height - MOUSE_FUDGE_FACTOR)) {
815 +                XEvent event;
816 +                while (XCheckTypedEvent(x_display, MotionNotify, &event)) {
817 +                        delta_x = x - mouse_last_x; delta_y = y - mouse_last_y;
818 +                        mouse_last_x = x; mouse_last_y = y;
819 +                        ADBMouseMoved(delta_x, delta_y);
820 +                }
821 +                mouse_last_x = width/2;
822 +                mouse_last_y = height/2;
823 +                XWarpPointer(x_display, None, w, 0, 0, 0, 0, mouse_last_x, mouse_last_y);
824 +                for (int i=0; i<10; i++) {
825 +                        XMaskEvent(x_display, PointerMotionMask, &event);
826 +                        if (event.xmotion.x > (mouse_last_x - MOUSE_FUDGE_FACTOR)
827 +                         && event.xmotion.x < (mouse_last_x + MOUSE_FUDGE_FACTOR)
828 +                         && event.xmotion.y > (mouse_last_y - MOUSE_FUDGE_FACTOR)
829 +                         && event.xmotion.y < (mouse_last_y + MOUSE_FUDGE_FACTOR))
830 +                                break;
831 +                }
832 +        }
833 + }
834 +
835  
836   #if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA)
837   /*
# Line 612 | Line 883 | void driver_dga::suspend(void)
883   #endif
884          XUngrabPointer(x_display, CurrentTime);
885          XUngrabKeyboard(x_display, CurrentTime);
886 +        restore_mouse_accel();
887          XUnmapWindow(x_display, w);
888          wait_unmapped(w);
889  
# Line 639 | Line 911 | void driver_dga::resume(void)
911          XMapRaised(x_display, w);
912          wait_mapped(w);
913          XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
914 <        XGrabKeyboard(x_display, rootwin, 1, GrabModeAsync, GrabModeAsync, CurrentTime);
915 <        XGrabPointer(x_display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
914 >        XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
915 >        XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
916 >        disable_mouse_accel();
917   #ifdef ENABLE_XF86_DGA
918          XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
919          XF86DGASetViewPort(x_display, screen, 0, 0);
# Line 787 | Line 1060 | driver_fbdev::driver_fbdev(const video_m
1060          XGrabPointer(x_display, w, True,
1061                  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1062                  GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
1063 +        disable_mouse_accel();
1064          
1065          // Calculate bytes per row
1066          int bytes_per_row = TrivialBytesPerRow(mode.x, mode.depth);
1067          
1068          // Map frame buffer
1069 <        if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) {
1070 <                if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) {
1069 >        the_buffer_size = height * bytes_per_row;
1070 >        if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) {
1071 >                if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) {
1072                          char str[256];
1073                          sprintf(str, GetString(STR_FBDEV_MMAP_ERR), strerror(errno));
1074                          ErrorAlert(str);
# Line 832 | Line 1107 | driver_fbdev::driver_fbdev(const video_m
1107   // Close display
1108   driver_fbdev::~driver_fbdev()
1109   {
1110 +        if (!use_vosf) {
1111 +                if (the_buffer != MAP_FAILED) {
1112 +                        // don't free() the screen buffer in driver_base dtor
1113 +                        munmap(the_buffer, the_buffer_size);
1114 +                        the_buffer = NULL;
1115 +                }
1116 +        }
1117 + #ifdef ENABLE_VOSF
1118 +        else {
1119 +                if (the_host_buffer != MAP_FAILED) {
1120 +                        // don't free() the screen buffer in driver_base dtor
1121 +                        munmap(the_host_buffer, the_buffer_size);
1122 +                        the_host_buffer = NULL;
1123 +                }
1124 +                if (the_buffer_copy != VM_MAP_FAILED) {
1125 +                        vm_release(the_buffer_copy, the_buffer_size);
1126 +                        the_buffer_copy = NULL;
1127 +                }
1128 +                if (the_buffer != VM_MAP_FAILED) {
1129 +                        vm_release(the_buffer, the_buffer_size);
1130 +                        the_buffer = NULL;
1131 +                }
1132 +        }
1133 + #endif
1134   }
1135   #endif
1136  
# Line 901 | Line 1200 | driver_xf86dga::driver_xf86dga(const vid
1200          XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
1201          XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
1202          XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
1203 +        disable_mouse_accel();
1204  
1205          int v_width, v_bank, v_size;
1206          XF86DGAGetVideo(x_display, screen, (char **)&the_buffer, &v_width, &v_bank, &v_size);
# Line 917 | Line 1217 | driver_xf86dga::driver_xf86dga(const vid
1217  
1218          // Init blitting routines
1219          int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth);
1220 < #ifdef VIDEO_VOSF
1220 > #if VIDEO_VOSF
1221   #if REAL_ADDRESSING || DIRECT_ADDRESSING
1222          // Screen_blitter_init() returns TRUE if VOSF is mandatory
1223          // i.e. the framebuffer update function is not Blit_Copy_Raw
# Line 948 | Line 1248 | driver_xf86dga::driver_xf86dga(const vid
1248   driver_xf86dga::~driver_xf86dga()
1249   {
1250          XF86DGADirectVideo(x_display, screen, 0);
1251 +        if (!use_vosf) {
1252 +                // don't free() the screen buffer in driver_base dtor
1253 +                the_buffer = NULL;
1254 +        }
1255 + #ifdef ENABLE_VOSF
1256 +        else {
1257 +                // don't free() the screen buffer in driver_base dtor
1258 +                the_host_buffer = NULL;
1259 +                
1260 +                if (the_buffer_copy != VM_MAP_FAILED) {
1261 +                        vm_release(the_buffer_copy, the_buffer_size);
1262 +                        the_buffer_copy = NULL;
1263 +                }
1264 +                if (the_buffer != VM_MAP_FAILED) {
1265 +                        vm_release(the_buffer, the_buffer_size);
1266 +                        the_buffer = NULL;
1267 +                }
1268 +        }
1269 + #endif
1270   #ifdef ENABLE_XF86_VIDMODE
1271          if (has_vidmode)
1272                  XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]);
# Line 1045 | Line 1364 | static void keycode_init(void)
1364   // Open display for specified mode
1365   static bool video_open(const video_mode &mode)
1366   {
1367 +        D(bug("video_open()\n"));
1368 +
1369 +        // Find best available X visual
1370 +        if (!find_visual_for_depth(mode.depth)) {
1371 +                ErrorAlert(STR_NO_XVISUAL_ERR);
1372 +                return false;
1373 +        }
1374 +
1375 +        // Create color maps
1376 +        if (color_class == PseudoColor || color_class == DirectColor) {
1377 +                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1378 +                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1379 +        } else {
1380 +                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocNone);
1381 +                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocNone);
1382 +        }
1383 +
1384 +        // Find pixel format of direct modes
1385 +        if (color_class == DirectColor || color_class == TrueColor) {
1386 +                rshift = gshift = bshift = 0;
1387 +                rloss = gloss = bloss = 8;
1388 +                uint32 mask;
1389 +                for (mask=vis->red_mask; !(mask&1); mask>>=1)
1390 +                        ++rshift;
1391 +                for (; mask&1; mask>>=1)
1392 +                        --rloss;
1393 +                for (mask=vis->green_mask; !(mask&1); mask>>=1)
1394 +                        ++gshift;
1395 +                for (; mask&1; mask>>=1)
1396 +                        --gloss;
1397 +                for (mask=vis->blue_mask; !(mask&1); mask>>=1)
1398 +                        ++bshift;
1399 +                for (; mask&1; mask>>=1)
1400 +                        --bloss;
1401 +        }
1402 +
1403 +        // Preset palette pixel values for CLUT or gamma table
1404 +        if (color_class == DirectColor) {
1405 +                int num = vis->map_entries;
1406 +                for (int i=0; i<num; i++) {
1407 +                        int c = (i * 256) / num;
1408 +                        palette[i].pixel = map_rgb(c, c, c);
1409 +                        palette[i].flags = DoRed | DoGreen | DoBlue;
1410 +                }
1411 +        } else if (color_class == PseudoColor) {
1412 +                for (int i=0; i<256; i++) {
1413 +                        palette[i].pixel = i;
1414 +                        palette[i].flags = DoRed | DoGreen | DoBlue;
1415 +                }
1416 +        }
1417 +
1418          // Load gray ramp to color map
1419 <        int num = (vis->c_class == DirectColor ? vis->map_entries : 256);
1419 >        int num = (color_class == DirectColor ? vis->map_entries : 256);
1420          for (int i=0; i<num; i++) {
1421                  int c = (i * 256) / num;
1422                  palette[i].red = c * 0x0101;
1423                  palette[i].green = c * 0x0101;
1424                  palette[i].blue = c * 0x0101;
1055                if (vis->c_class == PseudoColor)
1056                        palette[i].pixel = i;
1057                palette[i].flags = DoRed | DoGreen | DoBlue;
1425          }
1426 <        if (cmap[0] && cmap[1]) {
1426 >        if (color_class == PseudoColor || color_class == DirectColor) {
1427                  XStoreColors(x_display, cmap[0], palette, num);
1428                  XStoreColors(x_display, cmap[1], palette, num);
1429          }
1430  
1431   #ifdef ENABLE_VOSF
1432          // Load gray ramp to 8->16/32 expand map
1433 <        if (!IsDirectMode(mode) && (vis->c_class == TrueColor || vis->c_class == DirectColor))
1433 >        if (!IsDirectMode(mode) && xdepth > 8)
1434                  for (int i=0; i<256; i++)
1435                          ExpandMap[i] = map_rgb(i, i, i);
1436   #endif
# Line 1094 | Line 1461 | static bool video_open(const video_mode
1461  
1462   #ifdef ENABLE_VOSF
1463          if (use_vosf) {
1464 <                // Initialize the mainBuffer structure
1465 <                if (!video_init_buffer()) {
1464 >                // Initialize the VOSF system
1465 >                if (!video_vosf_init()) {
1466                          ErrorAlert(STR_VOSF_INIT_ERR);
1467                  return false;
1468                  }
1102
1103                // Initialize the handler for SIGSEGV
1104                if (!sigsegv_install_handler(screen_fault_handler)) {
1105                        ErrorAlert("Could not initialize Video on SEGV signals");
1106                        return false;
1107                }
1469          }
1470   #endif
1471          
# Line 1155 | Line 1516 | bool VideoInit(bool classic)
1516          // Find screen and root window
1517          screen = XDefaultScreen(x_display);
1518          rootwin = XRootWindow(x_display, screen);
1519 <        
1520 <        // Get screen depth
1521 <        xdepth = DefaultDepth(x_display, screen);
1519 >
1520 >        // Get sorted list of available depths
1521 >        avail_depths = XListDepths(x_display, screen, &num_depths);
1522 >        if (avail_depths == NULL) {
1523 >                ErrorAlert(STR_UNSUPP_DEPTH_ERR);
1524 >                return false;
1525 >        }
1526 >        sort(avail_depths, avail_depths + num_depths);
1527          
1528   #ifdef ENABLE_FBDEV_DGA
1529          // Frame buffer name
# Line 1197 | Line 1563 | bool VideoInit(bool classic)
1563          black_pixel = BlackPixel(x_display, screen);
1564          white_pixel = WhitePixel(x_display, screen);
1565  
1200        // Get appropriate visual
1201        int color_class;
1202        switch (xdepth) {
1203                case 1:
1204                        color_class = StaticGray;
1205                        break;
1206                case 8:
1207                        color_class = PseudoColor;
1208                        break;
1209                case 15:
1210                case 16:
1211                case 24:
1212                case 32: // Try DirectColor first, as this will allow gamma correction
1213                        color_class = DirectColor;
1214                        if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo))
1215                                color_class = TrueColor;
1216                        break;
1217                default:
1218                        ErrorAlert(STR_UNSUPP_DEPTH_ERR);
1219                        return false;
1220        }
1221        if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) {
1222                ErrorAlert(STR_NO_XVISUAL_ERR);
1223                return false;
1224        }
1225        if (visualInfo.depth != xdepth) {
1226                ErrorAlert(STR_NO_XVISUAL_ERR);
1227                return false;
1228        }
1229        vis = visualInfo.visual;
1230
1231        // Create color maps
1232        if (color_class == PseudoColor || color_class == DirectColor) {
1233                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1234                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1235        }
1236
1237        // Find pixel format of direct modes
1238        if (color_class == DirectColor || color_class == TrueColor) {
1239                rshift = gshift = bshift = 0;
1240                rloss = gloss = bloss = 8;
1241                uint32 mask;
1242                for (mask=vis->red_mask; !(mask&1); mask>>=1)
1243                        ++rshift;
1244                for (; mask&1; mask>>=1)
1245                        --rloss;
1246                for (mask=vis->green_mask; !(mask&1); mask>>=1)
1247                        ++gshift;
1248                for (; mask&1; mask>>=1)
1249                        --gloss;
1250                for (mask=vis->blue_mask; !(mask&1); mask>>=1)
1251                        ++bshift;
1252                for (; mask&1; mask>>=1)
1253                        --bloss;
1254        }
1255
1256        // Preset palette pixel values for gamma table
1257        if (color_class == DirectColor) {
1258                int num = vis->map_entries;
1259                for (int i=0; i<num; i++) {
1260                        int c = (i * 256) / num;
1261                        palette[i].pixel = map_rgb(c, c, c);
1262                }
1263        }
1264
1566          // Get screen mode from preferences
1567          const char *mode_str;
1568          if (classic_mode)
# Line 1296 | Line 1597 | bool VideoInit(bool classic)
1597                  default_height = DisplayHeight(x_display, screen);
1598  
1599          // Mac screen depth follows X depth
1600 <        video_depth default_depth = DepthModeForPixelDepth(xdepth);
1600 >        video_depth default_depth = VDEPTH_1BIT;
1601 >        switch (DefaultDepth(x_display, screen)) {
1602 >                case 8:
1603 >                        default_depth = VDEPTH_8BIT;
1604 >                        break;
1605 >                case 15: case 16:
1606 >                        default_depth = VDEPTH_16BIT;
1607 >                        break;
1608 >                case 24: case 32:
1609 >                        default_depth = VDEPTH_32BIT;
1610 >                        break;
1611 >        }
1612  
1613          // Construct list of supported modes
1614          if (display_type == DISPLAY_WINDOW) {
1615                  if (classic)
1616                          add_mode(512, 342, 0x80, 64, VDEPTH_1BIT);
1617                  else {
1618 <                        if (default_depth != VDEPTH_1BIT)
1619 <                                add_window_modes(VDEPTH_1BIT);  // 1-bit modes are always available
1620 < #ifdef ENABLE_VOSF
1309 <                        if (default_depth > VDEPTH_8BIT) {
1310 <                                add_window_modes(VDEPTH_2BIT);  // 2, 4 and 8-bit modes are also possible on 16/32-bit screens with VOSF blitters
1311 <                                add_window_modes(VDEPTH_4BIT);
1312 <                                add_window_modes(VDEPTH_8BIT);
1618 >                        for (unsigned d=VDEPTH_1BIT; d<=VDEPTH_32BIT; d++) {
1619 >                                if (find_visual_for_depth(video_depth(d)))
1620 >                                        add_window_modes(video_depth(d));
1621                          }
1314 #endif
1315                        add_window_modes(default_depth);
1622                  }
1623          } else
1624                  add_mode(default_width, default_height, 0x80, TrivialBytesPerRow(default_width, default_depth), default_depth);
1625 +        if (VideoModes.empty()) {
1626 +                ErrorAlert(STR_NO_XVISUAL_ERR);
1627 +                return false;
1628 +        }
1629 +        video_init_depth_list();
1630 +
1631 + #if DEBUG
1632 +        D(bug("Available video modes:\n"));
1633 +        vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
1634 +        while (i != end) {
1635 +                int bits = 1 << i->depth;
1636 +                if (bits == 16)
1637 +                        bits = 15;
1638 +                else if (bits == 32)
1639 +                        bits = 24;
1640 +                D(bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits));
1641 +                ++i;
1642 +        }
1643 + #endif
1644  
1645          // Find requested default mode and open display
1646          if (VideoModes.size() == 1)
# Line 1339 | Line 1664 | bool VideoInit(bool classic)
1664   // Close display
1665   static void video_close(void)
1666   {
1667 +        D(bug("video_close()\n"));
1668 +
1669          // Stop redraw thread
1670   #ifdef HAVE_PTHREADS
1671          if (redraw_thread_active) {
# Line 1354 | Line 1681 | static void video_close(void)
1681          // Unlock frame buffer
1682          UNLOCK_FRAME_BUFFER;
1683          XSync(x_display, false);
1684 +        D(bug(" frame buffer unlocked\n"));
1685  
1686   #ifdef ENABLE_VOSF
1359        // Deinitialize VOSF
1687          if (use_vosf) {
1688 <                if (mainBuffer.pageInfo) {
1689 <                        free(mainBuffer.pageInfo);
1363 <                        mainBuffer.pageInfo = NULL;
1364 <                }
1365 <                if (mainBuffer.dirtyPages) {
1366 <                        free(mainBuffer.dirtyPages);
1367 <                        mainBuffer.dirtyPages = NULL;
1368 <                }
1688 >                // Deinitialize VOSF
1689 >                video_vosf_exit();
1690          }
1691   #endif
1692  
1693          // Close display
1694          delete drv;
1695          drv = NULL;
1375 }
1376
1377 void VideoExit(void)
1378 {
1379        // Close display
1380        video_close();
1696  
1697          // Free colormaps
1698          if (cmap[0]) {
# Line 1388 | Line 1703 | void VideoExit(void)
1703                  XFreeColormap(x_display, cmap[1]);
1704                  cmap[1] = 0;
1705          }
1706 + }
1707 +
1708 + void VideoExit(void)
1709 + {
1710 +        // Close display
1711 +        video_close();
1712  
1713   #ifdef ENABLE_XF86_VIDMODE
1714          // Free video mode list
# Line 1404 | Line 1725 | void VideoExit(void)
1725                  fbdev_fd = -1;
1726          }
1727   #endif
1728 +
1729 +        // Free depth list
1730 +        if (avail_depths) {
1731 +                XFree(avail_depths);
1732 +                avail_depths = NULL;
1733 +        }
1734   }
1735  
1736  
# Line 1445 | Line 1772 | void video_set_palette(uint8 *pal, int n
1772  
1773          // Convert colors to XColor array
1774          int num_out = 256;
1775 +        bool stretch = false;
1776          if (IsDirectMode(VideoMonitor.mode)) {
1777                  // If X is in 565 mode we have to stretch the gamma table from 32 to 64 entries
1778                  num_out = vis->map_entries;
1779 +                stretch = true;
1780          }
1781          XColor *p = palette;
1782          for (int i=0; i<num_out; i++) {
1783 <                int c = (i * num_in) / num_out;
1783 >                int c = (stretch ? (i * num_in) / num_out : i);
1784                  p->red = pal[c*3 + 0] * 0x0101;
1785                  p->green = pal[c*3 + 1] * 0x0101;
1786                  p->blue = pal[c*3 + 2] * 0x0101;
1458                if (vis->c_class == PseudoColor)
1459                        p->pixel = i;
1460                p->flags = DoRed | DoGreen | DoBlue;
1787                  p++;
1788          }
1789  
1790   #ifdef ENABLE_VOSF
1791          // Recalculate pixel color expansion map
1792 <        if (!IsDirectMode(VideoMonitor.mode) && (vis->c_class == TrueColor || vis->c_class == DirectColor)) {
1792 >        if (!IsDirectMode(VideoMonitor.mode) && xdepth > 8) {
1793                  for (int i=0; i<256; i++) {
1794 <                        int c = i % num_in; // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
1794 >                        int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
1795                          ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]);
1796                  }
1797  
# Line 1502 | Line 1828 | void video_switch_to_mode(const video_mo
1828  
1829  
1830   /*
1831 < *  Translate key event to Mac keycode
1831 > *  Translate key event to Mac keycode, returns -1 if no keycode was found
1832 > *  and -2 if the key was recognized as a hotkey
1833   */
1834  
1835 < static int kc_decode(KeySym ks)
1835 > static int kc_decode(KeySym ks, bool key_down)
1836   {
1837          switch (ks) {
1838                  case XK_A: case XK_a: return 0x00;
# Line 1558 | Line 1885 | static int kc_decode(KeySym ks)
1885                  case XK_period: case XK_greater: return 0x2f;
1886                  case XK_slash: case XK_question: return 0x2c;
1887  
1888 < #if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA)
1562 <                case XK_Tab: if (ctrl_down) {drv->suspend(); return -1;} else return 0x30;
1563 < #else
1564 <                case XK_Tab: return 0x30;
1565 < #endif
1888 >                case XK_Tab: if (ctrl_down) {if (key_down) drv->suspend(); return -2;} else return 0x30;
1889                  case XK_Return: return 0x24;
1890                  case XK_space: return 0x31;
1891                  case XK_BackSpace: return 0x33;
# Line 1596 | Line 1919 | static int kc_decode(KeySym ks)
1919                  case XK_Left: return 0x3b;
1920                  case XK_Right: return 0x3c;
1921  
1922 <                case XK_Escape: if (ctrl_down) {quit_full_screen = true; emerg_quit = true; return -1;} else return 0x35;
1922 >                case XK_Escape: if (ctrl_down) {if (key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35;
1923  
1924 <                case XK_F1: if (ctrl_down) {SysMountFirstFloppy(); return -1;} else return 0x7a;
1924 >                case XK_F1: if (ctrl_down) {if (key_down) SysMountFirstFloppy(); return -2;} else return 0x7a;
1925                  case XK_F2: return 0x78;
1926                  case XK_F3: return 0x63;
1927                  case XK_F4: return 0x76;
1928 <                case XK_F5: return 0x60;
1928 >                case XK_F5: if (ctrl_down) {if (key_down) drv->toggle_mouse_grab(); return -2;} else return 0x60;
1929                  case XK_F6: return 0x61;
1930                  case XK_F7: return 0x62;
1931                  case XK_F8: return 0x64;
# Line 1650 | Line 1973 | static int kc_decode(KeySym ks)
1973          return -1;
1974   }
1975  
1976 < static int event2keycode(XKeyEvent &ev)
1976 > static int event2keycode(XKeyEvent &ev, bool key_down)
1977   {
1978          KeySym ks;
1656        int as;
1979          int i = 0;
1980  
1981          do {
1982                  ks = XLookupKeysym(&ev, i++);
1983 <                as = kc_decode(ks);
1984 <                if (as != -1)
1983 >                int as = kc_decode(ks, key_down);
1984 >                if (as >= 0)
1985 >                        return as;
1986 >                if (as == -2)
1987                          return as;
1988          } while (ks != NoSymbol);
1989  
# Line 1678 | Line 2002 | static void handle_events(void)
2002                  XNextEvent(x_display, &event);
2003  
2004                  switch (event.type) {
2005 +
2006                          // Mouse button
2007                          case ButtonPress: {
2008                                  unsigned int button = event.xbutton.button;
# Line 1706 | Line 2031 | static void handle_events(void)
2031                          }
2032  
2033                          // Mouse moved
1709                        case EnterNotify:
2034                          case MotionNotify:
2035 <                                ADBMouseMoved(event.xmotion.x, event.xmotion.y);
2035 >                                drv->mouse_moved(event.xmotion.x, event.xmotion.y);
2036 >                                break;
2037 >
2038 >                        // Mouse entered window
2039 >                        case EnterNotify:
2040 >                                if (event.xcrossing.mode != NotifyGrab && event.xcrossing.mode != NotifyUngrab)
2041 >                                        drv->mouse_moved(event.xmotion.x, event.xmotion.y);
2042                                  break;
2043  
2044                          // Keyboard
2045                          case KeyPress: {
2046 <                                int code;
2046 >                                int code = -1;
2047                                  if (use_keycodes) {
2048 <                                        event2keycode(event.xkey);      // This is called to process the hotkeys
2049 <                                        code = keycode_table[event.xkey.keycode & 0xff];
2048 >                                        if (event2keycode(event.xkey, true) != -2)      // This is called to process the hotkeys
2049 >                                                code = keycode_table[event.xkey.keycode & 0xff];
2050                                  } else
2051 <                                        code = event2keycode(event.xkey);
2052 <                                if (code != -1) {
2051 >                                        code = event2keycode(event.xkey, true);
2052 >                                if (code >= 0) {
2053                                          if (!emul_suspended) {
2054                                                  if (code == 0x39) {     // Caps Lock pressed
2055                                                          if (caps_on) {
# Line 1741 | Line 2071 | static void handle_events(void)
2071                                  break;
2072                          }
2073                          case KeyRelease: {
2074 <                                int code;
2074 >                                int code = -1;
2075                                  if (use_keycodes) {
2076 <                                        event2keycode(event.xkey);      // This is called to process the hotkeys
2077 <                                        code = keycode_table[event.xkey.keycode & 0xff];
2076 >                                        if (event2keycode(event.xkey, false) != -2)     // This is called to process the hotkeys
2077 >                                                code = keycode_table[event.xkey.keycode & 0xff];
2078                                  } else
2079 <                                        code = event2keycode(event.xkey);
2080 <                                if (code != -1 && code != 0x39) {       // Don't propagate Caps Lock releases
2079 >                                        code = event2keycode(event.xkey, false);
2080 >                                if (code >= 0 && code != 0x39) {        // Don't propagate Caps Lock releases
2081                                          ADBKeyUp(code);
2082                                          if (code == 0x36)
2083                                                  ctrl_down = false;
# Line 1888 | Line 2218 | static void update_display_dynamic(int t
2218   static void update_display_static(driver_window *drv)
2219   {
2220          // Incremental update code
2221 <        int wide = 0, high = 0, x1, x2, y1, y2, i, j;
2221 >        unsigned wide = 0, high = 0, x1, x2, y1, y2, i, j;
2222          int bytes_per_row = VideoMonitor.mode.bytes_per_row;
2223          int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x;
2224          uint8 *p, *p2;
# Line 2011 | Line 2341 | static void update_display_static(driver
2341  
2342   static inline void possibly_quit_dga_mode()
2343   {
2344 <        // Quit DGA mode if requested
2344 >        // Quit DGA mode if requested (something terrible has happened and we
2345 >        // want to give control back to the user)
2346          if (quit_full_screen) {
2347                  quit_full_screen = false;
2348                  delete drv;
# Line 2019 | Line 2350 | static inline void possibly_quit_dga_mod
2350          }
2351   }
2352  
2353 + static inline void possibly_ungrab_mouse()
2354 + {
2355 +        // Ungrab mouse if requested (something terrible has happened and we
2356 +        // want to give control back to the user)
2357 +        if (quit_full_screen) {
2358 +                quit_full_screen = false;
2359 +                if (drv)
2360 +                        drv->ungrab_mouse();
2361 +        }
2362 + }
2363 +
2364   static inline void handle_palette_changes(void)
2365   {
2366          LOCK_PALETTE;
# Line 2035 | Line 2377 | static void video_refresh_dga(void)
2377   {
2378          // Quit DGA mode if requested
2379          possibly_quit_dga_mode();
2038        
2039        // Handle X events
2040        handle_events();
2041        
2042        // Handle palette changes
2043        handle_palette_changes();
2380   }
2381  
2382   #ifdef ENABLE_VOSF
# Line 2050 | Line 2386 | static void video_refresh_dga_vosf(void)
2386          // Quit DGA mode if requested
2387          possibly_quit_dga_mode();
2388          
2053        // Handle X events
2054        handle_events();
2055        
2056        // Handle palette changes
2057        handle_palette_changes();
2058        
2389          // Update display (VOSF variant)
2390          static int tick_counter = 0;
2391          if (++tick_counter >= frame_skip) {
# Line 2071 | Line 2401 | static void video_refresh_dga_vosf(void)
2401  
2402   static void video_refresh_window_vosf(void)
2403   {
2404 <        // Quit DGA mode if requested
2405 <        possibly_quit_dga_mode();
2076 <        
2077 <        // Handle X events
2078 <        handle_events();
2079 <        
2080 <        // Handle palette changes
2081 <        handle_palette_changes();
2404 >        // Ungrab mouse if requested
2405 >        possibly_ungrab_mouse();
2406          
2407          // Update display (VOSF variant)
2408          static int tick_counter = 0;
# Line 2096 | Line 2420 | static void video_refresh_window_vosf(vo
2420  
2421   static void video_refresh_window_static(void)
2422   {
2423 <        // Handle X events
2424 <        handle_events();
2425 <        
2102 <        // Handle_palette changes
2103 <        handle_palette_changes();
2104 <        
2423 >        // Ungrab mouse if requested
2424 >        possibly_ungrab_mouse();
2425 >
2426          // Update display (static variant)
2427          static int tick_counter = 0;
2428          if (++tick_counter >= frame_skip) {
# Line 2112 | Line 2433 | static void video_refresh_window_static(
2433  
2434   static void video_refresh_window_dynamic(void)
2435   {
2436 <        // Handle X events
2437 <        handle_events();
2438 <        
2118 <        // Handle_palette changes
2119 <        handle_palette_changes();
2120 <        
2436 >        // Ungrab mouse if requested
2437 >        possibly_ungrab_mouse();
2438 >
2439          // Update display (dynamic variant)
2440          static int tick_counter = 0;
2441          tick_counter++;
# Line 2153 | Line 2471 | static void VideoRefreshInit(void)
2471          }
2472   }
2473  
2474 + // This function is called on non-threaded platforms from a timer interrupt
2475   void VideoRefresh(void)
2476   {
2477          // We need to check redraw_thread_active to inhibit refreshed during
2478          // mode changes on non-threaded platforms
2479 <        if (redraw_thread_active)
2480 <                video_refresh();
2479 >        if (!redraw_thread_active)
2480 >                return;
2481 >
2482 >        // Handle X events
2483 >        handle_events();
2484 >
2485 >        // Handle palette changes
2486 >        handle_palette_changes();
2487 >
2488 >        // Update display
2489 >        video_refresh();
2490   }
2491  
2492 + const int VIDEO_REFRESH_HZ = 60;
2493 + const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
2494 +
2495   #ifdef HAVE_PTHREADS
2496   static void *redraw_func(void *arg)
2497   {
2498 +        int fd = ConnectionNumber(x_display);
2499 +
2500          uint64 start = GetTicks_usec();
2501          int64 ticks = 0;
2502 <        uint64 next = GetTicks_usec();
2502 >        uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY;
2503 >
2504          while (!redraw_thread_cancel) {
2505 <                video_refresh();
2172 <                next += 16667;
2505 >
2506                  int64 delay = next - GetTicks_usec();
2507 <                if (delay > 0)
2508 <                        Delay_usec(delay);
2509 <                else if (delay < -16667)
2507 >                if (delay < -VIDEO_REFRESH_DELAY) {
2508 >
2509 >                        // We are lagging far behind, so we reset the delay mechanism
2510                          next = GetTicks_usec();
2511 <                ticks++;
2511 >
2512 >                } else if (delay <= 0) {
2513 >
2514 >                        // Delay expired, refresh display
2515 >                        handle_events();
2516 >                        handle_palette_changes();
2517 >                        video_refresh();
2518 >                        next += VIDEO_REFRESH_DELAY;
2519 >                        ticks++;
2520 >
2521 >                } else {
2522 >
2523 >                        // No display refresh pending, check for X events
2524 >                        fd_set readfds;
2525 >                        FD_ZERO(&readfds);
2526 >                        FD_SET(fd, &readfds);
2527 >                        struct timeval timeout;
2528 >                        timeout.tv_sec = 0;
2529 >                        timeout.tv_usec = delay;
2530 >                        if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
2531 >                                handle_events();
2532 >                }
2533          }
2534 +
2535          uint64 end = GetTicks_usec();
2536 <        // printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, ticks * 1000000 / (end - start));
2536 >        D(bug("%Ld refreshes in %Ld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
2537          return NULL;
2538   }
2539   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines