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.7 by cebix, 1999-10-21T13:19:24Z vs.
Revision 1.76 by gbeauche, 2005-01-30T21:42:14Z

# Line 1 | Line 1
1   /*
2   *  video_x.cpp - Video/graphics emulation, X11 specific stuff
3   *
4 < *  Basilisk II (C) 1997-1999 Christian Bauer
4 > *  Basilisk II (C) 1997-2005 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 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 34 | Line 35
35   #include <X11/extensions/XShm.h>
36   #include <sys/ipc.h>
37   #include <sys/shm.h>
37 #include <pthread.h>
38   #include <errno.h>
39  
40 + #include <algorithm>
41 +
42 + #ifdef HAVE_PTHREADS
43 + # include <pthread.h>
44 + #endif
45 +
46 + #ifdef ENABLE_XF86_DGA
47 + # include <X11/extensions/xf86dga.h>
48 + #endif
49 +
50 + #ifdef ENABLE_XF86_VIDMODE
51 + # include <X11/extensions/xf86vmode.h>
52 + #endif
53 +
54 + #ifdef ENABLE_FBDEV_DGA
55 + # include <sys/mman.h>
56 + #endif
57 +
58   #include "cpu_emulation.h"
59   #include "main.h"
60   #include "adb.h"
# Line 44 | Line 62
62   #include "prefs.h"
63   #include "user_strings.h"
64   #include "video.h"
65 + #include "video_blit.h"
66  
67 < #define DEBUG 1
67 > #define DEBUG 0
68   #include "debug.h"
69  
51 #if ENABLE_XF86_DGA
52 #include <X11/extensions/xf86dga.h>
53 #endif
54
55 #if ENABLE_FBDEV_DGA
56 #include <sys/mman.h>
57 #endif
58
70  
71 + // Supported video modes
72 + static vector<video_mode> VideoModes;
73  
74   // Display types
75   enum {
# Line 64 | Line 77 | enum {
77          DISPLAY_DGA             // DGA fullscreen display
78   };
79  
67
80   // Constants
81   const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes";
82 < const char FBDEVICES_FILE_NAME[] = DATADIR "/fbdevices";
82 >
83 > static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask | StructureNotifyMask;
84 > static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask;
85  
86  
87   // Global variables
88 < static int32 frame_skip;
88 > static int32 frame_skip;                                                        // Prefs items
89 > static int16 mouse_wheel_mode;
90 > static int16 mouse_wheel_lines;
91 >
92   static int display_type = DISPLAY_WINDOW;                       // See enum above
93 < static uint8 *the_buffer;                                                       // Mac frame buffer
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 < static volatile bool redraw_thread_cancel = false;      // Flag: Cancel Redraw thread
99 > #ifdef HAVE_PTHREADS
100 > static pthread_attr_t redraw_thread_attr;                       // Redraw thread attributes
101 > static volatile bool redraw_thread_cancel;                      // Flag: Cancel Redraw thread
102   static pthread_t redraw_thread;                                         // Redraw thread
103 + #endif
104  
105   static bool has_dga = false;                                            // Flag: Video DGA capable
106 + static bool has_vidmode = false;                                        // Flag: VidMode extension available
107 +
108 + #ifdef ENABLE_VOSF
109 + static bool use_vosf = true;                                            // Flag: VOSF enabled
110 + #else
111 + static const bool use_vosf = false;                                     // VOSF not possible
112 + #endif
113  
114   static bool ctrl_down = false;                                          // Flag: Ctrl key pressed
115   static bool caps_on = false;                                            // Flag: Caps Lock on
# Line 92 | Line 123 | static bool use_keycodes = false;                                      //
123   static int keycode_table[256];                                          // X keycode -> Mac keycode translation table
124  
125   // X11 variables
126 + char *x_display_name = NULL;                                            // X11 display name
127 + Display *x_display = NULL;                                                      // X11 display handle
128   static int screen;                                                                      // Screen number
129 < static int xdepth;                                                                      // Depth of X screen
130 < static int depth;                                                                       // Depth of Mac frame buffer
131 < static Window rootwin, the_win;                                         // Root window and our window
99 < static XVisualInfo visualInfo;
100 < static Visual *vis;
101 < static Colormap cmap[2];                                                        // Two colormaps (DGA) for 8-bit mode
129 > static Window rootwin;                                                          // Root window and our window
130 > static int num_depths = 0;                                                      // Number of available X depths
131 > static int *avail_depths = NULL;                                        // List of available X depths
132   static XColor black, white;
133   static unsigned long black_pixel, white_pixel;
134   static int eventmask;
105 static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask;
106 static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
135  
136 < static pthread_mutex_t palette_lock = PTHREAD_MUTEX_INITIALIZER;        // Mutex to protect palette
137 < static XColor palette[256];                                                     // Color palette for 8-bit mode
138 < static bool palette_changed = false;                            // Flag: Palette changed, redraw thread must set new colors
139 <
140 < // Variables for window mode
113 < static GC the_gc;
114 < static XImage *img = NULL;
115 < static XShmSegmentInfo shminfo;
116 < static XImage *cursor_image, *cursor_mask_image;
117 < static Pixmap cursor_map, cursor_mask_map;
118 < static Cursor mac_cursor;
119 < static GC cursor_gc, cursor_mask_gc;
120 < static uint8 *the_buffer_copy = NULL;                           // Copy of Mac frame buffer
121 < static uint8 the_cursor[64];                                            // Cursor image data
122 < static bool have_shm = false;                                           // Flag: SHM extensions available
123 <
124 < // Variables for XF86 DGA mode
125 < static int current_dga_cmap;                                            // Number (0 or 1) of currently installed DGA colormap
126 < static Window suspend_win;                                                      // "Suspend" window
127 < static void *fb_save = NULL;                                            // Saved frame buffer for suspend
128 < static pthread_mutex_t frame_buffer_lock = PTHREAD_MUTEX_INITIALIZER;   // Mutex to protect frame buffer
136 > static int xdepth;                                                                      // Depth of X screen
137 > static VisualFormat visualFormat;
138 > static XVisualInfo visualInfo;
139 > static Visual *vis;
140 > static int color_class;
141  
142 < // Variables for fbdev DGA mode
143 < const char FBDEVICE_FILE_NAME[] = "/dev/fb";
144 < static int fbdev_fd;
142 > static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes
143 >
144 > static Colormap cmap[2] = {0, 0};                                       // Colormaps for indexed modes (DGA needs two of them)
145 >
146 > static XColor x_palette[256];                                                   // Color palette to be used as CLUT and gamma table
147 > static bool x_palette_changed = false;                          // Flag: Palette changed, redraw thread must set new colors
148 >
149 > #ifdef ENABLE_FBDEV_DGA
150 > static int fbdev_fd = -1;
151 > #endif
152 >
153 > #ifdef ENABLE_XF86_VIDMODE
154 > static XF86VidModeModeInfo **x_video_modes = NULL;      // Array of all available modes
155 > static int num_x_video_modes;
156 > #endif
157 >
158 > // Mutex to protect palette
159 > #ifdef HAVE_PTHREADS
160 > static pthread_mutex_t x_palette_lock = PTHREAD_MUTEX_INITIALIZER;
161 > #define LOCK_PALETTE pthread_mutex_lock(&x_palette_lock)
162 > #define UNLOCK_PALETTE pthread_mutex_unlock(&x_palette_lock)
163 > #else
164 > #define LOCK_PALETTE
165 > #define UNLOCK_PALETTE
166 > #endif
167 >
168 > // Mutex to protect frame buffer
169 > #ifdef HAVE_PTHREADS
170 > static pthread_mutex_t frame_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
171 > #define LOCK_FRAME_BUFFER pthread_mutex_lock(&frame_buffer_lock);
172 > #define UNLOCK_FRAME_BUFFER pthread_mutex_unlock(&frame_buffer_lock);
173 > #else
174 > #define LOCK_FRAME_BUFFER
175 > #define UNLOCK_FRAME_BUFFER
176 > #endif
177 >
178 > // Variables for non-VOSF incremental refresh
179 > static const int sm_uptd[] = {4,1,6,3,0,5,2,7};
180 > static int sm_no_boxes[] = {1,8,32,64,128,300};
181 > static bool updt_box[17][17];
182 > static int nr_boxes;
183 >
184 > // Video refresh function
185 > static void VideoRefreshInit(void);
186 > static void (*video_refresh)(void);
187  
188  
189   // Prototypes
190   static void *redraw_func(void *arg);
137 static int event2keycode(XKeyEvent *ev);
138
191  
192   // From main_unix.cpp
193 + extern char *x_display_name;
194   extern Display *x_display;
195 + extern void *vm_acquire_mac(size_t size);
196  
197   // From sys_unix.cpp
198   extern void SysMountFirstFloppy(void);
199  
200 + // From clip_unix.cpp
201 + extern void ClipboardSelectionClear(XSelectionClearEvent *);
202 + extern void ClipboardSelectionRequest(XSelectionRequestEvent *);
203 +
204  
205   /*
206 < *  Initialization
206 > *  monitor_desc subclass for X11 display
207   */
208  
209 < // Set VideoMonitor according to video mode
210 < void set_video_monitor(int width, int height, int bytes_per_row, bool native_byte_order)
209 > class X11_monitor_desc : public monitor_desc {
210 > public:
211 >        X11_monitor_desc(const vector<video_mode> &available_modes, video_depth default_depth, uint32 default_id) : monitor_desc(available_modes, default_depth, default_id) {}
212 >        ~X11_monitor_desc() {}
213 >
214 >        virtual void switch_to_current_mode(void);
215 >        virtual void set_palette(uint8 *pal, int num);
216 >
217 >        bool video_open(void);
218 >        void video_close(void);
219 > };
220 >
221 >
222 > /*
223 > *  Utility functions
224 > */
225 >
226 > // Map video_mode depth ID to numerical depth value
227 > static inline int depth_of_video_mode(video_mode const & mode)
228   {
229 <        int layout = FLAYOUT_DIRECT;
229 >        int depth = -1;
230 >        switch (mode.depth) {
231 >        case VDEPTH_1BIT:
232 >                depth = 1;
233 >                break;
234 >        case VDEPTH_2BIT:
235 >                depth = 2;
236 >                break;
237 >        case VDEPTH_4BIT:
238 >                depth = 4;
239 >                break;
240 >        case VDEPTH_8BIT:
241 >                depth = 8;
242 >                break;
243 >        case VDEPTH_16BIT:
244 >                depth = 16;
245 >                break;
246 >        case VDEPTH_32BIT:
247 >                depth = 32;
248 >                break;
249 >        default:
250 >                abort();
251 >        }
252 >        return depth;
253 > }
254 >
255 > // Map RGB color to pixel value (this only works in TrueColor/DirectColor visuals)
256 > static inline uint32 map_rgb(uint8 red, uint8 green, uint8 blue)
257 > {
258 >        return ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift);
259 > }
260 >
261 > // Do we have a visual for handling the specified Mac depth? If so, set the
262 > // global variables "xdepth", "visualInfo", "vis" and "color_class".
263 > static bool find_visual_for_depth(video_depth depth)
264 > {
265 >        D(bug("have_visual_for_depth(%d)\n", 1 << depth));
266 >
267 >        // 1-bit works always and uses default visual
268 >        if (depth == VDEPTH_1BIT) {
269 >                vis = DefaultVisual(x_display, screen);
270 >                visualInfo.visualid = XVisualIDFromVisual(vis);
271 >                int num = 0;
272 >                XVisualInfo *vi = XGetVisualInfo(x_display, VisualIDMask, &visualInfo, &num);
273 >                visualInfo = vi[0];
274 >                XFree(vi);
275 >                xdepth = visualInfo.depth;
276 >                color_class = visualInfo.c_class;
277 >                D(bug(" found visual ID 0x%02x, depth %d\n", visualInfo.visualid, xdepth));
278 >                return true;
279 >        }
280 >
281 >        // Calculate minimum and maximum supported X depth
282 >        int min_depth = 1, max_depth = 32;
283          switch (depth) {
284 <                case 1:
285 <                        layout = FLAYOUT_DIRECT;
286 <                        VideoMonitor.mode = VMODE_1BIT;
284 > #ifdef ENABLE_VOSF
285 >                case VDEPTH_2BIT:
286 >                case VDEPTH_4BIT:       // VOSF blitters can convert 2/4/8-bit -> 8/16/32-bit
287 >                case VDEPTH_8BIT:
288 >                        min_depth = 8;
289 >                        max_depth = 32;
290                          break;
291 <                case 8:
292 <                        layout = FLAYOUT_DIRECT;
293 <                        VideoMonitor.mode = VMODE_8BIT;
294 <                        break;
295 <                case 15:
296 <                        layout = FLAYOUT_HOST_555;
297 <                        VideoMonitor.mode = VMODE_16BIT;
291 > #else
292 >                case VDEPTH_2BIT:
293 >                case VDEPTH_4BIT:       // 2/4-bit requires VOSF blitters
294 >                        return false;
295 >                case VDEPTH_8BIT:       // 8-bit without VOSF requires an 8-bit visual
296 >                        min_depth = 8;
297 >                        max_depth = 8;
298                          break;
299 <                case 16:
300 <                        layout = FLAYOUT_HOST_565;
301 <                        VideoMonitor.mode = VMODE_16BIT;
299 > #endif
300 >                case VDEPTH_16BIT:      // 16-bit requires a 15/16-bit visual
301 >                        min_depth = 15;
302 >                        max_depth = 16;
303                          break;
304 <                case 24:
305 <                case 32:
306 <                        layout = FLAYOUT_HOST_888;
175 <                        VideoMonitor.mode = VMODE_32BIT;
304 >                case VDEPTH_32BIT:      // 32-bit requires a 24/32-bit visual
305 >                        min_depth = 24;
306 >                        max_depth = 32;
307                          break;
308          }
309 <        VideoMonitor.x = width;
310 <        VideoMonitor.y = height;
311 <        VideoMonitor.bytes_per_row = bytes_per_row;
309 >        D(bug(" minimum required X depth is %d, maximum supported X depth is %d\n", min_depth, max_depth));
310 >
311 >        // Try to find a visual for one of the color depths
312 >        bool visual_found = false;
313 >        for (int i=0; i<num_depths && !visual_found; i++) {
314 >
315 >                xdepth = avail_depths[i];
316 >                D(bug(" trying to find visual for depth %d\n", xdepth));
317 >                if (xdepth < min_depth || xdepth > max_depth)
318 >                        continue;
319 >
320 >                // Determine best color class for this depth
321 >                switch (xdepth) {
322 >                        case 1: // Try StaticGray or StaticColor
323 >                                if (XMatchVisualInfo(x_display, screen, xdepth, StaticGray, &visualInfo)
324 >                                 || XMatchVisualInfo(x_display, screen, xdepth, StaticColor, &visualInfo))
325 >                                        visual_found = true;
326 >                                break;
327 >                        case 8: // Need PseudoColor
328 >                                if (XMatchVisualInfo(x_display, screen, xdepth, PseudoColor, &visualInfo))
329 >                                        visual_found = true;
330 >                                break;
331 >                        case 15:
332 >                        case 16:
333 >                        case 24:
334 >                        case 32: // Try DirectColor first, as this will allow gamma correction
335 >                                if (XMatchVisualInfo(x_display, screen, xdepth, DirectColor, &visualInfo)
336 >                                 || XMatchVisualInfo(x_display, screen, xdepth, TrueColor, &visualInfo))
337 >                                        visual_found = true;
338 >                                break;
339 >                        default:
340 >                                D(bug("  not a supported depth\n"));
341 >                                break;
342 >                }
343 >        }
344 >        if (!visual_found)
345 >                return false;
346 >
347 >        // Visual was found
348 >        vis = visualInfo.visual;
349 >        color_class = visualInfo.c_class;
350 >        D(bug(" found visual ID 0x%02x, depth %d, class ", visualInfo.visualid, xdepth));
351 > #if DEBUG
352 >        switch (color_class) {
353 >                case StaticGray: D(bug("StaticGray\n")); break;
354 >                case GrayScale: D(bug("GrayScale\n")); break;
355 >                case StaticColor: D(bug("StaticColor\n")); break;
356 >                case PseudoColor: D(bug("PseudoColor\n")); break;
357 >                case TrueColor: D(bug("TrueColor\n")); break;
358 >                case DirectColor: D(bug("DirectColor\n")); break;
359 >        }
360 > #endif
361 >        return true;
362 > }
363 >
364 > // Add mode to list of supported modes
365 > static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth)
366 > {
367 >        video_mode mode;
368 >        mode.x = width;
369 >        mode.y = height;
370 >        mode.resolution_id = resolution_id;
371 >        mode.bytes_per_row = bytes_per_row;
372 >        mode.depth = depth;
373 >        VideoModes.push_back(mode);
374 > }
375 >
376 > // Add standard list of windowed modes for given color depth
377 > static void add_window_modes(video_depth depth)
378 > {
379 >        add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth);
380 >        add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth);
381 >        add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth);
382 >        add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth), depth);
383 >        add_mode(1152, 870, 0x84, TrivialBytesPerRow(1152, depth), depth);
384 >        add_mode(1280, 1024, 0x85, TrivialBytesPerRow(1280, depth), depth);
385 >        add_mode(1600, 1200, 0x86, TrivialBytesPerRow(1600, depth), depth);
386 > }
387 >
388 > // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
389 > static void set_mac_frame_buffer(X11_monitor_desc &monitor, video_depth depth, bool native_byte_order)
390 > {
391 > #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
392 >        int layout = FLAYOUT_DIRECT;
393 >        if (depth == VDEPTH_16BIT)
394 >                layout = (xdepth == 15) ? FLAYOUT_HOST_555 : FLAYOUT_HOST_565;
395 >        else if (depth == VDEPTH_32BIT)
396 >                layout = (xdepth == 24) ? FLAYOUT_HOST_888 : FLAYOUT_DIRECT;
397          if (native_byte_order)
398                  MacFrameLayout = layout;
399          else
400                  MacFrameLayout = FLAYOUT_DIRECT;
401 +        monitor.set_mac_frame_base(MacFrameBaseMac);
402 +
403 +        // Set variables used by UAE memory banking
404 +        const video_mode &mode = monitor.get_current_mode();
405 +        MacFrameBaseHost = the_buffer;
406 +        MacFrameSize = mode.bytes_per_row * mode.y;
407 +        InitFrameBufferMapping();
408 + #else
409 +        monitor.set_mac_frame_base(Host2MacAddr(the_buffer));
410 + #endif
411 +        D(bug("monitor.mac_frame_base = %08x\n", monitor.get_mac_frame_base()));
412 + }
413 +
414 + // Set window name and class
415 + static void set_window_name(Window w, int name)
416 + {
417 +        const char *str = GetString(name);
418 +        XStoreName(x_display, w, str);
419 +        XSetIconName(x_display, w, str);
420 +
421 +        XClassHint *hints;
422 +        hints = XAllocClassHint();
423 +        if (hints) {
424 +                hints->res_name = "BasiliskII";
425 +                hints->res_class = "BasiliskII";
426 +                XSetClassHint(x_display, w, hints);
427 +                XFree(hints);
428 +        }
429 + }
430 +
431 + // Set window input focus flag
432 + static void set_window_focus(Window w)
433 + {
434 +        XWMHints *hints = XAllocWMHints();
435 +        if (hints) {
436 +                hints->input = True;
437 +                hints->initial_state = NormalState;
438 +                hints->flags = InputHint | StateHint;
439 +                XSetWMHints(x_display, w, hints);
440 +                XFree(hints);
441 +        }
442 + }
443 +
444 + // Set WM_DELETE_WINDOW protocol on window (preventing it from being destroyed by the WM when clicking on the "close" widget)
445 + static Atom WM_DELETE_WINDOW = (Atom)0;
446 + static void set_window_delete_protocol(Window w)
447 + {
448 +        WM_DELETE_WINDOW = XInternAtom(x_display, "WM_DELETE_WINDOW", false);
449 +        XSetWMProtocols(x_display, w, &WM_DELETE_WINDOW, 1);
450 + }
451 +
452 + // Wait until window is mapped/unmapped
453 + void wait_mapped(Window w)
454 + {
455 +        XEvent e;
456 +        do {
457 +                XMaskEvent(x_display, StructureNotifyMask, &e);
458 +        } while ((e.type != MapNotify) || (e.xmap.event != w));
459 + }
460 +
461 + void wait_unmapped(Window w)
462 + {
463 +        XEvent e;
464 +        do {
465 +                XMaskEvent(x_display, StructureNotifyMask, &e);
466 +        } while ((e.type != UnmapNotify) || (e.xmap.event != w));
467   }
468  
469   // Trap SHM errors
# Line 197 | Line 479 | static int error_handler(Display *d, XEr
479                  return old_error_handler(d, e);
480   }
481  
482 < // Init window mode
483 < static bool init_window(int width, int height)
482 >
483 > /*
484 > *  Display "driver" classes
485 > */
486 >
487 > class driver_base {
488 > public:
489 >        driver_base(X11_monitor_desc &m);
490 >        virtual ~driver_base();
491 >
492 >        virtual void update_palette(void);
493 >        virtual void suspend(void) {}
494 >        virtual void resume(void) {}
495 >        virtual void toggle_mouse_grab(void) {}
496 >        virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); }
497 >
498 >        void disable_mouse_accel(void);
499 >        void restore_mouse_accel(void);
500 >
501 >        virtual void grab_mouse(void) {}
502 >        virtual void ungrab_mouse(void) {}
503 >
504 > public:
505 >        X11_monitor_desc &monitor; // Associated video monitor
506 >        const video_mode &mode;    // Video mode handled by the driver
507 >
508 >        bool init_ok;   // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer)
509 >        Window w;               // The window we draw into
510 >
511 >        int orig_accel_numer, orig_accel_denom, orig_threshold; // Original mouse acceleration
512 > };
513 >
514 > class driver_window;
515 > static void update_display_window_vosf(driver_window *drv);
516 > static void update_display_dynamic(int ticker, driver_window *drv);
517 > static void update_display_static(driver_window *drv);
518 >
519 > class driver_window : public driver_base {
520 >        friend void update_display_window_vosf(driver_window *drv);
521 >        friend void update_display_dynamic(int ticker, driver_window *drv);
522 >        friend void update_display_static(driver_window *drv);
523 >
524 > public:
525 >        driver_window(X11_monitor_desc &monitor);
526 >        ~driver_window();
527 >
528 >        void toggle_mouse_grab(void);
529 >        void mouse_moved(int x, int y);
530 >
531 >        void grab_mouse(void);
532 >        void ungrab_mouse(void);
533 >
534 > private:
535 >        GC gc;
536 >        XImage *img;
537 >        bool have_shm;                                  // Flag: SHM extensions available
538 >        XShmSegmentInfo shminfo;
539 >        Cursor mac_cursor;
540 >        bool mouse_grabbed;                             // Flag: mouse pointer grabbed, using relative mouse mode
541 >        int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode)
542 > };
543 >
544 > static driver_base *drv = NULL; // Pointer to currently used driver object
545 >
546 > #ifdef ENABLE_VOSF
547 > # include "video_vosf.h"
548 > #endif
549 >
550 > driver_base::driver_base(X11_monitor_desc &m)
551 > : monitor(m), mode(m.get_current_mode()), init_ok(false), w(0)
552   {
553 <        // Set absolute mouse mode
554 <        ADBSetRelMouseMode(false);
553 >        the_buffer = NULL;
554 >        the_buffer_copy = NULL;
555 >        XGetPointerControl(x_display, &orig_accel_numer, &orig_accel_denom, &orig_threshold);
556 > }
557  
558 <        // Read frame skip prefs
559 <        frame_skip = PrefsFindInt32("frameskip");
560 <        if (frame_skip == 0)
561 <                frame_skip = 1;
558 > driver_base::~driver_base()
559 > {
560 >        ungrab_mouse();
561 >        restore_mouse_accel();
562  
563 <        // Create window
564 <        XSetWindowAttributes wattr;
565 <        wattr.event_mask = eventmask = win_eventmask;
566 <        wattr.background_pixel = black_pixel;
567 <        wattr.border_pixel = black_pixel;
216 <        wattr.backing_store = Always;
217 <        wattr.backing_planes = xdepth;
563 >        if (w) {
564 >                XUnmapWindow(x_display, w);
565 >                wait_unmapped(w);
566 >                XDestroyWindow(x_display, w);
567 >        }
568  
569 <        XSync(x_display, false);
220 <        the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
221 <                InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel |
222 <                CWBackingStore | CWBackingPlanes, &wattr);
223 <        XSync(x_display, false);
224 <        XStoreName(x_display, the_win, GetString(STR_WINDOW_TITLE));
225 <        XMapRaised(x_display, the_win);
569 >        XFlush(x_display);
570          XSync(x_display, false);
571  
572 <        // Set colormap
573 <        if (depth == 8) {
574 <                XSetWindowColormap(x_display, the_win, cmap[0]);
575 <                XSetWMColormapWindows(x_display, the_win, &the_win, 1);
572 >        // Free frame buffer(s)
573 >        if (!use_vosf) {
574 >                if (the_buffer) {
575 >                        free(the_buffer);
576 >                        the_buffer = NULL;
577 >                }
578 >                if (the_buffer_copy) {
579 >                        free(the_buffer_copy);
580 >                        the_buffer_copy = NULL;
581 >                }
582          }
583 + #ifdef ENABLE_VOSF
584 +        else {
585 +                // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will
586 +                if (the_buffer != VM_MAP_FAILED) {
587 +                        D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
588 +                        vm_release(the_buffer, the_buffer_size);
589 +                        the_buffer = NULL;
590 +                }
591 +                if (the_host_buffer) {
592 +                        D(bug(" freeing the_host_buffer at %p\n", the_host_buffer));
593 +                        free(the_host_buffer);
594 +                        the_host_buffer = NULL;
595 +                }
596 +                if (the_buffer_copy) {
597 +                        D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
598 +                        free(the_buffer_copy);
599 +                        the_buffer_copy = NULL;
600 +                }
601 +        }
602 + #endif
603 + }
604  
605 <        // Make window unresizable
606 <        XSizeHints *hints;
607 <        if ((hints = XAllocSizeHints()) != NULL) {
608 <                hints->min_width = width;
609 <                hints->max_width = width;
610 <                hints->min_height = height;
611 <                hints->max_height = height;
612 <                hints->flags = PMinSize | PMaxSize;
613 <                XSetWMNormalHints(x_display, the_win, hints);
243 <                XFree((char *)hints);
605 > // Palette has changed
606 > void driver_base::update_palette(void)
607 > {
608 >        if (color_class == PseudoColor || color_class == DirectColor) {
609 >                int num = vis->map_entries;
610 >                if (!IsDirectMode(monitor.get_current_mode()) && color_class == DirectColor)
611 >                        return; // Indexed mode on true color screen, don't set CLUT
612 >                XStoreColors(x_display, cmap[0], x_palette, num);
613 >                XStoreColors(x_display, cmap[1], x_palette, num);
614          }
615 <        
615 >        XSync(x_display, false);
616 > }
617 >
618 > // Disable mouse acceleration
619 > void driver_base::disable_mouse_accel(void)
620 > {
621 >        XChangePointerControl(x_display, True, False, 1, 1, 0);
622 > }
623 >
624 > // Restore mouse acceleration to original value
625 > void driver_base::restore_mouse_accel(void)
626 > {
627 >        XChangePointerControl(x_display, True, True, orig_accel_numer, orig_accel_denom, orig_threshold);
628 > }
629 >
630 >
631 > /*
632 > *  Windowed display driver
633 > */
634 >
635 > // Open display
636 > driver_window::driver_window(X11_monitor_desc &m)
637 > : driver_base(m), gc(0), img(NULL), have_shm(false), mac_cursor(0), mouse_grabbed(false)
638 > {
639 >        int width = mode.x, height = mode.y;
640 >        int aligned_width = (width + 15) & ~15;
641 >        int aligned_height = (height + 15) & ~15;
642 >
643 >        // Set absolute mouse mode
644 >        ADBSetRelMouseMode(mouse_grabbed);
645 >
646 >        // Create window (setting background_pixel, border_pixel and colormap is
647 >        // mandatory when using a non-default visual; in 1-bit mode we use the
648 >        // default visual, so we can also use the default colormap)
649 >        XSetWindowAttributes wattr;
650 >        wattr.event_mask = eventmask = win_eventmask;
651 >        wattr.background_pixel = (vis == DefaultVisual(x_display, screen) ? black_pixel : 0);
652 >        wattr.border_pixel = 0;
653 >        wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]);
654 >        w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
655 >                InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWColormap, &wattr);
656 >        D(bug(" window created\n"));
657 >
658 >        // Set window name/class
659 >        set_window_name(w, STR_WINDOW_TITLE);
660 >
661 >        // Indicate that we want keyboard input
662 >        set_window_focus(w);
663 >
664 >        // Set delete protocol property
665 >        set_window_delete_protocol(w);
666 >
667 >        // Make window unresizable
668 >        {
669 >                XSizeHints *hints = XAllocSizeHints();
670 >                if (hints) {
671 >                        hints->min_width = width;
672 >                        hints->max_width = width;
673 >                        hints->min_height = height;
674 >                        hints->max_height = height;
675 >                        hints->flags = PMinSize | PMaxSize;
676 >                        XSetWMNormalHints(x_display, w, hints);
677 >                        XFree(hints);
678 >                }
679 >        }
680 >        D(bug(" window attributes set\n"));
681 >        
682 >        // Show window
683 >        XMapWindow(x_display, w);
684 >        wait_mapped(w);
685 >        D(bug(" window mapped\n"));
686 >
687 >        // 1-bit mode is big-endian; if the X server is little-endian, we can't
688 >        // use SHM because that doesn't allow changing the image byte order
689 >        bool need_msb_image = (mode.depth == VDEPTH_1BIT && XImageByteOrder(x_display) == LSBFirst);
690 >
691          // Try to create and attach SHM image
692 <        have_shm = false;
248 <        if (depth != 1 && XShmQueryExtension(x_display)) {
692 >        if (local_X11 && !need_msb_image && XShmQueryExtension(x_display)) {
693  
694                  // Create SHM image ("height + 2" for safety)
695 <                img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
696 <                shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
697 <                the_buffer = (uint8 *)shmat(shminfo.shmid, 0, 0);
698 <                shminfo.shmaddr = img->data = (char *)the_buffer;
695 >                img = XShmCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
696 >                D(bug(" shm image created\n"));
697 >                shminfo.shmid = shmget(IPC_PRIVATE, (aligned_height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
698 >                the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
699 >                shminfo.shmaddr = img->data = (char *)the_buffer_copy;
700                  shminfo.readOnly = False;
701  
702                  // Try to attach SHM image, catching errors
# Line 263 | Line 708 | static bool init_window(int width, int h
708                  if (shm_error) {
709                          shmdt(shminfo.shmaddr);
710                          XDestroyImage(img);
711 +                        img = NULL;
712                          shminfo.shmid = -1;
713                  } else {
714                          have_shm = true;
715                          shmctl(shminfo.shmid, IPC_RMID, 0);
716                  }
717 +                D(bug(" shm image attached\n"));
718          }
719          
720          // Create normal X image if SHM doesn't work ("height + 2" for safety)
721          if (!have_shm) {
722 <                int bytes_per_row = width;
723 <                switch (depth) {
724 <                        case 1:
725 <                                bytes_per_row /= 8;
279 <                                break;
280 <                        case 15:
281 <                        case 16:
282 <                                bytes_per_row *= 2;
283 <                                break;
284 <                        case 24:
285 <                        case 32:
286 <                                bytes_per_row *= 4;
287 <                                break;
288 <                }
289 <                the_buffer = (uint8 *)malloc((height + 2) * bytes_per_row);
290 <                img = XCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)the_buffer, width, height, 32, bytes_per_row);
722 >                int bytes_per_row = (mode.depth == VDEPTH_1BIT ? aligned_width/8 : TrivialBytesPerRow(aligned_width, DepthModeForPixelDepth(xdepth)));
723 >                the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
724 >                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);
725 >                D(bug(" X image created\n"));
726          }
727  
728 <        // 1-Bit mode is big-endian
294 <        if (depth == 1) {
728 >        if (need_msb_image) {
729                  img->byte_order = MSBFirst;
730                  img->bitmap_bit_order = MSBFirst;
731          }
732  
733 <        // Allocate memory for frame buffer copy
734 <        the_buffer_copy = (uint8 *)malloc((height + 2) * img->bytes_per_line);
733 > #ifdef ENABLE_VOSF
734 >        use_vosf = true;
735 >        // Allocate memory for frame buffer (SIZE is extended to page-boundary)
736 >        the_host_buffer = the_buffer_copy;
737 >        the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
738 >        the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size);
739 >        the_buffer_copy = (uint8 *)malloc(the_buffer_size);
740 >        D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
741 > #else
742 >        // Allocate memory for frame buffer
743 >        the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
744 >        D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
745 > #endif
746  
747          // Create GC
748 <        the_gc = XCreateGC(x_display, the_win, 0, 0);
749 <        XSetState(x_display, the_gc, black_pixel, white_pixel, GXcopy, AllPlanes);
748 >        gc = XCreateGC(x_display, w, 0, 0);
749 >        XSetState(x_display, gc, black_pixel, white_pixel, GXcopy, AllPlanes);
750  
751 <        // Create cursor
752 <        cursor_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)the_cursor, 16, 16, 16, 2);
753 <        cursor_image->byte_order = MSBFirst;
754 <        cursor_image->bitmap_bit_order = MSBFirst;
755 <        cursor_mask_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)the_cursor+32, 16, 16, 16, 2);
756 <        cursor_mask_image->byte_order = MSBFirst;
312 <        cursor_mask_image->bitmap_bit_order = MSBFirst;
313 <        cursor_map = XCreatePixmap(x_display, the_win, 16, 16, 1);
314 <        cursor_mask_map = XCreatePixmap(x_display, the_win, 16, 16, 1);
315 <        cursor_gc = XCreateGC(x_display, cursor_map, 0, 0);
316 <        cursor_mask_gc = XCreateGC(x_display, cursor_mask_map, 0, 0);
317 <        mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0);
751 >        // Create no_cursor
752 >        mac_cursor = XCreatePixmapCursor(x_display,
753 >           XCreatePixmap(x_display, w, 1, 1, 1),
754 >           XCreatePixmap(x_display, w, 1, 1, 1),
755 >           &black, &white, 0, 0);
756 >        XDefineCursor(x_display, w, mac_cursor);
757  
758 <        // Set VideoMonitor
758 >        // Init blitting routines
759 >        bool native_byte_order;
760   #ifdef WORDS_BIGENDIAN
761 <        set_video_monitor(width, height, img->bytes_per_line, img->bitmap_bit_order == MSBFirst);
761 >        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
762   #else
763 <        set_video_monitor(width, height, img->bytes_per_line, img->bitmap_bit_order == LSBFirst);
763 >        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
764   #endif
765 <        
766 < #if REAL_ADDRESSING
767 <        VideoMonitor.mac_frame_base = (uint32)the_buffer;
768 <        MacFrameLayout = FLAYOUT_DIRECT;
765 > #ifdef ENABLE_VOSF
766 >        Screen_blitter_init(visualFormat, native_byte_order, depth_of_video_mode(mode));
767 > #endif
768 >
769 >        // Set frame buffer base
770 >        set_mac_frame_buffer(monitor, mode.depth, native_byte_order);
771 >
772 >        // Everything went well
773 >        init_ok = true;
774 > }
775 >
776 > // Close display
777 > driver_window::~driver_window()
778 > {
779 >        if (have_shm) {
780 >                XShmDetach(x_display, &shminfo);
781 > #ifdef ENABLE_VOSF
782 >                the_host_buffer = NULL; // don't free() in driver_base dtor
783   #else
784 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
784 >                the_buffer_copy = NULL; // don't free() in driver_base dtor
785   #endif
786 <        return true;
786 >        }
787 >        if (img) {
788 >                if (!have_shm)
789 >                        img->data = NULL;
790 >                XDestroyImage(img);
791 >        }
792 >        if (have_shm) {
793 >                shmdt(shminfo.shmaddr);
794 >                shmctl(shminfo.shmid, IPC_RMID, 0);
795 >        }
796 >        if (gc)
797 >                XFreeGC(x_display, gc);
798 > }
799 >
800 > // Toggle mouse grab
801 > void driver_window::toggle_mouse_grab(void)
802 > {
803 >        if (mouse_grabbed)
804 >                ungrab_mouse();
805 >        else
806 >                grab_mouse();
807 > }
808 >
809 > // Grab mouse, switch to relative mouse mode
810 > void driver_window::grab_mouse(void)
811 > {
812 >        int result;
813 >        for (int i=0; i<10; i++) {
814 >                result = XGrabPointer(x_display, w, True, 0,
815 >                        GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
816 >                if (result != AlreadyGrabbed)
817 >                        break;
818 >                Delay_usec(100000);
819 >        }
820 >        if (result == GrabSuccess) {
821 >                XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED));
822 >                ADBSetRelMouseMode(mouse_grabbed = true);
823 >                disable_mouse_accel();
824 >        }
825 > }
826 >
827 > // Ungrab mouse, switch to absolute mouse mode
828 > void driver_window::ungrab_mouse(void)
829 > {
830 >        if (mouse_grabbed) {
831 >                XUngrabPointer(x_display, CurrentTime);
832 >                XStoreName(x_display, w, GetString(STR_WINDOW_TITLE));
833 >                ADBSetRelMouseMode(mouse_grabbed = false);
834 >                restore_mouse_accel();
835 >        }
836 > }
837 >
838 > // Mouse moved
839 > void driver_window::mouse_moved(int x, int y)
840 > {
841 >        if (!mouse_grabbed) {
842 >                mouse_last_x = x; mouse_last_y = y;
843 >                ADBMouseMoved(x, y);
844 >                return;
845 >        }
846 >
847 >        // Warped mouse motion (this code is taken from SDL)
848 >
849 >        // Post first mouse event
850 >        int width = monitor.get_current_mode().x, height = monitor.get_current_mode().y;
851 >        int delta_x = x - mouse_last_x, delta_y = y - mouse_last_y;
852 >        mouse_last_x = x; mouse_last_y = y;
853 >        ADBMouseMoved(delta_x, delta_y);
854 >
855 >        // Only warp the pointer when it has reached the edge
856 >        const int MOUSE_FUDGE_FACTOR = 8;
857 >        if (x < MOUSE_FUDGE_FACTOR || x > (width - MOUSE_FUDGE_FACTOR)
858 >         || y < MOUSE_FUDGE_FACTOR || y > (height - MOUSE_FUDGE_FACTOR)) {
859 >                XEvent event;
860 >                while (XCheckTypedEvent(x_display, MotionNotify, &event)) {
861 >                        delta_x = x - mouse_last_x; delta_y = y - mouse_last_y;
862 >                        mouse_last_x = x; mouse_last_y = y;
863 >                        ADBMouseMoved(delta_x, delta_y);
864 >                }
865 >                mouse_last_x = width/2;
866 >                mouse_last_y = height/2;
867 >                XWarpPointer(x_display, None, w, 0, 0, 0, 0, mouse_last_x, mouse_last_y);
868 >                for (int i=0; i<10; i++) {
869 >                        XMaskEvent(x_display, PointerMotionMask, &event);
870 >                        if (event.xmotion.x > (mouse_last_x - MOUSE_FUDGE_FACTOR)
871 >                         && event.xmotion.x < (mouse_last_x + MOUSE_FUDGE_FACTOR)
872 >                         && event.xmotion.y > (mouse_last_y - MOUSE_FUDGE_FACTOR)
873 >                         && event.xmotion.y < (mouse_last_y + MOUSE_FUDGE_FACTOR))
874 >                                break;
875 >                }
876 >        }
877 > }
878 >
879 >
880 > #if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA)
881 > /*
882 > *  DGA display driver base class
883 > */
884 >
885 > class driver_dga : public driver_base {
886 > public:
887 >        driver_dga(X11_monitor_desc &monitor);
888 >        ~driver_dga();
889 >
890 >        void suspend(void);
891 >        void resume(void);
892 >
893 > private:
894 >        Window suspend_win;             // "Suspend" information window
895 >        void *fb_save;                  // Saved frame buffer for suspend/resume
896 > };
897 >
898 > driver_dga::driver_dga(X11_monitor_desc &m)
899 > : driver_base(m), suspend_win(0), fb_save(NULL)
900 > {
901 > }
902 >
903 > driver_dga::~driver_dga()
904 > {
905 >        XUngrabPointer(x_display, CurrentTime);
906 >        XUngrabKeyboard(x_display, CurrentTime);
907 > }
908 >
909 > // Suspend emulation
910 > void driver_dga::suspend(void)
911 > {
912 >        // Release ctrl key
913 >        ADBKeyUp(0x36);
914 >        ctrl_down = false;
915 >
916 >        // Lock frame buffer (this will stop the MacOS thread)
917 >        LOCK_FRAME_BUFFER;
918 >
919 >        // Save frame buffer
920 >        fb_save = malloc(mode.y * mode.bytes_per_row);
921 >        if (fb_save)
922 >                memcpy(fb_save, the_buffer, mode.y * mode.bytes_per_row);
923 >
924 >        // Close full screen display
925 > #ifdef ENABLE_XF86_DGA
926 >        XF86DGADirectVideo(x_display, screen, 0);
927 > #endif
928 >        XUngrabPointer(x_display, CurrentTime);
929 >        XUngrabKeyboard(x_display, CurrentTime);
930 >        restore_mouse_accel();
931 >        XUnmapWindow(x_display, w);
932 >        wait_unmapped(w);
933 >
934 >        // Open "suspend" window
935 >        XSetWindowAttributes wattr;
936 >        wattr.event_mask = KeyPressMask;
937 >        wattr.background_pixel = black_pixel;
938 >                
939 >        suspend_win = XCreateWindow(x_display, rootwin, 0, 0, 512, 1, 0, xdepth,
940 >                InputOutput, vis, CWEventMask | CWBackPixel, &wattr);
941 >        set_window_name(suspend_win, STR_SUSPEND_WINDOW_TITLE);
942 >        set_window_focus(suspend_win);
943 >        XMapWindow(x_display, suspend_win);
944 >        emul_suspended = true;
945 > }
946 >
947 > // Resume emulation
948 > void driver_dga::resume(void)
949 > {
950 >        // Close "suspend" window
951 >        XDestroyWindow(x_display, suspend_win);
952 >        XSync(x_display, false);
953 >
954 >        // Reopen full screen display
955 >        XMapRaised(x_display, w);
956 >        wait_mapped(w);
957 >        XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
958 >        XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
959 >        XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
960 >        disable_mouse_accel();
961 > #ifdef ENABLE_XF86_DGA
962 >        XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
963 >        XF86DGASetViewPort(x_display, screen, 0, 0);
964 > #endif
965 >        XSync(x_display, false);
966 >        
967 >        // the_buffer already contains the data to restore. i.e. since a temporary
968 >        // frame buffer is used when VOSF is actually used, fb_save is therefore
969 >        // not necessary.
970 > #ifdef ENABLE_VOSF
971 >        if (use_vosf) {
972 >                LOCK_VOSF;
973 >                PFLAG_SET_ALL;
974 >                UNLOCK_VOSF;
975 >                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
976 >        }
977 > #endif
978 >        
979 >        // Restore frame buffer
980 >        if (fb_save) {
981 > #ifdef ENABLE_VOSF
982 >                // Don't copy fb_save to the temporary frame buffer in VOSF mode
983 >                if (!use_vosf)
984 > #endif
985 >                memcpy(the_buffer, fb_save, mode.y * mode.bytes_per_row);
986 >                free(fb_save);
987 >                fb_save = NULL;
988 >        }
989 >        
990 >        // Unlock frame buffer (and continue MacOS thread)
991 >        UNLOCK_FRAME_BUFFER;
992 >        emul_suspended = false;
993   }
994 + #endif
995 +
996 +
997 + #ifdef ENABLE_FBDEV_DGA
998 + /*
999 + *  fbdev DGA display driver
1000 + */
1001  
1002 < // Init fbdev DGA display
1003 < static bool init_fbdev_dga(char *in_fb_name)
1002 > const char FBDEVICES_FILE_NAME[] = DATADIR "/fbdevices";
1003 > const char FBDEVICE_FILE_NAME[] = "/dev/fb";
1004 >
1005 > class driver_fbdev : public driver_dga {
1006 > public:
1007 >        driver_fbdev(X11_monitor_desc &monitor);
1008 >        ~driver_fbdev();
1009 > };
1010 >
1011 > // Open display
1012 > driver_fbdev::driver_fbdev(X11_monitor_desc &m) : driver_dga(m)
1013   {
1014 < #if ENABLE_FBDEV_DGA
1014 >        int width = mode.x, height = mode.y;
1015 >
1016 >        // Set absolute mouse mode
1017 >        ADBSetRelMouseMode(false);
1018 >        
1019          // Find the maximum depth available
1020          int ndepths, max_depth(0);
1021          int *depths = XListDepths(x_display, screen, &ndepths);
1022          if (depths == NULL) {
1023 <                fprintf(stderr, "Error: could not determine the maximal depth available\n");
1024 <                return false;
1023 >                printf("FATAL: Could not determine the maximal depth available\n");
1024 >                return;
1025          } else {
1026                  while (ndepths-- > 0) {
1027                          if (depths[ndepths] > max_depth)
# Line 350 | Line 1030 | static bool init_fbdev_dga(char *in_fb_n
1030          }
1031          
1032          // Get fbdevices file path from preferences
1033 <        const char *fbd_path = PrefsFindString("fbdevices");
1033 >        const char *fbd_path = PrefsFindString("fbdevicefile");
1034          
1035          // Open fbdevices file
1036          FILE *fp = fopen(fbd_path ? fbd_path : FBDEVICES_FILE_NAME, "r");
# Line 358 | Line 1038 | static bool init_fbdev_dga(char *in_fb_n
1038                  char str[256];
1039                  sprintf(str, GetString(STR_NO_FBDEVICE_FILE_ERR), fbd_path ? fbd_path : FBDEVICES_FILE_NAME, strerror(errno));
1040                  ErrorAlert(str);
1041 <                return false;
1041 >                return;
1042          }
1043          
1044          int fb_depth;           // supported depth
# Line 377 | Line 1057 | static bool init_fbdev_dga(char *in_fb_n
1057                  if ((line[0] == '#') || (line[0] == ';') || (line[0] == '\0'))
1058                          continue;
1059                  
1060 <                if ((sscanf(line, "%s %d %x", &fb_name, &fb_depth, &fb_offset) == 3)
1061 <                && (strcmp(fb_name, in_fb_name) == 0) && (fb_depth == max_depth)) {
1060 >                if ((sscanf(line, "%19s %d %x", fb_name, &fb_depth, &fb_offset) == 3)
1061 >                 && (strcmp(fb_name, fb_name) == 0) && (fb_depth == max_depth)) {
1062                          device_found = true;
1063                          break;
1064                  }
# Line 390 | Line 1070 | static bool init_fbdev_dga(char *in_fb_n
1070          // Frame buffer name not found ? Then, display warning
1071          if (!device_found) {
1072                  char str[256];
1073 <                sprintf(str, GetString(STR_FBDEV_NAME_ERR), in_fb_name, max_depth);
1073 >                sprintf(str, GetString(STR_FBDEV_NAME_ERR), fb_name, max_depth);
1074                  ErrorAlert(str);
1075 <                return false;
1075 >                return;
1076          }
1077          
398        int width = DisplayWidth(x_display, screen);
399        int height = DisplayHeight(x_display, screen);
400        depth = fb_depth; // max_depth
401        
402        // Set relative mouse mode
403        ADBSetRelMouseMode(false);
404        
1078          // Create window
1079          XSetWindowAttributes wattr;
1080 <        wattr.override_redirect = True;
1081 <        wattr.backing_store             = NotUseful;
1082 <        wattr.background_pixel  = white_pixel;
1083 <        wattr.border_pixel              = black_pixel;
411 <        wattr.event_mask                = eventmask = dga_eventmask;
1080 >        wattr.event_mask = eventmask = dga_eventmask;
1081 >        wattr.background_pixel = white_pixel;
1082 >        wattr.override_redirect = True;
1083 >        wattr.colormap = cmap[0];
1084          
1085 <        XSync(x_display, false);
414 <        the_win = XCreateWindow(x_display, rootwin,
1085 >        w = XCreateWindow(x_display, rootwin,
1086                  0, 0, width, height,
1087                  0, xdepth, InputOutput, vis,
1088 <                CWEventMask|CWBackPixel|CWBorderPixel|CWOverrideRedirect|CWBackingStore,
1088 >                CWEventMask | CWBackPixel | CWOverrideRedirect | (fb_depth <= 8 ? CWColormap : 0),
1089                  &wattr);
1090 <        XSync(x_display, false);
1091 <        XMapRaised(x_display, the_win);
1092 <        XSync(x_display, false);
1090 >
1091 >        // Set window name/class
1092 >        set_window_name(w, STR_WINDOW_TITLE);
1093 >
1094 >        // Indicate that we want keyboard input
1095 >        set_window_focus(w);
1096 >
1097 >        // Show window
1098 >        XMapRaised(x_display, w);
1099 >        wait_mapped(w);
1100          
1101          // Grab mouse and keyboard
1102 <        XGrabKeyboard(x_display, the_win, True,
1102 >        XGrabKeyboard(x_display, w, True,
1103                  GrabModeAsync, GrabModeAsync, CurrentTime);
1104 <        XGrabPointer(x_display, the_win, True,
1104 >        XGrabPointer(x_display, w, True,
1105                  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1106 <                GrabModeAsync, GrabModeAsync, the_win, None, CurrentTime);
1107 <        
430 <        // Set colormap
431 <        if (depth == 8) {
432 <                XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap = 0]);
433 <                XSetWMColormapWindows(x_display, the_win, &the_win, 1);
434 <        }
1106 >                GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
1107 >        disable_mouse_accel();
1108          
1109 <        // Set VideoMonitor
1110 <        int bytes_per_row = width;
438 <        switch (depth) {
439 <                case 1:
440 <                        bytes_per_row = ((width | 7) & ~7) >> 3;
441 <                        break;
442 <                case 15:
443 <                case 16:
444 <                        bytes_per_row *= 2;
445 <                        break;
446 <                case 24:
447 <                case 32:
448 <                        bytes_per_row *= 4;
449 <                        break;
450 <        }
1109 >        // Calculate bytes per row
1110 >        int bytes_per_row = TrivialBytesPerRow(mode.x, mode.depth);
1111          
1112 <        if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) {
1113 <                if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) {
1112 >        // Map frame buffer
1113 >        the_buffer_size = height * bytes_per_row;
1114 >        if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) {
1115 >                if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) {
1116                          char str[256];
1117                          sprintf(str, GetString(STR_FBDEV_MMAP_ERR), strerror(errno));
1118                          ErrorAlert(str);
1119 <                        return false;
1119 >                        return;
1120                  }
1121          }
1122          
1123 <        set_video_monitor(width, height, bytes_per_row, true);
1124 < #if REAL_ADDRESSING
1125 <        VideoMonitor.mac_frame_base = (uint32)the_buffer;
1126 <        MacFrameLayout = FLAYOUT_DIRECT;
1123 > #if ENABLE_VOSF
1124 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
1125 >        // Screen_blitter_init() returns TRUE if VOSF is mandatory
1126 >        // i.e. the framebuffer update function is not Blit_Copy_Raw
1127 >        use_vosf = Screen_blitter_init(visualFormat, true, mode.depth);
1128 >        
1129 >        if (use_vosf) {
1130 >          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1131 >          the_host_buffer = the_buffer;
1132 >          the_buffer_size = page_extend((height + 2) * bytes_per_row);
1133 >          the_buffer_copy = (uint8 *)malloc(the_buffer_size);
1134 >          the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size);
1135 >        }
1136   #else
1137 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
1137 >        use_vosf = false;
1138 > #endif
1139   #endif
1140          
1141 <        printf("FbDev DGA with %s in %d-bit mode enabled\n", fb_name, fb_depth);
1142 <        return true;
1143 < #else
1144 <        ErrorAlert("Basilisk II has been compiled with fbdev DGA support disabled.");
1145 <        return false;
1141 >        // Set frame buffer base
1142 >        const_cast<video_mode *>(&mode)->bytes_per_row = bytes_per_row;
1143 >        const_cast<video_mode *>(&mode)->depth = DepthModeForPixelDepth(fb_depth);
1144 >        set_mac_frame_buffer(monitor, mode.depth, true);
1145 >
1146 >        // Everything went well
1147 >        init_ok = true;
1148 > }
1149 >
1150 > // Close display
1151 > driver_fbdev::~driver_fbdev()
1152 > {
1153 >        if (!use_vosf) {
1154 >                if (the_buffer != MAP_FAILED) {
1155 >                        // don't free() the screen buffer in driver_base dtor
1156 >                        munmap(the_buffer, the_buffer_size);
1157 >                        the_buffer = NULL;
1158 >                }
1159 >        }
1160 > #ifdef ENABLE_VOSF
1161 >        else {
1162 >                if (the_host_buffer != MAP_FAILED) {
1163 >                        // don't free() the screen buffer in driver_base dtor
1164 >                        munmap(the_host_buffer, the_buffer_size);
1165 >                        the_host_buffer = NULL;
1166 >                }
1167 >        }
1168   #endif
1169   }
1170 + #endif
1171 +
1172  
1173 < // Init XF86 DGA display
1174 < static bool init_xf86_dga(int width, int height)
1173 > #ifdef ENABLE_XF86_DGA
1174 > /*
1175 > *  XFree86 DGA display driver
1176 > */
1177 >
1178 > class driver_xf86dga : public driver_dga {
1179 > public:
1180 >        driver_xf86dga(X11_monitor_desc &monitor);
1181 >        ~driver_xf86dga();
1182 >
1183 >        void update_palette(void);
1184 >        void resume(void);
1185 >
1186 > private:
1187 >        int current_dga_cmap;                                   // Number (0 or 1) of currently installed DGA colormap
1188 > };
1189 >
1190 > // Open display
1191 > driver_xf86dga::driver_xf86dga(X11_monitor_desc &m)
1192 > : driver_dga(m), current_dga_cmap(0)
1193   {
1194 < #if ENABLE_XF86_DGA
1194 >        int width = mode.x, height = mode.y;
1195 >
1196          // Set relative mouse mode
1197          ADBSetRelMouseMode(true);
1198  
1199 + #ifdef ENABLE_XF86_VIDMODE
1200 +        // Switch to best mode
1201 +        if (has_vidmode) {
1202 +                int best = 0;
1203 +                for (int i=1; i<num_x_video_modes; i++) {
1204 +                        if (x_video_modes[i]->hdisplay >= width && x_video_modes[i]->vdisplay >= height &&
1205 +                                x_video_modes[i]->hdisplay <= x_video_modes[best]->hdisplay && x_video_modes[i]->vdisplay <= x_video_modes[best]->vdisplay) {
1206 +                                best = i;
1207 +                        }
1208 +                }
1209 +                XF86VidModeSwitchToMode(x_display, screen, x_video_modes[best]);
1210 +                XF86VidModeSetViewPort(x_display, screen, 0, 0);
1211 +                XSync(x_display, false);
1212 +        }
1213 + #endif
1214 +
1215          // Create window
1216          XSetWindowAttributes wattr;
1217          wattr.event_mask = eventmask = dga_eventmask;
487        wattr.border_pixel = black_pixel;
1218          wattr.override_redirect = True;
1219 +        wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]);
1220  
1221 <        XSync(x_display, false);
1222 <        the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
1223 <                InputOutput, vis, CWEventMask | CWBorderPixel | CWOverrideRedirect, &wattr);
1224 <        XSync(x_display, false);
1225 <        XStoreName(x_display, the_win, GetString(STR_WINDOW_TITLE));
1226 <        XMapRaised(x_display, the_win);
1227 <        XSync(x_display, false);
1221 >        w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
1222 >                InputOutput, vis, CWEventMask | CWOverrideRedirect |
1223 >                (color_class == DirectColor ? CWColormap : 0), &wattr);
1224 >
1225 >        // Set window name/class
1226 >        set_window_name(w, STR_WINDOW_TITLE);
1227 >
1228 >        // Indicate that we want keyboard input
1229 >        set_window_focus(w);
1230 >
1231 >        // Show window
1232 >        XMapRaised(x_display, w);
1233 >        wait_mapped(w);
1234  
1235          // Establish direct screen connection
1236 <        XMoveResizeWindow(x_display, the_win, 0, 0, width, height);
1236 >        XMoveResizeWindow(x_display, w, 0, 0, width, height);
1237          XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
1238          XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
1239          XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
1240 +        disable_mouse_accel();
1241  
1242          int v_width, v_bank, v_size;
1243          XF86DGAGetVideo(x_display, screen, (char **)&the_buffer, &v_width, &v_bank, &v_size);
# Line 508 | Line 1246 | static bool init_xf86_dga(int width, int
1246          XF86DGASetVidPage(x_display, screen, 0);
1247  
1248          // Set colormap
1249 <        if (depth == 8) {
1250 <                XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap = 0]);
513 <                XSetWMColormapWindows(x_display, the_win, &the_win, 1);
1249 >        if (!IsDirectMode(mode)) {
1250 >                XSetWindowColormap(x_display, w, cmap[current_dga_cmap = 0]);
1251                  XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1252          }
1253 +        XSync(x_display, false);
1254  
1255 <        // Set VideoMonitor
1256 <        int bytes_per_row = (v_width + 7) & ~7;
1257 <        switch (depth) {
1258 <                case 1:
1259 <                        bytes_per_row /= 8;
1260 <                        break;
523 <                case 15:
524 <                case 16:
525 <                        bytes_per_row *= 2;
526 <                        break;
527 <                case 24:
528 <                case 32:
529 <                        bytes_per_row *= 4;
530 <                        break;
531 <        }
532 <        set_video_monitor(width, height, bytes_per_row, true);
533 < #if REAL_ADDRESSING
534 <        VideoMonitor.mac_frame_base = (uint32)the_buffer;
535 <        MacFrameLayout = FLAYOUT_DIRECT;
1255 >        // Init blitting routines
1256 >        int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth);
1257 > #if ENABLE_VOSF
1258 >        bool native_byte_order;
1259 > #ifdef WORDS_BIGENDIAN
1260 >        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
1261   #else
1262 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
1262 >        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
1263   #endif
1264 <        return true;
1264 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
1265 >        // Screen_blitter_init() returns TRUE if VOSF is mandatory
1266 >        // i.e. the framebuffer update function is not Blit_Copy_Raw
1267 >        use_vosf = Screen_blitter_init(visualFormat, native_byte_order, depth_of_video_mode(mode));
1268 >        
1269 >        if (use_vosf) {
1270 >          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1271 >          the_host_buffer = the_buffer;
1272 >          the_buffer_size = page_extend((height + 2) * bytes_per_row);
1273 >          the_buffer_copy = (uint8 *)malloc(the_buffer_size);
1274 >          the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size);
1275 >        }
1276   #else
1277 <        ErrorAlert("Basilisk II has been compiled with XF86 DGA support disabled.");
1278 <        return false;
1277 >        use_vosf = false;
1278 > #endif
1279 > #endif
1280 >        
1281 >        // Set frame buffer base
1282 >        const_cast<video_mode *>(&mode)->bytes_per_row = bytes_per_row;
1283 >        set_mac_frame_buffer(monitor, mode.depth, true);
1284 >
1285 >        // Everything went well
1286 >        init_ok = true;
1287 > }
1288 >
1289 > // Close display
1290 > driver_xf86dga::~driver_xf86dga()
1291 > {
1292 >        XF86DGADirectVideo(x_display, screen, 0);
1293 >        if (!use_vosf) {
1294 >                // don't free() the screen buffer in driver_base dtor
1295 >                the_buffer = NULL;
1296 >        }
1297 > #ifdef ENABLE_VOSF
1298 >        else {
1299 >                // don't free() the screen buffer in driver_base dtor
1300 >                the_host_buffer = NULL;
1301 >        }
1302 > #endif
1303 > #ifdef ENABLE_XF86_VIDMODE
1304 >        if (has_vidmode)
1305 >                XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]);
1306   #endif
1307   }
1308  
1309 + // Palette has changed
1310 + void driver_xf86dga::update_palette(void)
1311 + {
1312 +        driver_dga::update_palette();
1313 +        current_dga_cmap ^= 1;
1314 +        if (!IsDirectMode(monitor.get_current_mode()) && cmap[current_dga_cmap])
1315 +                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1316 + }
1317 +
1318 + // Resume emulation
1319 + void driver_xf86dga::resume(void)
1320 + {
1321 +        driver_dga::resume();
1322 +        if (!IsDirectMode(monitor.get_current_mode()))
1323 +                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1324 + }
1325 + #endif
1326 +
1327 +
1328 + /*
1329 + *  Initialization
1330 + */
1331 +
1332   // Init keycode translation table
1333   static void keycode_init(void)
1334   {
# Line 567 | Line 1353 | static void keycode_init(void)
1353  
1354                  // Search for server vendor string, then read keycodes
1355                  const char *vendor = ServerVendor(x_display);
1356 +                // Force use of MacX mappings on MacOS X with Apple's X server
1357 +                int dummy;
1358 +                if (XQueryExtension(x_display, "Apple-DRI", &dummy, &dummy, &dummy))
1359 +                        vendor = "MacX";
1360                  bool vendor_found = false;
1361                  char line[256];
1362                  while (fgets(line, 255, f)) {
# Line 608 | Line 1398 | static void keycode_init(void)
1398          }
1399   }
1400  
1401 + // Open display for current mode
1402 + bool X11_monitor_desc::video_open(void)
1403 + {
1404 +        D(bug("video_open()\n"));
1405 +        const video_mode &mode = get_current_mode();
1406 +
1407 +        // Find best available X visual
1408 +        if (!find_visual_for_depth(mode.depth)) {
1409 +                ErrorAlert(STR_NO_XVISUAL_ERR);
1410 +                return false;
1411 +        }
1412 +
1413 +        // Build up visualFormat structure
1414 +        visualFormat.depth = visualInfo.depth;
1415 +        visualFormat.Rmask = visualInfo.red_mask;
1416 +        visualFormat.Gmask = visualInfo.green_mask;
1417 +        visualFormat.Bmask = visualInfo.blue_mask;
1418 +
1419 +        // Create color maps
1420 +        if (color_class == PseudoColor || color_class == DirectColor) {
1421 +                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1422 +                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1423 +        } else {
1424 +                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocNone);
1425 +                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocNone);
1426 +        }
1427 +
1428 +        // Find pixel format of direct modes
1429 +        if (color_class == DirectColor || color_class == TrueColor) {
1430 +                rshift = gshift = bshift = 0;
1431 +                rloss = gloss = bloss = 8;
1432 +                uint32 mask;
1433 +                for (mask=vis->red_mask; !(mask&1); mask>>=1)
1434 +                        ++rshift;
1435 +                for (; mask&1; mask>>=1)
1436 +                        --rloss;
1437 +                for (mask=vis->green_mask; !(mask&1); mask>>=1)
1438 +                        ++gshift;
1439 +                for (; mask&1; mask>>=1)
1440 +                        --gloss;
1441 +                for (mask=vis->blue_mask; !(mask&1); mask>>=1)
1442 +                        ++bshift;
1443 +                for (; mask&1; mask>>=1)
1444 +                        --bloss;
1445 +        }
1446 +
1447 +        // Preset palette pixel values for CLUT or gamma table
1448 +        if (color_class == DirectColor) {
1449 +                int num = vis->map_entries;
1450 +                for (int i=0; i<num; i++) {
1451 +                        int c = (i * 256) / num;
1452 +                        x_palette[i].pixel = map_rgb(c, c, c);
1453 +                        x_palette[i].flags = DoRed | DoGreen | DoBlue;
1454 +                }
1455 +        } else if (color_class == PseudoColor) {
1456 +                for (int i=0; i<256; i++) {
1457 +                        x_palette[i].pixel = i;
1458 +                        x_palette[i].flags = DoRed | DoGreen | DoBlue;
1459 +                }
1460 +        }
1461 +
1462 +        // Load gray ramp to color map
1463 +        int num = (color_class == DirectColor ? vis->map_entries : 256);
1464 +        for (int i=0; i<num; i++) {
1465 +                int c = (i * 256) / num;
1466 +                x_palette[i].red = c * 0x0101;
1467 +                x_palette[i].green = c * 0x0101;
1468 +                x_palette[i].blue = c * 0x0101;
1469 +        }
1470 +        if (color_class == PseudoColor || color_class == DirectColor) {
1471 +                XStoreColors(x_display, cmap[0], x_palette, num);
1472 +                XStoreColors(x_display, cmap[1], x_palette, num);
1473 +        }
1474 +
1475 + #ifdef ENABLE_VOSF
1476 +        // Load gray ramp to 8->16/32 expand map
1477 +        if (!IsDirectMode(mode) && xdepth > 8)
1478 +                for (int i=0; i<256; i++)
1479 +                        ExpandMap[i] = map_rgb(i, i, i);
1480 + #endif
1481 +
1482 +        // Create display driver object of requested type
1483 +        switch (display_type) {
1484 +                case DISPLAY_WINDOW:
1485 +                        drv = new driver_window(*this);
1486 +                        break;
1487 + #ifdef ENABLE_FBDEV_DGA
1488 +                case DISPLAY_DGA:
1489 +                        drv = new driver_fbdev(*this);
1490 +                        break;
1491 + #endif
1492 + #ifdef ENABLE_XF86_DGA
1493 +                case DISPLAY_DGA:
1494 +                        drv = new driver_xf86dga(*this);
1495 +                        break;
1496 + #endif
1497 +        }
1498 +        if (drv == NULL)
1499 +                return false;
1500 +        if (!drv->init_ok) {
1501 +                delete drv;
1502 +                drv = NULL;
1503 +                return false;
1504 +        }
1505 +
1506 + #ifdef ENABLE_VOSF
1507 +        if (use_vosf) {
1508 +                // Initialize the VOSF system
1509 +                if (!video_vosf_init(*this)) {
1510 +                        ErrorAlert(STR_VOSF_INIT_ERR);
1511 +                return false;
1512 +                }
1513 +        }
1514 + #endif
1515 +        
1516 +        // Initialize VideoRefresh function
1517 +        VideoRefreshInit();
1518 +
1519 +        // Lock down frame buffer
1520 +        XSync(x_display, false);
1521 +        LOCK_FRAME_BUFFER;
1522 +
1523 +        // Start redraw/input thread
1524 + #ifdef HAVE_PTHREADS
1525 +        redraw_thread_cancel = false;
1526 +        Set_pthread_attr(&redraw_thread_attr, 0);
1527 +        redraw_thread_active = (pthread_create(&redraw_thread, &redraw_thread_attr, redraw_func, NULL) == 0);
1528 +        if (!redraw_thread_active) {
1529 +                printf("FATAL: cannot create redraw thread\n");
1530 +                return false;
1531 +        }
1532 + #else
1533 +        redraw_thread_active = true;
1534 + #endif
1535 +
1536 +        return true;
1537 + }
1538 +
1539   bool VideoInit(bool classic)
1540   {
1541 +        classic_mode = classic;
1542 +
1543 + #ifdef ENABLE_VOSF
1544 +        // Zero the mainBuffer structure
1545 +        mainBuffer.dirtyPages = NULL;
1546 +        mainBuffer.pageInfo = NULL;
1547 + #endif
1548 +        
1549 +        // Check if X server runs on local machine
1550 +        local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0)
1551 +                 || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0);
1552 +    
1553          // Init keycode translation
1554          keycode_init();
1555  
1556 +        // Read prefs
1557 +        frame_skip = PrefsFindInt32("frameskip");
1558 +        mouse_wheel_mode = PrefsFindInt32("mousewheelmode");
1559 +        mouse_wheel_lines = PrefsFindInt32("mousewheellines");
1560 +
1561          // Find screen and root window
1562          screen = XDefaultScreen(x_display);
1563          rootwin = XRootWindow(x_display, screen);
1564 +
1565 +        // Get sorted list of available depths
1566 +        avail_depths = XListDepths(x_display, screen, &num_depths);
1567 +        if (avail_depths == NULL) {
1568 +                ErrorAlert(STR_UNSUPP_DEPTH_ERR);
1569 +                return false;
1570 +        }
1571 +        std::sort(avail_depths, avail_depths + num_depths);
1572          
1573 <        // Get screen depth
621 <        xdepth = DefaultDepth(x_display, screen);
622 <        
623 < #if ENABLE_FBDEV_DGA
1573 > #ifdef ENABLE_FBDEV_DGA
1574          // Frame buffer name
1575          char fb_name[20];
1576          
1577 <        // Could do fbdev dga ?
1577 >        // Could do fbdev DGA?
1578          if ((fbdev_fd = open(FBDEVICE_FILE_NAME, O_RDWR)) != -1)
1579                  has_dga = true;
1580          else
1581                  has_dga = false;
1582   #endif
1583 <        
1584 < #if ENABLE_XF86_DGA
1583 >
1584 > #ifdef ENABLE_XF86_DGA
1585          // DGA available?
1586 <        int event_base, error_base;
1587 <        if (XF86DGAQueryExtension(x_display, &event_base, &error_base)) {
1586 >        int dga_event_base, dga_error_base;
1587 >        if (local_X11 && XF86DGAQueryExtension(x_display, &dga_event_base, &dga_error_base)) {
1588                  int dga_flags = 0;
1589                  XF86DGAQueryDirectVideo(x_display, screen, &dga_flags);
1590                  has_dga = dga_flags & XF86DGADirectPresent;
# Line 642 | Line 1592 | bool VideoInit(bool classic)
1592                  has_dga = false;
1593   #endif
1594  
1595 + #ifdef ENABLE_XF86_VIDMODE
1596 +        // VidMode available?
1597 +        int vm_event_base, vm_error_base;
1598 +        has_vidmode = XF86VidModeQueryExtension(x_display, &vm_event_base, &vm_error_base);
1599 +        if (has_vidmode)
1600 +                XF86VidModeGetAllModeLines(x_display, screen, &num_x_video_modes, &x_video_modes);
1601 + #endif
1602 +        
1603          // Find black and white colors
1604          XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:00/00/00", &black);
1605          XAllocColor(x_display, DefaultColormap(x_display, screen), &black);
# Line 650 | Line 1608 | bool VideoInit(bool classic)
1608          black_pixel = BlackPixel(x_display, screen);
1609          white_pixel = WhitePixel(x_display, screen);
1610  
653        // Get appropriate visual
654        int color_class;
655        switch (xdepth) {
656                case 1:
657                        color_class = StaticGray;
658                        break;
659                case 8:
660                        color_class = PseudoColor;
661                        break;
662                case 15:
663                case 16:
664                case 24:
665                case 32:
666                        color_class = TrueColor;
667                        break;
668                default:
669                        ErrorAlert(GetString(STR_UNSUPP_DEPTH_ERR));
670                        return false;
671        }
672        if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) {
673                ErrorAlert(GetString(STR_NO_XVISUAL_ERR));
674                return false;
675        }
676        if (visualInfo.depth != xdepth) {
677                ErrorAlert(GetString(STR_NO_XVISUAL_ERR));
678                return false;
679        }
680        vis = visualInfo.visual;
681
682        // Mac screen depth is always 1 bit in Classic mode, but follows X depth otherwise
683        classic_mode = classic;
684        if (classic)
685                depth = 1;
686        else
687                depth = xdepth;
688
689        // Create color maps for 8 bit mode
690        if (depth == 8) {
691                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
692                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll);
693                XInstallColormap(x_display, cmap[0]);
694                XInstallColormap(x_display, cmap[1]);
695        }
696
1611          // Get screen mode from preferences
1612          const char *mode_str;
1613 <        if (classic)
1613 >        if (classic_mode)
1614                  mode_str = "win/512/342";
1615          else
1616                  mode_str = PrefsFindString("screen");
1617  
1618 <        // Determine type and mode
1619 <        int width = 512, height = 384;
1618 >        // Determine display type and default dimensions
1619 >        int default_width = 512, default_height = 384;
1620          display_type = DISPLAY_WINDOW;
1621          if (mode_str) {
1622 <                if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2)
1622 >                if (sscanf(mode_str, "win/%d/%d", &default_width, &default_height) == 2) {
1623                          display_type = DISPLAY_WINDOW;
1624 < #if ENABLE_FBDEV_DGA
1625 <                else if (has_dga && sscanf(mode_str, "dga/%s", fb_name) == 1) {
1626 < #else
1627 <                else if (has_dga && sscanf(mode_str, "dga/%d/%d", &width, &height) == 2) {
1624 > #ifdef ENABLE_FBDEV_DGA
1625 >                } else if (has_dga && sscanf(mode_str, "dga/%19s", fb_name) == 1) {
1626 >                        display_type = DISPLAY_DGA;
1627 >                        default_width = -1; default_height = -1; // use entire screen
1628   #endif
1629 + #ifdef ENABLE_XF86_DGA
1630 +                } else if (has_dga && sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2) {
1631                          display_type = DISPLAY_DGA;
1632 <                        if (width > DisplayWidth(x_display, screen))
1633 <                                width = DisplayWidth(x_display, screen);
718 <                        if (height > DisplayHeight(x_display, screen))
719 <                                height = DisplayHeight(x_display, screen);
720 <                }
721 <                if (width <= 0)
722 <                        width = DisplayWidth(x_display, screen);
723 <                if (height <= 0)
724 <                        height = DisplayHeight(x_display, screen);
1632 > #endif
1633 >                }
1634          }
1635 <
1636 <        // Initialize according to display type
1637 <        switch (display_type) {
1638 <                case DISPLAY_WINDOW:
1639 <                        if (!init_window(width, height))
1640 <                                return false;
1635 >        if (default_width <= 0)
1636 >                default_width = DisplayWidth(x_display, screen);
1637 >        else if (default_width > DisplayWidth(x_display, screen))
1638 >                default_width = DisplayWidth(x_display, screen);
1639 >        if (default_height <= 0)
1640 >                default_height = DisplayHeight(x_display, screen);
1641 >        else if (default_height > DisplayHeight(x_display, screen))
1642 >                default_height = DisplayHeight(x_display, screen);
1643 >
1644 >        // Mac screen depth follows X depth
1645 >        video_depth default_depth = VDEPTH_1BIT;
1646 >        switch (DefaultDepth(x_display, screen)) {
1647 >                case 8:
1648 >                        default_depth = VDEPTH_8BIT;
1649                          break;
1650 <                case DISPLAY_DGA:
1651 < #if ENABLE_FBDEV_DGA
1652 <                        if (!init_fbdev_dga(fb_name))
1653 < #else
1654 <                        if (!init_xf86_dga(width, height))
738 < #endif
739 <                                return false;
1650 >                case 15: case 16:
1651 >                        default_depth = VDEPTH_16BIT;
1652 >                        break;
1653 >                case 24: case 32:
1654 >                        default_depth = VDEPTH_32BIT;
1655                          break;
1656          }
1657  
1658 <        // Lock down frame buffer
1659 <        pthread_mutex_lock(&frame_buffer_lock);
1658 >        // Construct list of supported modes
1659 >        if (display_type == DISPLAY_WINDOW) {
1660 >                if (classic)
1661 >                        add_mode(512, 342, 0x80, 64, VDEPTH_1BIT);
1662 >                else {
1663 >                        for (unsigned d=VDEPTH_1BIT; d<=VDEPTH_32BIT; d++) {
1664 >                                if (find_visual_for_depth(video_depth(d)))
1665 >                                        add_window_modes(video_depth(d));
1666 >                        }
1667 >                }
1668 >        } else
1669 >                add_mode(default_width, default_height, 0x80, TrivialBytesPerRow(default_width, default_depth), default_depth);
1670 >        if (VideoModes.empty()) {
1671 >                ErrorAlert(STR_NO_XVISUAL_ERR);
1672 >                return false;
1673 >        }
1674  
1675 < #if !REAL_ADDRESSING
1676 <        // Set variables for UAE memory mapping
1677 <        MacFrameBaseHost = the_buffer;
1678 <        MacFrameSize = VideoMonitor.bytes_per_row * VideoMonitor.y;
1675 >        // Find requested default mode with specified dimensions
1676 >        uint32 default_id;
1677 >        std::vector<video_mode>::const_iterator i, end = VideoModes.end();
1678 >        for (i = VideoModes.begin(); i != end; ++i) {
1679 >                if (i->x == default_width && i->y == default_height && i->depth == default_depth) {
1680 >                        default_id = i->resolution_id;
1681 >                        break;
1682 >                }
1683 >        }
1684 >        if (i == end) { // not found, use first available mode
1685 >                default_depth = VideoModes[0].depth;
1686 >                default_id = VideoModes[0].resolution_id;
1687 >        }
1688  
1689 <        // No special frame buffer in Classic mode (frame buffer is in Mac RAM)
1690 <        if (classic)
1691 <                MacFrameLayout = FLAYOUT_NONE;
1689 > #if DEBUG
1690 >        D(bug("Available video modes:\n"));
1691 >        for (i = VideoModes.begin(); i != end; ++i) {
1692 >                int bits = 1 << i->depth;
1693 >                if (bits == 16)
1694 >                        bits = 15;
1695 >                else if (bits == 32)
1696 >                        bits = 24;
1697 >                D(bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits));
1698 >        }
1699   #endif
1700  
1701 <        // Start redraw/input thread
1702 <        XSync(x_display, false);
1703 <        redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0);
1704 <        if (!redraw_thread_active)
1705 <                printf("FATAL: cannot create redraw thread\n");
1706 <        return redraw_thread_active;
1701 >        // Create X11_monitor_desc for this (the only) display
1702 >        X11_monitor_desc *monitor = new X11_monitor_desc(VideoModes, default_depth, default_id);
1703 >        VideoMonitors.push_back(monitor);
1704 >
1705 >        // Open display
1706 >        return monitor->video_open();
1707   }
1708  
1709  
# Line 766 | Line 1711 | bool VideoInit(bool classic)
1711   *  Deinitialization
1712   */
1713  
1714 < void VideoExit(void)
1714 > // Close display
1715 > void X11_monitor_desc::video_close(void)
1716   {
1717 +        D(bug("video_close()\n"));
1718 +
1719          // Stop redraw thread
1720 + #ifdef HAVE_PTHREADS
1721          if (redraw_thread_active) {
1722                  redraw_thread_cancel = true;
1723   #ifdef HAVE_PTHREAD_CANCEL
1724                  pthread_cancel(redraw_thread);
1725   #endif
1726                  pthread_join(redraw_thread, NULL);
778                redraw_thread_active = false;
1727          }
1728 + #endif
1729 +        redraw_thread_active = false;
1730  
1731          // Unlock frame buffer
1732 <        pthread_mutex_unlock(&frame_buffer_lock);
1732 >        UNLOCK_FRAME_BUFFER;
1733 >        XSync(x_display, false);
1734 >        D(bug(" frame buffer unlocked\n"));
1735  
1736 <        // Close window and server connection
1737 <        if (x_display != NULL) {
1738 <                XSync(x_display, false);
1736 > #ifdef ENABLE_VOSF
1737 >        if (use_vosf) {
1738 >                // Deinitialize VOSF
1739 >                video_vosf_exit();
1740 >        }
1741 > #endif
1742  
1743 < #if ENABLE_XF86_DGA
1744 <                if (display_type == DISPLAY_DGA) {
1745 <                        XF86DGADirectVideo(x_display, screen, 0);
1746 <                        XUngrabPointer(x_display, CurrentTime);
1747 <                        XUngrabKeyboard(x_display, CurrentTime);
1748 <                }
1743 >        // Close display
1744 >        delete drv;
1745 >        drv = NULL;
1746 >
1747 >        // Free colormaps
1748 >        if (cmap[0]) {
1749 >                XFreeColormap(x_display, cmap[0]);
1750 >                cmap[0] = 0;
1751 >        }
1752 >        if (cmap[1]) {
1753 >                XFreeColormap(x_display, cmap[1]);
1754 >                cmap[1] = 0;
1755 >        }
1756 > }
1757 >
1758 > void VideoExit(void)
1759 > {
1760 >        // Close displays
1761 >        vector<monitor_desc *>::iterator i, end = VideoMonitors.end();
1762 >        for (i = VideoMonitors.begin(); i != end; ++i)
1763 >                dynamic_cast<X11_monitor_desc *>(*i)->video_close();
1764 >
1765 > #ifdef ENABLE_XF86_VIDMODE
1766 >        // Free video mode list
1767 >        if (x_video_modes) {
1768 >                XFree(x_video_modes);
1769 >                x_video_modes = NULL;
1770 >        }
1771   #endif
1772  
1773 < #if ENABLE_FBDEV_DGA
1774 <                if (display_type == DISPLAY_DGA) {
1775 <                        XUngrabPointer(x_display, CurrentTime);
1776 <                        XUngrabKeyboard(x_display, CurrentTime);
1777 <                        close(fbdev_fd);
1778 <                }
1773 > #ifdef ENABLE_FBDEV_DGA
1774 >        // Close framebuffer device
1775 >        if (fbdev_fd >= 0) {
1776 >                close(fbdev_fd);
1777 >                fbdev_fd = -1;
1778 >        }
1779   #endif
803                
804                if (the_buffer_copy) {
805                        free(the_buffer_copy);
806                        the_buffer_copy = NULL;
807                }
1780  
1781 <                XFlush(x_display);
1782 <                XSync(x_display, false);
1783 <                if (depth == 8) {
1784 <                        XFreeColormap(x_display, cmap[0]);
813 <                        XFreeColormap(x_display, cmap[1]);
814 <                }
1781 >        // Free depth list
1782 >        if (avail_depths) {
1783 >                XFree(avail_depths);
1784 >                avail_depths = NULL;
1785          }
1786   }
1787  
# Line 823 | Line 1793 | void VideoExit(void)
1793   void VideoQuitFullScreen(void)
1794   {
1795          D(bug("VideoQuitFullScreen()\n"));
1796 <        if (display_type == DISPLAY_DGA)
827 <                quit_full_screen = true;
1796 >        quit_full_screen = true;
1797   }
1798  
1799  
# Line 840 | Line 1809 | void VideoInterrupt(void)
1809  
1810          // Temporarily give up frame buffer lock (this is the point where
1811          // we are suspended when the user presses Ctrl-Tab)
1812 <        pthread_mutex_unlock(&frame_buffer_lock);
1813 <        pthread_mutex_lock(&frame_buffer_lock);
1812 >        UNLOCK_FRAME_BUFFER;
1813 >        LOCK_FRAME_BUFFER;
1814   }
1815  
1816  
# Line 849 | Line 1818 | void VideoInterrupt(void)
1818   *  Set palette
1819   */
1820  
1821 < void video_set_palette(uint8 *pal)
1821 > void X11_monitor_desc::set_palette(uint8 *pal, int num_in)
1822   {
1823 <        pthread_mutex_lock(&palette_lock);
1823 >        const video_mode &mode = get_current_mode();
1824 >
1825 >        LOCK_PALETTE;
1826  
1827          // Convert colors to XColor array
1828 <        for (int i=0; i<256; i++) {
1829 <                palette[i].pixel = i;
1830 <                palette[i].red = pal[i*3] * 0x0101;
1831 <                palette[i].green = pal[i*3+1] * 0x0101;
1832 <                palette[i].blue = pal[i*3+2] * 0x0101;
1833 <                palette[i].flags = DoRed | DoGreen | DoBlue;
1828 >        int num_out = 256;
1829 >        bool stretch = false;
1830 >        if (IsDirectMode(mode)) {
1831 >                // If X is in 565 mode we have to stretch the gamma table from 32 to 64 entries
1832 >                num_out = vis->map_entries;
1833 >                stretch = true;
1834 >        }
1835 >        XColor *p = x_palette;
1836 >        for (int i=0; i<num_out; i++) {
1837 >                int c = (stretch ? (i * num_in) / num_out : i);
1838 >                p->red = pal[c*3 + 0] * 0x0101;
1839 >                p->green = pal[c*3 + 1] * 0x0101;
1840 >                p->blue = pal[c*3 + 2] * 0x0101;
1841 >                p++;
1842 >        }
1843 >
1844 > #ifdef ENABLE_VOSF
1845 >        // Recalculate pixel color expansion map
1846 >        if (!IsDirectMode(mode) && xdepth > 8) {
1847 >                for (int i=0; i<256; i++) {
1848 >                        int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
1849 >                        ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]);
1850 >                }
1851 >
1852 >                // We have to redraw everything because the interpretation of pixel values changed
1853 >                LOCK_VOSF;
1854 >                PFLAG_SET_ALL;
1855 >                UNLOCK_VOSF;
1856 >                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
1857          }
1858 + #endif
1859  
1860          // Tell redraw thread to change palette
1861 <        palette_changed = true;
1861 >        x_palette_changed = true;
1862  
1863 <        pthread_mutex_unlock(&palette_lock);
1863 >        UNLOCK_PALETTE;
1864   }
1865  
1866  
1867   /*
1868 < *  Suspend/resume emulator
1868 > *  Switch video mode
1869   */
1870  
1871 < #if ENABLE_XF86_DGA || ENABLE_FBDEV_DGA
877 < static void suspend_emul(void)
878 < {
879 <        if (display_type == DISPLAY_DGA) {
880 <                // Release ctrl key
881 <                ADBKeyUp(0x36);
882 <                ctrl_down = false;
883 <
884 <                // Lock frame buffer (this will stop the MacOS thread)
885 <                pthread_mutex_lock(&frame_buffer_lock);
886 <
887 <                // Save frame buffer
888 <                fb_save = malloc(VideoMonitor.y * VideoMonitor.bytes_per_row);
889 <                if (fb_save)
890 <                        memcpy(fb_save, the_buffer, VideoMonitor.y * VideoMonitor.bytes_per_row);
891 <
892 <                // Close full screen display
893 < #if ENABLE_XF86_DGA
894 <                XF86DGADirectVideo(x_display, screen, 0);
895 < #endif
896 <                XUngrabPointer(x_display, CurrentTime);
897 <                XUngrabKeyboard(x_display, CurrentTime);
898 <                XUnmapWindow(x_display, the_win);
899 <                XSync(x_display, false);
900 <
901 <                // Open "suspend" window
902 <                XSetWindowAttributes wattr;
903 <                wattr.event_mask = KeyPressMask;
904 <                wattr.background_pixel = black_pixel;
905 <                wattr.border_pixel = black_pixel;
906 <                wattr.backing_store = Always;
907 <                wattr.backing_planes = xdepth;
908 <                wattr.colormap = DefaultColormap(x_display, screen);
909 <                
910 <                XSync(x_display, false);
911 <                suspend_win = XCreateWindow(x_display, rootwin, 0, 0, 512, 1, 0, xdepth,
912 <                        InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel |
913 <                        CWBackingStore | CWBackingPlanes | (xdepth == 8 ? CWColormap : 0), &wattr);
914 <                XSync(x_display, false);
915 <                XStoreName(x_display, suspend_win, GetString(STR_SUSPEND_WINDOW_TITLE));
916 <                XMapRaised(x_display, suspend_win);
917 <                XSync(x_display, false);
918 <                emul_suspended = true;
919 <        }
920 < }
921 <
922 < static void resume_emul(void)
1871 > void X11_monitor_desc::switch_to_current_mode(void)
1872   {
1873 <        // Close "suspend" window
1874 <        XDestroyWindow(x_display, suspend_win);
1875 <        XSync(x_display, false);
1873 >        // Close and reopen display
1874 >        video_close();
1875 >        video_open();
1876  
1877 <        // Reopen full screen display
1878 <        XMapRaised(x_display, the_win);
1879 <        XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
931 <        XSync(x_display, false);
932 <        XGrabKeyboard(x_display, rootwin, 1, GrabModeAsync, GrabModeAsync, CurrentTime);
933 <        XGrabPointer(x_display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
934 < #if ENABLE_XF86_DGA
935 <        XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
936 <        XF86DGASetViewPort(x_display, screen, 0, 0);
937 < #endif
938 <        XSync(x_display, false);
939 <
940 <        // Restore frame buffer
941 <        if (fb_save) {
942 <                memcpy(the_buffer, fb_save, VideoMonitor.y * VideoMonitor.bytes_per_row);
943 <                free(fb_save);
944 <                fb_save = NULL;
1877 >        if (drv == NULL) {
1878 >                ErrorAlert(STR_OPEN_WINDOW_ERR);
1879 >                QuitEmulator();
1880          }
946        
947        if (depth == 8)
948 #if ENABLE_XF86_DGA
949                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
950 #endif
951 #if ENABLE_FBDEV_DGA
952                XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap]);
953 #endif
954
955        // Unlock frame buffer (and continue MacOS thread)
956        pthread_mutex_unlock(&frame_buffer_lock);
957        emul_suspended = false;
1881   }
959 #endif
1882  
1883  
1884   /*
1885 < *  Translate key event to Mac keycode
1885 > *  Translate key event to Mac keycode, returns -1 if no keycode was found
1886 > *  and -2 if the key was recognized as a hotkey
1887   */
1888  
1889 < static int kc_decode(KeySym ks)
1889 > static int kc_decode(KeySym ks, bool key_down)
1890   {
1891          switch (ks) {
1892                  case XK_A: case XK_a: return 0x00;
# Line 1016 | Line 1939 | static int kc_decode(KeySym ks)
1939                  case XK_period: case XK_greater: return 0x2f;
1940                  case XK_slash: case XK_question: return 0x2c;
1941  
1942 < #if ENABLE_XF86_DGA || ENABLE_FBDEV_DGA
1020 <                case XK_Tab: if (ctrl_down) {suspend_emul(); return -1;} else return 0x30;
1021 < #else
1022 <                case XK_Tab: return 0x30;
1023 < #endif
1942 >                case XK_Tab: if (ctrl_down) {if (key_down) drv->suspend(); return -2;} else return 0x30;
1943                  case XK_Return: return 0x24;
1944                  case XK_space: return 0x31;
1945                  case XK_BackSpace: return 0x33;
# Line 1054 | Line 1973 | static int kc_decode(KeySym ks)
1973                  case XK_Left: return 0x3b;
1974                  case XK_Right: return 0x3c;
1975  
1976 <                case XK_Escape: if (ctrl_down) {quit_full_screen = true; emerg_quit = true; return -1;} else return 0x35;
1976 >                case XK_Escape: if (ctrl_down) {if (key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35;
1977  
1978 <                case XK_F1: if (ctrl_down) {SysMountFirstFloppy(); return -1;} else return 0x7a;
1978 >                case XK_F1: if (ctrl_down) {if (key_down) SysMountFirstFloppy(); return -2;} else return 0x7a;
1979                  case XK_F2: return 0x78;
1980                  case XK_F3: return 0x63;
1981                  case XK_F4: return 0x76;
1982 <                case XK_F5: return 0x60;
1982 >                case XK_F5: if (ctrl_down) {if (key_down) drv->toggle_mouse_grab(); return -2;} else return 0x60;
1983                  case XK_F6: return 0x61;
1984                  case XK_F7: return 0x62;
1985                  case XK_F8: return 0x64;
# Line 1108 | Line 2027 | static int kc_decode(KeySym ks)
2027          return -1;
2028   }
2029  
2030 < static int event2keycode(XKeyEvent *ev)
2030 > static int event2keycode(XKeyEvent &ev, bool key_down)
2031   {
2032          KeySym ks;
1114        int as;
2033          int i = 0;
2034  
2035          do {
2036 <                ks = XLookupKeysym(ev, i++);
2037 <                as = kc_decode(ks);
2038 <                if (as != -1)
2036 >                ks = XLookupKeysym(&ev, i++);
2037 >                int as = kc_decode(ks, key_down);
2038 >                if (as >= 0)
2039 >                        return as;
2040 >                if (as == -2)
2041                          return as;
2042          } while (ks != NoSymbol);
2043  
# Line 1131 | Line 2051 | static int event2keycode(XKeyEvent *ev)
2051  
2052   static void handle_events(void)
2053   {
1134        XEvent event;
2054          for (;;) {
2055 <                if (!XCheckMaskEvent(x_display, eventmask, &event))
2056 <                        break;
2055 >                XEvent event;
2056 >                XDisplayLock();
2057  
2058 +                if (!XCheckMaskEvent(x_display, eventmask, &event)) {
2059 +                        // Handle clipboard events
2060 +                        if (XCheckTypedEvent(x_display, SelectionRequest, &event))
2061 +                                ClipboardSelectionRequest(&event.xselectionrequest);
2062 +                        else if (XCheckTypedEvent(x_display, SelectionClear, &event))
2063 +                                ClipboardSelectionClear(&event.xselectionclear);
2064 +
2065 +                        // Window "close" widget clicked
2066 +                        else if (XCheckTypedEvent(x_display, ClientMessage, &event)) {
2067 +                                if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) {
2068 +                                        ADBKeyDown(0x7f);       // Power key
2069 +                                        ADBKeyUp(0x7f);
2070 +                                }
2071 +                        }
2072 +                        XDisplayUnlock();
2073 +                        break;
2074 +                }
2075 +                
2076                  switch (event.type) {
2077 +
2078                          // Mouse button
2079                          case ButtonPress: {
2080 <                                unsigned int button = ((XButtonEvent *)&event)->button;
2080 >                                unsigned int button = event.xbutton.button;
2081                                  if (button < 4)
2082                                          ADBMouseDown(button - 1);
2083 +                                else if (button < 6) {  // Wheel mouse
2084 +                                        if (mouse_wheel_mode == 0) {
2085 +                                                int key = (button == 5) ? 0x79 : 0x74;  // Page up/down
2086 +                                                ADBKeyDown(key);
2087 +                                                ADBKeyUp(key);
2088 +                                        } else {
2089 +                                                int key = (button == 5) ? 0x3d : 0x3e;  // Cursor up/down
2090 +                                                for(int i=0; i<mouse_wheel_lines; i++) {
2091 +                                                        ADBKeyDown(key);
2092 +                                                        ADBKeyUp(key);
2093 +                                                }
2094 +                                        }
2095 +                                }
2096                                  break;
2097                          }
2098                          case ButtonRelease: {
2099 <                                unsigned int button = ((XButtonEvent *)&event)->button;
2099 >                                unsigned int button = event.xbutton.button;
2100                                  if (button < 4)
2101                                          ADBMouseUp(button - 1);
2102                                  break;
2103                          }
2104  
2105                          // Mouse moved
1155                        case EnterNotify:
1156                                ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
1157                                break;
2106                          case MotionNotify:
2107 <                                ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
2107 >                                drv->mouse_moved(event.xmotion.x, event.xmotion.y);
2108 >                                break;
2109 >
2110 >                        // Mouse entered window
2111 >                        case EnterNotify:
2112 >                                if (event.xcrossing.mode != NotifyGrab && event.xcrossing.mode != NotifyUngrab)
2113 >                                        drv->mouse_moved(event.xmotion.x, event.xmotion.y);
2114                                  break;
2115  
2116                          // Keyboard
2117                          case KeyPress: {
2118 <                                int code;
2118 >                                int code = -1;
2119                                  if (use_keycodes) {
2120 <                                        event2keycode((XKeyEvent *)&event);     // This is called to process the hotkeys
2121 <                                        code = keycode_table[((XKeyEvent *)&event)->keycode & 0xff];
2120 >                                        if (event2keycode(event.xkey, true) != -2)      // This is called to process the hotkeys
2121 >                                                code = keycode_table[event.xkey.keycode & 0xff];
2122                                  } else
2123 <                                        code = event2keycode((XKeyEvent *)&event);
2124 <                                if (code != -1) {
2123 >                                        code = event2keycode(event.xkey, true);
2124 >                                if (code >= 0) {
2125                                          if (!emul_suspended) {
2126                                                  if (code == 0x39) {     // Caps Lock pressed
2127                                                          if (caps_on) {
# Line 1182 | Line 2136 | static void handle_events(void)
2136                                                  if (code == 0x36)
2137                                                          ctrl_down = true;
2138                                          } else {
1185 #if ENABLE_XF86_DGA || ENABLE_FBDEV_DGA
2139                                                  if (code == 0x31)
2140 <                                                        resume_emul();  // Space wakes us up
1188 < #endif
2140 >                                                        drv->resume();  // Space wakes us up
2141                                          }
2142                                  }
2143                                  break;
2144                          }
2145                          case KeyRelease: {
2146 <                                int code;
2146 >                                int code = -1;
2147                                  if (use_keycodes) {
2148 <                                        event2keycode((XKeyEvent *)&event);     // This is called to process the hotkeys
2149 <                                        code = keycode_table[((XKeyEvent *)&event)->keycode & 0xff];
2148 >                                        if (event2keycode(event.xkey, false) != -2)     // This is called to process the hotkeys
2149 >                                                code = keycode_table[event.xkey.keycode & 0xff];
2150                                  } else
2151 <                                        code = event2keycode((XKeyEvent *)&event);
2152 <                                if (code != -1 && code != 0x39) {       // Don't propagate Caps Lock releases
2151 >                                        code = event2keycode(event.xkey, false);
2152 >                                if (code >= 0 && code != 0x39) {        // Don't propagate Caps Lock releases
2153                                          ADBKeyUp(code);
2154                                          if (code == 0x36)
2155                                                  ctrl_down = false;
# Line 1207 | Line 2159 | static void handle_events(void)
2159  
2160                          // Hidden parts exposed, force complete refresh of window
2161                          case Expose:
2162 <                                if (display_type == DISPLAY_WINDOW)
2163 <                                        memset(the_buffer_copy, 0, VideoMonitor.bytes_per_row * VideoMonitor.y);
2162 >                                if (display_type == DISPLAY_WINDOW) {
2163 >                                        const video_mode &mode = VideoMonitors[0]->get_current_mode();
2164 > #ifdef ENABLE_VOSF
2165 >                                        if (use_vosf) {                 // VOSF refresh
2166 >                                                LOCK_VOSF;
2167 >                                                PFLAG_SET_ALL;
2168 >                                                UNLOCK_VOSF;
2169 >                                                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
2170 >                                        }
2171 >                                        else
2172 > #endif
2173 >                                        if (frame_skip == 0) {  // Dynamic refresh
2174 >                                                int x1, y1;
2175 >                                                for (y1=0; y1<16; y1++)
2176 >                                                for (x1=0; x1<16; x1++)
2177 >                                                        updt_box[x1][y1] = true;
2178 >                                                nr_boxes = 16 * 16;
2179 >                                        } else                                  // Static refresh
2180 >                                                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
2181 >                                }
2182                                  break;
2183                  }
2184 +
2185 +                XDisplayUnlock();
2186          }
2187   }
2188  
# Line 1219 | Line 2191 | static void handle_events(void)
2191   *  Window display update
2192   */
2193  
2194 < static void update_display(void)
2194 > // Dynamic display update (variable frame rate for each box)
2195 > static void update_display_dynamic(int ticker, driver_window *drv)
2196 > {
2197 >        int y1, y2, y2s, y2a, i, x1, xm, xmo, ymo, yo, yi, yil, xi;
2198 >        int xil = 0;
2199 >        int rxm = 0, rxmo = 0;
2200 >        const video_mode &mode = drv->monitor.get_current_mode();
2201 >        int bytes_per_row = mode.bytes_per_row;
2202 >        int bytes_per_pixel = mode.bytes_per_row / mode.x;
2203 >        int rx = mode.bytes_per_row / 16;
2204 >        int ry = mode.y / 16;
2205 >        int max_box;
2206 >
2207 >        y2s = sm_uptd[ticker % 8];
2208 >        y2a = 8;
2209 >        for (i = 0; i < 6; i++)
2210 >                if (ticker % (2 << i))
2211 >                        break;
2212 >        max_box = sm_no_boxes[i];
2213 >
2214 >        if (y2a) {
2215 >                for (y1=0; y1<16; y1++) {
2216 >                        for (y2=y2s; y2 < ry; y2 += y2a) {
2217 >                                i = ((y1 * ry) + y2) * bytes_per_row;
2218 >                                for (x1=0; x1<16; x1++, i += rx) {
2219 >                                        if (updt_box[x1][y1] == false) {
2220 >                                                if (memcmp(&the_buffer_copy[i], &the_buffer[i], rx)) {
2221 >                                                        updt_box[x1][y1] = true;
2222 >                                                        nr_boxes++;
2223 >                                                }
2224 >                                        }
2225 >                                }
2226 >                        }
2227 >                }
2228 >        }
2229 >
2230 >        XDisplayLock();
2231 >        if ((nr_boxes <= max_box) && (nr_boxes)) {
2232 >                for (y1=0; y1<16; y1++) {
2233 >                        for (x1=0; x1<16; x1++) {
2234 >                                if (updt_box[x1][y1] == true) {
2235 >                                        if (rxm == 0)
2236 >                                                xm = x1;
2237 >                                        rxm += rx;
2238 >                                        updt_box[x1][y1] = false;
2239 >                                }
2240 >                                if (((updt_box[x1+1][y1] == false) || (x1 == 15)) && (rxm)) {
2241 >                                        if ((rxmo != rxm) || (xmo != xm) || (yo != y1 - 1)) {
2242 >                                                if (rxmo) {
2243 >                                                        xi = xmo * rx;
2244 >                                                        yi = ymo * ry;
2245 >                                                        xil = rxmo;
2246 >                                                        yil = (yo - ymo +1) * ry;
2247 >                                                }
2248 >                                                rxmo = rxm;
2249 >                                                xmo = xm;
2250 >                                                ymo = y1;
2251 >                                        }
2252 >                                        rxm = 0;
2253 >                                        yo = y1;
2254 >                                }      
2255 >                                if (xil) {
2256 >                                        i = (yi * bytes_per_row) + xi;
2257 >                                        for (y2=0; y2 < yil; y2++, i += bytes_per_row)
2258 >                                                memcpy(&the_buffer_copy[i], &the_buffer[i], xil);
2259 >                                        if (mode.depth == VDEPTH_1BIT) {
2260 >                                                if (drv->have_shm)
2261 >                                                        XShmPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil, 0);
2262 >                                                else
2263 >                                                        XPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil);
2264 >                                        } else {
2265 >                                                if (drv->have_shm)
2266 >                                                        XShmPutImage(x_display, drv->w, drv->gc, drv->img, xi / bytes_per_pixel, yi, xi / bytes_per_pixel, yi, xil / bytes_per_pixel, yil, 0);
2267 >                                                else
2268 >                                                        XPutImage(x_display, drv->w, drv->gc, drv->img, xi / bytes_per_pixel, yi, xi / bytes_per_pixel, yi, xil / bytes_per_pixel, yil);
2269 >                                        }
2270 >                                        xil = 0;
2271 >                                }
2272 >                                if ((x1 == 15) && (y1 == 15) && (rxmo)) {
2273 >                                        x1--;
2274 >                                        xi = xmo * rx;
2275 >                                        yi = ymo * ry;
2276 >                                        xil = rxmo;
2277 >                                        yil = (yo - ymo +1) * ry;
2278 >                                        rxmo = 0;
2279 >                                }
2280 >                        }
2281 >                }
2282 >                nr_boxes = 0;
2283 >        }
2284 >        XDisplayUnlock();
2285 > }
2286 >
2287 > // Static display update (fixed frame rate, but incremental)
2288 > static void update_display_static(driver_window *drv)
2289   {
1224        // In classic mode, copy the frame buffer from Mac RAM
1225        if (classic_mode)
1226                memcpy(the_buffer, Mac2HostAddr(0x3fa700), VideoMonitor.bytes_per_row * VideoMonitor.y);
1227        
2290          // Incremental update code
2291 <        int wide = 0, high = 0, x1, x2, y1, y2, i, j;
2292 <        int bytes_per_row = VideoMonitor.bytes_per_row;
2293 <        int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
2291 >        unsigned wide = 0, high = 0, x1, x2, y1, y2, i, j;
2292 >        const video_mode &mode = drv->monitor.get_current_mode();
2293 >        int bytes_per_row = mode.bytes_per_row;
2294 >        int bytes_per_pixel = mode.bytes_per_row / mode.x;
2295          uint8 *p, *p2;
2296  
2297          // Check for first line from top and first line from bottom that have changed
2298          y1 = 0;
2299 <        for (j=0; j<VideoMonitor.y; j++) {
2299 >        for (j=0; j<mode.y; j++) {
2300                  if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
2301                          y1 = j;
2302                          break;
2303                  }
2304          }
2305          y2 = y1 - 1;
2306 <        for (j=VideoMonitor.y-1; j>=y1; j--) {
2306 >        for (j=mode.y-1; j>=y1; j--) {
2307                  if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
2308                          y2 = j;
2309                          break;
# Line 1250 | Line 2313 | static void update_display(void)
2313  
2314          // Check for first column from left and first column from right that have changed
2315          if (high) {
2316 <                if (depth == 1) {
2317 <                        x1 = VideoMonitor.x;
2316 >                if (mode.depth == VDEPTH_1BIT) {
2317 >                        x1 = mode.x - 1;
2318                          for (j=y1; j<=y2; j++) {
2319                                  p = &the_buffer[j * bytes_per_row];
2320                                  p2 = &the_buffer_copy[j * bytes_per_row];
# Line 1260 | Line 2323 | static void update_display(void)
2323                                                  x1 = i << 3;
2324                                                  break;
2325                                          }
2326 <                                        p++;
1264 <                                        p2++;
2326 >                                        p++; p2++;
2327                                  }
2328                          }
2329                          x2 = x1;
# Line 1270 | Line 2332 | static void update_display(void)
2332                                  p2 = &the_buffer_copy[j * bytes_per_row];
2333                                  p += bytes_per_row;
2334                                  p2 += bytes_per_row;
2335 <                                for (i=(VideoMonitor.x>>3); i>(x2>>3); i--) {
2336 <                                        p--;
1275 <                                        p2--;
2335 >                                for (i=(mode.x>>3); i>(x2>>3); i--) {
2336 >                                        p--; p2--;
2337                                          if (*p != *p2) {
2338 <                                                x2 = i << 3;
2338 >                                                x2 = (i << 3) + 7;
2339                                                  break;
2340                                          }
2341                                  }
2342                          }
2343 <                        wide = x2 - x1;
2343 >                        wide = x2 - x1 + 1;
2344  
2345                          // Update copy of the_buffer
2346                          if (high && wide) {
2347                                  for (j=y1; j<=y2; j++) {
2348                                          i = j * bytes_per_row + (x1 >> 3);
2349 <                                        memcpy(&the_buffer_copy[i], &the_buffer[i], wide >> 3);
2349 >                                        memcpy(the_buffer_copy + i, the_buffer + i, wide >> 3);
2350                                  }
2351                          }
2352  
2353                  } else {
2354 <                        x1 = VideoMonitor.x;
2354 >                        x1 = mode.x;
2355                          for (j=y1; j<=y2; j++) {
2356                                  p = &the_buffer[j * bytes_per_row];
2357                                  p2 = &the_buffer_copy[j * bytes_per_row];
2358 <                                for (i=0; i<x1; i++) {
2359 <                                        if (memcmp(p, p2, bytes_per_pixel)) {
2360 <                                                x1 = i;
2358 >                                for (i=0; i<x1*bytes_per_pixel; i++) {
2359 >                                        if (*p != *p2) {
2360 >                                                x1 = i / bytes_per_pixel;
2361                                                  break;
2362                                          }
2363 <                                        p += bytes_per_pixel;
1303 <                                        p2 += bytes_per_pixel;
2363 >                                        p++; p2++;
2364                                  }
2365                          }
2366                          x2 = x1;
# Line 1309 | Line 2369 | static void update_display(void)
2369                                  p2 = &the_buffer_copy[j * bytes_per_row];
2370                                  p += bytes_per_row;
2371                                  p2 += bytes_per_row;
2372 <                                for (i=VideoMonitor.x; i>x2; i--) {
2373 <                                        p -= bytes_per_pixel;
2374 <                                        p2 -= bytes_per_pixel;
2375 <                                        if (memcmp(p, p2, bytes_per_pixel)) {
2376 <                                                x2 = i;
2372 >                                for (i=mode.x*bytes_per_pixel; i>x2*bytes_per_pixel; i--) {
2373 >                                        p--;
2374 >                                        p2--;
2375 >                                        if (*p != *p2) {
2376 >                                                x2 = i / bytes_per_pixel;
2377                                                  break;
2378                                          }
2379                                  }
# Line 1324 | Line 2384 | static void update_display(void)
2384                          if (high && wide) {
2385                                  for (j=y1; j<=y2; j++) {
2386                                          i = j * bytes_per_row + x1 * bytes_per_pixel;
2387 <                                        memcpy(&the_buffer_copy[i], &the_buffer[i], bytes_per_pixel * wide);
2387 >                                        memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * wide);
2388                                  }
2389                          }
2390                  }
2391          }
2392  
2393          // Refresh display
2394 +        XDisplayLock();
2395          if (high && wide) {
2396 <                if (have_shm)
2397 <                        XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high, 0);
2396 >                if (drv->have_shm)
2397 >                        XShmPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high, 0);
2398                  else
2399 <                        XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high);
2399 >                        XPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high);
2400 >        }
2401 >        XDisplayUnlock();
2402 > }
2403 >
2404 >
2405 > /*
2406 > *      Screen refresh functions
2407 > */
2408 >
2409 > // We suggest the compiler to inline the next two functions so that it
2410 > // may specialise the code according to the current screen depth and
2411 > // display type. A clever compiler would do that job by itself though...
2412 >
2413 > // NOTE: update_display_vosf is inlined too
2414 >
2415 > static inline void possibly_quit_dga_mode()
2416 > {
2417 >        // Quit DGA mode if requested (something terrible has happened and we
2418 >        // want to give control back to the user)
2419 >        if (quit_full_screen) {
2420 >                quit_full_screen = false;
2421 >                delete drv;
2422 >                drv = NULL;
2423          }
2424 + }
2425  
2426 <        // Has the Mac started? (cursor data is not valid otherwise)
2427 <        if (HasMacStarted()) {
2426 > static inline void possibly_ungrab_mouse()
2427 > {
2428 >        // Ungrab mouse if requested (something terrible has happened and we
2429 >        // want to give control back to the user)
2430 >        if (quit_full_screen) {
2431 >                quit_full_screen = false;
2432 >                if (drv)
2433 >                        drv->ungrab_mouse();
2434 >        }
2435 > }
2436  
2437 <                // Set new cursor image if it was changed
2438 <                if (memcmp(the_cursor, Mac2HostAddr(0x844), 64)) {
2439 <                        memcpy(the_cursor, Mac2HostAddr(0x844), 64);
2440 <                        memcpy(cursor_image->data, the_cursor, 32);
2441 <                        memcpy(cursor_mask_image->data, the_cursor+32, 32);
2442 <                        XFreeCursor(x_display, mac_cursor);
2443 <                        XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);
2444 <                        XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16);
2445 <                        mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, ReadMacInt8(0x885), ReadMacInt8(0x887));
2446 <                        XDefineCursor(x_display, the_win, mac_cursor);
2437 > static inline void handle_palette_changes(void)
2438 > {
2439 >        LOCK_PALETTE;
2440 >
2441 >        if (x_palette_changed) {
2442 >                x_palette_changed = false;
2443 >                XDisplayLock();
2444 >                drv->update_palette();
2445 >                XDisplayUnlock();
2446 >        }
2447 >
2448 >        UNLOCK_PALETTE;
2449 > }
2450 >
2451 > static void video_refresh_dga(void)
2452 > {
2453 >        // Quit DGA mode if requested
2454 >        possibly_quit_dga_mode();
2455 > }
2456 >
2457 > #ifdef ENABLE_VOSF
2458 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
2459 > static void video_refresh_dga_vosf(void)
2460 > {
2461 >        // Quit DGA mode if requested
2462 >        possibly_quit_dga_mode();
2463 >        
2464 >        // Update display (VOSF variant)
2465 >        static int tick_counter = 0;
2466 >        if (++tick_counter >= frame_skip) {
2467 >                tick_counter = 0;
2468 >                if (mainBuffer.dirty) {
2469 >                        LOCK_VOSF;
2470 >                        update_display_dga_vosf();
2471 >                        UNLOCK_VOSF;
2472                  }
2473          }
2474   }
2475 + #endif
2476 +
2477 + static void video_refresh_window_vosf(void)
2478 + {
2479 +        // Ungrab mouse if requested
2480 +        possibly_ungrab_mouse();
2481 +        
2482 +        // Update display (VOSF variant)
2483 +        static int tick_counter = 0;
2484 +        if (++tick_counter >= frame_skip) {
2485 +                tick_counter = 0;
2486 +                if (mainBuffer.dirty) {
2487 +                        XDisplayLock();
2488 +                        LOCK_VOSF;
2489 +                        update_display_window_vosf(static_cast<driver_window *>(drv));
2490 +                        UNLOCK_VOSF;
2491 +                        XSync(x_display, false); // Let the server catch up
2492 +                        XDisplayUnlock();
2493 +                }
2494 +        }
2495 + }
2496 + #endif // def ENABLE_VOSF
2497 +
2498 + static void video_refresh_window_static(void)
2499 + {
2500 +        // Ungrab mouse if requested
2501 +        possibly_ungrab_mouse();
2502 +
2503 +        // Update display (static variant)
2504 +        static int tick_counter = 0;
2505 +        if (++tick_counter >= frame_skip) {
2506 +                tick_counter = 0;
2507 +                update_display_static(static_cast<driver_window *>(drv));
2508 +        }
2509 + }
2510 +
2511 + static void video_refresh_window_dynamic(void)
2512 + {
2513 +        // Ungrab mouse if requested
2514 +        possibly_ungrab_mouse();
2515 +
2516 +        // Update display (dynamic variant)
2517 +        static int tick_counter = 0;
2518 +        tick_counter++;
2519 +        update_display_dynamic(tick_counter, static_cast<driver_window *>(drv));
2520 + }
2521  
2522  
2523   /*
2524   *  Thread for screen refresh, input handling etc.
2525   */
2526  
2527 + static void VideoRefreshInit(void)
2528 + {
2529 +        // TODO: set up specialised 8bpp VideoRefresh handlers ?
2530 +        if (display_type == DISPLAY_DGA) {
2531 + #if ENABLE_VOSF && (REAL_ADDRESSING || DIRECT_ADDRESSING)
2532 +                if (use_vosf)
2533 +                        video_refresh = video_refresh_dga_vosf;
2534 +                else
2535 + #endif
2536 +                        video_refresh = video_refresh_dga;
2537 +        }
2538 +        else {
2539 + #ifdef ENABLE_VOSF
2540 +                if (use_vosf)
2541 +                        video_refresh = video_refresh_window_vosf;
2542 +                else
2543 + #endif
2544 +                if (frame_skip == 0)
2545 +                        video_refresh = video_refresh_window_dynamic;
2546 +                else
2547 +                        video_refresh = video_refresh_window_static;
2548 +        }
2549 + }
2550 +
2551 + // This function is called on non-threaded platforms from a timer interrupt
2552 + void VideoRefresh(void)
2553 + {
2554 +        // We need to check redraw_thread_active to inhibit refreshed during
2555 +        // mode changes on non-threaded platforms
2556 +        if (!redraw_thread_active)
2557 +                return;
2558 +
2559 +        // Handle X events
2560 +        handle_events();
2561 +
2562 +        // Handle palette changes
2563 +        handle_palette_changes();
2564 +
2565 +        // Update display
2566 +        video_refresh();
2567 + }
2568 +
2569 + const int VIDEO_REFRESH_HZ = 60;
2570 + const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
2571 +
2572 + #ifdef HAVE_PTHREADS
2573   static void *redraw_func(void *arg)
2574   {
2575 <        int tick_counter = 0;
2575 >        int fd = ConnectionNumber(x_display);
2576 >
2577 >        uint64 start = GetTicks_usec();
2578 >        int64 ticks = 0;
2579 >        uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY;
2580  
2581          while (!redraw_thread_cancel) {
2582  
2583 <                // Wait
2584 < #ifdef HAVE_NANOSLEEP
1371 <                struct timespec req = {0, 16666667};
1372 <                nanosleep(&req, NULL);
1373 < #else
1374 <                usleep(16667);
1375 < #endif
2583 >                int64 delay = next - GetTicks_usec();
2584 >                if (delay < -VIDEO_REFRESH_DELAY) {
2585  
2586 < #if ENABLE_XF86_DGA
2587 <                // Quit DGA mode if requested
1379 <                if (quit_full_screen) {
1380 <                        quit_full_screen = false;
1381 <                        if (display_type == DISPLAY_DGA) {
1382 <                                XF86DGADirectVideo(x_display, screen, 0);
1383 <                                XUngrabPointer(x_display, CurrentTime);
1384 <                                XUngrabKeyboard(x_display, CurrentTime);
1385 <                                XUnmapWindow(x_display, the_win);
1386 <                                XSync(x_display, false);
1387 <                        }
1388 <                }
1389 < #endif
2586 >                        // We are lagging far behind, so we reset the delay mechanism
2587 >                        next = GetTicks_usec();
2588  
2589 < #if ENABLE_FBDEV_DGA
1392 <                // Quit DGA mode if requested
1393 <                if (quit_full_screen) {
1394 <                        quit_full_screen = false;
1395 <                        if (display_type == DISPLAY_DGA) {
1396 <                                XUngrabPointer(x_display, CurrentTime);
1397 <                                XUngrabKeyboard(x_display, CurrentTime);
1398 <                                XUnmapWindow(x_display, the_win);
1399 <                                XSync(x_display, false);
1400 <                        }
1401 <                }
1402 < #endif
1403 <                // Handle X events
1404 <                handle_events();
2589 >                } else if (delay <= 0) {
2590  
2591 <                // Handle palette changes
2592 <                pthread_mutex_lock(&palette_lock);
2593 <                if (palette_changed) {
2594 <                        palette_changed = false;
2595 <                        if (depth == 8) {
2596 <                                XStoreColors(x_display, cmap[0], palette, 256);
1412 <                                XStoreColors(x_display, cmap[1], palette, 256);
1413 <                                
1414 < #if ENABLE_XF86_DGA
1415 <                                if (display_type == DISPLAY_DGA) {
1416 <                                        current_dga_cmap ^= 1;
1417 <                                        XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1418 <                                }
1419 < #endif
1420 <                                
1421 < #if ENABLE_FBDEV_DGA
1422 <                                if (display_type == DISPLAY_DGA)
1423 <                                        XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap]);
1424 < #endif
1425 <                        }
1426 <                }
1427 <                pthread_mutex_unlock(&palette_lock);
2591 >                        // Delay expired, refresh display
2592 >                        handle_events();
2593 >                        handle_palette_changes();
2594 >                        video_refresh();
2595 >                        next += VIDEO_REFRESH_DELAY;
2596 >                        ticks++;
2597  
2598 <                // In window mode, update display and mouse pointer
2599 <                if (display_type == DISPLAY_WINDOW) {
2600 <                        tick_counter++;
2601 <                        if (tick_counter >= frame_skip) {
2602 <                                tick_counter = 0;
2603 <                                update_display();
2604 <                        }
2598 >                } else {
2599 >
2600 >                        // No display refresh pending, check for X events
2601 >                        fd_set readfds;
2602 >                        FD_ZERO(&readfds);
2603 >                        FD_SET(fd, &readfds);
2604 >                        struct timeval timeout;
2605 >                        timeout.tv_sec = 0;
2606 >                        timeout.tv_usec = delay;
2607 >                        if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
2608 >                                handle_events();
2609                  }
2610          }
2611 +
2612 +        uint64 end = GetTicks_usec();
2613 +        D(bug("%Ld refreshes in %Ld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
2614          return NULL;
2615   }
2616 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines