ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/video_x.cpp
Revision: 1.5
Committed: 2003-11-20T16:24:57Z (20 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +6 -2 lines
Log Message:
fix shm screen image allocation.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video_x.cpp - Video/graphics emulation, X11 specific stuff
3     *
4     * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <X11/Xlib.h>
22     #include <X11/Xutil.h>
23     #include <X11/keysym.h>
24     #include <X11/extensions/XShm.h>
25     #include <sys/ipc.h>
26     #include <sys/shm.h>
27     #include <pthread.h>
28    
29     #include "sysdeps.h"
30     #include "main.h"
31     #include "adb.h"
32     #include "prefs.h"
33     #include "user_strings.h"
34     #include "about_window.h"
35     #include "video.h"
36     #include "video_defs.h"
37    
38     #define DEBUG 0
39     #include "debug.h"
40    
41     #ifdef ENABLE_XF86_DGA
42     #include <X11/extensions/xf86dga.h>
43     #endif
44    
45     #ifdef ENABLE_XF86_VIDMODE
46     #include <X11/extensions/xf86vmode.h>
47     #endif
48    
49    
50     // Global variables
51     static int32 frame_skip;
52     static bool redraw_thread_active = false; // Flag: Redraw thread installed
53     static pthread_t redraw_thread; // Redraw thread
54    
55 gbeauche 1.4 static bool local_X11; // Flag: X server running on local machine?
56 cebix 1.1 static volatile bool thread_stop_req = false;
57     static volatile bool thread_stop_ack = false; // Acknowledge for thread_stop_req
58    
59     static bool has_dga = false; // Flag: Video DGA capable
60     static bool has_vidmode = false; // Flag: VidMode extension available
61    
62 gbeauche 1.3 #ifdef ENABLE_VOSF
63     static bool use_vosf = true; // Flag: VOSF enabled
64     #else
65     static const bool use_vosf = false; // VOSF not possible
66     #endif
67    
68 cebix 1.1 static bool palette_changed = false; // Flag: Palette changed, redraw thread must update palette
69     static bool ctrl_down = false; // Flag: Ctrl key pressed
70     static bool quit_full_screen = false; // Flag: DGA close requested from redraw thread
71     static volatile bool quit_full_screen_ack = false; // Acknowledge for quit_full_screen
72     static bool emerg_quit = false; // Flag: Ctrl-Esc pressed, emergency quit requested from MacOS thread
73    
74     static bool emul_suspended = false; // Flag: emulator suspended
75     static Window suspend_win; // "Suspend" window
76     static void *fb_save = NULL; // Saved frame buffer for suspend
77    
78     // X11 variables
79     static int screen; // Screen number
80     static int xdepth; // Depth of X screen
81     static int depth; // Depth of Mac frame buffer
82     static Window rootwin, the_win; // Root window and our window
83     static XVisualInfo visualInfo;
84     static Visual *vis;
85     static Colormap cmap[2]; // Two colormaps (DGA) for 8-bit mode
86     static XColor black, white;
87     static unsigned long black_pixel, white_pixel;
88     static int eventmask;
89     static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask;
90     static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
91    
92     // Variables for window mode
93     static GC the_gc;
94     static XImage *img = NULL;
95     static XShmSegmentInfo shminfo;
96     static XImage *cursor_image, *cursor_mask_image;
97     static Pixmap cursor_map, cursor_mask_map;
98     static Cursor mac_cursor;
99     static GC cursor_gc, cursor_mask_gc;
100     static bool cursor_changed = false; // Flag: Cursor changed, window_func must update cursor
101     static bool have_shm = false; // Flag: SHM present and usable
102 gbeauche 1.3 static uint8 *the_buffer = NULL; // Pointer to Mac frame buffer
103 cebix 1.1 static uint8 *the_buffer_copy = NULL; // Copy of Mac frame buffer
104 gbeauche 1.3 static uint32 the_buffer_size; // Size of allocated the_buffer
105 cebix 1.1
106     // Variables for DGA mode
107     static char *dga_screen_base;
108     static int dga_fb_width;
109     static int current_dga_cmap;
110    
111     #ifdef ENABLE_XF86_VIDMODE
112     // Variables for XF86 VidMode support
113     static XF86VidModeModeInfo **x_video_modes; // Array of all available modes
114     static int num_x_video_modes;
115     #endif
116    
117    
118     // Prototypes
119     static void *redraw_func(void *arg);
120    
121    
122 gbeauche 1.4 // From main_unix.cpp
123     extern char *x_display_name;
124 cebix 1.1 extern Display *x_display;
125    
126     // From sys_unix.cpp
127     extern void SysMountFirstFloppy(void);
128    
129    
130 gbeauche 1.3 // Video acceleration through SIGSEGV
131     #ifdef ENABLE_VOSF
132     # include "video_vosf.h"
133     #endif
134    
135    
136 cebix 1.1 /*
137     * Open display (window or fullscreen)
138     */
139    
140     // Trap SHM errors
141     static bool shm_error = false;
142     static int (*old_error_handler)(Display *, XErrorEvent *);
143    
144     static int error_handler(Display *d, XErrorEvent *e)
145     {
146     if (e->error_code == BadAccess) {
147     shm_error = true;
148     return 0;
149     } else
150     return old_error_handler(d, e);
151     }
152    
153     // Open window
154     static bool open_window(int width, int height)
155     {
156 gbeauche 1.3 int aligned_width = (width + 15) & ~15;
157     int aligned_height = (height + 15) & ~15;
158    
159 cebix 1.1 // Set absolute mouse mode
160     ADBSetRelMouseMode(false);
161    
162     // Read frame skip prefs
163     frame_skip = PrefsFindInt32("frameskip");
164     if (frame_skip == 0)
165     frame_skip = 1;
166    
167     // Create window
168     XSetWindowAttributes wattr;
169     wattr.event_mask = eventmask = win_eventmask;
170     wattr.background_pixel = black_pixel;
171     wattr.border_pixel = black_pixel;
172     wattr.backing_store = NotUseful;
173    
174     XSync(x_display, false);
175     the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
176     InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWBackingStore, &wattr);
177     XSync(x_display, false);
178     XStoreName(x_display, the_win, GetString(STR_WINDOW_TITLE));
179     XMapRaised(x_display, the_win);
180     XSync(x_display, false);
181    
182     // Set colormap
183     if (depth == 8) {
184     XSetWindowColormap(x_display, the_win, cmap[0]);
185     XSetWMColormapWindows(x_display, the_win, &the_win, 1);
186     }
187    
188     // Make window unresizable
189     XSizeHints *hints;
190     if ((hints = XAllocSizeHints()) != NULL) {
191     hints->min_width = width;
192     hints->max_width = width;
193     hints->min_height = height;
194     hints->max_height = height;
195     hints->flags = PMinSize | PMaxSize;
196     XSetWMNormalHints(x_display, the_win, hints);
197     XFree((char *)hints);
198     }
199    
200 gbeauche 1.5 // 1-bit mode is big-endian; if the X server is little-endian, we can't
201     // use SHM because that doesn't allow changing the image byte order
202     bool need_msb_image = (depth == 1 && XImageByteOrder(x_display) == LSBFirst);
203    
204 cebix 1.1 // Try to create and attach SHM image
205     have_shm = false;
206 gbeauche 1.5 if (local_X11 && !need_msb_image && XShmQueryExtension(x_display)) {
207 cebix 1.1
208     // Create SHM image ("height + 2" for safety)
209 gbeauche 1.5 img = XShmCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
210 cebix 1.1 shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
211 gbeauche 1.3 the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
212     shminfo.shmaddr = img->data = (char *)the_buffer_copy;
213 cebix 1.1 shminfo.readOnly = False;
214    
215     // Try to attach SHM image, catching errors
216     shm_error = false;
217     old_error_handler = XSetErrorHandler(error_handler);
218     XShmAttach(x_display, &shminfo);
219     XSync(x_display, false);
220     XSetErrorHandler(old_error_handler);
221     if (shm_error) {
222     shmdt(shminfo.shmaddr);
223     XDestroyImage(img);
224     shminfo.shmid = -1;
225     } else {
226     have_shm = true;
227     shmctl(shminfo.shmid, IPC_RMID, 0);
228     }
229     }
230    
231     // Create normal X image if SHM doesn't work ("height + 2" for safety)
232     if (!have_shm) {
233 gbeauche 1.3 int bytes_per_row = aligned_width;
234 cebix 1.1 switch (depth) {
235     case 1:
236     bytes_per_row /= 8;
237     break;
238     case 15:
239     case 16:
240     bytes_per_row *= 2;
241     break;
242     case 24:
243     case 32:
244     bytes_per_row *= 4;
245     break;
246     }
247 gbeauche 1.3 the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
248     img = XCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row);
249 cebix 1.1 }
250    
251     // 1-Bit mode is big-endian
252     if (depth == 1) {
253     img->byte_order = MSBFirst;
254     img->bitmap_bit_order = MSBFirst;
255     }
256    
257 gbeauche 1.3 #ifdef ENABLE_VOSF
258     use_vosf = true;
259     // Allocate memory for frame buffer (SIZE is extended to page-boundary)
260     the_host_buffer = the_buffer_copy;
261     the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
262     the_buffer = (uint8 *)vm_acquire(the_buffer_size);
263     the_buffer_copy = (uint8 *)malloc(the_buffer_size);
264     D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
265     #else
266     // Allocate memory for frame buffer
267     the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
268     D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
269     #endif
270     screen_base = (uint32)the_buffer;
271 cebix 1.1
272     // Create GC
273     the_gc = XCreateGC(x_display, the_win, 0, 0);
274     XSetForeground(x_display, the_gc, black_pixel);
275    
276     // Create cursor
277     cursor_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 4, 16, 16, 16, 2);
278     cursor_image->byte_order = MSBFirst;
279     cursor_image->bitmap_bit_order = MSBFirst;
280     cursor_mask_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 36, 16, 16, 16, 2);
281     cursor_mask_image->byte_order = MSBFirst;
282     cursor_mask_image->bitmap_bit_order = MSBFirst;
283     cursor_map = XCreatePixmap(x_display, the_win, 16, 16, 1);
284     cursor_mask_map = XCreatePixmap(x_display, the_win, 16, 16, 1);
285     cursor_gc = XCreateGC(x_display, cursor_map, 0, 0);
286     cursor_mask_gc = XCreateGC(x_display, cursor_mask_map, 0, 0);
287     mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0);
288     cursor_changed = false;
289    
290 gbeauche 1.3 // Init blitting routines
291     bool native_byte_order;
292     #ifdef WORDS_BIGENDIAN
293     native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
294     #else
295     native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
296     #endif
297     #ifdef ENABLE_VOSF
298     Screen_blitter_init(&visualInfo, native_byte_order, depth);
299     #endif
300    
301 cebix 1.1 // Set bytes per row
302     VModes[cur_mode].viRowBytes = img->bytes_per_line;
303     XSync(x_display, false);
304     return true;
305     }
306    
307     // Open DGA display (!! should use X11 VidMode extensions to set mode)
308     static bool open_dga(int width, int height)
309     {
310     #ifdef ENABLE_XF86_DGA
311     // Set relative mouse mode
312     ADBSetRelMouseMode(true);
313    
314     #ifdef ENABLE_XF86_VIDMODE
315     // Switch to best mode
316     if (has_vidmode) {
317     int best = 0;
318     for (int i=1; i<num_x_video_modes; i++) {
319     if (x_video_modes[i]->hdisplay >= width && x_video_modes[i]->vdisplay >= height &&
320     x_video_modes[i]->hdisplay <= x_video_modes[best]->hdisplay && x_video_modes[i]->vdisplay <= x_video_modes[best]->vdisplay) {
321     best = i;
322     }
323     }
324     XF86VidModeSwitchToMode(x_display, screen, x_video_modes[best]);
325     XF86VidModeSetViewPort(x_display, screen, 0, 0);
326     }
327     #endif
328    
329     // Establish direct screen connection
330     XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
331     XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
332     XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
333     XF86DGASetViewPort(x_display, screen, 0, 0);
334     XF86DGASetVidPage(x_display, screen, 0);
335    
336     // Set colormap
337     if (depth == 8)
338     XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
339    
340     // Set bytes per row
341     int bytes_per_row = (dga_fb_width + 7) & ~7;
342     switch (depth) {
343     case 15:
344     case 16:
345     bytes_per_row *= 2;
346     break;
347     case 24:
348     case 32:
349     bytes_per_row *= 4;
350     break;
351     }
352 gbeauche 1.3
353     #if ENABLE_VOSF
354     bool native_byte_order;
355     #ifdef WORDS_BIGENDIAN
356     native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
357     #else
358     native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
359     #endif
360     #if REAL_ADDRESSING || DIRECT_ADDRESSING
361     // Screen_blitter_init() returns TRUE if VOSF is mandatory
362     // i.e. the framebuffer update function is not Blit_Copy_Raw
363     use_vosf = Screen_blitter_init(&visualInfo, native_byte_order, depth);
364    
365     if (use_vosf) {
366     // Allocate memory for frame buffer (SIZE is extended to page-boundary)
367     the_host_buffer = the_buffer;
368     the_buffer_size = page_extend((height + 2) * bytes_per_row);
369     the_buffer_copy = (uint8 *)malloc(the_buffer_size);
370     the_buffer = (uint8 *)vm_acquire(the_buffer_size);
371     }
372     #else
373     use_vosf = false;
374     the_buffer = dga_screen_base;
375     #endif
376     #endif
377     screen_base = (uint32)the_buffer;
378    
379 cebix 1.1 VModes[cur_mode].viRowBytes = bytes_per_row;
380     XSync(x_display, false);
381     return true;
382     #else
383     ErrorAlert("SheepShaver has been compiled with DGA support disabled.");
384     return false;
385     #endif
386     }
387    
388     static bool open_display(void)
389     {
390     display_type = VModes[cur_mode].viType;
391     switch (VModes[cur_mode].viAppleMode) {
392     case APPLE_1_BIT:
393     depth = 1;
394     break;
395     case APPLE_2_BIT:
396     depth = 2;
397     break;
398     case APPLE_4_BIT:
399     depth = 4;
400     break;
401     case APPLE_8_BIT:
402     depth = 8;
403     break;
404     case APPLE_16_BIT:
405 gbeauche 1.2 depth = xdepth == 15 ? 15 : 16;
406 cebix 1.1 break;
407     case APPLE_32_BIT:
408     depth = 32;
409     break;
410     }
411 gbeauche 1.3
412     bool display_open = false;
413 cebix 1.1 if (display_type == DIS_SCREEN)
414 gbeauche 1.3 display_open = open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
415 cebix 1.1 else if (display_type == DIS_WINDOW)
416 gbeauche 1.3 display_open = open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
417    
418     #ifdef ENABLE_VOSF
419     if (use_vosf) {
420     // Initialize the VOSF system
421     if (!video_vosf_init()) {
422     ErrorAlert(GetString(STR_VOSF_INIT_ERR));
423     return false;
424     }
425     }
426     #endif
427    
428     return display_open;
429 cebix 1.1 }
430    
431    
432     /*
433     * Close display
434     */
435    
436     // Close window
437     static void close_window(void)
438     {
439 gbeauche 1.3 if (have_shm) {
440     XShmDetach(x_display, &shminfo);
441     #ifdef ENABLE_VOSF
442     the_host_buffer = NULL; // don't free() in driver_base dtor
443     #else
444     the_buffer_copy = NULL; // don't free() in driver_base dtor
445     #endif
446     }
447     if (img) {
448     if (!have_shm)
449     img->data = NULL;
450     XDestroyImage(img);
451     }
452     if (have_shm) {
453     shmdt(shminfo.shmaddr);
454     shmctl(shminfo.shmid, IPC_RMID, 0);
455     }
456     if (the_gc)
457     XFreeGC(x_display, the_gc);
458    
459 cebix 1.1 // Close window
460     XDestroyWindow(x_display, the_win);
461     }
462    
463     // Close DGA mode
464     static void close_dga(void)
465     {
466     #ifdef ENABLE_XF86_DGA
467     XF86DGADirectVideo(x_display, screen, 0);
468     XUngrabPointer(x_display, CurrentTime);
469     XUngrabKeyboard(x_display, CurrentTime);
470     #endif
471    
472     #ifdef ENABLE_XF86_VIDMODE
473     if (has_vidmode)
474     XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]);
475     #endif
476 gbeauche 1.3
477     if (!use_vosf) {
478     // don't free() the screen buffer in driver_base dtor
479     the_buffer = NULL;
480     }
481     #ifdef ENABLE_VOSF
482     else {
483     // don't free() the screen buffer in driver_base dtor
484     the_host_buffer = NULL;
485     }
486     #endif
487 cebix 1.1 }
488    
489     static void close_display(void)
490     {
491     if (display_type == DIS_SCREEN)
492     close_dga();
493     else if (display_type == DIS_WINDOW)
494     close_window();
495 gbeauche 1.3
496     #ifdef ENABLE_VOSF
497     if (use_vosf) {
498     // Deinitialize VOSF
499     video_vosf_exit();
500     }
501     #endif
502    
503     // Free frame buffer(s)
504     if (!use_vosf) {
505     if (the_buffer_copy) {
506     free(the_buffer_copy);
507     the_buffer_copy = NULL;
508     }
509     }
510     #ifdef ENABLE_VOSF
511     else {
512     // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will
513     if (the_buffer != VM_MAP_FAILED) {
514     D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
515     vm_release(the_buffer, the_buffer_size);
516     the_buffer = NULL;
517     }
518     if (the_host_buffer) {
519     D(bug(" freeing the_host_buffer at %p\n", the_host_buffer));
520     free(the_host_buffer);
521     the_host_buffer = NULL;
522     }
523     if (the_buffer_copy) {
524     D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
525     free(the_buffer_copy);
526     the_buffer_copy = NULL;
527     }
528     }
529     #endif
530 cebix 1.1 }
531    
532    
533     /*
534     * Initialization
535     */
536    
537     static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type)
538     {
539     if (allow & test) {
540     p->viType = type;
541     switch (apple_id) {
542     case APPLE_W_640x480:
543     case APPLE_640x480:
544     p->viXsize = 640;
545     p->viYsize = 480;
546     break;
547     case APPLE_W_800x600:
548     case APPLE_800x600:
549     p->viXsize = 800;
550     p->viYsize = 600;
551     break;
552     case APPLE_1024x768:
553     p->viXsize = 1024;
554     p->viYsize = 768;
555     break;
556     case APPLE_1152x900:
557     p->viXsize = 1152;
558     p->viYsize = 900;
559     break;
560     case APPLE_1280x1024:
561     p->viXsize = 1280;
562     p->viYsize = 1024;
563     break;
564     case APPLE_1600x1200:
565     p->viXsize = 1600;
566     p->viYsize = 1200;
567     break;
568     }
569     switch (apple_mode) {
570     case APPLE_8_BIT:
571     p->viRowBytes = p->viXsize;
572     break;
573     case APPLE_16_BIT:
574     p->viRowBytes = p->viXsize * 2;
575     break;
576     case APPLE_32_BIT:
577     p->viRowBytes = p->viXsize * 4;
578     break;
579     }
580     p->viAppleMode = apple_mode;
581     p->viAppleID = apple_id;
582     p++;
583     }
584     }
585    
586     static bool has_mode(int x, int y)
587     {
588     #ifdef ENABLE_XF86_VIDMODE
589     for (int i=0; i<num_x_video_modes; i++)
590     if (x_video_modes[i]->hdisplay >= x && x_video_modes[i]->vdisplay >= y)
591     return true;
592     return false;
593     #else
594     return DisplayWidth(x_display, screen) >= x && DisplayHeight(x_display, screen) >= y;
595     #endif
596     }
597    
598     bool VideoInit(void)
599     {
600 gbeauche 1.3 #ifdef ENABLE_VOSF
601     // Zero the mainBuffer structure
602     mainBuffer.dirtyPages = NULL;
603     mainBuffer.pageInfo = NULL;
604     #endif
605    
606 gbeauche 1.4 // Check if X server runs on local machine
607     local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0)
608     || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0);
609    
610 cebix 1.1 // Init variables
611     private_data = NULL;
612     cur_mode = 0; // Window 640x480
613     video_activated = true;
614    
615     // Find screen and root window
616     screen = XDefaultScreen(x_display);
617     rootwin = XRootWindow(x_display, screen);
618    
619     // Get screen depth
620     xdepth = DefaultDepth(x_display, screen);
621    
622     #ifdef ENABLE_XF86_DGA
623     // DGA available?
624     int event_base, error_base;
625 gbeauche 1.4 if (local_X11 && XF86DGAQueryExtension(x_display, &event_base, &error_base)) {
626 cebix 1.1 int dga_flags = 0;
627     XF86DGAQueryDirectVideo(x_display, screen, &dga_flags);
628     has_dga = dga_flags & XF86DGADirectPresent;
629     } else
630     has_dga = false;
631     #endif
632    
633     #ifdef ENABLE_XF86_VIDMODE
634     // VidMode available?
635     int vm_event_base, vm_error_base;
636     has_vidmode = XF86VidModeQueryExtension(x_display, &vm_event_base, &vm_error_base);
637     if (has_vidmode)
638     XF86VidModeGetAllModeLines(x_display, screen, &num_x_video_modes, &x_video_modes);
639     #endif
640    
641     // Find black and white colors
642     XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:00/00/00", &black);
643     XAllocColor(x_display, DefaultColormap(x_display, screen), &black);
644     XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:ff/ff/ff", &white);
645     XAllocColor(x_display, DefaultColormap(x_display, screen), &white);
646     black_pixel = BlackPixel(x_display, screen);
647     white_pixel = WhitePixel(x_display, screen);
648    
649     // Get appropriate visual
650     int color_class;
651     switch (xdepth) {
652     #if 0
653     case 1:
654     color_class = StaticGray;
655     break;
656     #endif
657     case 8:
658     color_class = PseudoColor;
659     break;
660     case 15:
661     case 16:
662     case 24:
663     case 32:
664     color_class = TrueColor;
665     break;
666     default:
667     ErrorAlert(GetString(STR_UNSUPP_DEPTH_ERR));
668     return false;
669     }
670     if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) {
671     ErrorAlert(GetString(STR_NO_XVISUAL_ERR));
672     return false;
673     }
674     if (visualInfo.depth != xdepth) {
675     ErrorAlert(GetString(STR_NO_XVISUAL_ERR));
676     return false;
677     }
678     vis = visualInfo.visual;
679    
680     // Mac screen depth follows X depth (for now)
681     depth = xdepth;
682    
683     // Create color maps for 8 bit mode
684     if (depth == 8) {
685     cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
686     cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll);
687     XInstallColormap(x_display, cmap[0]);
688     XInstallColormap(x_display, cmap[1]);
689     }
690    
691     // Construct video mode table
692     int mode = APPLE_8_BIT;
693     int bpr_mult = 8;
694     switch (depth) {
695     case 1:
696     mode = APPLE_1_BIT;
697     bpr_mult = 1;
698     break;
699     case 8:
700     mode = APPLE_8_BIT;
701     bpr_mult = 8;
702     break;
703     case 15:
704     case 16:
705     mode = APPLE_16_BIT;
706     bpr_mult = 16;
707     break;
708     case 24:
709     case 32:
710     mode = APPLE_32_BIT;
711     bpr_mult = 32;
712     break;
713     }
714    
715     uint32 window_modes = PrefsFindInt32("windowmodes");
716     uint32 screen_modes = PrefsFindInt32("screenmodes");
717     if (!has_dga)
718     screen_modes = 0;
719     if (window_modes == 0 && screen_modes == 0)
720     window_modes |= 3; // Allow at least 640x480 and 800x600 window modes
721    
722     VideoInfo *p = VModes;
723     add_mode(p, window_modes, 1, mode, APPLE_W_640x480, DIS_WINDOW);
724     add_mode(p, window_modes, 2, mode, APPLE_W_800x600, DIS_WINDOW);
725     if (has_vidmode) {
726     if (has_mode(640, 480))
727     add_mode(p, screen_modes, 1, mode, APPLE_640x480, DIS_SCREEN);
728     if (has_mode(800, 600))
729     add_mode(p, screen_modes, 2, mode, APPLE_800x600, DIS_SCREEN);
730     if (has_mode(1024, 768))
731     add_mode(p, screen_modes, 4, mode, APPLE_1024x768, DIS_SCREEN);
732     if (has_mode(1152, 900))
733     add_mode(p, screen_modes, 8, mode, APPLE_1152x900, DIS_SCREEN);
734     if (has_mode(1280, 1024))
735     add_mode(p, screen_modes, 16, mode, APPLE_1280x1024, DIS_SCREEN);
736     if (has_mode(1600, 1200))
737     add_mode(p, screen_modes, 32, mode, APPLE_1600x1200, DIS_SCREEN);
738     } else if (screen_modes) {
739     int xsize = DisplayWidth(x_display, screen);
740     int ysize = DisplayHeight(x_display, screen);
741     int apple_id;
742     if (xsize < 800)
743     apple_id = APPLE_640x480;
744     else if (xsize < 1024)
745     apple_id = APPLE_800x600;
746     else if (xsize < 1152)
747     apple_id = APPLE_1024x768;
748     else if (xsize < 1280)
749     apple_id = APPLE_1152x900;
750     else if (xsize < 1600)
751     apple_id = APPLE_1280x1024;
752     else
753     apple_id = APPLE_1600x1200;
754     p->viType = DIS_SCREEN;
755     p->viRowBytes = 0;
756     p->viXsize = xsize;
757     p->viYsize = ysize;
758     p->viAppleMode = mode;
759     p->viAppleID = apple_id;
760     p++;
761     }
762     p->viType = DIS_INVALID; // End marker
763     p->viRowBytes = 0;
764     p->viXsize = p->viYsize = 0;
765     p->viAppleMode = 0;
766     p->viAppleID = 0;
767    
768     #ifdef ENABLE_XF86_DGA
769     if (has_dga && screen_modes) {
770     int v_bank, v_size;
771     XF86DGAGetVideo(x_display, screen, &dga_screen_base, &dga_fb_width, &v_bank, &v_size);
772     D(bug("DGA screen_base %p, v_width %d\n", dga_screen_base, dga_fb_width));
773     }
774     #endif
775    
776     // Open window/screen
777     if (!open_display())
778     return false;
779    
780     #if 0
781     // Ignore errors from now on
782     XSetErrorHandler(ignore_errors);
783     #endif
784    
785     // Start periodic thread
786     XSync(x_display, false);
787     redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0);
788     D(bug("Redraw thread installed (%ld)\n", redraw_thread));
789     return true;
790     }
791    
792    
793     /*
794     * Deinitialization
795     */
796    
797     void VideoExit(void)
798     {
799     // Stop redraw thread
800     if (redraw_thread_active) {
801     pthread_cancel(redraw_thread);
802     pthread_join(redraw_thread, NULL);
803     redraw_thread_active = false;
804     }
805    
806 gbeauche 1.3 #ifdef ENABLE_VOSF
807     if (use_vosf) {
808     // Deinitialize VOSF
809     video_vosf_exit();
810     }
811     #endif
812    
813 cebix 1.1 // Close window and server connection
814     if (x_display != NULL) {
815     XSync(x_display, false);
816     close_display();
817     XFlush(x_display);
818     XSync(x_display, false);
819     if (depth == 8) {
820     XFreeColormap(x_display, cmap[0]);
821     XFreeColormap(x_display, cmap[1]);
822     }
823     }
824     }
825    
826    
827     /*
828     * Suspend/resume emulator
829     */
830    
831     extern void PauseEmulator(void);
832     extern void ResumeEmulator(void);
833    
834     static void suspend_emul(void)
835     {
836     if (display_type == DIS_SCREEN) {
837     // Release ctrl key
838     ADBKeyUp(0x36);
839     ctrl_down = false;
840    
841     // Pause MacOS thread
842     PauseEmulator();
843     emul_suspended = true;
844    
845     // Save frame buffer
846     fb_save = malloc(VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes);
847     if (fb_save)
848     memcpy(fb_save, (void *)screen_base, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes);
849    
850     // Close full screen display
851     #ifdef ENABLE_XF86_DGA
852     XF86DGADirectVideo(x_display, screen, 0);
853     XUngrabPointer(x_display, CurrentTime);
854     XUngrabKeyboard(x_display, CurrentTime);
855     #endif
856     XSync(x_display, false);
857    
858     // Open "suspend" window
859     XSetWindowAttributes wattr;
860     wattr.event_mask = KeyPressMask;
861     wattr.background_pixel = black_pixel;
862     wattr.border_pixel = black_pixel;
863     wattr.backing_store = Always;
864     wattr.backing_planes = xdepth;
865     wattr.colormap = DefaultColormap(x_display, screen);
866     XSync(x_display, false);
867     suspend_win = XCreateWindow(x_display, rootwin, 0, 0, 512, 1, 0, xdepth,
868     InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel |
869     CWBackingStore | CWBackingPlanes | (xdepth == 8 ? CWColormap : 0), &wattr);
870     XSync(x_display, false);
871     XStoreName(x_display, suspend_win, GetString(STR_SUSPEND_WINDOW_TITLE));
872     XMapRaised(x_display, suspend_win);
873     XSync(x_display, false);
874     }
875     }
876    
877     static void resume_emul(void)
878     {
879     // Close "suspend" window
880     XDestroyWindow(x_display, suspend_win);
881     XSync(x_display, false);
882    
883     // Reopen full screen display
884     XGrabKeyboard(x_display, rootwin, 1, GrabModeAsync, GrabModeAsync, CurrentTime);
885     XGrabPointer(x_display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
886     XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
887     XF86DGASetViewPort(x_display, screen, 0, 0);
888     XSync(x_display, false);
889    
890 gbeauche 1.3 // the_buffer already contains the data to restore. i.e. since a temporary
891     // frame buffer is used when VOSF is actually used, fb_save is therefore
892     // not necessary.
893     #ifdef ENABLE_VOSF
894     if (use_vosf) {
895     LOCK_VOSF;
896     PFLAG_SET_ALL;
897     UNLOCK_VOSF;
898     memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
899     }
900     #endif
901    
902 cebix 1.1 // Restore frame buffer
903     if (fb_save) {
904 gbeauche 1.3 #ifdef ENABLE_VOSF
905     // Don't copy fb_save to the temporary frame buffer in VOSF mode
906     if (!use_vosf)
907     #endif
908 cebix 1.1 memcpy((void *)screen_base, fb_save, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes);
909     free(fb_save);
910     fb_save = NULL;
911     }
912     if (depth == 8)
913     palette_changed = true;
914    
915     // Resume MacOS thread
916     emul_suspended = false;
917     ResumeEmulator();
918     }
919    
920    
921     /*
922     * Close screen in full-screen mode
923     */
924    
925     void VideoQuitFullScreen(void)
926     {
927     D(bug("VideoQuitFullScreen()\n"));
928     if (display_type == DIS_SCREEN) {
929     quit_full_screen = true;
930     while (!quit_full_screen_ack) ;
931     }
932     }
933    
934    
935     /*
936     * X11 event handling
937     */
938    
939     // Translate key event to Mac keycode
940     static int kc_decode(KeySym ks)
941     {
942     switch (ks) {
943     case XK_A: case XK_a: return 0x00;
944     case XK_B: case XK_b: return 0x0b;
945     case XK_C: case XK_c: return 0x08;
946     case XK_D: case XK_d: return 0x02;
947     case XK_E: case XK_e: return 0x0e;
948     case XK_F: case XK_f: return 0x03;
949     case XK_G: case XK_g: return 0x05;
950     case XK_H: case XK_h: return 0x04;
951     case XK_I: case XK_i: return 0x22;
952     case XK_J: case XK_j: return 0x26;
953     case XK_K: case XK_k: return 0x28;
954     case XK_L: case XK_l: return 0x25;
955     case XK_M: case XK_m: return 0x2e;
956     case XK_N: case XK_n: return 0x2d;
957     case XK_O: case XK_o: return 0x1f;
958     case XK_P: case XK_p: return 0x23;
959     case XK_Q: case XK_q: return 0x0c;
960     case XK_R: case XK_r: return 0x0f;
961     case XK_S: case XK_s: return 0x01;
962     case XK_T: case XK_t: return 0x11;
963     case XK_U: case XK_u: return 0x20;
964     case XK_V: case XK_v: return 0x09;
965     case XK_W: case XK_w: return 0x0d;
966     case XK_X: case XK_x: return 0x07;
967     case XK_Y: case XK_y: return 0x10;
968     case XK_Z: case XK_z: return 0x06;
969    
970     case XK_1: case XK_exclam: return 0x12;
971     case XK_2: case XK_at: return 0x13;
972     case XK_3: case XK_numbersign: return 0x14;
973     case XK_4: case XK_dollar: return 0x15;
974     case XK_5: case XK_percent: return 0x17;
975     case XK_6: return 0x16;
976     case XK_7: return 0x1a;
977     case XK_8: return 0x1c;
978     case XK_9: return 0x19;
979     case XK_0: return 0x1d;
980    
981     case XK_grave: case XK_asciitilde: return 0x0a;
982     case XK_minus: case XK_underscore: return 0x1b;
983     case XK_equal: case XK_plus: return 0x18;
984     case XK_bracketleft: case XK_braceleft: return 0x21;
985     case XK_bracketright: case XK_braceright: return 0x1e;
986     case XK_backslash: case XK_bar: return 0x2a;
987     case XK_semicolon: case XK_colon: return 0x29;
988     case XK_apostrophe: case XK_quotedbl: return 0x27;
989     case XK_comma: case XK_less: return 0x2b;
990     case XK_period: case XK_greater: return 0x2f;
991     case XK_slash: case XK_question: return 0x2c;
992    
993     case XK_Tab: if (ctrl_down) {suspend_emul(); return -1;} else return 0x30;
994     case XK_Return: return 0x24;
995     case XK_space: return 0x31;
996     case XK_BackSpace: return 0x33;
997    
998     case XK_Delete: return 0x75;
999     case XK_Insert: return 0x72;
1000     case XK_Home: case XK_Help: return 0x73;
1001     case XK_End: return 0x77;
1002     #ifdef __hpux
1003     case XK_Prior: return 0x74;
1004     case XK_Next: return 0x79;
1005     #else
1006     case XK_Page_Up: return 0x74;
1007     case XK_Page_Down: return 0x79;
1008     #endif
1009    
1010     case XK_Control_L: return 0x36;
1011     case XK_Control_R: return 0x36;
1012     case XK_Shift_L: return 0x38;
1013     case XK_Shift_R: return 0x38;
1014     case XK_Alt_L: return 0x37;
1015     case XK_Alt_R: return 0x37;
1016     case XK_Meta_L: return 0x3a;
1017     case XK_Meta_R: return 0x3a;
1018     case XK_Menu: return 0x32;
1019     case XK_Caps_Lock: return 0x39;
1020     case XK_Num_Lock: return 0x47;
1021    
1022     case XK_Up: return 0x3e;
1023     case XK_Down: return 0x3d;
1024     case XK_Left: return 0x3b;
1025     case XK_Right: return 0x3c;
1026    
1027     case XK_Escape: if (ctrl_down) {quit_full_screen = true; emerg_quit = true; return -1;} else return 0x35;
1028    
1029     case XK_F1: if (ctrl_down) {SysMountFirstFloppy(); return -1;} else return 0x7a;
1030     case XK_F2: return 0x78;
1031     case XK_F3: return 0x63;
1032     case XK_F4: return 0x76;
1033     case XK_F5: return 0x60;
1034     case XK_F6: return 0x61;
1035     case XK_F7: return 0x62;
1036     case XK_F8: return 0x64;
1037     case XK_F9: return 0x65;
1038     case XK_F10: return 0x6d;
1039     case XK_F11: return 0x67;
1040     case XK_F12: return 0x6f;
1041    
1042     case XK_Print: return 0x69;
1043     case XK_Scroll_Lock: return 0x6b;
1044     case XK_Pause: return 0x71;
1045    
1046     #if defined(XK_KP_Prior) && defined(XK_KP_Left) && defined(XK_KP_Insert) && defined (XK_KP_End)
1047     case XK_KP_0: case XK_KP_Insert: return 0x52;
1048     case XK_KP_1: case XK_KP_End: return 0x53;
1049     case XK_KP_2: case XK_KP_Down: return 0x54;
1050     case XK_KP_3: case XK_KP_Next: return 0x55;
1051     case XK_KP_4: case XK_KP_Left: return 0x56;
1052     case XK_KP_5: case XK_KP_Begin: return 0x57;
1053     case XK_KP_6: case XK_KP_Right: return 0x58;
1054     case XK_KP_7: case XK_KP_Home: return 0x59;
1055     case XK_KP_8: case XK_KP_Up: return 0x5b;
1056     case XK_KP_9: case XK_KP_Prior: return 0x5c;
1057     case XK_KP_Decimal: case XK_KP_Delete: return 0x41;
1058     #else
1059     case XK_KP_0: return 0x52;
1060     case XK_KP_1: return 0x53;
1061     case XK_KP_2: return 0x54;
1062     case XK_KP_3: return 0x55;
1063     case XK_KP_4: return 0x56;
1064     case XK_KP_5: return 0x57;
1065     case XK_KP_6: return 0x58;
1066     case XK_KP_7: return 0x59;
1067     case XK_KP_8: return 0x5b;
1068     case XK_KP_9: return 0x5c;
1069     case XK_KP_Decimal: return 0x41;
1070     #endif
1071     case XK_KP_Add: return 0x45;
1072     case XK_KP_Subtract: return 0x4e;
1073     case XK_KP_Multiply: return 0x43;
1074     case XK_KP_Divide: return 0x4b;
1075     case XK_KP_Enter: return 0x4c;
1076     case XK_KP_Equal: return 0x51;
1077     }
1078     return -1;
1079     }
1080    
1081     static int event2keycode(XKeyEvent *ev)
1082     {
1083     KeySym ks;
1084     int as;
1085     int i = 0;
1086    
1087     do {
1088     ks = XLookupKeysym(ev, i++);
1089     as = kc_decode(ks);
1090     if (as != -1)
1091     return as;
1092     } while (ks != NoSymbol);
1093    
1094     return -1;
1095     }
1096    
1097     static void handle_events(void)
1098     {
1099     // Handle events
1100     for (;;) {
1101     XEvent event;
1102    
1103     if (!XCheckMaskEvent(x_display, eventmask, &event))
1104     break;
1105    
1106     switch (event.type) {
1107     // Mouse button
1108     case ButtonPress: {
1109     unsigned int button = ((XButtonEvent *)&event)->button;
1110     if (button < 4)
1111     ADBMouseDown(button - 1);
1112     break;
1113     }
1114     case ButtonRelease: {
1115     unsigned int button = ((XButtonEvent *)&event)->button;
1116     if (button < 4)
1117     ADBMouseUp(button - 1);
1118     break;
1119     }
1120    
1121     // Mouse moved
1122     case EnterNotify:
1123     ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
1124     break;
1125     case MotionNotify:
1126     ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
1127     break;
1128    
1129     // Keyboard
1130     case KeyPress: {
1131     int code;
1132     if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1133     if (!emul_suspended) {
1134     ADBKeyDown(code);
1135     if (code == 0x36)
1136     ctrl_down = true;
1137     } else {
1138     if (code == 0x31)
1139     resume_emul(); // Space wakes us up
1140     }
1141     }
1142     break;
1143     }
1144     case KeyRelease: {
1145     int code;
1146     if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1147     ADBKeyUp(code);
1148     if (code == 0x36)
1149     ctrl_down = false;
1150     }
1151     break;
1152     }
1153    
1154     // Hidden parts exposed, force complete refresh
1155     case Expose:
1156 gbeauche 1.3 #ifdef ENABLE_VOSF
1157     if (use_vosf) { // VOSF refresh
1158     LOCK_VOSF;
1159     PFLAG_SET_ALL;
1160     UNLOCK_VOSF;
1161     }
1162     #endif
1163 cebix 1.1 memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
1164     break;
1165     }
1166     }
1167     }
1168    
1169    
1170     /*
1171     * Execute video VBL routine
1172     */
1173    
1174     void VideoVBL(void)
1175     {
1176     if (emerg_quit)
1177     QuitEmulator();
1178    
1179     // Execute video VBL
1180     if (private_data != NULL && private_data->interruptsEnabled)
1181     VSLDoInterruptService(private_data->vslServiceID);
1182     }
1183    
1184    
1185     /*
1186     * Install graphics acceleration
1187     */
1188    
1189     #if 0
1190     // Rectangle blitting
1191     static void accl_bitblt(accl_params *p)
1192     {
1193     D(bug("accl_bitblt\n"));
1194    
1195     // Get blitting parameters
1196     int16 src_X = p->src_rect[1] - p->src_bounds[1];
1197     int16 src_Y = p->src_rect[0] - p->src_bounds[0];
1198     int16 dest_X = p->dest_rect[1] - p->dest_bounds[1];
1199     int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0];
1200     int16 width = p->dest_rect[3] - p->dest_rect[1] - 1;
1201     int16 height = p->dest_rect[2] - p->dest_rect[0] - 1;
1202     D(bug(" src X %d, src Y %d, dest X %d, dest Y %d\n", src_X, src_Y, dest_X, dest_Y));
1203     D(bug(" width %d, height %d\n", width, height));
1204    
1205     // And perform the blit
1206     bitblt_hook(src_X, src_Y, dest_X, dest_Y, width, height);
1207     }
1208    
1209     static bool accl_bitblt_hook(accl_params *p)
1210     {
1211     D(bug("accl_draw_hook %p\n", p));
1212    
1213     // Check if we can accelerate this bitblt
1214     if (p->src_base_addr == screen_base && p->dest_base_addr == screen_base &&
1215     display_type == DIS_SCREEN && bitblt_hook != NULL &&
1216     ((uint32 *)p)[0x18 >> 2] + ((uint32 *)p)[0x128 >> 2] == 0 &&
1217     ((uint32 *)p)[0x130 >> 2] == 0 &&
1218     p->transfer_mode == 0 &&
1219     p->src_row_bytes > 0 && ((uint32 *)p)[0x15c >> 2] > 0) {
1220    
1221     // Yes, set function pointer
1222     p->draw_proc = accl_bitblt;
1223     return true;
1224     }
1225     return false;
1226     }
1227    
1228     // Rectangle filling/inversion
1229     static void accl_fillrect8(accl_params *p)
1230     {
1231     D(bug("accl_fillrect8\n"));
1232    
1233     // Get filling parameters
1234     int16 dest_X = p->dest_rect[1] - p->dest_bounds[1];
1235     int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0];
1236     int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1;
1237     int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1;
1238     uint8 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen;
1239     D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y));
1240     D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max));
1241    
1242     // And perform the fill
1243     fillrect8_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color);
1244     }
1245    
1246     static void accl_fillrect32(accl_params *p)
1247     {
1248     D(bug("accl_fillrect32\n"));
1249    
1250     // Get filling parameters
1251     int16 dest_X = p->dest_rect[1] - p->dest_bounds[1];
1252     int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0];
1253     int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1;
1254     int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1;
1255     uint32 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen;
1256     D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y));
1257     D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max));
1258    
1259     // And perform the fill
1260     fillrect32_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color);
1261     }
1262    
1263     static void accl_invrect(accl_params *p)
1264     {
1265     D(bug("accl_invrect\n"));
1266    
1267     // Get inversion parameters
1268     int16 dest_X = p->dest_rect[1] - p->dest_bounds[1];
1269     int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0];
1270     int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1;
1271     int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1;
1272     D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y));
1273     D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max));
1274    
1275     //!!?? pen_mode == 14
1276    
1277     // And perform the inversion
1278     invrect_hook(dest_X, dest_Y, dest_X_max, dest_Y_max);
1279     }
1280    
1281     static bool accl_fillrect_hook(accl_params *p)
1282     {
1283     D(bug("accl_fillrect_hook %p\n", p));
1284    
1285     // Check if we can accelerate this fillrect
1286     if (p->dest_base_addr == screen_base && ((uint32 *)p)[0x284 >> 2] != 0 && display_type == DIS_SCREEN) {
1287     if (p->transfer_mode == 8) {
1288     // Fill
1289     if (p->dest_pixel_size == 8 && fillrect8_hook != NULL) {
1290     p->draw_proc = accl_fillrect8;
1291     return true;
1292     } else if (p->dest_pixel_size == 32 && fillrect32_hook != NULL) {
1293     p->draw_proc = accl_fillrect32;
1294     return true;
1295     }
1296     } else if (p->transfer_mode == 10 && invrect_hook != NULL) {
1297     // Invert
1298     p->draw_proc = accl_invrect;
1299     return true;
1300     }
1301     }
1302     return false;
1303     }
1304    
1305     // Wait for graphics operation to finish
1306     static bool accl_sync_hook(void *arg)
1307     {
1308     D(bug("accl_sync_hook %p\n", arg));
1309     if (sync_hook != NULL)
1310     sync_hook();
1311     return true;
1312     }
1313    
1314     static struct accl_hook_info bitblt_hook_info = {accl_bitblt_hook, accl_sync_hook, ACCL_BITBLT};
1315     static struct accl_hook_info fillrect_hook_info = {accl_fillrect_hook, accl_sync_hook, ACCL_FILLRECT};
1316     #endif
1317    
1318     void VideoInstallAccel(void)
1319     {
1320     // Install acceleration hooks
1321     if (PrefsFindBool("gfxaccel")) {
1322     D(bug("Video: Installing acceleration hooks\n"));
1323     //!! NQDMisc(6, &bitblt_hook_info);
1324     // NQDMisc(6, &fillrect_hook_info);
1325     }
1326     }
1327    
1328    
1329     /*
1330     * Change video mode
1331     */
1332    
1333     int16 video_mode_change(VidLocals *csSave, uint32 ParamPtr)
1334     {
1335     /* return if no mode change */
1336     if ((csSave->saveData == ReadMacInt32(ParamPtr + csData)) &&
1337     (csSave->saveMode == ReadMacInt16(ParamPtr + csMode))) return noErr;
1338    
1339     /* first find video mode in table */
1340     for (int i=0; VModes[i].viType != DIS_INVALID; i++) {
1341     if ((ReadMacInt16(ParamPtr + csMode) == VModes[i].viAppleMode) &&
1342     (ReadMacInt32(ParamPtr + csData) == VModes[i].viAppleID)) {
1343     csSave->saveMode = ReadMacInt16(ParamPtr + csMode);
1344     csSave->saveData = ReadMacInt32(ParamPtr + csData);
1345     csSave->savePage = ReadMacInt16(ParamPtr + csPage);
1346    
1347     // Disable interrupts and pause redraw thread
1348     DisableInterrupt();
1349     thread_stop_ack = false;
1350     thread_stop_req = true;
1351     while (!thread_stop_ack) ;
1352    
1353     /* close old display */
1354     close_display();
1355    
1356     /* open new display */
1357     cur_mode = i;
1358     bool ok = open_display();
1359    
1360     /* opening the screen failed? Then bail out */
1361     if (!ok) {
1362     ErrorAlert(GetString(STR_FULL_SCREEN_ERR));
1363     QuitEmulator();
1364     }
1365    
1366     WriteMacInt32(ParamPtr + csBaseAddr, screen_base);
1367     csSave->saveBaseAddr=screen_base;
1368     csSave->saveData=VModes[cur_mode].viAppleID;/* First mode ... */
1369     csSave->saveMode=VModes[cur_mode].viAppleMode;
1370    
1371     // Enable interrupts and resume redraw thread
1372     thread_stop_req = false;
1373     EnableInterrupt();
1374     return noErr;
1375     }
1376     }
1377     return paramErr;
1378     }
1379    
1380    
1381     /*
1382     * Set color palette
1383     */
1384    
1385     void video_set_palette(void)
1386     {
1387     palette_changed = true;
1388     }
1389    
1390    
1391     /*
1392     * Set cursor image for window
1393     */
1394    
1395     void video_set_cursor(void)
1396     {
1397     cursor_changed = true;
1398     }
1399    
1400    
1401     /*
1402     * Thread for window refresh, event handling and other periodic actions
1403     */
1404    
1405     static void update_display(void)
1406     {
1407     // Incremental update code
1408     int wide = 0, high = 0, x1, x2, y1, y2, i, j;
1409     int bytes_per_row = VModes[cur_mode].viRowBytes;
1410     int bytes_per_pixel = VModes[cur_mode].viRowBytes / VModes[cur_mode].viXsize;
1411     uint8 *p, *p2;
1412    
1413     // Check for first line from top and first line from bottom that have changed
1414     y1 = 0;
1415     for (j=0; j<VModes[cur_mode].viYsize; j++) {
1416     if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
1417     y1 = j;
1418     break;
1419     }
1420     }
1421     y2 = y1 - 1;
1422     for (j=VModes[cur_mode].viYsize-1; j>=y1; j--) {
1423     if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
1424     y2 = j;
1425     break;
1426     }
1427     }
1428     high = y2 - y1 + 1;
1429    
1430     // Check for first column from left and first column from right that have changed
1431     if (high) {
1432     if (depth == 1) {
1433     x1 = VModes[cur_mode].viXsize;
1434     for (j=y1; j<=y2; j++) {
1435     p = &the_buffer[j * bytes_per_row];
1436     p2 = &the_buffer_copy[j * bytes_per_row];
1437     for (i=0; i<(x1>>3); i++) {
1438     if (*p != *p2) {
1439     x1 = i << 3;
1440     break;
1441     }
1442     p++;
1443     p2++;
1444     }
1445     }
1446     x2 = x1;
1447     for (j=y1; j<=y2; j++) {
1448     p = &the_buffer[j * bytes_per_row];
1449     p2 = &the_buffer_copy[j * bytes_per_row];
1450     p += bytes_per_row;
1451     p2 += bytes_per_row;
1452     for (i=(VModes[cur_mode].viXsize>>3); i>(x2>>3); i--) {
1453     p--;
1454     p2--;
1455     if (*p != *p2) {
1456     x2 = i << 3;
1457     break;
1458     }
1459     }
1460     }
1461     wide = x2 - x1;
1462    
1463     // Update copy of the_buffer
1464     if (high && wide) {
1465     for (j=y1; j<=y2; j++) {
1466     i = j * bytes_per_row + (x1 >> 3);
1467     memcpy(&the_buffer_copy[i], &the_buffer[i], wide >> 3);
1468     }
1469     }
1470    
1471     } else {
1472     x1 = VModes[cur_mode].viXsize;
1473     for (j=y1; j<=y2; j++) {
1474     p = &the_buffer[j * bytes_per_row];
1475     p2 = &the_buffer_copy[j * bytes_per_row];
1476     for (i=0; i<x1; i++) {
1477     if (memcmp(p, p2, bytes_per_pixel)) {
1478     x1 = i;
1479     break;
1480     }
1481     p += bytes_per_pixel;
1482     p2 += bytes_per_pixel;
1483     }
1484     }
1485     x2 = x1;
1486     for (j=y1; j<=y2; j++) {
1487     p = &the_buffer[j * bytes_per_row];
1488     p2 = &the_buffer_copy[j * bytes_per_row];
1489     p += bytes_per_row;
1490     p2 += bytes_per_row;
1491     for (i=VModes[cur_mode].viXsize; i>x2; i--) {
1492     p -= bytes_per_pixel;
1493     p2 -= bytes_per_pixel;
1494     if (memcmp(p, p2, bytes_per_pixel)) {
1495     x2 = i;
1496     break;
1497     }
1498     }
1499     }
1500     wide = x2 - x1;
1501    
1502     // Update copy of the_buffer
1503     if (high && wide) {
1504     for (j=y1; j<=y2; j++) {
1505     i = j * bytes_per_row + x1 * bytes_per_pixel;
1506     memcpy(&the_buffer_copy[i], &the_buffer[i], bytes_per_pixel * wide);
1507     }
1508     }
1509     }
1510     }
1511    
1512     // Refresh display
1513     if (high && wide) {
1514     if (have_shm)
1515     XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high, 0);
1516     else
1517     XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high);
1518     }
1519     }
1520    
1521     static void *redraw_func(void *arg)
1522     {
1523     int tick_counter = 0;
1524     struct timespec req = {0, 16666667};
1525    
1526     for (;;) {
1527    
1528     // Wait
1529     nanosleep(&req, NULL);
1530    
1531     // Pause if requested (during video mode switches)
1532     while (thread_stop_req)
1533     thread_stop_ack = true;
1534    
1535     // Handle X11 events
1536     handle_events();
1537    
1538     // Quit DGA mode if requested
1539     if (quit_full_screen) {
1540     quit_full_screen = false;
1541     if (display_type == DIS_SCREEN) {
1542     #ifdef ENABLE_XF86_DGA
1543     XF86DGADirectVideo(x_display, screen, 0);
1544     XUngrabPointer(x_display, CurrentTime);
1545     XUngrabKeyboard(x_display, CurrentTime);
1546     #endif
1547     XSync(x_display, false);
1548     quit_full_screen_ack = true;
1549     return NULL;
1550     }
1551     }
1552    
1553     // Refresh display and set cursor image in window mode
1554     if (display_type == DIS_WINDOW) {
1555     tick_counter++;
1556     if (tick_counter >= frame_skip) {
1557     tick_counter = 0;
1558    
1559     // Update display
1560 gbeauche 1.3 #ifdef ENABLE_VOSF
1561     if (use_vosf) {
1562     if (mainBuffer.dirty) {
1563     LOCK_VOSF;
1564     update_display_window_vosf();
1565     UNLOCK_VOSF;
1566     XSync(x_display, false); // Let the server catch up
1567     }
1568     }
1569     else
1570     #endif
1571     update_display();
1572 cebix 1.1
1573     // Set new cursor image if it was changed
1574     if (cursor_changed) {
1575     cursor_changed = false;
1576     memcpy(cursor_image->data, MacCursor + 4, 32);
1577     memcpy(cursor_mask_image->data, MacCursor + 36, 32);
1578     XFreeCursor(x_display, mac_cursor);
1579     XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);
1580     XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16);
1581     mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]);
1582     XDefineCursor(x_display, the_win, mac_cursor);
1583     }
1584     }
1585     }
1586 gbeauche 1.3 #ifdef ENABLE_VOSF
1587     else if (use_vosf) {
1588     // Update display (VOSF variant)
1589     static int tick_counter = 0;
1590     if (++tick_counter >= frame_skip) {
1591     tick_counter = 0;
1592     if (mainBuffer.dirty) {
1593     LOCK_VOSF;
1594     update_display_dga_vosf();
1595     UNLOCK_VOSF;
1596     }
1597     }
1598     }
1599     #endif
1600 cebix 1.1
1601     // Set new palette if it was changed
1602     if (palette_changed && !emul_suspended) {
1603     palette_changed = false;
1604     XColor c[256];
1605     for (int i=0; i<256; i++) {
1606     c[i].pixel = i;
1607     c[i].red = mac_pal[i].red * 0x0101;
1608     c[i].green = mac_pal[i].green * 0x0101;
1609     c[i].blue = mac_pal[i].blue * 0x0101;
1610     c[i].flags = DoRed | DoGreen | DoBlue;
1611     }
1612     if (depth == 8) {
1613     XStoreColors(x_display, cmap[0], c, 256);
1614     XStoreColors(x_display, cmap[1], c, 256);
1615     #ifdef ENABLE_XF86_DGA
1616     if (display_type == DIS_SCREEN) {
1617     current_dga_cmap ^= 1;
1618     XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1619     }
1620     #endif
1621     }
1622     }
1623     }
1624     return NULL;
1625     }