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.56 by gbeauche, 2001-07-07T09:14:47Z vs.
Revision 1.81 by gbeauche, 2005-06-11T06:52:22Z

# Line 1 | Line 1
1   /*
2   *  video_x.cpp - Video/graphics emulation, X11 specific stuff
3   *
4 < *  Basilisk II (C) 1997-2001 Christian Bauer
4 > *  Basilisk II (C) 1997-2005 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 39 | Line 39
39  
40   #include <algorithm>
41  
42 #ifndef NO_STD_NAMESPACE
43 using std::sort;
44 #endif
45
42   #ifdef HAVE_PTHREADS
43   # include <pthread.h>
44   #endif
# Line 66 | Line 62 | using std::sort;
62   #include "prefs.h"
63   #include "user_strings.h"
64   #include "video.h"
65 + #include "video_blit.h"
66  
67   #define DEBUG 0
68   #include "debug.h"
69  
70  
71 + // Supported video modes
72 + static vector<video_mode> VideoModes;
73 +
74   // Display types
75   enum {
76          DISPLAY_WINDOW, // X11 window, using MIT SHM extensions if possible
# Line 80 | Line 80 | enum {
80   // Constants
81   const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes";
82  
83 < static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask;
83 > static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask | StructureNotifyMask;
84   static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask;
85  
86  
# Line 97 | Line 97 | static uint32 the_buffer_size;                                         // S
97  
98   static bool redraw_thread_active = false;                       // Flag: Redraw thread installed
99   #ifdef HAVE_PTHREADS
100 + static pthread_attr_t redraw_thread_attr;                       // Redraw thread attributes
101   static volatile bool redraw_thread_cancel;                      // Flag: Cancel Redraw thread
102 + static volatile bool redraw_thread_cancel_ack;          // Flag: Acknowledge for redraw thread cancellation
103   static pthread_t redraw_thread;                                         // Redraw thread
104   #endif
105  
# Line 122 | Line 124 | static bool use_keycodes = false;                                      //
124   static int keycode_table[256];                                          // X keycode -> Mac keycode translation table
125  
126   // X11 variables
127 + char *x_display_name = NULL;                                            // X11 display name
128 + Display *x_display = NULL;                                                      // X11 display handle
129   static int screen;                                                                      // Screen number
130   static Window rootwin;                                                          // Root window and our window
131   static int num_depths = 0;                                                      // Number of available X depths
# Line 131 | Line 135 | static unsigned long black_pixel, white_
135   static int eventmask;
136  
137   static int xdepth;                                                                      // Depth of X screen
138 + static VisualFormat visualFormat;
139   static XVisualInfo visualInfo;
140   static Visual *vis;
141   static int color_class;
# Line 139 | Line 144 | static int rshift, rloss, gshift, gloss,
144  
145   static Colormap cmap[2] = {0, 0};                                       // Colormaps for indexed modes (DGA needs two of them)
146  
147 < static XColor palette[256];                                                     // Color palette to be used as CLUT and gamma table
148 < static bool palette_changed = false;                            // Flag: Palette changed, redraw thread must set new colors
147 > static XColor x_palette[256];                                                   // Color palette to be used as CLUT and gamma table
148 > static bool x_palette_changed = false;                          // Flag: Palette changed, redraw thread must set new colors
149  
150   #ifdef ENABLE_FBDEV_DGA
151   static int fbdev_fd = -1;
# Line 153 | Line 158 | static int num_x_video_modes;
158  
159   // Mutex to protect palette
160   #ifdef HAVE_PTHREADS
161 < static pthread_mutex_t palette_lock = PTHREAD_MUTEX_INITIALIZER;
162 < #define LOCK_PALETTE pthread_mutex_lock(&palette_lock)
163 < #define UNLOCK_PALETTE pthread_mutex_unlock(&palette_lock)
161 > static pthread_mutex_t x_palette_lock = PTHREAD_MUTEX_INITIALIZER;
162 > #define LOCK_PALETTE pthread_mutex_lock(&x_palette_lock)
163 > #define UNLOCK_PALETTE pthread_mutex_unlock(&x_palette_lock)
164   #else
165   #define LOCK_PALETTE
166   #define UNLOCK_PALETTE
# Line 184 | Line 189 | static void (*video_refresh)(void);
189  
190   // Prototypes
191   static void *redraw_func(void *arg);
187 static int event2keycode(XKeyEvent &ev);
192  
193   // From main_unix.cpp
194   extern char *x_display_name;
195   extern Display *x_display;
196 + extern void *vm_acquire_mac(size_t size);
197  
198   // From sys_unix.cpp
199   extern void SysMountFirstFloppy(void);
200  
201 + // From clip_unix.cpp
202 + extern void ClipboardSelectionClear(XSelectionClearEvent *);
203 + extern void ClipboardSelectionRequest(XSelectionRequestEvent *);
204 +
205 +
206 + /*
207 + *  monitor_desc subclass for X11 display
208 + */
209 +
210 + class X11_monitor_desc : public monitor_desc {
211 + public:
212 +        X11_monitor_desc(const vector<video_mode> &available_modes, video_depth default_depth, uint32 default_id) : monitor_desc(available_modes, default_depth, default_id) {}
213 +        ~X11_monitor_desc() {}
214 +
215 +        virtual void switch_to_current_mode(void);
216 +        virtual void set_palette(uint8 *pal, int num);
217 +
218 +        bool video_open(void);
219 +        void video_close(void);
220 + };
221 +
222  
223   /*
224   *  Utility functions
225   */
226  
227 + // Map video_mode depth ID to numerical depth value
228 + static inline int depth_of_video_mode(video_mode const & mode)
229 + {
230 +        int depth = -1;
231 +        switch (mode.depth) {
232 +        case VDEPTH_1BIT:
233 +                depth = 1;
234 +                break;
235 +        case VDEPTH_2BIT:
236 +                depth = 2;
237 +                break;
238 +        case VDEPTH_4BIT:
239 +                depth = 4;
240 +                break;
241 +        case VDEPTH_8BIT:
242 +                depth = 8;
243 +                break;
244 +        case VDEPTH_16BIT:
245 +                depth = 16;
246 +                break;
247 +        case VDEPTH_32BIT:
248 +                depth = 32;
249 +                break;
250 +        default:
251 +                abort();
252 +        }
253 +        return depth;
254 + }
255 +
256   // Map RGB color to pixel value (this only works in TrueColor/DirectColor visuals)
257   static inline uint32 map_rgb(uint8 red, uint8 green, uint8 blue)
258   {
# Line 210 | Line 265 | static bool find_visual_for_depth(video_
265   {
266          D(bug("have_visual_for_depth(%d)\n", 1 << depth));
267  
268 +        // 1-bit works always and uses default visual
269 +        if (depth == VDEPTH_1BIT) {
270 +                vis = DefaultVisual(x_display, screen);
271 +                visualInfo.visualid = XVisualIDFromVisual(vis);
272 +                int num = 0;
273 +                XVisualInfo *vi = XGetVisualInfo(x_display, VisualIDMask, &visualInfo, &num);
274 +                visualInfo = vi[0];
275 +                XFree(vi);
276 +                xdepth = visualInfo.depth;
277 +                color_class = visualInfo.c_class;
278 +                D(bug(" found visual ID 0x%02x, depth %d\n", visualInfo.visualid, xdepth));
279 +                return true;
280 +        }
281 +
282          // Calculate minimum and maximum supported X depth
283          int min_depth = 1, max_depth = 32;
284          switch (depth) {
216                case VDEPTH_1BIT:       // 1-bit works always
217                        min_depth = 1;
218                        max_depth = 32;
219                        break;
285   #ifdef ENABLE_VOSF
286                  case VDEPTH_2BIT:
287                  case VDEPTH_4BIT:       // VOSF blitters can convert 2/4/8-bit -> 8/16/32-bit
# Line 294 | Line 359 | static bool find_visual_for_depth(video_
359                  case DirectColor: D(bug("DirectColor\n")); break;
360          }
361   #endif
362 +        return true;
363   }
364  
365   // Add mode to list of supported modes
# Line 321 | Line 387 | static void add_window_modes(video_depth
387   }
388  
389   // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
390 < static void set_mac_frame_buffer(video_depth depth, bool native_byte_order)
390 > static void set_mac_frame_buffer(X11_monitor_desc &monitor, video_depth depth, bool native_byte_order)
391   {
392   #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
393          int layout = FLAYOUT_DIRECT;
# Line 333 | Line 399 | static void set_mac_frame_buffer(video_d
399                  MacFrameLayout = layout;
400          else
401                  MacFrameLayout = FLAYOUT_DIRECT;
402 <        VideoMonitor.mac_frame_base = MacFrameBaseMac;
402 >        monitor.set_mac_frame_base(MacFrameBaseMac);
403  
404          // Set variables used by UAE memory banking
405 +        const video_mode &mode = monitor.get_current_mode();
406          MacFrameBaseHost = the_buffer;
407 <        MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y;
407 >        MacFrameSize = mode.bytes_per_row * mode.y;
408          InitFrameBufferMapping();
409   #else
410 <        VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer);
410 >        monitor.set_mac_frame_base(Host2MacAddr(the_buffer));
411   #endif
412 <        D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base));
412 >        D(bug("monitor.mac_frame_base = %08x\n", monitor.get_mac_frame_base()));
413   }
414  
415   // Set window name and class
# Line 420 | Line 487 | static int error_handler(Display *d, XEr
487  
488   class driver_base {
489   public:
490 <        driver_base();
490 >        driver_base(X11_monitor_desc &m);
491          virtual ~driver_base();
492  
493          virtual void update_palette(void);
# Line 429 | Line 496 | public:
496          virtual void toggle_mouse_grab(void) {}
497          virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); }
498  
499 +        void disable_mouse_accel(void);
500 +        void restore_mouse_accel(void);
501 +
502          virtual void grab_mouse(void) {}
503          virtual void ungrab_mouse(void) {}
504  
505   public:
506 +        X11_monitor_desc &monitor; // Associated video monitor
507 +        const video_mode &mode;    // Video mode handled by the driver
508 +
509          bool init_ok;   // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer)
510          Window w;               // The window we draw into
511 +
512 +        int orig_accel_numer, orig_accel_denom, orig_threshold; // Original mouse acceleration
513   };
514  
515   class driver_window;
# Line 448 | Line 523 | class driver_window : public driver_base
523          friend void update_display_static(driver_window *drv);
524  
525   public:
526 <        driver_window(const video_mode &mode);
526 >        driver_window(X11_monitor_desc &monitor);
527          ~driver_window();
528  
529          void toggle_mouse_grab(void);
# Line 467 | Line 542 | private:
542          int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode)
543   };
544  
545 + class driver_dga;
546 + static void update_display_dga_vosf(driver_dga *drv);
547 +
548 + class driver_dga : public driver_base {
549 +        friend void update_display_dga_vosf(driver_dga *drv);
550 +
551 + public:
552 +        driver_dga(X11_monitor_desc &monitor);
553 +        ~driver_dga();
554 +
555 +        void suspend(void);
556 +        void resume(void);
557 +
558 + protected:
559 +        struct FakeXImage {
560 +                int width, height;              // size of image
561 +                int depth;                              // depth of image
562 +                int bytes_per_line;             // accelerator to next line
563 +
564 +                FakeXImage(int w, int h, int d)
565 +                        : width(w), height(h), depth(d)
566 +                        { bytes_per_line = TrivialBytesPerRow(width, DepthModeForPixelDepth(depth)); }
567 +        };
568 +        FakeXImage *img;
569 +
570 + private:
571 +        Window suspend_win;             // "Suspend" information window
572 +        void *fb_save;                  // Saved frame buffer for suspend/resume
573 + };
574 +
575   static driver_base *drv = NULL; // Pointer to currently used driver object
576  
577   #ifdef ENABLE_VOSF
578   # include "video_vosf.h"
579   #endif
580  
581 < driver_base::driver_base()
582 < : init_ok(false), w(0)
581 > driver_base::driver_base(X11_monitor_desc &m)
582 > : monitor(m), mode(m.get_current_mode()), init_ok(false), w(0)
583   {
584          the_buffer = NULL;
585          the_buffer_copy = NULL;
586 +        XGetPointerControl(x_display, &orig_accel_numer, &orig_accel_denom, &orig_threshold);
587   }
588  
589   driver_base::~driver_base()
590   {
591          ungrab_mouse();
592 +        restore_mouse_accel();
593  
594          if (w) {
595                  XUnmapWindow(x_display, w);
# Line 506 | Line 613 | driver_base::~driver_base()
613          }
614   #ifdef ENABLE_VOSF
615          else {
616 +                // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will
617 +                if (the_buffer != VM_MAP_FAILED) {
618 +                        D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
619 +                        vm_release(the_buffer, the_buffer_size);
620 +                        the_buffer = NULL;
621 +                }
622                  if (the_host_buffer) {
623 +                        D(bug(" freeing the_host_buffer at %p\n", the_host_buffer));
624                          free(the_host_buffer);
625                          the_host_buffer = NULL;
626                  }
513                if (the_buffer) {
514                        free(the_buffer);
515                        the_buffer = NULL;
516                }
627                  if (the_buffer_copy) {
628 +                        D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
629                          free(the_buffer_copy);
630                          the_buffer_copy = NULL;
631                  }
# Line 525 | Line 636 | driver_base::~driver_base()
636   // Palette has changed
637   void driver_base::update_palette(void)
638   {
639 <        if (cmap[0] && cmap[1]) {
639 >        if (color_class == PseudoColor || color_class == DirectColor) {
640                  int num = vis->map_entries;
641 <                if (!IsDirectMode(VideoMonitor.mode) && color_class == DirectColor)
641 >                if (!IsDirectMode(monitor.get_current_mode()) && color_class == DirectColor)
642                          return; // Indexed mode on true color screen, don't set CLUT
643 <                XStoreColors(x_display, cmap[0], palette, num);
644 <                XStoreColors(x_display, cmap[1], palette, num);
643 >                XStoreColors(x_display, cmap[0], x_palette, num);
644 >                XStoreColors(x_display, cmap[1], x_palette, num);
645          }
646          XSync(x_display, false);
647   }
648  
649 + // Disable mouse acceleration
650 + void driver_base::disable_mouse_accel(void)
651 + {
652 +        XChangePointerControl(x_display, True, False, 1, 1, 0);
653 + }
654 +
655 + // Restore mouse acceleration to original value
656 + void driver_base::restore_mouse_accel(void)
657 + {
658 +        XChangePointerControl(x_display, True, True, orig_accel_numer, orig_accel_denom, orig_threshold);
659 + }
660 +
661  
662   /*
663   *  Windowed display driver
664   */
665  
666   // Open display
667 < driver_window::driver_window(const video_mode &mode)
668 < : gc(0), img(NULL), have_shm(false), mouse_grabbed(false), mac_cursor(0)
667 > driver_window::driver_window(X11_monitor_desc &m)
668 > : driver_base(m), gc(0), img(NULL), have_shm(false), mac_cursor(0), mouse_grabbed(false)
669   {
670          int width = mode.x, height = mode.y;
671          int aligned_width = (width + 15) & ~15;
# Line 551 | Line 674 | driver_window::driver_window(const video
674          // Set absolute mouse mode
675          ADBSetRelMouseMode(mouse_grabbed);
676  
677 <        // Create window
677 >        // Create window (setting background_pixel, border_pixel and colormap is
678 >        // mandatory when using a non-default visual; in 1-bit mode we use the
679 >        // default visual, so we can also use the default colormap)
680          XSetWindowAttributes wattr;
681          wattr.event_mask = eventmask = win_eventmask;
682 <        wattr.background_pixel = black_pixel;
683 <        wattr.colormap = (mode.depth == VDEPTH_1BIT && color_class == PseudoColor ? DefaultColormap(x_display, screen) : cmap[0]);
682 >        wattr.background_pixel = (vis == DefaultVisual(x_display, screen) ? black_pixel : 0);
683 >        wattr.border_pixel = 0;
684 >        wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]);
685          w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
686 <                InputOutput, vis, CWEventMask | CWBackPixel | (color_class == PseudoColor || color_class == DirectColor ? CWColormap : 0), &wattr);
686 >                InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWColormap, &wattr);
687 >        D(bug(" window created\n"));
688  
689          // Set window name/class
690          set_window_name(w, STR_WINDOW_TITLE);
# Line 581 | Line 708 | driver_window::driver_window(const video
708                          XFree(hints);
709                  }
710          }
711 +        D(bug(" window attributes set\n"));
712          
713          // Show window
714          XMapWindow(x_display, w);
715          wait_mapped(w);
716 +        D(bug(" window mapped\n"));
717  
718          // 1-bit mode is big-endian; if the X server is little-endian, we can't
719          // use SHM because that doesn't allow changing the image byte order
# Line 595 | Line 724 | driver_window::driver_window(const video
724  
725                  // Create SHM image ("height + 2" for safety)
726                  img = XShmCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
727 +                D(bug(" shm image created\n"));
728                  shminfo.shmid = shmget(IPC_PRIVATE, (aligned_height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
729                  the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
730                  shminfo.shmaddr = img->data = (char *)the_buffer_copy;
# Line 615 | Line 745 | driver_window::driver_window(const video
745                          have_shm = true;
746                          shmctl(shminfo.shmid, IPC_RMID, 0);
747                  }
748 +                D(bug(" shm image attached\n"));
749          }
750          
751          // Create normal X image if SHM doesn't work ("height + 2" for safety)
# Line 622 | Line 753 | driver_window::driver_window(const video
753                  int bytes_per_row = (mode.depth == VDEPTH_1BIT ? aligned_width/8 : TrivialBytesPerRow(aligned_width, DepthModeForPixelDepth(xdepth)));
754                  the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
755                  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);
756 +                D(bug(" X image created\n"));
757          }
758  
759          if (need_msb_image) {
# Line 634 | Line 766 | driver_window::driver_window(const video
766          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
767          the_host_buffer = the_buffer_copy;
768          the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
769 <        the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
770 <        the_buffer = (uint8 *)vm_acquire(the_buffer_size);
769 >        the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size);
770 >        the_buffer_copy = (uint8 *)malloc(the_buffer_size);
771          D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
772   #else
773          // Allocate memory for frame buffer
# Line 662 | Line 794 | driver_window::driver_window(const video
794          native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
795   #endif
796   #ifdef ENABLE_VOSF
797 <        Screen_blitter_init(&visualInfo, native_byte_order, mode.depth);
797 >        Screen_blitter_init(visualFormat, native_byte_order, depth_of_video_mode(mode));
798   #endif
799  
800 <        // Set VideoMonitor
801 <        VideoMonitor.mode = mode;
670 <        set_mac_frame_buffer(mode.depth, native_byte_order);
800 >        // Set frame buffer base
801 >        set_mac_frame_buffer(monitor, mode.depth, native_byte_order);
802  
803          // Everything went well
804          init_ok = true;
# Line 684 | Line 815 | driver_window::~driver_window()
815                  the_buffer_copy = NULL; // don't free() in driver_base dtor
816   #endif
817          }
818 < #ifdef ENABLE_VOSF
819 <        if (use_vosf) {
820 <                // don't free() memory mapped buffers in driver_base dtor
690 <                if (the_buffer != VM_MAP_FAILED) {
691 <                        vm_release(the_buffer, the_buffer_size);
692 <                        the_buffer = NULL;
693 <                }
694 <                if (the_buffer_copy != VM_MAP_FAILED) {
695 <                        vm_release(the_buffer_copy, the_buffer_size);
696 <                        the_buffer_copy = NULL;
697 <                }
698 <        }
699 < #endif
700 <        if (img)
818 >        if (img) {
819 >                if (!have_shm)
820 >                        img->data = NULL;
821                  XDestroyImage(img);
822 +        }
823          if (have_shm) {
824                  shmdt(shminfo.shmaddr);
825                  shmctl(shminfo.shmid, IPC_RMID, 0);
# Line 728 | Line 849 | void driver_window::grab_mouse(void)
849                  Delay_usec(100000);
850          }
851          if (result == GrabSuccess) {
731                ADBSetRelMouseMode(mouse_grabbed = true);
852                  XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED));
853 <                XSync(x_display, false);
853 >                ADBSetRelMouseMode(mouse_grabbed = true);
854 >                disable_mouse_accel();
855          }
856   }
857  
# Line 741 | Line 862 | void driver_window::ungrab_mouse(void)
862                  XUngrabPointer(x_display, CurrentTime);
863                  XStoreName(x_display, w, GetString(STR_WINDOW_TITLE));
864                  ADBSetRelMouseMode(mouse_grabbed = false);
865 +                restore_mouse_accel();
866          }
867   }
868  
# Line 756 | Line 878 | void driver_window::mouse_moved(int x, i
878          // Warped mouse motion (this code is taken from SDL)
879  
880          // Post first mouse event
881 <        int width = VideoMonitor.mode.x, height = VideoMonitor.mode.y;
881 >        int width = monitor.get_current_mode().x, height = monitor.get_current_mode().y;
882          int delta_x = x - mouse_last_x, delta_y = y - mouse_last_y;
883          mouse_last_x = x; mouse_last_y = y;
884          ADBMouseMoved(delta_x, delta_y);
# Line 791 | Line 913 | void driver_window::mouse_moved(int x, i
913   *  DGA display driver base class
914   */
915  
916 < class driver_dga : public driver_base {
917 < public:
796 <        driver_dga();
797 <        ~driver_dga();
798 <
799 <        void suspend(void);
800 <        void resume(void);
801 <
802 < private:
803 <        Window suspend_win;             // "Suspend" information window
804 <        void *fb_save;                  // Saved frame buffer for suspend/resume
805 < };
806 <
807 < driver_dga::driver_dga()
808 < : suspend_win(0), fb_save(NULL)
916 > driver_dga::driver_dga(X11_monitor_desc &m)
917 >        : driver_base(m), suspend_win(0), fb_save(NULL), img(NULL)
918   {
919   }
920  
# Line 813 | Line 922 | driver_dga::~driver_dga()
922   {
923          XUngrabPointer(x_display, CurrentTime);
924          XUngrabKeyboard(x_display, CurrentTime);
925 +
926 +        if (img)
927 +                delete img;
928   }
929  
930   // Suspend emulation
# Line 826 | Line 938 | void driver_dga::suspend(void)
938          LOCK_FRAME_BUFFER;
939  
940          // Save frame buffer
941 <        fb_save = malloc(VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row);
941 >        fb_save = malloc(mode.y * mode.bytes_per_row);
942          if (fb_save)
943 <                memcpy(fb_save, the_buffer, VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row);
943 >                memcpy(fb_save, the_buffer, mode.y * mode.bytes_per_row);
944  
945          // Close full screen display
946   #ifdef ENABLE_XF86_DGA
# Line 836 | Line 948 | void driver_dga::suspend(void)
948   #endif
949          XUngrabPointer(x_display, CurrentTime);
950          XUngrabKeyboard(x_display, CurrentTime);
951 +        restore_mouse_accel();
952          XUnmapWindow(x_display, w);
953          wait_unmapped(w);
954  
# Line 865 | Line 978 | void driver_dga::resume(void)
978          XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
979          XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
980          XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
981 +        disable_mouse_accel();
982   #ifdef ENABLE_XF86_DGA
983          XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
984          XF86DGASetViewPort(x_display, screen, 0, 0);
# Line 879 | Line 993 | void driver_dga::resume(void)
993                  LOCK_VOSF;
994                  PFLAG_SET_ALL;
995                  UNLOCK_VOSF;
996 <                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
996 >                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
997          }
998   #endif
999          
# Line 889 | Line 1003 | void driver_dga::resume(void)
1003                  // Don't copy fb_save to the temporary frame buffer in VOSF mode
1004                  if (!use_vosf)
1005   #endif
1006 <                memcpy(the_buffer, fb_save, VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row);
1006 >                memcpy(the_buffer, fb_save, mode.y * mode.bytes_per_row);
1007                  free(fb_save);
1008                  fb_save = NULL;
1009          }
# Line 911 | Line 1025 | const char FBDEVICE_FILE_NAME[] = "/dev/
1025  
1026   class driver_fbdev : public driver_dga {
1027   public:
1028 <        driver_fbdev(const video_mode &mode);
1028 >        driver_fbdev(X11_monitor_desc &monitor);
1029          ~driver_fbdev();
1030   };
1031  
1032   // Open display
1033 < driver_fbdev::driver_fbdev(const video_mode &mode)
1033 > driver_fbdev::driver_fbdev(X11_monitor_desc &m) : driver_dga(m)
1034   {
1035          int width = mode.x, height = mode.y;
1036  
# Line 964 | Line 1078 | driver_fbdev::driver_fbdev(const video_m
1078                  if ((line[0] == '#') || (line[0] == ';') || (line[0] == '\0'))
1079                          continue;
1080                  
1081 <                if ((sscanf(line, "%19s %d %x", &fb_name, &fb_depth, &fb_offset) == 3)
1081 >                if ((sscanf(line, "%19s %d %x", fb_name, &fb_depth, &fb_offset) == 3)
1082                   && (strcmp(fb_name, fb_name) == 0) && (fb_depth == max_depth)) {
1083                          device_found = true;
1084                          break;
# Line 1011 | Line 1125 | driver_fbdev::driver_fbdev(const video_m
1125          XGrabPointer(x_display, w, True,
1126                  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1127                  GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
1128 +        disable_mouse_accel();
1129          
1130          // Calculate bytes per row
1131          int bytes_per_row = TrivialBytesPerRow(mode.x, mode.depth);
# Line 1030 | Line 1145 | driver_fbdev::driver_fbdev(const video_m
1145   #if REAL_ADDRESSING || DIRECT_ADDRESSING
1146          // Screen_blitter_init() returns TRUE if VOSF is mandatory
1147          // i.e. the framebuffer update function is not Blit_Copy_Raw
1148 <        use_vosf = Screen_blitter_init(&visualInfo, true, mode.depth);
1148 >        use_vosf = Screen_blitter_init(visualFormat, true, mode.depth);
1149          
1150          if (use_vosf) {
1151            // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1152            the_host_buffer = the_buffer;
1153            the_buffer_size = page_extend((height + 2) * bytes_per_row);
1154 <          the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
1155 <          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
1154 >          the_buffer_copy = (uint8 *)malloc(the_buffer_size);
1155 >          the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size);
1156 >
1157 >          // Fake image for DGA/VOSF mode to know about display bounds
1158 >          img = new FakeXImage(width, height, depth_of_video_mode(mode));
1159          }
1160   #else
1161          use_vosf = false;
1162   #endif
1163   #endif
1164          
1165 <        // Set VideoMonitor
1166 <        VideoModes[0].bytes_per_row = bytes_per_row;
1167 <        VideoModes[0].depth = DepthModeForPixelDepth(fb_depth);
1168 <        VideoMonitor.mode = mode;
1051 <        set_mac_frame_buffer(mode.depth, true);
1165 >        // Set frame buffer base
1166 >        const_cast<video_mode *>(&mode)->bytes_per_row = bytes_per_row;
1167 >        const_cast<video_mode *>(&mode)->depth = DepthModeForPixelDepth(fb_depth);
1168 >        set_mac_frame_buffer(monitor, mode.depth, true);
1169  
1170          // Everything went well
1171          init_ok = true;
# Line 1071 | Line 1188 | driver_fbdev::~driver_fbdev()
1188                          munmap(the_host_buffer, the_buffer_size);
1189                          the_host_buffer = NULL;
1190                  }
1074                if (the_buffer_copy != VM_MAP_FAILED) {
1075                        vm_release(the_buffer_copy, the_buffer_size);
1076                        the_buffer_copy = NULL;
1077                }
1078                if (the_buffer != VM_MAP_FAILED) {
1079                        vm_release(the_buffer, the_buffer_size);
1080                        the_buffer = NULL;
1081                }
1191          }
1192   #endif
1193   }
# Line 1092 | Line 1201 | driver_fbdev::~driver_fbdev()
1201  
1202   class driver_xf86dga : public driver_dga {
1203   public:
1204 <        driver_xf86dga(const video_mode &mode);
1204 >        driver_xf86dga(X11_monitor_desc &monitor);
1205          ~driver_xf86dga();
1206  
1207          void update_palette(void);
# Line 1103 | Line 1212 | private:
1212   };
1213  
1214   // Open display
1215 < driver_xf86dga::driver_xf86dga(const video_mode &mode)
1216 < : current_dga_cmap(0)
1215 > driver_xf86dga::driver_xf86dga(X11_monitor_desc &m)
1216 > : driver_dga(m), current_dga_cmap(0)
1217   {
1218          int width = mode.x, height = mode.y;
1219  
# Line 1131 | Line 1240 | driver_xf86dga::driver_xf86dga(const vid
1240          XSetWindowAttributes wattr;
1241          wattr.event_mask = eventmask = dga_eventmask;
1242          wattr.override_redirect = True;
1243 +        wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]);
1244  
1245          w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
1246 <                InputOutput, vis, CWEventMask | CWOverrideRedirect, &wattr);
1246 >                InputOutput, vis, CWEventMask | CWOverrideRedirect |
1247 >                (color_class == DirectColor ? CWColormap : 0), &wattr);
1248  
1249          // Set window name/class
1250          set_window_name(w, STR_WINDOW_TITLE);
# Line 1150 | Line 1261 | driver_xf86dga::driver_xf86dga(const vid
1261          XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
1262          XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
1263          XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
1264 +        disable_mouse_accel();
1265  
1266          int v_width, v_bank, v_size;
1267          XF86DGAGetVideo(x_display, screen, (char **)&the_buffer, &v_width, &v_bank, &v_size);
# Line 1166 | Line 1278 | driver_xf86dga::driver_xf86dga(const vid
1278  
1279          // Init blitting routines
1280          int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth);
1281 < #if VIDEO_VOSF
1281 > #if ENABLE_VOSF
1282 >        bool native_byte_order;
1283 > #ifdef WORDS_BIGENDIAN
1284 >        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
1285 > #else
1286 >        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
1287 > #endif
1288   #if REAL_ADDRESSING || DIRECT_ADDRESSING
1289          // Screen_blitter_init() returns TRUE if VOSF is mandatory
1290          // i.e. the framebuffer update function is not Blit_Copy_Raw
1291 <        use_vosf = Screen_blitter_init(&visualInfo, true, mode.depth);
1291 >        use_vosf = Screen_blitter_init(visualFormat, native_byte_order, depth_of_video_mode(mode));
1292          
1293          if (use_vosf) {
1294            // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1295            the_host_buffer = the_buffer;
1296            the_buffer_size = page_extend((height + 2) * bytes_per_row);
1297 <          the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
1298 <          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
1297 >          the_buffer_copy = (uint8 *)malloc(the_buffer_size);
1298 >          the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size);
1299 >
1300 >          // Fake image for DGA/VOSF mode to know about display bounds
1301 >          img = new FakeXImage((v_width + 7) & ~7, height, depth_of_video_mode(mode));
1302          }
1303   #else
1304          use_vosf = false;
1305   #endif
1306   #endif
1307          
1308 <        // Set VideoMonitor
1308 >        // Set frame buffer base
1309          const_cast<video_mode *>(&mode)->bytes_per_row = bytes_per_row;
1310 <        VideoMonitor.mode = mode;
1190 <        set_mac_frame_buffer(mode.depth, true);
1310 >        set_mac_frame_buffer(monitor, mode.depth, true);
1311  
1312          // Everything went well
1313          init_ok = true;
# Line 1205 | Line 1325 | driver_xf86dga::~driver_xf86dga()
1325          else {
1326                  // don't free() the screen buffer in driver_base dtor
1327                  the_host_buffer = NULL;
1208                
1209                if (the_buffer_copy != VM_MAP_FAILED) {
1210                        vm_release(the_buffer_copy, the_buffer_size);
1211                        the_buffer_copy = NULL;
1212                }
1213                if (the_buffer != VM_MAP_FAILED) {
1214                        vm_release(the_buffer, the_buffer_size);
1215                        the_buffer = NULL;
1216                }
1328          }
1329   #endif
1330   #ifdef ENABLE_XF86_VIDMODE
# Line 1227 | Line 1338 | void driver_xf86dga::update_palette(void
1338   {
1339          driver_dga::update_palette();
1340          current_dga_cmap ^= 1;
1341 <        if (!IsDirectMode(VideoMonitor.mode) && cmap[current_dga_cmap])
1341 >        if (!IsDirectMode(monitor.get_current_mode()) && cmap[current_dga_cmap])
1342                  XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1343   }
1344  
# Line 1235 | Line 1346 | void driver_xf86dga::update_palette(void
1346   void driver_xf86dga::resume(void)
1347   {
1348          driver_dga::resume();
1349 <        if (!IsDirectMode(VideoMonitor.mode))
1349 >        if (!IsDirectMode(monitor.get_current_mode()))
1350                  XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1351   }
1352   #endif
# Line 1269 | Line 1380 | static void keycode_init(void)
1380  
1381                  // Search for server vendor string, then read keycodes
1382                  const char *vendor = ServerVendor(x_display);
1383 +                // Force use of MacX mappings on MacOS X with Apple's X server
1384 +                int dummy;
1385 +                if (XQueryExtension(x_display, "Apple-DRI", &dummy, &dummy, &dummy))
1386 +                        vendor = "MacX";
1387                  bool vendor_found = false;
1388                  char line[256];
1389                  while (fgets(line, 255, f)) {
# Line 1310 | Line 1425 | static void keycode_init(void)
1425          }
1426   }
1427  
1428 < // Open display for specified mode
1429 < static bool video_open(const video_mode &mode)
1428 > // Open display for current mode
1429 > bool X11_monitor_desc::video_open(void)
1430   {
1431 +        D(bug("video_open()\n"));
1432 +        const video_mode &mode = get_current_mode();
1433 +
1434          // Find best available X visual
1435          if (!find_visual_for_depth(mode.depth)) {
1436                  ErrorAlert(STR_NO_XVISUAL_ERR);
1437                  return false;
1438          }
1439  
1440 +        // Build up visualFormat structure
1441 +        visualFormat.fullscreen = (display_type == DISPLAY_DGA);
1442 +        visualFormat.depth = visualInfo.depth;
1443 +        visualFormat.Rmask = visualInfo.red_mask;
1444 +        visualFormat.Gmask = visualInfo.green_mask;
1445 +        visualFormat.Bmask = visualInfo.blue_mask;
1446 +
1447          // Create color maps
1448          if (color_class == PseudoColor || color_class == DirectColor) {
1449                  cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1450                  cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll);
1451 +        } else {
1452 +                cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocNone);
1453 +                cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocNone);
1454          }
1455  
1456          // Find pixel format of direct modes
# Line 1344 | Line 1472 | static bool video_open(const video_mode
1472                          --bloss;
1473          }
1474  
1475 <        // Preset palette pixel values for gamma table
1475 >        // Preset palette pixel values for CLUT or gamma table
1476          if (color_class == DirectColor) {
1477                  int num = vis->map_entries;
1478                  for (int i=0; i<num; i++) {
1479                          int c = (i * 256) / num;
1480 <                        palette[i].pixel = map_rgb(c, c, c);
1480 >                        x_palette[i].pixel = map_rgb(c, c, c);
1481 >                        x_palette[i].flags = DoRed | DoGreen | DoBlue;
1482 >                }
1483 >        } else if (color_class == PseudoColor) {
1484 >                for (int i=0; i<256; i++) {
1485 >                        x_palette[i].pixel = i;
1486 >                        x_palette[i].flags = DoRed | DoGreen | DoBlue;
1487                  }
1488          }
1489  
# Line 1357 | Line 1491 | static bool video_open(const video_mode
1491          int num = (color_class == DirectColor ? vis->map_entries : 256);
1492          for (int i=0; i<num; i++) {
1493                  int c = (i * 256) / num;
1494 <                palette[i].red = c * 0x0101;
1495 <                palette[i].green = c * 0x0101;
1496 <                palette[i].blue = c * 0x0101;
1497 <                if (color_class == PseudoColor)
1498 <                        palette[i].pixel = i;
1499 <                palette[i].flags = DoRed | DoGreen | DoBlue;
1500 <        }
1367 <        if (cmap[0] && cmap[1]) {
1368 <                XStoreColors(x_display, cmap[0], palette, num);
1369 <                XStoreColors(x_display, cmap[1], palette, num);
1494 >                x_palette[i].red = c * 0x0101;
1495 >                x_palette[i].green = c * 0x0101;
1496 >                x_palette[i].blue = c * 0x0101;
1497 >        }
1498 >        if (color_class == PseudoColor || color_class == DirectColor) {
1499 >                XStoreColors(x_display, cmap[0], x_palette, num);
1500 >                XStoreColors(x_display, cmap[1], x_palette, num);
1501          }
1502  
1503   #ifdef ENABLE_VOSF
1504          // Load gray ramp to 8->16/32 expand map
1505 <        if (!IsDirectMode(mode) && (color_class == TrueColor || color_class == DirectColor))
1505 >        if (!IsDirectMode(mode) && xdepth > 8)
1506                  for (int i=0; i<256; i++)
1507                          ExpandMap[i] = map_rgb(i, i, i);
1508   #endif
# Line 1379 | Line 1510 | static bool video_open(const video_mode
1510          // Create display driver object of requested type
1511          switch (display_type) {
1512                  case DISPLAY_WINDOW:
1513 <                        drv = new driver_window(mode);
1513 >                        drv = new driver_window(*this);
1514                          break;
1515   #ifdef ENABLE_FBDEV_DGA
1516                  case DISPLAY_DGA:
1517 <                        drv = new driver_fbdev(mode);
1517 >                        drv = new driver_fbdev(*this);
1518                          break;
1519   #endif
1520   #ifdef ENABLE_XF86_DGA
1521                  case DISPLAY_DGA:
1522 <                        drv = new driver_xf86dga(mode);
1522 >                        drv = new driver_xf86dga(*this);
1523                          break;
1524   #endif
1525          }
# Line 1403 | Line 1534 | static bool video_open(const video_mode
1534   #ifdef ENABLE_VOSF
1535          if (use_vosf) {
1536                  // Initialize the VOSF system
1537 <                if (!video_vosf_init()) {
1537 >                if (!video_vosf_init(*this)) {
1538                          ErrorAlert(STR_VOSF_INIT_ERR);
1539                  return false;
1540                  }
# Line 1418 | Line 1549 | static bool video_open(const video_mode
1549          LOCK_FRAME_BUFFER;
1550  
1551          // Start redraw/input thread
1552 < #ifdef HAVE_PTHREADS
1552 > #ifdef USE_PTHREADS_SERVICES
1553          redraw_thread_cancel = false;
1554 <        redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0);
1554 >        Set_pthread_attr(&redraw_thread_attr, 0);
1555 >        redraw_thread_active = (pthread_create(&redraw_thread, &redraw_thread_attr, redraw_func, NULL) == 0);
1556          if (!redraw_thread_active) {
1557                  printf("FATAL: cannot create redraw thread\n");
1558                  return false;
# Line 1464 | Line 1596 | bool VideoInit(bool classic)
1596                  ErrorAlert(STR_UNSUPP_DEPTH_ERR);
1597                  return false;
1598          }
1599 <        sort(avail_depths, avail_depths + num_depths);
1599 >        std::sort(avail_depths, avail_depths + num_depths);
1600          
1601   #ifdef ENABLE_FBDEV_DGA
1602          // Frame buffer name
# Line 1567 | Line 1699 | bool VideoInit(bool classic)
1699                  ErrorAlert(STR_NO_XVISUAL_ERR);
1700                  return false;
1701          }
1702 <        video_init_depth_list();
1702 >
1703 >        // Find requested default mode with specified dimensions
1704 >        uint32 default_id;
1705 >        std::vector<video_mode>::const_iterator i, end = VideoModes.end();
1706 >        for (i = VideoModes.begin(); i != end; ++i) {
1707 >                if (i->x == default_width && i->y == default_height && i->depth == default_depth) {
1708 >                        default_id = i->resolution_id;
1709 >                        break;
1710 >                }
1711 >        }
1712 >        if (i == end) { // not found, use first available mode
1713 >                default_depth = VideoModes[0].depth;
1714 >                default_id = VideoModes[0].resolution_id;
1715 >        }
1716  
1717   #if DEBUG
1718          D(bug("Available video modes:\n"));
1719 <        vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
1575 <        while (i != end) {
1719 >        for (i = VideoModes.begin(); i != end; ++i) {
1720                  int bits = 1 << i->depth;
1721                  if (bits == 16)
1722                          bits = 15;
1723                  else if (bits == 32)
1724                          bits = 24;
1725                  D(bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits));
1582                ++i;
1726          }
1727   #endif
1728  
1729 <        // Find requested default mode and open display
1730 <        if (VideoModes.size() == 1)
1731 <                return video_open(VideoModes[0]);
1732 <        else {
1733 <                // Find mode with specified dimensions
1734 <                std::vector<video_mode>::const_iterator i, end = VideoModes.end();
1592 <                for (i = VideoModes.begin(); i != end; ++i) {
1593 <                        if (i->x == default_width && i->y == default_height && i->depth == default_depth)
1594 <                                return video_open(*i);
1595 <                }
1596 <                return video_open(VideoModes[0]);
1597 <        }
1729 >        // Create X11_monitor_desc for this (the only) display
1730 >        X11_monitor_desc *monitor = new X11_monitor_desc(VideoModes, default_depth, default_id);
1731 >        VideoMonitors.push_back(monitor);
1732 >
1733 >        // Open display
1734 >        return monitor->video_open();
1735   }
1736  
1737  
# Line 1603 | Line 1740 | bool VideoInit(bool classic)
1740   */
1741  
1742   // Close display
1743 < static void video_close(void)
1743 > void X11_monitor_desc::video_close(void)
1744   {
1745 +        D(bug("video_close()\n"));
1746 +
1747          // Stop redraw thread
1748 < #ifdef HAVE_PTHREADS
1748 > #ifdef USE_PTHREADS_SERVICES
1749          if (redraw_thread_active) {
1750                  redraw_thread_cancel = true;
1751 < #ifdef HAVE_PTHREAD_CANCEL
1613 <                pthread_cancel(redraw_thread);
1614 < #endif
1751 >                redraw_thread_cancel_ack = false;
1752                  pthread_join(redraw_thread, NULL);
1753 +                while (!redraw_thread_cancel_ack) ;
1754          }
1755   #endif
1756          redraw_thread_active = false;
# Line 1620 | Line 1758 | static void video_close(void)
1758          // Unlock frame buffer
1759          UNLOCK_FRAME_BUFFER;
1760          XSync(x_display, false);
1761 +        D(bug(" frame buffer unlocked\n"));
1762  
1763   #ifdef ENABLE_VOSF
1764          if (use_vosf) {
# Line 1645 | Line 1784 | static void video_close(void)
1784  
1785   void VideoExit(void)
1786   {
1787 <        // Close display
1788 <        video_close();
1787 >        // Close displays
1788 >        vector<monitor_desc *>::iterator i, end = VideoMonitors.end();
1789 >        for (i = VideoMonitors.begin(); i != end; ++i)
1790 >                dynamic_cast<X11_monitor_desc *>(*i)->video_close();
1791  
1792   #ifdef ENABLE_XF86_VIDMODE
1793          // Free video mode list
# Line 1704 | Line 1845 | void VideoInterrupt(void)
1845   *  Set palette
1846   */
1847  
1848 < void video_set_palette(uint8 *pal, int num_in)
1848 > void X11_monitor_desc::set_palette(uint8 *pal, int num_in)
1849   {
1850 +        const video_mode &mode = get_current_mode();
1851 +
1852          LOCK_PALETTE;
1853  
1854          // Convert colors to XColor array
1855          int num_out = 256;
1856          bool stretch = false;
1857 <        if (IsDirectMode(VideoMonitor.mode)) {
1857 >        if (IsDirectMode(mode)) {
1858                  // If X is in 565 mode we have to stretch the gamma table from 32 to 64 entries
1859                  num_out = vis->map_entries;
1860                  stretch = true;
1861          }
1862 <        XColor *p = palette;
1862 >        XColor *p = x_palette;
1863          for (int i=0; i<num_out; i++) {
1864                  int c = (stretch ? (i * num_in) / num_out : i);
1865                  p->red = pal[c*3 + 0] * 0x0101;
1866                  p->green = pal[c*3 + 1] * 0x0101;
1867                  p->blue = pal[c*3 + 2] * 0x0101;
1725                if (color_class == PseudoColor)
1726                        p->pixel = i;
1727                p->flags = DoRed | DoGreen | DoBlue;
1868                  p++;
1869          }
1870  
1871   #ifdef ENABLE_VOSF
1872          // Recalculate pixel color expansion map
1873 <        if (!IsDirectMode(VideoMonitor.mode) && (color_class == TrueColor || color_class == DirectColor)) {
1873 >        if (!IsDirectMode(mode) && xdepth > 8) {
1874                  for (int i=0; i<256; i++) {
1875                          int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
1876                          ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]);
# Line 1740 | Line 1880 | void video_set_palette(uint8 *pal, int n
1880                  LOCK_VOSF;
1881                  PFLAG_SET_ALL;
1882                  UNLOCK_VOSF;
1883 <                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
1883 >                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
1884          }
1885   #endif
1886  
1887          // Tell redraw thread to change palette
1888 <        palette_changed = true;
1888 >        x_palette_changed = true;
1889  
1890          UNLOCK_PALETTE;
1891   }
# Line 1755 | Line 1895 | void video_set_palette(uint8 *pal, int n
1895   *  Switch video mode
1896   */
1897  
1898 < void video_switch_to_mode(const video_mode &mode)
1898 > void X11_monitor_desc::switch_to_current_mode(void)
1899   {
1900          // Close and reopen display
1901          video_close();
1902 <        video_open(mode);
1902 >        video_open();
1903  
1904          if (drv == NULL) {
1905                  ErrorAlert(STR_OPEN_WINDOW_ERR);
# Line 1938 | Line 2078 | static int event2keycode(XKeyEvent &ev,
2078  
2079   static void handle_events(void)
2080   {
2081 <        while (XPending(x_display)) {
2081 >        for (;;) {
2082                  XEvent event;
2083 <                XNextEvent(x_display, &event);
2083 >                XDisplayLock();
2084  
2085 +                if (!XCheckMaskEvent(x_display, eventmask, &event)) {
2086 +                        // Handle clipboard events
2087 +                        if (XCheckTypedEvent(x_display, SelectionRequest, &event))
2088 +                                ClipboardSelectionRequest(&event.xselectionrequest);
2089 +                        else if (XCheckTypedEvent(x_display, SelectionClear, &event))
2090 +                                ClipboardSelectionClear(&event.xselectionclear);
2091 +
2092 +                        // Window "close" widget clicked
2093 +                        else if (XCheckTypedEvent(x_display, ClientMessage, &event)) {
2094 +                                if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) {
2095 +                                        ADBKeyDown(0x7f);       // Power key
2096 +                                        ADBKeyUp(0x7f);
2097 +                                }
2098 +                        }
2099 +                        XDisplayUnlock();
2100 +                        break;
2101 +                }
2102 +                
2103                  switch (event.type) {
2104 +
2105                          // Mouse button
2106                          case ButtonPress: {
2107                                  unsigned int button = event.xbutton.button;
# Line 1975 | Line 2134 | static void handle_events(void)
2134                                  drv->mouse_moved(event.xmotion.x, event.xmotion.y);
2135                                  break;
2136  
2137 +                        // Mouse entered window
2138 +                        case EnterNotify:
2139 +                                if (event.xcrossing.mode != NotifyGrab && event.xcrossing.mode != NotifyUngrab)
2140 +                                        drv->mouse_moved(event.xmotion.x, event.xmotion.y);
2141 +                                break;
2142 +
2143                          // Keyboard
2144                          case KeyPress: {
2145                                  int code = -1;
# Line 2022 | Line 2187 | static void handle_events(void)
2187                          // Hidden parts exposed, force complete refresh of window
2188                          case Expose:
2189                                  if (display_type == DISPLAY_WINDOW) {
2190 +                                        const video_mode &mode = VideoMonitors[0]->get_current_mode();
2191   #ifdef ENABLE_VOSF
2192                                          if (use_vosf) {                 // VOSF refresh
2193                                                  LOCK_VOSF;
2194                                                  PFLAG_SET_ALL;
2195                                                  UNLOCK_VOSF;
2196 <                                                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
2196 >                                                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
2197                                          }
2198                                          else
2199   #endif
# Line 2038 | Line 2204 | static void handle_events(void)
2204                                                          updt_box[x1][y1] = true;
2205                                                  nr_boxes = 16 * 16;
2206                                          } else                                  // Static refresh
2207 <                                                memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y);
2042 <                                }
2043 <                                break;
2044 <
2045 <                        // Window "close" widget clicked
2046 <                        case ClientMessage:
2047 <                                if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) {
2048 <                                        ADBKeyDown(0x7f);       // Power key
2049 <                                        ADBKeyUp(0x7f);
2207 >                                                memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
2208                                  }
2209                                  break;
2210                  }
2211 +
2212 +                XDisplayUnlock();
2213          }
2214   }
2215  
# Line 2064 | Line 2224 | static void update_display_dynamic(int t
2224          int y1, y2, y2s, y2a, i, x1, xm, xmo, ymo, yo, yi, yil, xi;
2225          int xil = 0;
2226          int rxm = 0, rxmo = 0;
2227 <        int bytes_per_row = VideoMonitor.mode.bytes_per_row;
2228 <        int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x;
2229 <        int rx = VideoMonitor.mode.bytes_per_row / 16;
2230 <        int ry = VideoMonitor.mode.y / 16;
2227 >        const video_mode &mode = drv->monitor.get_current_mode();
2228 >        int bytes_per_row = mode.bytes_per_row;
2229 >        int bytes_per_pixel = mode.bytes_per_row / mode.x;
2230 >        int rx = mode.bytes_per_row / 16;
2231 >        int ry = mode.y / 16;
2232          int max_box;
2233  
2234          y2s = sm_uptd[ticker % 8];
# Line 2093 | Line 2254 | static void update_display_dynamic(int t
2254                  }
2255          }
2256  
2257 +        XDisplayLock();
2258          if ((nr_boxes <= max_box) && (nr_boxes)) {
2259                  for (y1=0; y1<16; y1++) {
2260                          for (x1=0; x1<16; x1++) {
# Line 2121 | Line 2283 | static void update_display_dynamic(int t
2283                                          i = (yi * bytes_per_row) + xi;
2284                                          for (y2=0; y2 < yil; y2++, i += bytes_per_row)
2285                                                  memcpy(&the_buffer_copy[i], &the_buffer[i], xil);
2286 <                                        if (VideoMonitor.mode.depth == VDEPTH_1BIT) {
2286 >                                        if (mode.depth == VDEPTH_1BIT) {
2287                                                  if (drv->have_shm)
2288                                                          XShmPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil, 0);
2289                                                  else
# Line 2146 | Line 2308 | static void update_display_dynamic(int t
2308                  }
2309                  nr_boxes = 0;
2310          }
2311 +        XDisplayUnlock();
2312   }
2313  
2314   // Static display update (fixed frame rate, but incremental)
2315   static void update_display_static(driver_window *drv)
2316   {
2317          // Incremental update code
2318 <        int wide = 0, high = 0, x1, x2, y1, y2, i, j;
2319 <        int bytes_per_row = VideoMonitor.mode.bytes_per_row;
2320 <        int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x;
2318 >        unsigned wide = 0, high = 0, x1, x2, y1, y2, i, j;
2319 >        const video_mode &mode = drv->monitor.get_current_mode();
2320 >        int bytes_per_row = mode.bytes_per_row;
2321 >        int bytes_per_pixel = mode.bytes_per_row / mode.x;
2322          uint8 *p, *p2;
2323  
2324          // Check for first line from top and first line from bottom that have changed
2325          y1 = 0;
2326 <        for (j=0; j<VideoMonitor.mode.y; j++) {
2326 >        for (j=0; j<mode.y; j++) {
2327                  if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
2328                          y1 = j;
2329                          break;
2330                  }
2331          }
2332          y2 = y1 - 1;
2333 <        for (j=VideoMonitor.mode.y-1; j>=y1; j--) {
2333 >        for (j=mode.y-1; j>=y1; j--) {
2334                  if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
2335                          y2 = j;
2336                          break;
# Line 2176 | Line 2340 | static void update_display_static(driver
2340  
2341          // Check for first column from left and first column from right that have changed
2342          if (high) {
2343 <                if (VideoMonitor.mode.depth == VDEPTH_1BIT) {
2344 <                        x1 = VideoMonitor.mode.x - 1;
2343 >                if (mode.depth == VDEPTH_1BIT) {
2344 >                        x1 = mode.x - 1;
2345                          for (j=y1; j<=y2; j++) {
2346                                  p = &the_buffer[j * bytes_per_row];
2347                                  p2 = &the_buffer_copy[j * bytes_per_row];
# Line 2195 | Line 2359 | static void update_display_static(driver
2359                                  p2 = &the_buffer_copy[j * bytes_per_row];
2360                                  p += bytes_per_row;
2361                                  p2 += bytes_per_row;
2362 <                                for (i=(VideoMonitor.mode.x>>3); i>(x2>>3); i--) {
2362 >                                for (i=(mode.x>>3); i>(x2>>3); i--) {
2363                                          p--; p2--;
2364                                          if (*p != *p2) {
2365                                                  x2 = (i << 3) + 7;
# Line 2214 | Line 2378 | static void update_display_static(driver
2378                          }
2379  
2380                  } else {
2381 <                        x1 = VideoMonitor.mode.x;
2381 >                        x1 = mode.x;
2382                          for (j=y1; j<=y2; j++) {
2383                                  p = &the_buffer[j * bytes_per_row];
2384                                  p2 = &the_buffer_copy[j * bytes_per_row];
# Line 2232 | Line 2396 | static void update_display_static(driver
2396                                  p2 = &the_buffer_copy[j * bytes_per_row];
2397                                  p += bytes_per_row;
2398                                  p2 += bytes_per_row;
2399 <                                for (i=VideoMonitor.mode.x*bytes_per_pixel; i>x2*bytes_per_pixel; i--) {
2399 >                                for (i=mode.x*bytes_per_pixel; i>x2*bytes_per_pixel; i--) {
2400                                          p--;
2401                                          p2--;
2402                                          if (*p != *p2) {
# Line 2254 | Line 2418 | static void update_display_static(driver
2418          }
2419  
2420          // Refresh display
2421 +        XDisplayLock();
2422          if (high && wide) {
2423                  if (drv->have_shm)
2424                          XShmPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high, 0);
2425                  else
2426                          XPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high);
2427          }
2428 +        XDisplayUnlock();
2429   }
2430  
2431  
# Line 2299 | Line 2465 | static inline void handle_palette_change
2465   {
2466          LOCK_PALETTE;
2467  
2468 <        if (palette_changed) {
2469 <                palette_changed = false;
2468 >        if (x_palette_changed) {
2469 >                x_palette_changed = false;
2470 >                XDisplayLock();
2471                  drv->update_palette();
2472 +                XDisplayUnlock();
2473          }
2474  
2475          UNLOCK_PALETTE;
# Line 2311 | Line 2479 | static void video_refresh_dga(void)
2479   {
2480          // Quit DGA mode if requested
2481          possibly_quit_dga_mode();
2314        
2315        // Handle X events
2316        handle_events();
2317        
2318        // Handle palette changes
2319        handle_palette_changes();
2482   }
2483  
2484   #ifdef ENABLE_VOSF
# Line 2326 | Line 2488 | static void video_refresh_dga_vosf(void)
2488          // Quit DGA mode if requested
2489          possibly_quit_dga_mode();
2490          
2329        // Handle X events
2330        handle_events();
2331        
2332        // Handle palette changes
2333        handle_palette_changes();
2334        
2491          // Update display (VOSF variant)
2492          static int tick_counter = 0;
2493          if (++tick_counter >= frame_skip) {
2494                  tick_counter = 0;
2495                  if (mainBuffer.dirty) {
2496                          LOCK_VOSF;
2497 <                        update_display_dga_vosf();
2497 >                        update_display_dga_vosf(static_cast<driver_dga *>(drv));
2498                          UNLOCK_VOSF;
2499                  }
2500          }
# Line 2350 | Line 2506 | static void video_refresh_window_vosf(vo
2506          // Ungrab mouse if requested
2507          possibly_ungrab_mouse();
2508          
2353        // Handle X events
2354        handle_events();
2355        
2356        // Handle palette changes
2357        handle_palette_changes();
2358        
2509          // Update display (VOSF variant)
2510          static int tick_counter = 0;
2511          if (++tick_counter >= frame_skip) {
2512                  tick_counter = 0;
2513                  if (mainBuffer.dirty) {
2514 +                        XDisplayLock();
2515                          LOCK_VOSF;
2516                          update_display_window_vosf(static_cast<driver_window *>(drv));
2517                          UNLOCK_VOSF;
2518                          XSync(x_display, false); // Let the server catch up
2519 +                        XDisplayUnlock();
2520                  }
2521          }
2522   }
# Line 2375 | Line 2527 | static void video_refresh_window_static(
2527          // Ungrab mouse if requested
2528          possibly_ungrab_mouse();
2529  
2378        // Handle X events
2379        handle_events();
2380        
2381        // Handle_palette changes
2382        handle_palette_changes();
2383        
2530          // Update display (static variant)
2531          static int tick_counter = 0;
2532          if (++tick_counter >= frame_skip) {
# Line 2394 | Line 2540 | static void video_refresh_window_dynamic
2540          // Ungrab mouse if requested
2541          possibly_ungrab_mouse();
2542  
2397        // Handle X events
2398        handle_events();
2399        
2400        // Handle_palette changes
2401        handle_palette_changes();
2402        
2543          // Update display (dynamic variant)
2544          static int tick_counter = 0;
2545          tick_counter++;
# Line 2435 | Line 2575 | static void VideoRefreshInit(void)
2575          }
2576   }
2577  
2578 + // This function is called on non-threaded platforms from a timer interrupt
2579   void VideoRefresh(void)
2580   {
2581          // We need to check redraw_thread_active to inhibit refreshed during
2582          // mode changes on non-threaded platforms
2583 <        if (redraw_thread_active)
2584 <                video_refresh();
2583 >        if (!redraw_thread_active)
2584 >                return;
2585 >
2586 >        // Handle X events
2587 >        handle_events();
2588 >
2589 >        // Handle palette changes
2590 >        handle_palette_changes();
2591 >
2592 >        // Update display
2593 >        video_refresh();
2594   }
2595  
2596 < #ifdef HAVE_PTHREADS
2596 > const int VIDEO_REFRESH_HZ = 60;
2597 > const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
2598 >
2599 > #ifdef USE_PTHREADS_SERVICES
2600   static void *redraw_func(void *arg)
2601   {
2602 +        int fd = ConnectionNumber(x_display);
2603 +
2604          uint64 start = GetTicks_usec();
2605          int64 ticks = 0;
2606 <        uint64 next = GetTicks_usec();
2606 >        uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY;
2607 >
2608          while (!redraw_thread_cancel) {
2609 <                video_refresh();
2454 <                next += 16667;
2609 >
2610                  int64 delay = next - GetTicks_usec();
2611 <                if (delay > 0)
2612 <                        Delay_usec(delay);
2613 <                else if (delay < -16667)
2611 >                if (delay < -VIDEO_REFRESH_DELAY) {
2612 >
2613 >                        // We are lagging far behind, so we reset the delay mechanism
2614                          next = GetTicks_usec();
2615 <                ticks++;
2615 >
2616 >                } else if (delay <= 0) {
2617 >
2618 >                        // Delay expired, refresh display
2619 >                        handle_events();
2620 >                        handle_palette_changes();
2621 >                        video_refresh();
2622 >                        next += VIDEO_REFRESH_DELAY;
2623 >                        ticks++;
2624 >
2625 >                } else {
2626 >
2627 >                        // No display refresh pending, check for X events
2628 >                        fd_set readfds;
2629 >                        FD_ZERO(&readfds);
2630 >                        FD_SET(fd, &readfds);
2631 >                        struct timeval timeout;
2632 >                        timeout.tv_sec = 0;
2633 >                        timeout.tv_usec = delay;
2634 >                        if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
2635 >                                handle_events();
2636 >                }
2637          }
2638 +
2639          uint64 end = GetTicks_usec();
2640 <        // printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, ticks * 1000000 / (end - start));
2640 >        D(bug("%lld refreshes in %lld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
2641 >
2642 >        redraw_thread_cancel_ack = true;
2643          return NULL;
2644   }
2645   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines