ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/video_x.cpp
(Generate patch)

Comparing SheepShaver/src/Unix/video_x.cpp (file contents):
Revision 1.5 by gbeauche, 2003-11-20T16:24:57Z vs.
Revision 1.10 by gbeauche, 2003-12-31T18:16:55Z

# Line 1 | Line 1
1   /*
2   *  video_x.cpp - Video/graphics emulation, X11 specific stuff
3   *
4 < *  SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer
4 > *  SheepShaver (C) 1997-2003 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
# Line 18 | Line 18
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   */
20  
21 + #include "sysdeps.h"
22 +
23   #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 + #include <errno.h>
30   #include <pthread.h>
31  
32 < #include "sysdeps.h"
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 >
40   #include "main.h"
41   #include "adb.h"
42   #include "prefs.h"
# Line 38 | Line 48
48   #define DEBUG 0
49   #include "debug.h"
50  
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
51  
52 + // Constants
53 + const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes";
54  
55   // Global variables
56   static int32 frame_skip;
57 + static int16 mouse_wheel_mode;
58 + static int16 mouse_wheel_lines;
59   static bool redraw_thread_active = false;       // Flag: Redraw thread installed
60   static pthread_t redraw_thread;                         // Redraw thread
61  
# Line 74 | Line 81 | static bool emerg_quit = false;                                // Fl
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 + static bool use_keycodes = false;                       // Flag: Use keycodes rather than keysyms
85 + static int keycode_table[256];                          // X keycode -> Mac keycode translation table
86  
87   // X11 variables
88   static int screen;                                                      // Screen number
# Line 126 | Line 135 | extern Display *x_display;
135   // From sys_unix.cpp
136   extern void SysMountFirstFloppy(void);
137  
138 + // From clip_unix.cpp
139 + extern void ClipboardSelectionClear(XSelectionClearEvent *);
140 + extern void ClipboardSelectionRequest(XSelectionRequestEvent *);
141 +
142  
143   // Video acceleration through SIGSEGV
144   #ifdef ENABLE_VOSF
# Line 159 | Line 172 | static bool open_window(int width, int h
172          // Set absolute mouse mode
173          ADBSetRelMouseMode(false);
174  
162        // Read frame skip prefs
163        frame_skip = PrefsFindInt32("frameskip");
164        if (frame_skip == 0)
165                frame_skip = 1;
166
175          // Create window
176          XSetWindowAttributes wattr;
177          wattr.event_mask = eventmask = win_eventmask;
# Line 534 | Line 542 | static void close_display(void)
542   *  Initialization
543   */
544  
545 + // Init keycode translation table
546 + static void keycode_init(void)
547 + {
548 +        bool use_kc = PrefsFindBool("keycodes");
549 +        if (use_kc) {
550 +
551 +                // Get keycode file path from preferences
552 +                const char *kc_path = PrefsFindString("keycodefile");
553 +
554 +                // Open keycode table
555 +                FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r");
556 +                if (f == NULL) {
557 +                        char str[256];
558 +                        sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno));
559 +                        WarningAlert(str);
560 +                        return;
561 +                }
562 +
563 +                // Default translation table
564 +                for (int i=0; i<256; i++)
565 +                        keycode_table[i] = -1;
566 +
567 +                // Search for server vendor string, then read keycodes
568 +                const char *vendor = ServerVendor(x_display);
569 +                bool vendor_found = false;
570 +                char line[256];
571 +                while (fgets(line, 255, f)) {
572 +                        // Read line
573 +                        int len = strlen(line);
574 +                        if (len == 0)
575 +                                continue;
576 +                        line[len-1] = 0;
577 +
578 +                        // Comments begin with "#" or ";"
579 +                        if (line[0] == '#' || line[0] == ';' || line[0] == 0)
580 +                                continue;
581 +
582 +                        if (vendor_found) {
583 +                                // Read keycode
584 +                                int x_code, mac_code;
585 +                                if (sscanf(line, "%d %d", &x_code, &mac_code) == 2)
586 +                                        keycode_table[x_code & 0xff] = mac_code;
587 +                                else
588 +                                        break;
589 +                        } else {
590 +                                // Search for vendor string
591 +                                if (strstr(vendor, line) == vendor)
592 +                                        vendor_found = true;
593 +                        }
594 +                }
595 +
596 +                // Keycode file completely read
597 +                fclose(f);
598 +                use_keycodes = vendor_found;
599 +
600 +                // Vendor not found? Then display warning
601 +                if (!vendor_found) {
602 +                        char str[256];
603 +                        sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), vendor, kc_path ? kc_path : KEYCODE_FILE_NAME);
604 +                        WarningAlert(str);
605 +                        return;
606 +                }
607 +        }
608 + }
609 +
610   static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type)
611   {
612          if (allow & test) {
# Line 607 | Line 680 | bool VideoInit(void)
680          local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0)
681                   || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0);
682      
683 +        // Init keycode translation
684 +        keycode_init();
685 +
686 +        // Read frame skip prefs
687 +        frame_skip = PrefsFindInt32("frameskip");
688 +        if (frame_skip == 0)
689 +                frame_skip = 1;
690 +
691 +        // Read mouse wheel prefs
692 +        mouse_wheel_mode = PrefsFindInt32("mousewheelmode");
693 +        mouse_wheel_lines = PrefsFindInt32("mousewheellines");
694 +
695          // Init variables
696          private_data = NULL;
697          cur_mode = 0;   // Window 640x480
# Line 1078 | Line 1163 | static int kc_decode(KeySym ks)
1163          return -1;
1164   }
1165  
1166 < static int event2keycode(XKeyEvent *ev)
1166 > static int event2keycode(XKeyEvent &ev)
1167   {
1168          KeySym ks;
1169          int as;
1170          int i = 0;
1171  
1172          do {
1173 <                ks = XLookupKeysym(ev, i++);
1173 >                ks = XLookupKeysym(&ev, i++);
1174                  as = kc_decode(ks);
1175                  if (as != -1)
1176                          return as;
# Line 1100 | Line 1185 | static void handle_events(void)
1185          for (;;) {
1186                  XEvent event;
1187  
1188 <                if (!XCheckMaskEvent(x_display, eventmask, &event))
1188 >                XDisplayLock();
1189 >                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 >
1196 >                        XDisplayUnlock();
1197                          break;
1198 +                }
1199 +                XDisplayUnlock();
1200  
1201                  switch (event.type) {
1202                          // Mouse button
# Line 1109 | Line 1204 | static void handle_events(void)
1204                                  unsigned int button = ((XButtonEvent *)&event)->button;
1205                                  if (button < 4)
1206                                          ADBMouseDown(button - 1);
1207 +                                else if (button < 6) {  // Wheel mouse
1208 +                                        if (mouse_wheel_mode == 0) {
1209 +                                                int key = (button == 5) ? 0x79 : 0x74;  // Page up/down
1210 +                                                ADBKeyDown(key);
1211 +                                                ADBKeyUp(key);
1212 +                                        } else {
1213 +                                                int key = (button == 5) ? 0x3d : 0x3e;  // Cursor up/down
1214 +                                                for(int i=0; i<mouse_wheel_lines; i++) {
1215 +                                                        ADBKeyDown(key);
1216 +                                                        ADBKeyUp(key);
1217 +                                                }
1218 +                                        }
1219 +                                }
1220                                  break;
1221                          }
1222                          case ButtonRelease: {
# Line 1128 | Line 1236 | static void handle_events(void)
1236  
1237                          // Keyboard
1238                          case KeyPress: {
1239 <                                int code;
1240 <                                if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1239 >                                int code = event2keycode(event.xkey);
1240 >                                if (use_keycodes && code != -1)
1241 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1242 >                                if (code != -1) {
1243                                          if (!emul_suspended) {
1244                                                  ADBKeyDown(code);
1245                                                  if (code == 0x36)
# Line 1142 | Line 1252 | static void handle_events(void)
1252                                  break;
1253                          }
1254                          case KeyRelease: {
1255 <                                int code;
1256 <                                if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1255 >                                int code = event2keycode(event.xkey);
1256 >                                if (use_keycodes && code != 1)
1257 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1258 >                                if (code != -1) {
1259                                          ADBKeyUp(code);
1260                                          if (code == 0x36)
1261                                                  ctrl_down = false;
# Line 1511 | Line 1623 | static void update_display(void)
1623  
1624          // Refresh display
1625          if (high && wide) {
1626 +                XDisplayLock();
1627                  if (have_shm)
1628                          XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high, 0);
1629                  else
1630                          XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high);
1631 +                XDisplayUnlock();
1632          }
1633   }
1634  
1635 + const int VIDEO_REFRESH_HZ = 60;
1636 + const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
1637 +
1638   static void *redraw_func(void *arg)
1639   {
1640 <        int tick_counter = 0;
1524 <        struct timespec req = {0, 16666667};
1640 >        int fd = ConnectionNumber(x_display);
1641  
1642 <        for (;;) {
1642 >        uint64 start = GetTicks_usec();
1643 >        int64 ticks = 0;
1644 >        uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY;
1645  
1646 <                // Wait
1529 <                nanosleep(&req, NULL);
1646 >        for (;;) {
1647  
1648                  // Pause if requested (during video mode switches)
1649                  while (thread_stop_req)
1650                          thread_stop_ack = true;
1651  
1652 <                // Handle X11 events
1653 <                handle_events();
1652 >                int64 delay = next - GetTicks_usec();
1653 >                if (delay < -VIDEO_REFRESH_DELAY) {
1654 >
1655 >                        // We are lagging far behind, so we reset the delay mechanism
1656 >                        next = GetTicks_usec();
1657 >
1658 >                } else if (delay <= 0) {
1659  
1660 <                // Quit DGA mode if requested
1661 <                if (quit_full_screen) {
1662 <                        quit_full_screen = false;
1663 <                        if (display_type == DIS_SCREEN) {
1660 >                        // Delay expired, refresh display
1661 >                        next += VIDEO_REFRESH_DELAY;
1662 >                        ticks++;
1663 >
1664 >                        // Handle X11 events
1665 >                        handle_events();
1666 >
1667 >                        // Quit DGA mode if requested
1668 >                        if (quit_full_screen) {
1669 >                                quit_full_screen = false;
1670 >                                if (display_type == DIS_SCREEN) {
1671 >                                        XDisplayLock();
1672   #ifdef ENABLE_XF86_DGA
1673 <                                XF86DGADirectVideo(x_display, screen, 0);
1674 <                                XUngrabPointer(x_display, CurrentTime);
1675 <                                XUngrabKeyboard(x_display, CurrentTime);
1676 < #endif
1677 <                                XSync(x_display, false);
1678 <                                quit_full_screen_ack = true;
1679 <                                return NULL;
1673 >                                        XF86DGADirectVideo(x_display, screen, 0);
1674 >                                        XUngrabPointer(x_display, CurrentTime);
1675 >                                        XUngrabKeyboard(x_display, CurrentTime);
1676 > #endif
1677 >                                        XSync(x_display, false);
1678 >                                        XDisplayUnlock();
1679 >                                        quit_full_screen_ack = true;
1680 >                                        return NULL;
1681 >                                }
1682                          }
1551                }
1683  
1684 <                // Refresh display and set cursor image in window mode
1685 <                if (display_type == DIS_WINDOW) {
1686 <                        tick_counter++;
1687 <                        if (tick_counter >= frame_skip) {
1688 <                                tick_counter = 0;
1684 >                        // Refresh display and set cursor image in window mode
1685 >                        static int tick_counter = 0;
1686 >                        if (display_type == DIS_WINDOW) {
1687 >                                tick_counter++;
1688 >                                if (tick_counter >= frame_skip) {
1689 >                                        tick_counter = 0;
1690  
1691 <                                // Update display
1691 >                                        // Update display
1692   #ifdef ENABLE_VOSF
1693 <                                if (use_vosf) {
1694 <                                        if (mainBuffer.dirty) {
1695 <                                                LOCK_VOSF;
1696 <                                                update_display_window_vosf();
1697 <                                                UNLOCK_VOSF;
1698 <                                                XSync(x_display, false); // Let the server catch up
1693 >                                        if (use_vosf) {
1694 >                                                XDisplayLock();
1695 >                                                if (mainBuffer.dirty) {
1696 >                                                        LOCK_VOSF;
1697 >                                                        update_display_window_vosf();
1698 >                                                        UNLOCK_VOSF;
1699 >                                                        XSync(x_display, false); // Let the server catch up
1700 >                                                }
1701 >                                                XDisplayUnlock();
1702                                          }
1703 <                                }
1569 <                                else
1703 >                                        else
1704   #endif
1705 <                                        update_display();
1705 >                                                update_display();
1706  
1707 <                                // Set new cursor image if it was changed
1708 <                                if (cursor_changed) {
1709 <                                        cursor_changed = false;
1710 <                                        memcpy(cursor_image->data, MacCursor + 4, 32);
1711 <                                        memcpy(cursor_mask_image->data, MacCursor + 36, 32);
1712 <                                        XFreeCursor(x_display, mac_cursor);
1713 <                                        XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);
1714 <                                        XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16);
1715 <                                        mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]);
1716 <                                        XDefineCursor(x_display, the_win, mac_cursor);
1707 >                                        // Set new cursor image if it was changed
1708 >                                        if (cursor_changed) {
1709 >                                                cursor_changed = false;
1710 >                                                memcpy(cursor_image->data, MacCursor + 4, 32);
1711 >                                                memcpy(cursor_mask_image->data, MacCursor + 36, 32);
1712 >                                                XDisplayLock();
1713 >                                                XFreeCursor(x_display, mac_cursor);
1714 >                                                XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);
1715 >                                                XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16);
1716 >                                                mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]);
1717 >                                                XDefineCursor(x_display, the_win, mac_cursor);
1718 >                                                XDisplayUnlock();
1719 >                                        }
1720                                  }
1721                          }
1585                }
1722   #ifdef ENABLE_VOSF
1723 <                else if (use_vosf) {
1724 <                        // Update display (VOSF variant)
1725 <                        static int tick_counter = 0;
1726 <                        if (++tick_counter >= frame_skip) {
1727 <                                tick_counter = 0;
1728 <                                if (mainBuffer.dirty) {
1729 <                                        LOCK_VOSF;
1730 <                                        update_display_dga_vosf();
1731 <                                        UNLOCK_VOSF;
1723 >                        else if (use_vosf) {
1724 >                                // Update display (VOSF variant)
1725 >                                if (++tick_counter >= frame_skip) {
1726 >                                        tick_counter = 0;
1727 >                                        if (mainBuffer.dirty) {
1728 >                                                LOCK_VOSF;
1729 >                                                update_display_dga_vosf();
1730 >                                                UNLOCK_VOSF;
1731 >                                        }
1732                                  }
1733                          }
1598                }
1734   #endif
1735  
1736 <                // Set new palette if it was changed
1737 <                if (palette_changed && !emul_suspended) {
1738 <                        palette_changed = false;
1739 <                        XColor c[256];
1740 <                        for (int i=0; i<256; i++) {
1741 <                                c[i].pixel = i;
1742 <                                c[i].red = mac_pal[i].red * 0x0101;
1743 <                                c[i].green = mac_pal[i].green * 0x0101;
1744 <                                c[i].blue = mac_pal[i].blue * 0x0101;
1745 <                                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]);
1736 >                        // Set new palette if it was changed
1737 >                        if (palette_changed && !emul_suspended) {
1738 >                                palette_changed = false;
1739 >                                XColor c[256];
1740 >                                for (int i=0; i<256; i++) {
1741 >                                        c[i].pixel = i;
1742 >                                        c[i].red = mac_pal[i].red * 0x0101;
1743 >                                        c[i].green = mac_pal[i].green * 0x0101;
1744 >                                        c[i].blue = mac_pal[i].blue * 0x0101;
1745 >                                        c[i].flags = DoRed | DoGreen | DoBlue;
1746                                  }
1747 +                                if (depth == 8) {
1748 +                                        XDisplayLock();
1749 +                                        XStoreColors(x_display, cmap[0], c, 256);
1750 +                                        XStoreColors(x_display, cmap[1], c, 256);
1751 + #ifdef ENABLE_XF86_DGA
1752 +                                        if (display_type == DIS_SCREEN) {
1753 +                                                current_dga_cmap ^= 1;
1754 +                                                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1755 +                                        }
1756   #endif
1757 +                                        XDisplayUnlock();
1758 +                                }
1759                          }
1760 +
1761 +                } else {
1762 +
1763 +                        // No display refresh pending, check for X events
1764 +                        fd_set readfds;
1765 +                        FD_ZERO(&readfds);
1766 +                        FD_SET(fd, &readfds);
1767 +                        struct timeval timeout;
1768 +                        timeout.tv_sec = 0;
1769 +                        timeout.tv_usec = delay;
1770 +                        if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
1771 +                                handle_events();
1772                  }
1773          }
1774          return NULL;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines