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.55 by cebix, 2001-07-06T22:37:23Z

# 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-2001 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 + #ifndef NO_STD_NAMESPACE
43 + using std::sort;
44 + #endif
45 +
46 + #ifdef HAVE_PTHREADS
47 + # include <pthread.h>
48 + #endif
49 +
50 + #ifdef ENABLE_XF86_DGA
51 + # include <X11/extensions/xf86dga.h>
52 + #endif
53 +
54 + #ifdef ENABLE_XF86_VIDMODE
55 + # include <X11/extensions/xf86vmode.h>
56 + #endif
57 +
58 + #ifdef ENABLE_FBDEV_DGA
59 + # include <sys/mman.h>
60 + #endif
61 +
62   #include "cpu_emulation.h"
63   #include "main.h"
64   #include "adb.h"
# Line 45 | Line 67
67   #include "user_strings.h"
68   #include "video.h"
69  
70 < #define DEBUG 1
70 > #define DEBUG 0
71   #include "debug.h"
72  
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
59
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 | 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 >
97   static bool redraw_thread_active = false;                       // Flag: Redraw thread installed
98 < static volatile bool redraw_thread_cancel = false;      // Flag: Cancel Redraw thread
98 > #ifdef HAVE_PTHREADS
99 > static volatile bool redraw_thread_cancel;                      // Flag: Cancel Redraw thread
100   static pthread_t redraw_thread;                                         // Redraw thread
101 + #endif
102  
103   static bool has_dga = false;                                            // Flag: Video DGA capable
104 + static bool has_vidmode = false;                                        // Flag: VidMode extension available
105 +
106 + #ifdef ENABLE_VOSF
107 + static bool use_vosf = true;                                            // Flag: VOSF enabled
108 + #else
109 + static const bool use_vosf = false;                                     // VOSF not possible
110 + #endif
111  
112   static bool ctrl_down = false;                                          // Flag: Ctrl key pressed
113   static bool caps_on = false;                                            // Flag: Caps Lock on
# Line 93 | Line 122 | static int keycode_table[256];                                         // X
122  
123   // X11 variables
124   static int screen;                                                                      // Screen number
125 < static int xdepth;                                                                      // Depth of X screen
126 < static int depth;                                                                       // Depth of Mac frame buffer
127 < 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
125 > static Window rootwin;                                                          // Root window and our window
126 > static int num_depths = 0;                                                      // Number of available X depths
127 > static int *avail_depths = NULL;                                        // List of available X depths
128   static XColor black, white;
129   static unsigned long black_pixel, white_pixel;
130   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;
131  
132 < static pthread_mutex_t palette_lock = PTHREAD_MUTEX_INITIALIZER;        // Mutex to protect palette
133 < static XColor palette[256];                                                     // Color palette for 8-bit mode
132 > static int xdepth;                                                                      // Depth of X screen
133 > static XVisualInfo visualInfo;
134 > static Visual *vis;
135 > static int color_class;
136 >
137 > static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes
138 >
139 > static Colormap cmap[2] = {0, 0};                                       // Colormaps for indexed modes (DGA needs two of them)
140 >
141 > static XColor palette[256];                                                     // Color palette to be used as CLUT and gamma table
142   static bool palette_changed = false;                            // Flag: Palette changed, redraw thread must set new colors
143  
144 < // Variables for window mode
145 < static GC the_gc;
146 < 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
144 > #ifdef ENABLE_FBDEV_DGA
145 > static int fbdev_fd = -1;
146 > #endif
147  
148 < // Variables for fbdev DGA mode
149 < const char FBDEVICE_FILE_NAME[] = "/dev/fb";
150 < static int fbdev_fd;
148 > #ifdef ENABLE_XF86_VIDMODE
149 > static XF86VidModeModeInfo **x_video_modes = NULL;      // Array of all available modes
150 > static int num_x_video_modes;
151 > #endif
152 >
153 > // Mutex to protect palette
154 > #ifdef HAVE_PTHREADS
155 > static pthread_mutex_t palette_lock = PTHREAD_MUTEX_INITIALIZER;
156 > #define LOCK_PALETTE pthread_mutex_lock(&palette_lock)
157 > #define UNLOCK_PALETTE pthread_mutex_unlock(&palette_lock)
158 > #else
159 > #define LOCK_PALETTE
160 > #define UNLOCK_PALETTE
161 > #endif
162 >
163 > // Mutex to protect frame buffer
164 > #ifdef HAVE_PTHREADS
165 > static pthread_mutex_t frame_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
166 > #define LOCK_FRAME_BUFFER pthread_mutex_lock(&frame_buffer_lock);
167 > #define UNLOCK_FRAME_BUFFER pthread_mutex_unlock(&frame_buffer_lock);
168 > #else
169 > #define LOCK_FRAME_BUFFER
170 > #define UNLOCK_FRAME_BUFFER
171 > #endif
172 >
173 > // Variables for non-VOSF incremental refresh
174 > static const int sm_uptd[] = {4,1,6,3,0,5,2,7};
175 > static int sm_no_boxes[] = {1,8,32,64,128,300};
176 > static bool updt_box[17][17];
177 > static int nr_boxes;
178 >
179 > // Video refresh function
180 > static void VideoRefreshInit(void);
181 > static void (*video_refresh)(void);
182  
183  
184   // Prototypes
185   static void *redraw_func(void *arg);
186 < static int event2keycode(XKeyEvent *ev);
138 <
186 > static int event2keycode(XKeyEvent &ev);
187  
188   // From main_unix.cpp
189 + extern char *x_display_name;
190   extern Display *x_display;
191  
192   // From sys_unix.cpp
# Line 145 | Line 194 | extern void SysMountFirstFloppy(void);
194  
195  
196   /*
197 < *  Initialization
197 > *  Utility functions
198   */
199  
200 < // Set VideoMonitor according to video mode
201 < void set_video_monitor(int width, int height, int bytes_per_row, bool native_byte_order)
200 > // Map RGB color to pixel value (this only works in TrueColor/DirectColor visuals)
201 > static inline uint32 map_rgb(uint8 red, uint8 green, uint8 blue)
202   {
203 <        int layout = FLAYOUT_DIRECT;
203 >        return ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift);
204 > }
205 >
206 > // Do we have a visual for handling the specified Mac depth? If so, set the
207 > // global variables "xdepth", "visualInfo", "vis" and "color_class".
208 > static bool find_visual_for_depth(video_depth depth)
209 > {
210 >        D(bug("have_visual_for_depth(%d)\n", 1 << depth));
211 >
212 >        // Calculate minimum and maximum supported X depth
213 >        int min_depth = 1, max_depth = 32;
214          switch (depth) {
215 <                case 1:
216 <                        layout = FLAYOUT_DIRECT;
217 <                        VideoMonitor.mode = VMODE_1BIT;
215 >                case VDEPTH_1BIT:       // 1-bit works always
216 >                        min_depth = 1;
217 >                        max_depth = 32;
218                          break;
219 <                case 8:
220 <                        layout = FLAYOUT_DIRECT;
221 <                        VideoMonitor.mode = VMODE_8BIT;
219 > #ifdef ENABLE_VOSF
220 >                case VDEPTH_2BIT:
221 >                case VDEPTH_4BIT:       // VOSF blitters can convert 2/4/8-bit -> 8/16/32-bit
222 >                case VDEPTH_8BIT:
223 >                        min_depth = 8;
224 >                        max_depth = 32;
225                          break;
226 <                case 15:
227 <                        layout = FLAYOUT_HOST_555;
228 <                        VideoMonitor.mode = VMODE_16BIT;
226 > #else
227 >                case VDEPTH_2BIT:
228 >                case VDEPTH_4BIT:       // 2/4-bit requires VOSF blitters
229 >                        return false;
230 >                case VDEPTH_8BIT:       // 8-bit without VOSF requires an 8-bit visual
231 >                        min_depth = 8;
232 >                        max_depth = 8;
233                          break;
234 <                case 16:
235 <                        layout = FLAYOUT_HOST_565;
236 <                        VideoMonitor.mode = VMODE_16BIT;
234 > #endif
235 >                case VDEPTH_16BIT:      // 16-bit requires a 15/16-bit visual
236 >                        min_depth = 15;
237 >                        max_depth = 16;
238                          break;
239 <                case 24:
240 <                case 32:
241 <                        layout = FLAYOUT_HOST_888;
175 <                        VideoMonitor.mode = VMODE_32BIT;
239 >                case VDEPTH_32BIT:      // 32-bit requires a 24/32-bit visual
240 >                        min_depth = 24;
241 >                        max_depth = 32;
242                          break;
243          }
244 <        VideoMonitor.x = width;
245 <        VideoMonitor.y = height;
246 <        VideoMonitor.bytes_per_row = bytes_per_row;
244 >        D(bug(" minimum required X depth is %d, maximum supported X depth is %d\n", min_depth, max_depth));
245 >
246 >        // Try to find a visual for one of the color depths
247 >        bool visual_found = false;
248 >        for (int i=0; i<num_depths && !visual_found; i++) {
249 >
250 >                xdepth = avail_depths[i];
251 >                D(bug(" trying to find visual for depth %d\n", xdepth));
252 >                if (xdepth < min_depth || xdepth > max_depth)
253 >                        continue;
254 >
255 >                // Determine best color class for this depth
256 >                switch (xdepth) {
257 >                        case 1: // Try StaticGray or StaticColor
258 >                                if (XMatchVisualInfo(x_display, screen, xdepth, StaticGray, &visualInfo)
259 >                                 || XMatchVisualInfo(x_display, screen, xdepth, StaticColor, &visualInfo))
260 >                                        visual_found = true;
261 >                                break;
262 >                        case 8: // Need PseudoColor
263 >                                if (XMatchVisualInfo(x_display, screen, xdepth, PseudoColor, &visualInfo))
264 >                                        visual_found = true;
265 >                                break;
266 >                        case 15:
267 >                        case 16:
268 >                        case 24:
269 >                        case 32: // Try DirectColor first, as this will allow gamma correction
270 >                                if (XMatchVisualInfo(x_display, screen, xdepth, DirectColor, &visualInfo)
271 >                                 || XMatchVisualInfo(x_display, screen, xdepth, TrueColor, &visualInfo))
272 >                                        visual_found = true;
273 >                                break;
274 >                        default:
275 >                                D(bug("  not a supported depth\n"));
276 >                                break;
277 >                }
278 >        }
279 >        if (!visual_found)
280 >                return false;
281 >
282 >        // Visual was found
283 >        vis = visualInfo.visual;
284 >        color_class = visualInfo.c_class;
285 >        D(bug(" found visual ID 0x%02x, depth %d, class ", visualInfo.visualid, xdepth));
286 > #if DEBUG
287 >        switch (color_class) {
288 >                case StaticGray: D(bug("StaticGray\n")); break;
289 >                case GrayScale: D(bug("GrayScale\n")); break;
290 >                case StaticColor: D(bug("StaticColor\n")); break;
291 >                case PseudoColor: D(bug("PseudoColor\n")); break;
292 >                case TrueColor: D(bug("TrueColor\n")); break;
293 >                case DirectColor: D(bug("DirectColor\n")); break;
294 >        }
295 > #endif
296 > }
297 >
298 > // Add mode to list of supported modes
299 > static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth)
300 > {
301 >        video_mode mode;
302 >        mode.x = width;
303 >        mode.y = height;
304 >        mode.resolution_id = resolution_id;
305 >        mode.bytes_per_row = bytes_per_row;
306 >        mode.depth = depth;
307 >        VideoModes.push_back(mode);
308 > }
309 >
310 > // Add standard list of windowed modes for given color depth
311 > static void add_window_modes(video_depth depth)
312 > {
313 >        add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth);
314 >        add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth);
315 >        add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth);
316 >        add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth), depth);
317 >        add_mode(1152, 870, 0x84, TrivialBytesPerRow(1152, depth), depth);
318 >        add_mode(1280, 1024, 0x85, TrivialBytesPerRow(1280, depth), depth);
319 >        add_mode(1600, 1200, 0x86, TrivialBytesPerRow(1600, depth), depth);
320 > }
321 >
322 > // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
323 > static void set_mac_frame_buffer(video_depth depth, bool native_byte_order)
324 > {
325 > #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
326 >        int layout = FLAYOUT_DIRECT;
327 >        if (depth == VDEPTH_16BIT)
328 >                layout = (xdepth == 15) ? FLAYOUT_HOST_555 : FLAYOUT_HOST_565;
329 >        else if (depth == VDEPTH_32BIT)
330 >                layout = (xdepth == 24) ? FLAYOUT_HOST_888 : FLAYOUT_DIRECT;
331          if (native_byte_order)
332                  MacFrameLayout = layout;
333          else
334                  MacFrameLayout = FLAYOUT_DIRECT;
335 +        VideoMonitor.mac_frame_base = MacFrameBaseMac;
336 +
337 +        // Set variables used by UAE memory banking
338 +        MacFrameBaseHost = the_buffer;
339 +        MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y;
340 +        InitFrameBufferMapping();
341 + #else
342 +        VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer);
343 + #endif
344 +        D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base));
345 + }
346 +
347 + // Set window name and class
348 + static void set_window_name(Window w, int name)
349 + {
350 +        const char *str = GetString(name);
351 +        XStoreName(x_display, w, str);
352 +        XSetIconName(x_display, w, str);
353 +
354 +        XClassHint *hints;
355 +        hints = XAllocClassHint();
356 +        if (hints) {
357 +                hints->res_name = "BasiliskII";
358 +                hints->res_class = "BasiliskII";
359 +                XSetClassHint(x_display, w, hints);
360 +                XFree(hints);
361 +        }
362 + }
363 +
364 + // Set window input focus flag
365 + static void set_window_focus(Window w)
366 + {
367 +        XWMHints *hints = XAllocWMHints();
368 +        if (hints) {
369 +                hints->input = True;
370 +                hints->initial_state = NormalState;
371 +                hints->flags = InputHint | StateHint;
372 +                XSetWMHints(x_display, w, hints);
373 +                XFree(hints);
374 +        }
375 + }
376 +
377 + // Set WM_DELETE_WINDOW protocol on window (preventing it from being destroyed by the WM when clicking on the "close" widget)
378 + static Atom WM_DELETE_WINDOW = (Atom)0;
379 + static void set_window_delete_protocol(Window w)
380 + {
381 +        WM_DELETE_WINDOW = XInternAtom(x_display, "WM_DELETE_WINDOW", false);
382 +        XSetWMProtocols(x_display, w, &WM_DELETE_WINDOW, 1);
383 + }
384 +
385 + // Wait until window is mapped/unmapped
386 + void wait_mapped(Window w)
387 + {
388 +        XEvent e;
389 +        do {
390 +                XMaskEvent(x_display, StructureNotifyMask, &e);
391 +        } while ((e.type != MapNotify) || (e.xmap.event != w));
392 + }
393 +
394 + void wait_unmapped(Window w)
395 + {
396 +        XEvent e;
397 +        do {
398 +                XMaskEvent(x_display, StructureNotifyMask, &e);
399 +        } while ((e.type != UnmapNotify) || (e.xmap.event != w));
400   }
401  
402   // Trap SHM errors
# Line 197 | Line 412 | static int error_handler(Display *d, XEr
412                  return old_error_handler(d, e);
413   }
414  
415 < // Init window mode
416 < static bool init_window(int width, int height)
415 >
416 > /*
417 > *  Display "driver" classes
418 > */
419 >
420 > class driver_base {
421 > public:
422 >        driver_base();
423 >        virtual ~driver_base();
424 >
425 >        virtual void update_palette(void);
426 >        virtual void suspend(void) {}
427 >        virtual void resume(void) {}
428 >        virtual void toggle_mouse_grab(void) {}
429 >        virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); }
430 >
431 >        virtual void grab_mouse(void) {}
432 >        virtual void ungrab_mouse(void) {}
433 >
434 > public:
435 >        bool init_ok;   // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer)
436 >        Window w;               // The window we draw into
437 > };
438 >
439 > class driver_window;
440 > static void update_display_window_vosf(driver_window *drv);
441 > static void update_display_dynamic(int ticker, driver_window *drv);
442 > static void update_display_static(driver_window *drv);
443 >
444 > class driver_window : public driver_base {
445 >        friend void update_display_window_vosf(driver_window *drv);
446 >        friend void update_display_dynamic(int ticker, driver_window *drv);
447 >        friend void update_display_static(driver_window *drv);
448 >
449 > public:
450 >        driver_window(const video_mode &mode);
451 >        ~driver_window();
452 >
453 >        void toggle_mouse_grab(void);
454 >        void mouse_moved(int x, int y);
455 >
456 >        void grab_mouse(void);
457 >        void ungrab_mouse(void);
458 >
459 > private:
460 >        GC gc;
461 >        XImage *img;
462 >        bool have_shm;                                  // Flag: SHM extensions available
463 >        XShmSegmentInfo shminfo;
464 >        Cursor mac_cursor;
465 >        bool mouse_grabbed;                             // Flag: mouse pointer grabbed, using relative mouse mode
466 >        int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode)
467 > };
468 >
469 > static driver_base *drv = NULL; // Pointer to currently used driver object
470 >
471 > #ifdef ENABLE_VOSF
472 > # include "video_vosf.h"
473 > #endif
474 >
475 > driver_base::driver_base()
476 > : init_ok(false), w(0)
477 > {
478 >        the_buffer = NULL;
479 >        the_buffer_copy = NULL;
480 > }
481 >
482 > driver_base::~driver_base()
483   {
484 <        // Set absolute mouse mode
204 <        ADBSetRelMouseMode(false);
484 >        ungrab_mouse();
485  
486 <        // Read frame skip prefs
487 <        frame_skip = PrefsFindInt32("frameskip");
488 <        if (frame_skip == 0)
489 <                frame_skip = 1;
486 >        if (w) {
487 >                XUnmapWindow(x_display, w);
488 >                wait_unmapped(w);
489 >                XDestroyWindow(x_display, w);
490 >        }
491 >
492 >        XFlush(x_display);
493 >        XSync(x_display, false);
494 >
495 >        // Free frame buffer(s)
496 >        if (!use_vosf) {
497 >                if (the_buffer) {
498 >                        free(the_buffer);
499 >                        the_buffer = NULL;
500 >                }
501 >                if (the_buffer_copy) {
502 >                        free(the_buffer_copy);
503 >                        the_buffer_copy = NULL;
504 >                }
505 >        }
506 > #ifdef ENABLE_VOSF
507 >        else {
508 >                if (the_host_buffer) {
509 >                        free(the_host_buffer);
510 >                        the_host_buffer = NULL;
511 >                }
512 >                if (the_buffer != (uint8 *)VM_MAP_FAILED) {
513 >                        vm_release(the_buffer, the_buffer_size);
514 >                        the_buffer = NULL;
515 >                }
516 >                if (the_buffer_copy != (uint8 *)VM_MAP_FAILED) {
517 >                        vm_release(the_buffer_copy, the_buffer_size);
518 >                        the_buffer_copy = NULL;
519 >                }
520 >        }
521 > #endif
522 > }
523 >
524 > // Palette has changed
525 > void driver_base::update_palette(void)
526 > {
527 >        if (cmap[0] && cmap[1]) {
528 >                int num = vis->map_entries;
529 >                if (!IsDirectMode(VideoMonitor.mode) && color_class == DirectColor)
530 >                        return; // Indexed mode on true color screen, don't set CLUT
531 >                XStoreColors(x_display, cmap[0], palette, num);
532 >                XStoreColors(x_display, cmap[1], palette, num);
533 >        }
534 >        XSync(x_display, false);
535 > }
536 >
537 >
538 > /*
539 > *  Windowed display driver
540 > */
541 >
542 > // Open display
543 > driver_window::driver_window(const video_mode &mode)
544 > : gc(0), img(NULL), have_shm(false), mouse_grabbed(false), mac_cursor(0)
545 > {
546 >        int width = mode.x, height = mode.y;
547 >        int aligned_width = (width + 15) & ~15;
548 >        int aligned_height = (height + 15) & ~15;
549 >
550 >        // Set absolute mouse mode
551 >        ADBSetRelMouseMode(mouse_grabbed);
552  
553          // Create window
554          XSetWindowAttributes wattr;
555          wattr.event_mask = eventmask = win_eventmask;
556          wattr.background_pixel = black_pixel;
557 <        wattr.border_pixel = black_pixel;
558 <        wattr.backing_store = Always;
559 <        wattr.backing_planes = xdepth;
557 >        wattr.colormap = (mode.depth == VDEPTH_1BIT && color_class == PseudoColor ? DefaultColormap(x_display, screen) : cmap[0]);
558 >        w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
559 >                InputOutput, vis, CWEventMask | CWBackPixel | (color_class == PseudoColor || color_class == DirectColor ? CWColormap : 0), &wattr);
560  
561 <        XSync(x_display, false);
562 <        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);
226 <        XSync(x_display, false);
561 >        // Set window name/class
562 >        set_window_name(w, STR_WINDOW_TITLE);
563  
564 <        // Set colormap
565 <        if (depth == 8) {
566 <                XSetWindowColormap(x_display, the_win, cmap[0]);
567 <                XSetWMColormapWindows(x_display, the_win, &the_win, 1);
568 <        }
564 >        // Indicate that we want keyboard input
565 >        set_window_focus(w);
566 >
567 >        // Set delete protocol property
568 >        set_window_delete_protocol(w);
569  
570          // Make window unresizable
571 <        XSizeHints *hints;
572 <        if ((hints = XAllocSizeHints()) != NULL) {
573 <                hints->min_width = width;
574 <                hints->max_width = width;
575 <                hints->min_height = height;
576 <                hints->max_height = height;
577 <                hints->flags = PMinSize | PMaxSize;
578 <                XSetWMNormalHints(x_display, the_win, hints);
579 <                XFree((char *)hints);
571 >        {
572 >                XSizeHints *hints = XAllocSizeHints();
573 >                if (hints) {
574 >                        hints->min_width = width;
575 >                        hints->max_width = width;
576 >                        hints->min_height = height;
577 >                        hints->max_height = height;
578 >                        hints->flags = PMinSize | PMaxSize;
579 >                        XSetWMNormalHints(x_display, w, hints);
580 >                        XFree(hints);
581 >                }
582          }
583          
584 +        // Show window
585 +        XMapWindow(x_display, w);
586 +        wait_mapped(w);
587 +
588 +        // 1-bit mode is big-endian; if the X server is little-endian, we can't
589 +        // use SHM because that doesn't allow changing the image byte order
590 +        bool need_msb_image = (mode.depth == VDEPTH_1BIT && XImageByteOrder(x_display) == LSBFirst);
591 +
592          // Try to create and attach SHM image
593 <        have_shm = false;
248 <        if (depth != 1 && XShmQueryExtension(x_display)) {
593 >        if (local_X11 && !need_msb_image && XShmQueryExtension(x_display)) {
594  
595                  // Create SHM image ("height + 2" for safety)
596 <                img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
597 <                shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
598 <                the_buffer = (uint8 *)shmat(shminfo.shmid, 0, 0);
599 <                shminfo.shmaddr = img->data = (char *)the_buffer;
596 >                img = XShmCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
597 >                shminfo.shmid = shmget(IPC_PRIVATE, (aligned_height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
598 >                the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
599 >                shminfo.shmaddr = img->data = (char *)the_buffer_copy;
600                  shminfo.readOnly = False;
601  
602                  // Try to attach SHM image, catching errors
# Line 263 | Line 608 | static bool init_window(int width, int h
608                  if (shm_error) {
609                          shmdt(shminfo.shmaddr);
610                          XDestroyImage(img);
611 +                        img = NULL;
612                          shminfo.shmid = -1;
613                  } else {
614                          have_shm = true;
# Line 272 | Line 618 | static bool init_window(int width, int h
618          
619          // Create normal X image if SHM doesn't work ("height + 2" for safety)
620          if (!have_shm) {
621 <                int bytes_per_row = width;
622 <                switch (depth) {
623 <                        case 1:
278 <                                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);
621 >                int bytes_per_row = (mode.depth == VDEPTH_1BIT ? aligned_width/8 : TrivialBytesPerRow(aligned_width, DepthModeForPixelDepth(xdepth)));
622 >                the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
623 >                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);
624          }
625  
626 <        // 1-Bit mode is big-endian
294 <        if (depth == 1) {
626 >        if (need_msb_image) {
627                  img->byte_order = MSBFirst;
628                  img->bitmap_bit_order = MSBFirst;
629          }
630  
631 <        // Allocate memory for frame buffer copy
632 <        the_buffer_copy = (uint8 *)malloc((height + 2) * img->bytes_per_line);
631 > #ifdef ENABLE_VOSF
632 >        // Allocate memory for frame buffer (SIZE is extended to page-boundary)
633 >        the_host_buffer = the_buffer_copy;
634 >        the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
635 >        the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
636 >        the_buffer = (uint8 *)vm_acquire(the_buffer_size);
637 >        D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
638 > #else
639 >        // Allocate memory for frame buffer
640 >        the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
641 >        D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
642 > #endif
643  
644          // Create GC
645 <        the_gc = XCreateGC(x_display, the_win, 0, 0);
646 <        XSetState(x_display, the_gc, black_pixel, white_pixel, GXcopy, AllPlanes);
645 >        gc = XCreateGC(x_display, w, 0, 0);
646 >        XSetState(x_display, gc, black_pixel, white_pixel, GXcopy, AllPlanes);
647  
648 <        // Create cursor
649 <        cursor_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)the_cursor, 16, 16, 16, 2);
650 <        cursor_image->byte_order = MSBFirst;
651 <        cursor_image->bitmap_bit_order = MSBFirst;
652 <        cursor_mask_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)the_cursor+32, 16, 16, 16, 2);
653 <        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);
648 >        // Create no_cursor
649 >        mac_cursor = XCreatePixmapCursor(x_display,
650 >           XCreatePixmap(x_display, w, 1, 1, 1),
651 >           XCreatePixmap(x_display, w, 1, 1, 1),
652 >           &black, &white, 0, 0);
653 >        XDefineCursor(x_display, w, mac_cursor);
654  
655 <        // Set VideoMonitor
655 >        // Init blitting routines
656 >        bool native_byte_order;
657   #ifdef WORDS_BIGENDIAN
658 <        set_video_monitor(width, height, img->bytes_per_line, img->bitmap_bit_order == MSBFirst);
658 >        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
659   #else
660 <        set_video_monitor(width, height, img->bytes_per_line, img->bitmap_bit_order == LSBFirst);
660 >        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
661   #endif
662 <        
663 < #if REAL_ADDRESSING
664 <        VideoMonitor.mac_frame_base = (uint32)the_buffer;
665 <        MacFrameLayout = FLAYOUT_DIRECT;
662 > #ifdef ENABLE_VOSF
663 >        Screen_blitter_init(&visualInfo, native_byte_order, mode.depth);
664 > #endif
665 >
666 >        // Set VideoMonitor
667 >        VideoMonitor.mode = mode;
668 >        set_mac_frame_buffer(mode.depth, native_byte_order);
669 >
670 >        // Everything went well
671 >        init_ok = true;
672 > }
673 >
674 > // Close display
675 > driver_window::~driver_window()
676 > {
677 >        if (have_shm) {
678 >                XShmDetach(x_display, &shminfo);
679 > #ifdef ENABLE_VOSF
680 >                the_host_buffer = NULL; // don't free() in driver_base dtor
681   #else
682 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
682 >                the_buffer_copy = NULL; // don't free() in driver_base dtor
683   #endif
684 <        return true;
684 >        }
685 >        if (img)
686 >                XDestroyImage(img);
687 >        if (have_shm) {
688 >                shmdt(shminfo.shmaddr);
689 >                shmctl(shminfo.shmid, IPC_RMID, 0);
690 >        }
691 >        if (gc)
692 >                XFreeGC(x_display, gc);
693 > }
694 >
695 > // Toggle mouse grab
696 > void driver_window::toggle_mouse_grab(void)
697 > {
698 >        if (mouse_grabbed)
699 >                ungrab_mouse();
700 >        else
701 >                grab_mouse();
702 > }
703 >
704 > // Grab mouse, switch to relative mouse mode
705 > void driver_window::grab_mouse(void)
706 > {
707 >        int result;
708 >        for (int i=0; i<10; i++) {
709 >                result = XGrabPointer(x_display, w, True, 0,
710 >                        GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
711 >                if (result != AlreadyGrabbed)
712 >                        break;
713 >                Delay_usec(100000);
714 >        }
715 >        if (result == GrabSuccess) {
716 >                ADBSetRelMouseMode(mouse_grabbed = true);
717 >                XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED));
718 >                XSync(x_display, false);
719 >        }
720 > }
721 >
722 > // Ungrab mouse, switch to absolute mouse mode
723 > void driver_window::ungrab_mouse(void)
724 > {
725 >        if (mouse_grabbed) {
726 >                XUngrabPointer(x_display, CurrentTime);
727 >                XStoreName(x_display, w, GetString(STR_WINDOW_TITLE));
728 >                ADBSetRelMouseMode(mouse_grabbed = false);
729 >        }
730 > }
731 >
732 > // Mouse moved
733 > void driver_window::mouse_moved(int x, int y)
734 > {
735 >        if (!mouse_grabbed) {
736 >                mouse_last_x = x; mouse_last_y = y;
737 >                ADBMouseMoved(x, y);
738 >                return;
739 >        }
740 >
741 >        // Warped mouse motion (this code is taken from SDL)
742 >
743 >        // Post first mouse event
744 >        int width = VideoMonitor.mode.x, height = VideoMonitor.mode.y;
745 >        int delta_x = x - mouse_last_x, delta_y = y - mouse_last_y;
746 >        mouse_last_x = x; mouse_last_y = y;
747 >        ADBMouseMoved(delta_x, delta_y);
748 >
749 >        // Only warp the pointer when it has reached the edge
750 >        const int MOUSE_FUDGE_FACTOR = 8;
751 >        if (x < MOUSE_FUDGE_FACTOR || x > (width - MOUSE_FUDGE_FACTOR)
752 >         || y < MOUSE_FUDGE_FACTOR || y > (height - MOUSE_FUDGE_FACTOR)) {
753 >                XEvent event;
754 >                while (XCheckTypedEvent(x_display, MotionNotify, &event)) {
755 >                        delta_x = x - mouse_last_x; delta_y = y - mouse_last_y;
756 >                        mouse_last_x = x; mouse_last_y = y;
757 >                        ADBMouseMoved(delta_x, delta_y);
758 >                }
759 >                mouse_last_x = width/2;
760 >                mouse_last_y = height/2;
761 >                XWarpPointer(x_display, None, w, 0, 0, 0, 0, mouse_last_x, mouse_last_y);
762 >                for (int i=0; i<10; i++) {
763 >                        XMaskEvent(x_display, PointerMotionMask, &event);
764 >                        if (event.xmotion.x > (mouse_last_x - MOUSE_FUDGE_FACTOR)
765 >                         && event.xmotion.x < (mouse_last_x + MOUSE_FUDGE_FACTOR)
766 >                         && event.xmotion.y > (mouse_last_y - MOUSE_FUDGE_FACTOR)
767 >                         && event.xmotion.y < (mouse_last_y + MOUSE_FUDGE_FACTOR))
768 >                                break;
769 >                }
770 >        }
771 > }
772 >
773 >
774 > #if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA)
775 > /*
776 > *  DGA display driver base class
777 > */
778 >
779 > class driver_dga : public driver_base {
780 > public:
781 >        driver_dga();
782 >        ~driver_dga();
783 >
784 >        void suspend(void);
785 >        void resume(void);
786 >
787 > private:
788 >        Window suspend_win;             // "Suspend" information window
789 >        void *fb_save;                  // Saved frame buffer for suspend/resume
790 > };
791 >
792 > driver_dga::driver_dga()
793 > : suspend_win(0), fb_save(NULL)
794 > {
795 > }
796 >
797 > driver_dga::~driver_dga()
798 > {
799 >        XUngrabPointer(x_display, CurrentTime);
800 >        XUngrabKeyboard(x_display, CurrentTime);
801 > }
802 >
803 > // Suspend emulation
804 > void driver_dga::suspend(void)
805 > {
806 >        // Release ctrl key
807 >        ADBKeyUp(0x36);
808 >        ctrl_down = false;
809 >
810 >        // Lock frame buffer (this will stop the MacOS thread)
811 >        LOCK_FRAME_BUFFER;
812 >
813 >        // Save frame buffer
814 >        fb_save = malloc(VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row);
815 >        if (fb_save)
816 >                memcpy(fb_save, the_buffer, VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row);
817 >
818 >        // Close full screen display
819 > #ifdef ENABLE_XF86_DGA
820 >        XF86DGADirectVideo(x_display, screen, 0);
821 > #endif
822 >        XUngrabPointer(x_display, CurrentTime);
823 >        XUngrabKeyboard(x_display, CurrentTime);
824 >        XUnmapWindow(x_display, w);
825 >        wait_unmapped(w);
826 >
827 >        // Open "suspend" window
828 >        XSetWindowAttributes wattr;
829 >        wattr.event_mask = KeyPressMask;
830 >        wattr.background_pixel = black_pixel;
831 >                
832 >        suspend_win = XCreateWindow(x_display, rootwin, 0, 0, 512, 1, 0, xdepth,
833 >                InputOutput, vis, CWEventMask | CWBackPixel, &wattr);
834 >        set_window_name(suspend_win, STR_SUSPEND_WINDOW_TITLE);
835 >        set_window_focus(suspend_win);
836 >        XMapWindow(x_display, suspend_win);
837 >        emul_suspended = true;
838 > }
839 >
840 > // Resume emulation
841 > void driver_dga::resume(void)
842 > {
843 >        // Close "suspend" window
844 >        XDestroyWindow(x_display, suspend_win);
845 >        XSync(x_display, false);
846 >
847 >        // Reopen full screen display
848 >        XMapRaised(x_display, w);
849 >        wait_mapped(w);
850 >        XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
851 >        XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
852 >        XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
853 > #ifdef ENABLE_XF86_DGA
854 >        XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
855 >        XF86DGASetViewPort(x_display, screen, 0, 0);
856 > #endif
857 >        XSync(x_display, false);
858 >        
859 >        // the_buffer already contains the data to restore. i.e. since a temporary
860 >        // frame buffer is used when VOSF is actually used, fb_save is therefore
861 >        // not necessary.
862 > #ifdef ENABLE_VOSF
863 >        if (use_vosf) {
864 >                LOCK_VOSF;
865 >                PFLAG_SET_ALL;
866 >                UNLOCK_VOSF;
867 >                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
868 >        }
869 > #endif
870 >        
871 >        // Restore frame buffer
872 >        if (fb_save) {
873 > #ifdef ENABLE_VOSF
874 >                // Don't copy fb_save to the temporary frame buffer in VOSF mode
875 >                if (!use_vosf)
876 > #endif
877 >                memcpy(the_buffer, fb_save, VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row);
878 >                free(fb_save);
879 >                fb_save = NULL;
880 >        }
881 >        
882 >        // Unlock frame buffer (and continue MacOS thread)
883 >        UNLOCK_FRAME_BUFFER;
884 >        emul_suspended = false;
885   }
886 + #endif
887 +
888  
889 < // Init fbdev DGA display
890 < static bool init_fbdev_dga(char *in_fb_name)
889 > #ifdef ENABLE_FBDEV_DGA
890 > /*
891 > *  fbdev DGA display driver
892 > */
893 >
894 > const char FBDEVICES_FILE_NAME[] = DATADIR "/fbdevices";
895 > const char FBDEVICE_FILE_NAME[] = "/dev/fb";
896 >
897 > class driver_fbdev : public driver_dga {
898 > public:
899 >        driver_fbdev(const video_mode &mode);
900 >        ~driver_fbdev();
901 > };
902 >
903 > // Open display
904 > driver_fbdev::driver_fbdev(const video_mode &mode)
905   {
906 < #if ENABLE_FBDEV_DGA
906 >        int width = mode.x, height = mode.y;
907 >
908 >        // Set absolute mouse mode
909 >        ADBSetRelMouseMode(false);
910 >        
911          // Find the maximum depth available
912          int ndepths, max_depth(0);
913          int *depths = XListDepths(x_display, screen, &ndepths);
914          if (depths == NULL) {
915 <                fprintf(stderr, "Error: could not determine the maximal depth available\n");
916 <                return false;
915 >                printf("FATAL: Could not determine the maximal depth available\n");
916 >                return;
917          } else {
918                  while (ndepths-- > 0) {
919                          if (depths[ndepths] > max_depth)
# Line 350 | Line 922 | static bool init_fbdev_dga(char *in_fb_n
922          }
923          
924          // Get fbdevices file path from preferences
925 <        const char *fbd_path = PrefsFindString("fbdevices");
925 >        const char *fbd_path = PrefsFindString("fbdevicefile");
926          
927          // Open fbdevices file
928          FILE *fp = fopen(fbd_path ? fbd_path : FBDEVICES_FILE_NAME, "r");
# Line 358 | Line 930 | static bool init_fbdev_dga(char *in_fb_n
930                  char str[256];
931                  sprintf(str, GetString(STR_NO_FBDEVICE_FILE_ERR), fbd_path ? fbd_path : FBDEVICES_FILE_NAME, strerror(errno));
932                  ErrorAlert(str);
933 <                return false;
933 >                return;
934          }
935          
936          int fb_depth;           // supported depth
# Line 377 | Line 949 | static bool init_fbdev_dga(char *in_fb_n
949                  if ((line[0] == '#') || (line[0] == ';') || (line[0] == '\0'))
950                          continue;
951                  
952 <                if ((sscanf(line, "%s %d %x", &fb_name, &fb_depth, &fb_offset) == 3)
953 <                && (strcmp(fb_name, in_fb_name) == 0) && (fb_depth == max_depth)) {
952 >                if ((sscanf(line, "%19s %d %x", &fb_name, &fb_depth, &fb_offset) == 3)
953 >                 && (strcmp(fb_name, fb_name) == 0) && (fb_depth == max_depth)) {
954                          device_found = true;
955                          break;
956                  }
# Line 390 | Line 962 | static bool init_fbdev_dga(char *in_fb_n
962          // Frame buffer name not found ? Then, display warning
963          if (!device_found) {
964                  char str[256];
965 <                sprintf(str, GetString(STR_FBDEV_NAME_ERR), in_fb_name, max_depth);
965 >                sprintf(str, GetString(STR_FBDEV_NAME_ERR), fb_name, max_depth);
966                  ErrorAlert(str);
967 <                return false;
967 >                return;
968          }
969          
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        
970          // Create window
971          XSetWindowAttributes wattr;
972 <        wattr.override_redirect = True;
973 <        wattr.backing_store             = NotUseful;
974 <        wattr.background_pixel  = white_pixel;
975 <        wattr.border_pixel              = black_pixel;
411 <        wattr.event_mask                = eventmask = dga_eventmask;
972 >        wattr.event_mask = eventmask = dga_eventmask;
973 >        wattr.background_pixel = white_pixel;
974 >        wattr.override_redirect = True;
975 >        wattr.colormap = cmap[0];
976          
977 <        XSync(x_display, false);
414 <        the_win = XCreateWindow(x_display, rootwin,
977 >        w = XCreateWindow(x_display, rootwin,
978                  0, 0, width, height,
979                  0, xdepth, InputOutput, vis,
980 <                CWEventMask|CWBackPixel|CWBorderPixel|CWOverrideRedirect|CWBackingStore,
980 >                CWEventMask | CWBackPixel | CWOverrideRedirect | (fb_depth <= 8 ? CWColormap : 0),
981                  &wattr);
982 <        XSync(x_display, false);
983 <        XMapRaised(x_display, the_win);
984 <        XSync(x_display, false);
982 >
983 >        // Set window name/class
984 >        set_window_name(w, STR_WINDOW_TITLE);
985 >
986 >        // Indicate that we want keyboard input
987 >        set_window_focus(w);
988 >
989 >        // Show window
990 >        XMapRaised(x_display, w);
991 >        wait_mapped(w);
992          
993          // Grab mouse and keyboard
994 <        XGrabKeyboard(x_display, the_win, True,
994 >        XGrabKeyboard(x_display, w, True,
995                  GrabModeAsync, GrabModeAsync, CurrentTime);
996 <        XGrabPointer(x_display, the_win, True,
996 >        XGrabPointer(x_display, w, True,
997                  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
998 <                GrabModeAsync, GrabModeAsync, the_win, None, CurrentTime);
429 <        
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 <        }
998 >                GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
999          
1000 <        // Set VideoMonitor
1001 <        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 <        }
1000 >        // Calculate bytes per row
1001 >        int bytes_per_row = TrivialBytesPerRow(mode.x, mode.depth);
1002          
1003 +        // Map frame buffer
1004          if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) {
1005                  if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) {
1006                          char str[256];
1007                          sprintf(str, GetString(STR_FBDEV_MMAP_ERR), strerror(errno));
1008                          ErrorAlert(str);
1009 <                        return false;
1009 >                        return;
1010                  }
1011          }
1012          
1013 <        set_video_monitor(width, height, bytes_per_row, true);
1014 < #if REAL_ADDRESSING
1015 <        VideoMonitor.mac_frame_base = (uint32)the_buffer;
1016 <        MacFrameLayout = FLAYOUT_DIRECT;
1013 > #if ENABLE_VOSF
1014 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
1015 >        // Screen_blitter_init() returns TRUE if VOSF is mandatory
1016 >        // i.e. the framebuffer update function is not Blit_Copy_Raw
1017 >        use_vosf = Screen_blitter_init(&visualInfo, true, mode.depth);
1018 >        
1019 >        if (use_vosf) {
1020 >          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1021 >          the_host_buffer = the_buffer;
1022 >          the_buffer_size = page_extend((height + 2) * bytes_per_row);
1023 >          the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
1024 >          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
1025 >        }
1026   #else
1027 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
1027 >        use_vosf = false;
1028   #endif
468        
469        printf("FbDev DGA with %s in %d-bit mode enabled\n", fb_name, fb_depth);
470        return true;
471 #else
472        ErrorAlert("Basilisk II has been compiled with fbdev DGA support disabled.");
473        return false;
1029   #endif
1030 +        
1031 +        // Set VideoMonitor
1032 +        VideoModes[0].bytes_per_row = bytes_per_row;
1033 +        VideoModes[0].depth = DepthModeForPixelDepth(fb_depth);
1034 +        VideoMonitor.mode = mode;
1035 +        set_mac_frame_buffer(mode.depth, true);
1036 +
1037 +        // Everything went well
1038 +        init_ok = true;
1039   }
1040  
1041 < // Init XF86 DGA display
1042 < static bool init_xf86_dga(int width, int height)
1041 > // Close display
1042 > driver_fbdev::~driver_fbdev()
1043   {
1044 < #if ENABLE_XF86_DGA
1044 > }
1045 > #endif
1046 >
1047 >
1048 > #ifdef ENABLE_XF86_DGA
1049 > /*
1050 > *  XFree86 DGA display driver
1051 > */
1052 >
1053 > class driver_xf86dga : public driver_dga {
1054 > public:
1055 >        driver_xf86dga(const video_mode &mode);
1056 >        ~driver_xf86dga();
1057 >
1058 >        void update_palette(void);
1059 >        void resume(void);
1060 >
1061 > private:
1062 >        int current_dga_cmap;                                   // Number (0 or 1) of currently installed DGA colormap
1063 > };
1064 >
1065 > // Open display
1066 > driver_xf86dga::driver_xf86dga(const video_mode &mode)
1067 > : current_dga_cmap(0)
1068 > {
1069 >        int width = mode.x, height = mode.y;
1070 >
1071          // Set relative mouse mode
1072          ADBSetRelMouseMode(true);
1073  
1074 + #ifdef ENABLE_XF86_VIDMODE
1075 +        // Switch to best mode
1076 +        if (has_vidmode) {
1077 +                int best = 0;
1078 +                for (int i=1; i<num_x_video_modes; i++) {
1079 +                        if (x_video_modes[i]->hdisplay >= width && x_video_modes[i]->vdisplay >= height &&
1080 +                                x_video_modes[i]->hdisplay <= x_video_modes[best]->hdisplay && x_video_modes[i]->vdisplay <= x_video_modes[best]->vdisplay) {
1081 +                                best = i;
1082 +                        }
1083 +                }
1084 +                XF86VidModeSwitchToMode(x_display, screen, x_video_modes[best]);
1085 +                XF86VidModeSetViewPort(x_display, screen, 0, 0);
1086 +                XSync(x_display, false);
1087 +        }
1088 + #endif
1089 +
1090          // Create window
1091          XSetWindowAttributes wattr;
1092          wattr.event_mask = eventmask = dga_eventmask;
487        wattr.border_pixel = black_pixel;
1093          wattr.override_redirect = True;
1094  
1095 <        XSync(x_display, false);
1096 <        the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
1097 <                InputOutput, vis, CWEventMask | CWBorderPixel | CWOverrideRedirect, &wattr);
1098 <        XSync(x_display, false);
1099 <        XStoreName(x_display, the_win, GetString(STR_WINDOW_TITLE));
1100 <        XMapRaised(x_display, the_win);
1101 <        XSync(x_display, false);
1095 >        w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
1096 >                InputOutput, vis, CWEventMask | CWOverrideRedirect, &wattr);
1097 >
1098 >        // Set window name/class
1099 >        set_window_name(w, STR_WINDOW_TITLE);
1100 >
1101 >        // Indicate that we want keyboard input
1102 >        set_window_focus(w);
1103 >
1104 >        // Show window
1105 >        XMapRaised(x_display, w);
1106 >        wait_mapped(w);
1107  
1108          // Establish direct screen connection
1109 <        XMoveResizeWindow(x_display, the_win, 0, 0, width, height);
1109 >        XMoveResizeWindow(x_display, w, 0, 0, width, height);
1110          XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
1111          XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
1112          XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
# Line 508 | Line 1118 | static bool init_xf86_dga(int width, int
1118          XF86DGASetVidPage(x_display, screen, 0);
1119  
1120          // Set colormap
1121 <        if (depth == 8) {
1122 <                XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap = 0]);
513 <                XSetWMColormapWindows(x_display, the_win, &the_win, 1);
1121 >        if (!IsDirectMode(mode)) {
1122 >                XSetWindowColormap(x_display, w, cmap[current_dga_cmap = 0]);
1123                  XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1124          }
1125 +        XSync(x_display, false);
1126  
1127 <        // Set VideoMonitor
1128 <        int bytes_per_row = (v_width + 7) & ~7;
1129 <        switch (depth) {
1130 <                case 1:
1131 <                        bytes_per_row /= 8;
1132 <                        break;
1133 <                case 15:
1134 <                case 16:
1135 <                        bytes_per_row *= 2;
1136 <                        break;
1137 <                case 24:
1138 <                case 32:
1139 <                        bytes_per_row *= 4;
1140 <                        break;
1127 >        // Init blitting routines
1128 >        int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth);
1129 > #ifdef VIDEO_VOSF
1130 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
1131 >        // Screen_blitter_init() returns TRUE if VOSF is mandatory
1132 >        // i.e. the framebuffer update function is not Blit_Copy_Raw
1133 >        use_vosf = Screen_blitter_init(&visualInfo, true, mode.depth);
1134 >        
1135 >        if (use_vosf) {
1136 >          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1137 >          the_host_buffer = the_buffer;
1138 >          the_buffer_size = page_extend((height + 2) * bytes_per_row);
1139 >          the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
1140 >          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
1141          }
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;
1142   #else
1143 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
1143 >        use_vosf = false;
1144   #endif
1145 <        return true;
1146 < #else
1147 <        ErrorAlert("Basilisk II has been compiled with XF86 DGA support disabled.");
1148 <        return false;
1145 > #endif
1146 >        
1147 >        // Set VideoMonitor
1148 >        const_cast<video_mode *>(&mode)->bytes_per_row = bytes_per_row;
1149 >        VideoMonitor.mode = mode;
1150 >        set_mac_frame_buffer(mode.depth, true);
1151 >
1152 >        // Everything went well
1153 >        init_ok = true;
1154 > }
1155 >
1156 > // Close display
1157 > driver_xf86dga::~driver_xf86dga()
1158 > {
1159 >        XF86DGADirectVideo(x_display, screen, 0);
1160 > #ifdef ENABLE_XF86_VIDMODE
1161 >        if (has_vidmode)
1162 >                XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]);
1163   #endif
1164   }
1165  
1166 + // Palette has changed
1167 + void driver_xf86dga::update_palette(void)
1168 + {
1169 +        driver_dga::update_palette();
1170 +        current_dga_cmap ^= 1;
1171 +        if (!IsDirectMode(VideoMonitor.mode) && cmap[current_dga_cmap])
1172 +                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1173 + }
1174 +
1175 + // Resume emulation
1176 + void driver_xf86dga::resume(void)
1177 + {
1178 +        driver_dga::resume();
1179 +        if (!IsDirectMode(VideoMonitor.mode))
1180 +                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1181 + }
1182 + #endif
1183 +
1184 +
1185 + /*
1186 + *  Initialization
1187 + */
1188 +
1189   // Init keycode translation table
1190   static void keycode_init(void)
1191   {
# Line 608 | Line 1251 | static void keycode_init(void)
1251          }
1252   }
1253  
1254 + // Open display for specified mode
1255 + static bool video_open(const video_mode &mode)
1256 + {
1257 +        // Find best available X visual
1258 +        if (!find_visual_for_depth(mode.depth)) {
1259 +                ErrorAlert(STR_NO_XVISUAL_ERR);
1260 +                return false;
1261 +        }
1262 +
1263 +        // Create color maps
1264 +        if (color_class == PseudoColor || color_class == DirectColor) {
1265 +                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1266 +                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1267 +        }
1268 +
1269 +        // Find pixel format of direct modes
1270 +        if (color_class == DirectColor || color_class == TrueColor) {
1271 +                rshift = gshift = bshift = 0;
1272 +                rloss = gloss = bloss = 8;
1273 +                uint32 mask;
1274 +                for (mask=vis->red_mask; !(mask&1); mask>>=1)
1275 +                        ++rshift;
1276 +                for (; mask&1; mask>>=1)
1277 +                        --rloss;
1278 +                for (mask=vis->green_mask; !(mask&1); mask>>=1)
1279 +                        ++gshift;
1280 +                for (; mask&1; mask>>=1)
1281 +                        --gloss;
1282 +                for (mask=vis->blue_mask; !(mask&1); mask>>=1)
1283 +                        ++bshift;
1284 +                for (; mask&1; mask>>=1)
1285 +                        --bloss;
1286 +        }
1287 +
1288 +        // Preset palette pixel values for gamma table
1289 +        if (color_class == DirectColor) {
1290 +                int num = vis->map_entries;
1291 +                for (int i=0; i<num; i++) {
1292 +                        int c = (i * 256) / num;
1293 +                        palette[i].pixel = map_rgb(c, c, c);
1294 +                }
1295 +        }
1296 +
1297 +        // Load gray ramp to color map
1298 +        int num = (color_class == DirectColor ? vis->map_entries : 256);
1299 +        for (int i=0; i<num; i++) {
1300 +                int c = (i * 256) / num;
1301 +                palette[i].red = c * 0x0101;
1302 +                palette[i].green = c * 0x0101;
1303 +                palette[i].blue = c * 0x0101;
1304 +                if (color_class == PseudoColor)
1305 +                        palette[i].pixel = i;
1306 +                palette[i].flags = DoRed | DoGreen | DoBlue;
1307 +        }
1308 +        if (cmap[0] && cmap[1]) {
1309 +                XStoreColors(x_display, cmap[0], palette, num);
1310 +                XStoreColors(x_display, cmap[1], palette, num);
1311 +        }
1312 +
1313 + #ifdef ENABLE_VOSF
1314 +        // Load gray ramp to 8->16/32 expand map
1315 +        if (!IsDirectMode(mode) && (color_class == TrueColor || color_class == DirectColor))
1316 +                for (int i=0; i<256; i++)
1317 +                        ExpandMap[i] = map_rgb(i, i, i);
1318 + #endif
1319 +
1320 +        // Create display driver object of requested type
1321 +        switch (display_type) {
1322 +                case DISPLAY_WINDOW:
1323 +                        drv = new driver_window(mode);
1324 +                        break;
1325 + #ifdef ENABLE_FBDEV_DGA
1326 +                case DISPLAY_DGA:
1327 +                        drv = new driver_fbdev(mode);
1328 +                        break;
1329 + #endif
1330 + #ifdef ENABLE_XF86_DGA
1331 +                case DISPLAY_DGA:
1332 +                        drv = new driver_xf86dga(mode);
1333 +                        break;
1334 + #endif
1335 +        }
1336 +        if (drv == NULL)
1337 +                return false;
1338 +        if (!drv->init_ok) {
1339 +                delete drv;
1340 +                drv = NULL;
1341 +                return false;
1342 +        }
1343 +
1344 + #ifdef ENABLE_VOSF
1345 +        if (use_vosf) {
1346 +                // Initialize the mainBuffer structure
1347 +                if (!video_init_buffer()) {
1348 +                        ErrorAlert(STR_VOSF_INIT_ERR);
1349 +                return false;
1350 +                }
1351 +
1352 +                // Initialize the handler for SIGSEGV
1353 +                if (!sigsegv_install_handler(screen_fault_handler)) {
1354 +                        ErrorAlert("Could not initialize Video on SEGV signals");
1355 +                        return false;
1356 +                }
1357 +        }
1358 + #endif
1359 +        
1360 +        // Initialize VideoRefresh function
1361 +        VideoRefreshInit();
1362 +
1363 +        // Lock down frame buffer
1364 +        XSync(x_display, false);
1365 +        LOCK_FRAME_BUFFER;
1366 +
1367 +        // Start redraw/input thread
1368 + #ifdef HAVE_PTHREADS
1369 +        redraw_thread_cancel = false;
1370 +        redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0);
1371 +        if (!redraw_thread_active) {
1372 +                printf("FATAL: cannot create redraw thread\n");
1373 +                return false;
1374 +        }
1375 + #else
1376 +        redraw_thread_active = true;
1377 + #endif
1378 +
1379 +        return true;
1380 + }
1381 +
1382   bool VideoInit(bool classic)
1383   {
1384 +        classic_mode = classic;
1385 +
1386 + #ifdef ENABLE_VOSF
1387 +        // Zero the mainBuffer structure
1388 +        mainBuffer.dirtyPages = NULL;
1389 +        mainBuffer.pageInfo = NULL;
1390 + #endif
1391 +        
1392 +        // Check if X server runs on local machine
1393 +        local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0)
1394 +                 || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0);
1395 +    
1396          // Init keycode translation
1397          keycode_init();
1398  
1399 +        // Read prefs
1400 +        frame_skip = PrefsFindInt32("frameskip");
1401 +        mouse_wheel_mode = PrefsFindInt32("mousewheelmode");
1402 +        mouse_wheel_lines = PrefsFindInt32("mousewheellines");
1403 +
1404          // Find screen and root window
1405          screen = XDefaultScreen(x_display);
1406          rootwin = XRootWindow(x_display, screen);
1407 +
1408 +        // Get sorted list of available depths
1409 +        avail_depths = XListDepths(x_display, screen, &num_depths);
1410 +        if (avail_depths == NULL) {
1411 +                ErrorAlert(STR_UNSUPP_DEPTH_ERR);
1412 +                return false;
1413 +        }
1414 +        sort(avail_depths, avail_depths + num_depths);
1415          
1416 <        // Get screen depth
621 <        xdepth = DefaultDepth(x_display, screen);
622 <        
623 < #if ENABLE_FBDEV_DGA
1416 > #ifdef ENABLE_FBDEV_DGA
1417          // Frame buffer name
1418          char fb_name[20];
1419          
1420 <        // Could do fbdev dga ?
1420 >        // Could do fbdev DGA?
1421          if ((fbdev_fd = open(FBDEVICE_FILE_NAME, O_RDWR)) != -1)
1422                  has_dga = true;
1423          else
1424                  has_dga = false;
1425   #endif
1426 <        
1427 < #if ENABLE_XF86_DGA
1426 >
1427 > #ifdef ENABLE_XF86_DGA
1428          // DGA available?
1429 <        int event_base, error_base;
1430 <        if (XF86DGAQueryExtension(x_display, &event_base, &error_base)) {
1429 >        int dga_event_base, dga_error_base;
1430 >        if (local_X11 && XF86DGAQueryExtension(x_display, &dga_event_base, &dga_error_base)) {
1431                  int dga_flags = 0;
1432                  XF86DGAQueryDirectVideo(x_display, screen, &dga_flags);
1433                  has_dga = dga_flags & XF86DGADirectPresent;
# Line 642 | Line 1435 | bool VideoInit(bool classic)
1435                  has_dga = false;
1436   #endif
1437  
1438 + #ifdef ENABLE_XF86_VIDMODE
1439 +        // VidMode available?
1440 +        int vm_event_base, vm_error_base;
1441 +        has_vidmode = XF86VidModeQueryExtension(x_display, &vm_event_base, &vm_error_base);
1442 +        if (has_vidmode)
1443 +                XF86VidModeGetAllModeLines(x_display, screen, &num_x_video_modes, &x_video_modes);
1444 + #endif
1445 +        
1446          // Find black and white colors
1447          XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:00/00/00", &black);
1448          XAllocColor(x_display, DefaultColormap(x_display, screen), &black);
# Line 650 | Line 1451 | bool VideoInit(bool classic)
1451          black_pixel = BlackPixel(x_display, screen);
1452          white_pixel = WhitePixel(x_display, screen);
1453  
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
1454          // Get screen mode from preferences
1455          const char *mode_str;
1456 <        if (classic)
1456 >        if (classic_mode)
1457                  mode_str = "win/512/342";
1458          else
1459                  mode_str = PrefsFindString("screen");
1460  
1461 <        // Determine type and mode
1462 <        int width = 512, height = 384;
1461 >        // Determine display type and default dimensions
1462 >        int default_width = 512, default_height = 384;
1463          display_type = DISPLAY_WINDOW;
1464          if (mode_str) {
1465 <                if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2)
1465 >                if (sscanf(mode_str, "win/%d/%d", &default_width, &default_height) == 2) {
1466                          display_type = DISPLAY_WINDOW;
1467 < #if ENABLE_FBDEV_DGA
1468 <                else if (has_dga && sscanf(mode_str, "dga/%s", fb_name) == 1) {
1469 < #else
1470 <                else if (has_dga && sscanf(mode_str, "dga/%d/%d", &width, &height) == 2) {
1467 > #ifdef ENABLE_FBDEV_DGA
1468 >                } else if (has_dga && sscanf(mode_str, "dga/%19s", fb_name) == 1) {
1469 >                        display_type = DISPLAY_DGA;
1470 >                        default_width = -1; default_height = -1; // use entire screen
1471   #endif
1472 + #ifdef ENABLE_XF86_DGA
1473 +                } else if (has_dga && sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2) {
1474                          display_type = DISPLAY_DGA;
1475 <                        if (width > DisplayWidth(x_display, screen))
1476 <                                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);
1475 > #endif
1476 >                }
1477          }
1478 <
1479 <        // Initialize according to display type
1480 <        switch (display_type) {
1481 <                case DISPLAY_WINDOW:
1482 <                        if (!init_window(width, height))
1483 <                                return false;
1478 >        if (default_width <= 0)
1479 >                default_width = DisplayWidth(x_display, screen);
1480 >        else if (default_width > DisplayWidth(x_display, screen))
1481 >                default_width = DisplayWidth(x_display, screen);
1482 >        if (default_height <= 0)
1483 >                default_height = DisplayHeight(x_display, screen);
1484 >        else if (default_height > DisplayHeight(x_display, screen))
1485 >                default_height = DisplayHeight(x_display, screen);
1486 >
1487 >        // Mac screen depth follows X depth
1488 >        video_depth default_depth = VDEPTH_1BIT;
1489 >        switch (DefaultDepth(x_display, screen)) {
1490 >                case 8:
1491 >                        default_depth = VDEPTH_8BIT;
1492                          break;
1493 <                case DISPLAY_DGA:
1494 < #if ENABLE_FBDEV_DGA
1495 <                        if (!init_fbdev_dga(fb_name))
1496 < #else
1497 <                        if (!init_xf86_dga(width, height))
738 < #endif
739 <                                return false;
1493 >                case 15: case 16:
1494 >                        default_depth = VDEPTH_16BIT;
1495 >                        break;
1496 >                case 24: case 32:
1497 >                        default_depth = VDEPTH_32BIT;
1498                          break;
1499          }
1500  
1501 <        // Lock down frame buffer
1502 <        pthread_mutex_lock(&frame_buffer_lock);
1503 <
1504 < #if !REAL_ADDRESSING
1505 <        // Set variables for UAE memory mapping
1506 <        MacFrameBaseHost = the_buffer;
1507 <        MacFrameSize = VideoMonitor.bytes_per_row * VideoMonitor.y;
1501 >        // Construct list of supported modes
1502 >        if (display_type == DISPLAY_WINDOW) {
1503 >                if (classic)
1504 >                        add_mode(512, 342, 0x80, 64, VDEPTH_1BIT);
1505 >                else {
1506 >                        for (unsigned d=VDEPTH_1BIT; d<=VDEPTH_32BIT; d++) {
1507 >                                if (find_visual_for_depth(video_depth(d)))
1508 >                                        add_window_modes(video_depth(d));
1509 >                        }
1510 >                }
1511 >        } else
1512 >                add_mode(default_width, default_height, 0x80, TrivialBytesPerRow(default_width, default_depth), default_depth);
1513 >        if (VideoModes.empty()) {
1514 >                ErrorAlert(STR_NO_XVISUAL_ERR);
1515 >                return false;
1516 >        }
1517 >        video_init_depth_list();
1518  
1519 <        // No special frame buffer in Classic mode (frame buffer is in Mac RAM)
1520 <        if (classic)
1521 <                MacFrameLayout = FLAYOUT_NONE;
1519 > #if DEBUG
1520 >        D(bug("Available video modes:\n"));
1521 >        vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
1522 >        while (i != end) {
1523 >                int bits = 1 << i->depth;
1524 >                if (bits == 16)
1525 >                        bits = 15;
1526 >                else if (bits == 32)
1527 >                        bits = 24;
1528 >                D(bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits));
1529 >                ++i;
1530 >        }
1531   #endif
1532  
1533 <        // Start redraw/input thread
1534 <        XSync(x_display, false);
1535 <        redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0);
1536 <        if (!redraw_thread_active)
1537 <                printf("FATAL: cannot create redraw thread\n");
1538 <        return redraw_thread_active;
1533 >        // Find requested default mode and open display
1534 >        if (VideoModes.size() == 1)
1535 >                return video_open(VideoModes[0]);
1536 >        else {
1537 >                // Find mode with specified dimensions
1538 >                std::vector<video_mode>::const_iterator i, end = VideoModes.end();
1539 >                for (i = VideoModes.begin(); i != end; ++i) {
1540 >                        if (i->x == default_width && i->y == default_height && i->depth == default_depth)
1541 >                                return video_open(*i);
1542 >                }
1543 >                return video_open(VideoModes[0]);
1544 >        }
1545   }
1546  
1547  
# Line 766 | Line 1549 | bool VideoInit(bool classic)
1549   *  Deinitialization
1550   */
1551  
1552 < void VideoExit(void)
1552 > // Close display
1553 > static void video_close(void)
1554   {
1555          // Stop redraw thread
1556 + #ifdef HAVE_PTHREADS
1557          if (redraw_thread_active) {
1558                  redraw_thread_cancel = true;
1559   #ifdef HAVE_PTHREAD_CANCEL
1560                  pthread_cancel(redraw_thread);
1561   #endif
1562                  pthread_join(redraw_thread, NULL);
778                redraw_thread_active = false;
1563          }
1564 + #endif
1565 +        redraw_thread_active = false;
1566  
1567          // Unlock frame buffer
1568 <        pthread_mutex_unlock(&frame_buffer_lock);
1569 <
784 <        // Close window and server connection
785 <        if (x_display != NULL) {
786 <                XSync(x_display, false);
1568 >        UNLOCK_FRAME_BUFFER;
1569 >        XSync(x_display, false);
1570  
1571 < #if ENABLE_XF86_DGA
1572 <                if (display_type == DISPLAY_DGA) {
1573 <                        XF86DGADirectVideo(x_display, screen, 0);
1574 <                        XUngrabPointer(x_display, CurrentTime);
1575 <                        XUngrabKeyboard(x_display, CurrentTime);
1571 > #ifdef ENABLE_VOSF
1572 >        // Deinitialize VOSF
1573 >        if (use_vosf) {
1574 >                if (mainBuffer.pageInfo) {
1575 >                        free(mainBuffer.pageInfo);
1576 >                        mainBuffer.pageInfo = NULL;
1577                  }
1578 +                if (mainBuffer.dirtyPages) {
1579 +                        free(mainBuffer.dirtyPages);
1580 +                        mainBuffer.dirtyPages = NULL;
1581 +                }
1582 +        }
1583   #endif
1584  
1585 < #if ENABLE_FBDEV_DGA
1586 <                if (display_type == DISPLAY_DGA) {
1587 <                        XUngrabPointer(x_display, CurrentTime);
1588 <                        XUngrabKeyboard(x_display, CurrentTime);
1589 <                        close(fbdev_fd);
1590 <                }
1585 >        // Close display
1586 >        delete drv;
1587 >        drv = NULL;
1588 >
1589 >        // Free colormaps
1590 >        if (cmap[0]) {
1591 >                XFreeColormap(x_display, cmap[0]);
1592 >                cmap[0] = 0;
1593 >        }
1594 >        if (cmap[1]) {
1595 >                XFreeColormap(x_display, cmap[1]);
1596 >                cmap[1] = 0;
1597 >        }
1598 > }
1599 >
1600 > void VideoExit(void)
1601 > {
1602 >        // Close display
1603 >        video_close();
1604 >
1605 > #ifdef ENABLE_XF86_VIDMODE
1606 >        // Free video mode list
1607 >        if (x_video_modes) {
1608 >                XFree(x_video_modes);
1609 >                x_video_modes = NULL;
1610 >        }
1611   #endif
803                
804                if (the_buffer_copy) {
805                        free(the_buffer_copy);
806                        the_buffer_copy = NULL;
807                }
1612  
1613 <                XFlush(x_display);
1614 <                XSync(x_display, false);
1615 <                if (depth == 8) {
1616 <                        XFreeColormap(x_display, cmap[0]);
1617 <                        XFreeColormap(x_display, cmap[1]);
1618 <                }
1613 > #ifdef ENABLE_FBDEV_DGA
1614 >        // Close framebuffer device
1615 >        if (fbdev_fd >= 0) {
1616 >                close(fbdev_fd);
1617 >                fbdev_fd = -1;
1618 >        }
1619 > #endif
1620 >
1621 >        // Free depth list
1622 >        if (avail_depths) {
1623 >                XFree(avail_depths);
1624 >                avail_depths = NULL;
1625          }
1626   }
1627  
# Line 823 | Line 1633 | void VideoExit(void)
1633   void VideoQuitFullScreen(void)
1634   {
1635          D(bug("VideoQuitFullScreen()\n"));
1636 <        if (display_type == DISPLAY_DGA)
827 <                quit_full_screen = true;
1636 >        quit_full_screen = true;
1637   }
1638  
1639  
# Line 840 | Line 1649 | void VideoInterrupt(void)
1649  
1650          // Temporarily give up frame buffer lock (this is the point where
1651          // we are suspended when the user presses Ctrl-Tab)
1652 <        pthread_mutex_unlock(&frame_buffer_lock);
1653 <        pthread_mutex_lock(&frame_buffer_lock);
1652 >        UNLOCK_FRAME_BUFFER;
1653 >        LOCK_FRAME_BUFFER;
1654   }
1655  
1656  
# Line 849 | Line 1658 | void VideoInterrupt(void)
1658   *  Set palette
1659   */
1660  
1661 < void video_set_palette(uint8 *pal)
1661 > void video_set_palette(uint8 *pal, int num_in)
1662   {
1663 <        pthread_mutex_lock(&palette_lock);
1663 >        LOCK_PALETTE;
1664  
1665          // Convert colors to XColor array
1666 <        for (int i=0; i<256; i++) {
1667 <                palette[i].pixel = i;
1668 <                palette[i].red = pal[i*3] * 0x0101;
1669 <                palette[i].green = pal[i*3+1] * 0x0101;
1670 <                palette[i].blue = pal[i*3+2] * 0x0101;
1671 <                palette[i].flags = DoRed | DoGreen | DoBlue;
1666 >        int num_out = 256;
1667 >        bool stretch = false;
1668 >        if (IsDirectMode(VideoMonitor.mode)) {
1669 >                // If X is in 565 mode we have to stretch the gamma table from 32 to 64 entries
1670 >                num_out = vis->map_entries;
1671 >                stretch = true;
1672 >        }
1673 >        XColor *p = palette;
1674 >        for (int i=0; i<num_out; i++) {
1675 >                int c = (stretch ? (i * num_in) / num_out : i);
1676 >                p->red = pal[c*3 + 0] * 0x0101;
1677 >                p->green = pal[c*3 + 1] * 0x0101;
1678 >                p->blue = pal[c*3 + 2] * 0x0101;
1679 >                if (color_class == PseudoColor)
1680 >                        p->pixel = i;
1681 >                p->flags = DoRed | DoGreen | DoBlue;
1682 >                p++;
1683 >        }
1684 >
1685 > #ifdef ENABLE_VOSF
1686 >        // Recalculate pixel color expansion map
1687 >        if (!IsDirectMode(VideoMonitor.mode) && (color_class == TrueColor || color_class == DirectColor)) {
1688 >                for (int i=0; i<256; i++) {
1689 >                        int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
1690 >                        ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]);
1691 >                }
1692 >
1693 >                // We have to redraw everything because the interpretation of pixel values changed
1694 >                LOCK_VOSF;
1695 >                PFLAG_SET_ALL;
1696 >                UNLOCK_VOSF;
1697 >                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
1698          }
1699 + #endif
1700  
1701          // Tell redraw thread to change palette
1702          palette_changed = true;
1703  
1704 <        pthread_mutex_unlock(&palette_lock);
1704 >        UNLOCK_PALETTE;
1705   }
1706  
1707  
1708   /*
1709 < *  Suspend/resume emulator
1709 > *  Switch video mode
1710   */
1711  
1712 < #if ENABLE_XF86_DGA || ENABLE_FBDEV_DGA
877 < static void suspend_emul(void)
1712 > void video_switch_to_mode(const video_mode &mode)
1713   {
1714 <        if (display_type == DISPLAY_DGA) {
1715 <                // Release ctrl key
1716 <                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);
1714 >        // Close and reopen display
1715 >        video_close();
1716 >        video_open(mode);
1717  
1718 <                // Open "suspend" window
1719 <                XSetWindowAttributes wattr;
1720 <                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)
923 < {
924 <        // Close "suspend" window
925 <        XDestroyWindow(x_display, suspend_win);
926 <        XSync(x_display, false);
927 <
928 <        // Reopen full screen display
929 <        XMapRaised(x_display, the_win);
930 <        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;
1718 >        if (drv == NULL) {
1719 >                ErrorAlert(STR_OPEN_WINDOW_ERR);
1720 >                QuitEmulator();
1721          }
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;
1722   }
959 #endif
1723  
1724  
1725   /*
1726 < *  Translate key event to Mac keycode
1726 > *  Translate key event to Mac keycode, returns -1 if no keycode was found
1727 > *  and -2 if the key was recognized as a hotkey
1728   */
1729  
1730 < static int kc_decode(KeySym ks)
1730 > static int kc_decode(KeySym ks, bool key_down)
1731   {
1732          switch (ks) {
1733                  case XK_A: case XK_a: return 0x00;
# Line 1016 | Line 1780 | static int kc_decode(KeySym ks)
1780                  case XK_period: case XK_greater: return 0x2f;
1781                  case XK_slash: case XK_question: return 0x2c;
1782  
1783 < #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
1783 >                case XK_Tab: if (ctrl_down) {if (key_down) drv->suspend(); return -2;} else return 0x30;
1784                  case XK_Return: return 0x24;
1785                  case XK_space: return 0x31;
1786                  case XK_BackSpace: return 0x33;
# Line 1054 | Line 1814 | static int kc_decode(KeySym ks)
1814                  case XK_Left: return 0x3b;
1815                  case XK_Right: return 0x3c;
1816  
1817 <                case XK_Escape: if (ctrl_down) {quit_full_screen = true; emerg_quit = true; return -1;} else return 0x35;
1817 >                case XK_Escape: if (ctrl_down) {if (key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35;
1818  
1819 <                case XK_F1: if (ctrl_down) {SysMountFirstFloppy(); return -1;} else return 0x7a;
1819 >                case XK_F1: if (ctrl_down) {if (key_down) SysMountFirstFloppy(); return -2;} else return 0x7a;
1820                  case XK_F2: return 0x78;
1821                  case XK_F3: return 0x63;
1822                  case XK_F4: return 0x76;
1823 <                case XK_F5: return 0x60;
1823 >                case XK_F5: if (ctrl_down) {if (key_down) drv->toggle_mouse_grab(); return -2;} else return 0x60;
1824                  case XK_F6: return 0x61;
1825                  case XK_F7: return 0x62;
1826                  case XK_F8: return 0x64;
# Line 1108 | Line 1868 | static int kc_decode(KeySym ks)
1868          return -1;
1869   }
1870  
1871 < static int event2keycode(XKeyEvent *ev)
1871 > static int event2keycode(XKeyEvent &ev, bool key_down)
1872   {
1873          KeySym ks;
1114        int as;
1874          int i = 0;
1875  
1876          do {
1877 <                ks = XLookupKeysym(ev, i++);
1878 <                as = kc_decode(ks);
1879 <                if (as != -1)
1877 >                ks = XLookupKeysym(&ev, i++);
1878 >                int as = kc_decode(ks, key_down);
1879 >                if (as >= 0)
1880 >                        return as;
1881 >                if (as == -2)
1882                          return as;
1883          } while (ks != NoSymbol);
1884  
# Line 1131 | Line 1892 | static int event2keycode(XKeyEvent *ev)
1892  
1893   static void handle_events(void)
1894   {
1895 <        XEvent event;
1896 <        for (;;) {
1897 <                if (!XCheckMaskEvent(x_display, eventmask, &event))
1137 <                        break;
1895 >        while (XPending(x_display)) {
1896 >                XEvent event;
1897 >                XNextEvent(x_display, &event);
1898  
1899                  switch (event.type) {
1900                          // Mouse button
1901                          case ButtonPress: {
1902 <                                unsigned int button = ((XButtonEvent *)&event)->button;
1902 >                                unsigned int button = event.xbutton.button;
1903                                  if (button < 4)
1904                                          ADBMouseDown(button - 1);
1905 +                                else if (button < 6) {  // Wheel mouse
1906 +                                        if (mouse_wheel_mode == 0) {
1907 +                                                int key = (button == 5) ? 0x79 : 0x74;  // Page up/down
1908 +                                                ADBKeyDown(key);
1909 +                                                ADBKeyUp(key);
1910 +                                        } else {
1911 +                                                int key = (button == 5) ? 0x3d : 0x3e;  // Cursor up/down
1912 +                                                for(int i=0; i<mouse_wheel_lines; i++) {
1913 +                                                        ADBKeyDown(key);
1914 +                                                        ADBKeyUp(key);
1915 +                                                }
1916 +                                        }
1917 +                                }
1918                                  break;
1919                          }
1920                          case ButtonRelease: {
1921 <                                unsigned int button = ((XButtonEvent *)&event)->button;
1921 >                                unsigned int button = event.xbutton.button;
1922                                  if (button < 4)
1923                                          ADBMouseUp(button - 1);
1924                                  break;
1925                          }
1926  
1927                          // Mouse moved
1155                        case EnterNotify:
1156                                ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
1157                                break;
1928                          case MotionNotify:
1929 <                                ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
1929 >                                drv->mouse_moved(event.xmotion.x, event.xmotion.y);
1930                                  break;
1931  
1932                          // Keyboard
1933                          case KeyPress: {
1934 <                                int code;
1934 >                                int code = -1;
1935                                  if (use_keycodes) {
1936 <                                        event2keycode((XKeyEvent *)&event);     // This is called to process the hotkeys
1937 <                                        code = keycode_table[((XKeyEvent *)&event)->keycode & 0xff];
1936 >                                        if (event2keycode(event.xkey, true) != -2)      // This is called to process the hotkeys
1937 >                                                code = keycode_table[event.xkey.keycode & 0xff];
1938                                  } else
1939 <                                        code = event2keycode((XKeyEvent *)&event);
1940 <                                if (code != -1) {
1939 >                                        code = event2keycode(event.xkey, true);
1940 >                                if (code >= 0) {
1941                                          if (!emul_suspended) {
1942                                                  if (code == 0x39) {     // Caps Lock pressed
1943                                                          if (caps_on) {
# Line 1182 | Line 1952 | static void handle_events(void)
1952                                                  if (code == 0x36)
1953                                                          ctrl_down = true;
1954                                          } else {
1185 #if ENABLE_XF86_DGA || ENABLE_FBDEV_DGA
1955                                                  if (code == 0x31)
1956 <                                                        resume_emul();  // Space wakes us up
1188 < #endif
1956 >                                                        drv->resume();  // Space wakes us up
1957                                          }
1958                                  }
1959                                  break;
1960                          }
1961                          case KeyRelease: {
1962 <                                int code;
1962 >                                int code = -1;
1963                                  if (use_keycodes) {
1964 <                                        event2keycode((XKeyEvent *)&event);     // This is called to process the hotkeys
1965 <                                        code = keycode_table[((XKeyEvent *)&event)->keycode & 0xff];
1964 >                                        if (event2keycode(event.xkey, false) != -2)     // This is called to process the hotkeys
1965 >                                                code = keycode_table[event.xkey.keycode & 0xff];
1966                                  } else
1967 <                                        code = event2keycode((XKeyEvent *)&event);
1968 <                                if (code != -1 && code != 0x39) {       // Don't propagate Caps Lock releases
1967 >                                        code = event2keycode(event.xkey, false);
1968 >                                if (code >= 0 && code != 0x39) {        // Don't propagate Caps Lock releases
1969                                          ADBKeyUp(code);
1970                                          if (code == 0x36)
1971                                                  ctrl_down = false;
# Line 1207 | Line 1975 | static void handle_events(void)
1975  
1976                          // Hidden parts exposed, force complete refresh of window
1977                          case Expose:
1978 <                                if (display_type == DISPLAY_WINDOW)
1979 <                                        memset(the_buffer_copy, 0, VideoMonitor.bytes_per_row * VideoMonitor.y);
1978 >                                if (display_type == DISPLAY_WINDOW) {
1979 > #ifdef ENABLE_VOSF
1980 >                                        if (use_vosf) {                 // VOSF refresh
1981 >                                                LOCK_VOSF;
1982 >                                                PFLAG_SET_ALL;
1983 >                                                UNLOCK_VOSF;
1984 >                                                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
1985 >                                        }
1986 >                                        else
1987 > #endif
1988 >                                        if (frame_skip == 0) {  // Dynamic refresh
1989 >                                                int x1, y1;
1990 >                                                for (y1=0; y1<16; y1++)
1991 >                                                for (x1=0; x1<16; x1++)
1992 >                                                        updt_box[x1][y1] = true;
1993 >                                                nr_boxes = 16 * 16;
1994 >                                        } else                                  // Static refresh
1995 >                                                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
1996 >                                }
1997 >                                break;
1998 >
1999 >                        // Window "close" widget clicked
2000 >                        case ClientMessage:
2001 >                                if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) {
2002 >                                        ADBKeyDown(0x7f);       // Power key
2003 >                                        ADBKeyUp(0x7f);
2004 >                                }
2005                                  break;
2006                  }
2007          }
# Line 1219 | Line 2012 | static void handle_events(void)
2012   *  Window display update
2013   */
2014  
2015 < static void update_display(void)
2015 > // Dynamic display update (variable frame rate for each box)
2016 > static void update_display_dynamic(int ticker, driver_window *drv)
2017 > {
2018 >        int y1, y2, y2s, y2a, i, x1, xm, xmo, ymo, yo, yi, yil, xi;
2019 >        int xil = 0;
2020 >        int rxm = 0, rxmo = 0;
2021 >        int bytes_per_row = VideoMonitor.mode.bytes_per_row;
2022 >        int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x;
2023 >        int rx = VideoMonitor.mode.bytes_per_row / 16;
2024 >        int ry = VideoMonitor.mode.y / 16;
2025 >        int max_box;
2026 >
2027 >        y2s = sm_uptd[ticker % 8];
2028 >        y2a = 8;
2029 >        for (i = 0; i < 6; i++)
2030 >                if (ticker % (2 << i))
2031 >                        break;
2032 >        max_box = sm_no_boxes[i];
2033 >
2034 >        if (y2a) {
2035 >                for (y1=0; y1<16; y1++) {
2036 >                        for (y2=y2s; y2 < ry; y2 += y2a) {
2037 >                                i = ((y1 * ry) + y2) * bytes_per_row;
2038 >                                for (x1=0; x1<16; x1++, i += rx) {
2039 >                                        if (updt_box[x1][y1] == false) {
2040 >                                                if (memcmp(&the_buffer_copy[i], &the_buffer[i], rx)) {
2041 >                                                        updt_box[x1][y1] = true;
2042 >                                                        nr_boxes++;
2043 >                                                }
2044 >                                        }
2045 >                                }
2046 >                        }
2047 >                }
2048 >        }
2049 >
2050 >        if ((nr_boxes <= max_box) && (nr_boxes)) {
2051 >                for (y1=0; y1<16; y1++) {
2052 >                        for (x1=0; x1<16; x1++) {
2053 >                                if (updt_box[x1][y1] == true) {
2054 >                                        if (rxm == 0)
2055 >                                                xm = x1;
2056 >                                        rxm += rx;
2057 >                                        updt_box[x1][y1] = false;
2058 >                                }
2059 >                                if (((updt_box[x1+1][y1] == false) || (x1 == 15)) && (rxm)) {
2060 >                                        if ((rxmo != rxm) || (xmo != xm) || (yo != y1 - 1)) {
2061 >                                                if (rxmo) {
2062 >                                                        xi = xmo * rx;
2063 >                                                        yi = ymo * ry;
2064 >                                                        xil = rxmo;
2065 >                                                        yil = (yo - ymo +1) * ry;
2066 >                                                }
2067 >                                                rxmo = rxm;
2068 >                                                xmo = xm;
2069 >                                                ymo = y1;
2070 >                                        }
2071 >                                        rxm = 0;
2072 >                                        yo = y1;
2073 >                                }      
2074 >                                if (xil) {
2075 >                                        i = (yi * bytes_per_row) + xi;
2076 >                                        for (y2=0; y2 < yil; y2++, i += bytes_per_row)
2077 >                                                memcpy(&the_buffer_copy[i], &the_buffer[i], xil);
2078 >                                        if (VideoMonitor.mode.depth == VDEPTH_1BIT) {
2079 >                                                if (drv->have_shm)
2080 >                                                        XShmPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil, 0);
2081 >                                                else
2082 >                                                        XPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil);
2083 >                                        } else {
2084 >                                                if (drv->have_shm)
2085 >                                                        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);
2086 >                                                else
2087 >                                                        XPutImage(x_display, drv->w, drv->gc, drv->img, xi / bytes_per_pixel, yi, xi / bytes_per_pixel, yi, xil / bytes_per_pixel, yil);
2088 >                                        }
2089 >                                        xil = 0;
2090 >                                }
2091 >                                if ((x1 == 15) && (y1 == 15) && (rxmo)) {
2092 >                                        x1--;
2093 >                                        xi = xmo * rx;
2094 >                                        yi = ymo * ry;
2095 >                                        xil = rxmo;
2096 >                                        yil = (yo - ymo +1) * ry;
2097 >                                        rxmo = 0;
2098 >                                }
2099 >                        }
2100 >                }
2101 >                nr_boxes = 0;
2102 >        }
2103 > }
2104 >
2105 > // Static display update (fixed frame rate, but incremental)
2106 > static void update_display_static(driver_window *drv)
2107   {
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        
2108          // Incremental update code
2109          int wide = 0, high = 0, x1, x2, y1, y2, i, j;
2110 <        int bytes_per_row = VideoMonitor.bytes_per_row;
2111 <        int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
2110 >        int bytes_per_row = VideoMonitor.mode.bytes_per_row;
2111 >        int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x;
2112          uint8 *p, *p2;
2113  
2114          // Check for first line from top and first line from bottom that have changed
2115          y1 = 0;
2116 <        for (j=0; j<VideoMonitor.y; j++) {
2116 >        for (j=0; j<VideoMonitor.mode.y; j++) {
2117                  if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
2118                          y1 = j;
2119                          break;
2120                  }
2121          }
2122          y2 = y1 - 1;
2123 <        for (j=VideoMonitor.y-1; j>=y1; j--) {
2123 >        for (j=VideoMonitor.mode.y-1; j>=y1; j--) {
2124                  if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
2125                          y2 = j;
2126                          break;
# Line 1250 | Line 2130 | static void update_display(void)
2130  
2131          // Check for first column from left and first column from right that have changed
2132          if (high) {
2133 <                if (depth == 1) {
2134 <                        x1 = VideoMonitor.x;
2133 >                if (VideoMonitor.mode.depth == VDEPTH_1BIT) {
2134 >                        x1 = VideoMonitor.mode.x - 1;
2135                          for (j=y1; j<=y2; j++) {
2136                                  p = &the_buffer[j * bytes_per_row];
2137                                  p2 = &the_buffer_copy[j * bytes_per_row];
# Line 1260 | Line 2140 | static void update_display(void)
2140                                                  x1 = i << 3;
2141                                                  break;
2142                                          }
2143 <                                        p++;
1264 <                                        p2++;
2143 >                                        p++; p2++;
2144                                  }
2145                          }
2146                          x2 = x1;
# Line 1270 | Line 2149 | static void update_display(void)
2149                                  p2 = &the_buffer_copy[j * bytes_per_row];
2150                                  p += bytes_per_row;
2151                                  p2 += bytes_per_row;
2152 <                                for (i=(VideoMonitor.x>>3); i>(x2>>3); i--) {
2153 <                                        p--;
1275 <                                        p2--;
2152 >                                for (i=(VideoMonitor.mode.x>>3); i>(x2>>3); i--) {
2153 >                                        p--; p2--;
2154                                          if (*p != *p2) {
2155 <                                                x2 = i << 3;
2155 >                                                x2 = (i << 3) + 7;
2156                                                  break;
2157                                          }
2158                                  }
2159                          }
2160 <                        wide = x2 - x1;
2160 >                        wide = x2 - x1 + 1;
2161  
2162                          // Update copy of the_buffer
2163                          if (high && wide) {
2164                                  for (j=y1; j<=y2; j++) {
2165                                          i = j * bytes_per_row + (x1 >> 3);
2166 <                                        memcpy(&the_buffer_copy[i], &the_buffer[i], wide >> 3);
2166 >                                        memcpy(the_buffer_copy + i, the_buffer + i, wide >> 3);
2167                                  }
2168                          }
2169  
2170                  } else {
2171 <                        x1 = VideoMonitor.x;
2171 >                        x1 = VideoMonitor.mode.x;
2172                          for (j=y1; j<=y2; j++) {
2173                                  p = &the_buffer[j * bytes_per_row];
2174                                  p2 = &the_buffer_copy[j * bytes_per_row];
2175 <                                for (i=0; i<x1; i++) {
2176 <                                        if (memcmp(p, p2, bytes_per_pixel)) {
2177 <                                                x1 = i;
2175 >                                for (i=0; i<x1*bytes_per_pixel; i++) {
2176 >                                        if (*p != *p2) {
2177 >                                                x1 = i / bytes_per_pixel;
2178                                                  break;
2179                                          }
2180 <                                        p += bytes_per_pixel;
1303 <                                        p2 += bytes_per_pixel;
2180 >                                        p++; p2++;
2181                                  }
2182                          }
2183                          x2 = x1;
# Line 1309 | Line 2186 | static void update_display(void)
2186                                  p2 = &the_buffer_copy[j * bytes_per_row];
2187                                  p += bytes_per_row;
2188                                  p2 += bytes_per_row;
2189 <                                for (i=VideoMonitor.x; i>x2; i--) {
2190 <                                        p -= bytes_per_pixel;
2191 <                                        p2 -= bytes_per_pixel;
2192 <                                        if (memcmp(p, p2, bytes_per_pixel)) {
2193 <                                                x2 = i;
2189 >                                for (i=VideoMonitor.mode.x*bytes_per_pixel; i>x2*bytes_per_pixel; i--) {
2190 >                                        p--;
2191 >                                        p2--;
2192 >                                        if (*p != *p2) {
2193 >                                                x2 = i / bytes_per_pixel;
2194                                                  break;
2195                                          }
2196                                  }
# Line 1324 | Line 2201 | static void update_display(void)
2201                          if (high && wide) {
2202                                  for (j=y1; j<=y2; j++) {
2203                                          i = j * bytes_per_row + x1 * bytes_per_pixel;
2204 <                                        memcpy(&the_buffer_copy[i], &the_buffer[i], bytes_per_pixel * wide);
2204 >                                        memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * wide);
2205                                  }
2206                          }
2207                  }
# Line 1332 | Line 2209 | static void update_display(void)
2209  
2210          // Refresh display
2211          if (high && wide) {
2212 <                if (have_shm)
2213 <                        XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high, 0);
2212 >                if (drv->have_shm)
2213 >                        XShmPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high, 0);
2214                  else
2215 <                        XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high);
1339 <        }
1340 <
1341 <        // Has the Mac started? (cursor data is not valid otherwise)
1342 <        if (HasMacStarted()) {
1343 <
1344 <                // Set new cursor image if it was changed
1345 <                if (memcmp(the_cursor, Mac2HostAddr(0x844), 64)) {
1346 <                        memcpy(the_cursor, Mac2HostAddr(0x844), 64);
1347 <                        memcpy(cursor_image->data, the_cursor, 32);
1348 <                        memcpy(cursor_mask_image->data, the_cursor+32, 32);
1349 <                        XFreeCursor(x_display, mac_cursor);
1350 <                        XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);
1351 <                        XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16);
1352 <                        mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, ReadMacInt8(0x885), ReadMacInt8(0x887));
1353 <                        XDefineCursor(x_display, the_win, mac_cursor);
1354 <                }
2215 >                        XPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high);
2216          }
2217   }
2218  
2219  
2220   /*
2221 < *  Thread for screen refresh, input handling etc.
2221 > *      Screen refresh functions
2222   */
2223  
2224 < static void *redraw_func(void *arg)
2224 > // We suggest the compiler to inline the next two functions so that it
2225 > // may specialise the code according to the current screen depth and
2226 > // display type. A clever compiler would do that job by itself though...
2227 >
2228 > // NOTE: update_display_vosf is inlined too
2229 >
2230 > static inline void possibly_quit_dga_mode()
2231   {
2232 <        int tick_counter = 0;
2232 >        // Quit DGA mode if requested (something terrible has happened and we
2233 >        // want to give control back to the user)
2234 >        if (quit_full_screen) {
2235 >                quit_full_screen = false;
2236 >                delete drv;
2237 >                drv = NULL;
2238 >        }
2239 > }
2240  
2241 <        while (!redraw_thread_cancel) {
2241 > static inline void possibly_ungrab_mouse()
2242 > {
2243 >        // Ungrab mouse if requested (something terrible has happened and we
2244 >        // want to give control back to the user)
2245 >        if (quit_full_screen) {
2246 >                quit_full_screen = false;
2247 >                if (drv)
2248 >                        drv->ungrab_mouse();
2249 >        }
2250 > }
2251  
2252 <                // Wait
2253 < #ifdef HAVE_NANOSLEEP
2254 <                struct timespec req = {0, 16666667};
1372 <                nanosleep(&req, NULL);
1373 < #else
1374 <                usleep(16667);
1375 < #endif
2252 > static inline void handle_palette_changes(void)
2253 > {
2254 >        LOCK_PALETTE;
2255  
2256 < #if ENABLE_XF86_DGA
2257 <                // Quit DGA mode if requested
2258 <                if (quit_full_screen) {
2259 <                        quit_full_screen = false;
2260 <                        if (display_type == DISPLAY_DGA) {
2261 <                                XF86DGADirectVideo(x_display, screen, 0);
2262 <                                XUngrabPointer(x_display, CurrentTime);
2263 <                                XUngrabKeyboard(x_display, CurrentTime);
2264 <                                XUnmapWindow(x_display, the_win);
2265 <                                XSync(x_display, false);
2266 <                        }
2256 >        if (palette_changed) {
2257 >                palette_changed = false;
2258 >                drv->update_palette();
2259 >        }
2260 >
2261 >        UNLOCK_PALETTE;
2262 > }
2263 >
2264 > static void video_refresh_dga(void)
2265 > {
2266 >        // Quit DGA mode if requested
2267 >        possibly_quit_dga_mode();
2268 >        
2269 >        // Handle X events
2270 >        handle_events();
2271 >        
2272 >        // Handle palette changes
2273 >        handle_palette_changes();
2274 > }
2275 >
2276 > #ifdef ENABLE_VOSF
2277 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
2278 > static void video_refresh_dga_vosf(void)
2279 > {
2280 >        // Quit DGA mode if requested
2281 >        possibly_quit_dga_mode();
2282 >        
2283 >        // Handle X events
2284 >        handle_events();
2285 >        
2286 >        // Handle palette changes
2287 >        handle_palette_changes();
2288 >        
2289 >        // Update display (VOSF variant)
2290 >        static int tick_counter = 0;
2291 >        if (++tick_counter >= frame_skip) {
2292 >                tick_counter = 0;
2293 >                if (mainBuffer.dirty) {
2294 >                        LOCK_VOSF;
2295 >                        update_display_dga_vosf();
2296 >                        UNLOCK_VOSF;
2297                  }
2298 +        }
2299 + }
2300   #endif
2301  
2302 < #if ENABLE_FBDEV_DGA
2303 <                // Quit DGA mode if requested
2304 <                if (quit_full_screen) {
2305 <                        quit_full_screen = false;
2306 <                        if (display_type == DISPLAY_DGA) {
2307 <                                XUngrabPointer(x_display, CurrentTime);
2308 <                                XUngrabKeyboard(x_display, CurrentTime);
2309 <                                XUnmapWindow(x_display, the_win);
2310 <                                XSync(x_display, false);
2311 <                        }
2302 > static void video_refresh_window_vosf(void)
2303 > {
2304 >        // Ungrab mouse if requested
2305 >        possibly_ungrab_mouse();
2306 >        
2307 >        // Handle X events
2308 >        handle_events();
2309 >        
2310 >        // Handle palette changes
2311 >        handle_palette_changes();
2312 >        
2313 >        // Update display (VOSF variant)
2314 >        static int tick_counter = 0;
2315 >        if (++tick_counter >= frame_skip) {
2316 >                tick_counter = 0;
2317 >                if (mainBuffer.dirty) {
2318 >                        LOCK_VOSF;
2319 >                        update_display_window_vosf(static_cast<driver_window *>(drv));
2320 >                        UNLOCK_VOSF;
2321 >                        XSync(x_display, false); // Let the server catch up
2322                  }
2323 < #endif
2324 <                // Handle X events
2325 <                handle_events();
2323 >        }
2324 > }
2325 > #endif // def ENABLE_VOSF
2326  
2327 <                // Handle palette changes
2328 <                pthread_mutex_lock(&palette_lock);
2329 <                if (palette_changed) {
2330 <                        palette_changed = false;
2331 <                        if (depth == 8) {
2332 <                                XStoreColors(x_display, cmap[0], palette, 256);
2333 <                                XStoreColors(x_display, cmap[1], palette, 256);
2334 <                                
2335 < #if ENABLE_XF86_DGA
2336 <                                if (display_type == DISPLAY_DGA) {
2337 <                                        current_dga_cmap ^= 1;
2338 <                                        XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
2339 <                                }
2327 > static void video_refresh_window_static(void)
2328 > {
2329 >        // Ungrab mouse if requested
2330 >        possibly_ungrab_mouse();
2331 >
2332 >        // Handle X events
2333 >        handle_events();
2334 >        
2335 >        // Handle_palette changes
2336 >        handle_palette_changes();
2337 >        
2338 >        // Update display (static variant)
2339 >        static int tick_counter = 0;
2340 >        if (++tick_counter >= frame_skip) {
2341 >                tick_counter = 0;
2342 >                update_display_static(static_cast<driver_window *>(drv));
2343 >        }
2344 > }
2345 >
2346 > static void video_refresh_window_dynamic(void)
2347 > {
2348 >        // Ungrab mouse if requested
2349 >        possibly_ungrab_mouse();
2350 >
2351 >        // Handle X events
2352 >        handle_events();
2353 >        
2354 >        // Handle_palette changes
2355 >        handle_palette_changes();
2356 >        
2357 >        // Update display (dynamic variant)
2358 >        static int tick_counter = 0;
2359 >        tick_counter++;
2360 >        update_display_dynamic(tick_counter, static_cast<driver_window *>(drv));
2361 > }
2362 >
2363 >
2364 > /*
2365 > *  Thread for screen refresh, input handling etc.
2366 > */
2367 >
2368 > static void VideoRefreshInit(void)
2369 > {
2370 >        // TODO: set up specialised 8bpp VideoRefresh handlers ?
2371 >        if (display_type == DISPLAY_DGA) {
2372 > #if ENABLE_VOSF && (REAL_ADDRESSING || DIRECT_ADDRESSING)
2373 >                if (use_vosf)
2374 >                        video_refresh = video_refresh_dga_vosf;
2375 >                else
2376   #endif
2377 <                                
2378 < #if ENABLE_FBDEV_DGA
2379 <                                if (display_type == DISPLAY_DGA)
2380 <                                        XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap]);
2377 >                        video_refresh = video_refresh_dga;
2378 >        }
2379 >        else {
2380 > #ifdef ENABLE_VOSF
2381 >                if (use_vosf)
2382 >                        video_refresh = video_refresh_window_vosf;
2383 >                else
2384   #endif
2385 <                        }
2386 <                }
2387 <                pthread_mutex_unlock(&palette_lock);
2385 >                if (frame_skip == 0)
2386 >                        video_refresh = video_refresh_window_dynamic;
2387 >                else
2388 >                        video_refresh = video_refresh_window_static;
2389 >        }
2390 > }
2391  
2392 <                // In window mode, update display and mouse pointer
2393 <                if (display_type == DISPLAY_WINDOW) {
2394 <                        tick_counter++;
2395 <                        if (tick_counter >= frame_skip) {
2396 <                                tick_counter = 0;
2397 <                                update_display();
2398 <                        }
2399 <                }
2392 > void VideoRefresh(void)
2393 > {
2394 >        // We need to check redraw_thread_active to inhibit refreshed during
2395 >        // mode changes on non-threaded platforms
2396 >        if (redraw_thread_active)
2397 >                video_refresh();
2398 > }
2399 >
2400 > #ifdef HAVE_PTHREADS
2401 > static void *redraw_func(void *arg)
2402 > {
2403 >        uint64 start = GetTicks_usec();
2404 >        int64 ticks = 0;
2405 >        uint64 next = GetTicks_usec();
2406 >        while (!redraw_thread_cancel) {
2407 >                video_refresh();
2408 >                next += 16667;
2409 >                int64 delay = next - GetTicks_usec();
2410 >                if (delay > 0)
2411 >                        Delay_usec(delay);
2412 >                else if (delay < -16667)
2413 >                        next = GetTicks_usec();
2414 >                ticks++;
2415          }
2416 +        uint64 end = GetTicks_usec();
2417 +        // printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, ticks * 1000000 / (end - start));
2418          return NULL;
2419   }
2420 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines