ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/video_x.cpp
Revision: 1.9
Committed: 2003-12-31T11:37:26Z (20 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.8: +15 -2 lines
Log Message:
Handle copy-paste between X11 and MacOS. X11 events handling code has to
be improved in copy mode (when we own the selection to service other clients).
Also note that older klipper has a tendency to request clipboard data
several times per second.

File Contents

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