aboutsummaryrefslogtreecommitdiffstats
path: root/tools/ioemu/gui/x.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ioemu/gui/x.cc')
-rw-r--r--tools/ioemu/gui/x.cc1848
1 files changed, 1848 insertions, 0 deletions
diff --git a/tools/ioemu/gui/x.cc b/tools/ioemu/gui/x.cc
new file mode 100644
index 0000000000..5d1cae917a
--- /dev/null
+++ b/tools/ioemu/gui/x.cc
@@ -0,0 +1,1848 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: x.cc,v 1.76 2003/08/11 19:27:57 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#define XK_PUBLISHING
+#define XK_TECHNICAL
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins. For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_WITH_X11
+
+extern "C" {
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#if BX_HAVE_XPM_H
+#include <X11/xpm.h>
+#endif
+}
+
+#if BX_HAVE_XPM_H
+#include "icon_bochs.xpm"
+#else
+#include "icon_bochs.h"
+#endif
+
+#include "font/vga.bitmap.h"
+
+class bx_x_gui_c : public bx_gui_c {
+public:
+ bx_x_gui_c (void);
+ DECLARE_GUI_VIRTUAL_METHODS()
+#if BX_USE_IDLE_HACK
+ virtual void sim_is_idle(void);
+#endif
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_x_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(x)
+
+#define LOG_THIS theGui->
+
+#define MAX_MAPPED_STRING_LENGTH 10
+
+/* These are used as arguments to nearly every Xlib routine, so it saves
+ * routine arguments to declare them global. If there were
+ * additional source files, they would be declared extern there. */
+Display *bx_x_display;
+int bx_x_screen_num;
+static Colormap default_cmap;
+static unsigned long white_pixel=0, black_pixel=0;
+
+static char *progname; /* name this program was invoked by */
+
+static unsigned int text_rows=25, text_cols=80;
+static Bit8u h_panning = 0, v_panning = 0;
+
+static Window win;
+static GC gc, gc_inv, gc_headerbar, gc_headerbar_inv;
+static unsigned font_width, font_height;
+static unsigned dimension_x=0, dimension_y=0;
+static unsigned vga_bpp=8;
+
+static XImage *ximage = NULL;
+static unsigned imDepth, imWide, imBPP;
+
+// current cursor coordinates
+static int prev_x=-1, prev_y=-1;
+static int current_x=-1, current_y=-1;
+static unsigned mouse_button_state = 0;
+
+static unsigned prev_cursor_x=0;
+static unsigned prev_cursor_y=0;
+
+static int warp_home_x = 200;
+static int warp_home_y = 200;
+static int mouse_enable_x = 0;
+static int mouse_enable_y = 0;
+static int warp_dx = 0;
+static int warp_dy = 0;
+
+static void warp_cursor(int dx, int dy);
+static void disable_cursor();
+static void enable_cursor();
+
+static Bit32u convertStringToXKeysym (const char *string);
+
+static bx_bool x_init_done = false;
+
+static Pixmap vgafont[256];
+
+struct {
+ Pixmap bmap;
+ unsigned xdim;
+ unsigned ydim;
+ } bx_bitmaps[BX_MAX_PIXMAPS];
+unsigned bx_bitmap_entries = 0;
+
+static struct {
+ Pixmap bitmap;
+ unsigned xdim;
+ unsigned ydim;
+ unsigned xorigin;
+ unsigned yorigin;
+ unsigned alignment;
+ void (*f)(void);
+ } bx_headerbar_entry[BX_MAX_HEADERBAR_ENTRIES];
+static unsigned bx_headerbar_y = 0;
+static unsigned bx_headerbar_entries = 0;
+static unsigned bx_bitmap_left_xorigin = 0; // pixels from left
+static unsigned bx_bitmap_right_xorigin = 0; // pixels from right
+
+static void headerbar_click(int x, int y);
+static void send_keyboard_mouse_status(void);
+
+
+
+
+Bit32u ascii_to_key_event[0x5f] = {
+ // !"#$%&'
+ BX_KEY_SPACE,
+ BX_KEY_1,
+ BX_KEY_SINGLE_QUOTE,
+ BX_KEY_3,
+ BX_KEY_4,
+ BX_KEY_5,
+ BX_KEY_7,
+ BX_KEY_SINGLE_QUOTE,
+
+ // ()*+,-./
+ BX_KEY_9,
+ BX_KEY_0,
+ BX_KEY_8,
+ BX_KEY_EQUALS,
+ BX_KEY_COMMA,
+ BX_KEY_MINUS,
+ BX_KEY_PERIOD,
+ BX_KEY_SLASH,
+
+ // 01234567
+ BX_KEY_0,
+ BX_KEY_1,
+ BX_KEY_2,
+ BX_KEY_3,
+ BX_KEY_4,
+ BX_KEY_5,
+ BX_KEY_6,
+ BX_KEY_7,
+
+ // 89:;<=>?
+ BX_KEY_8,
+ BX_KEY_9,
+ BX_KEY_SEMICOLON,
+ BX_KEY_SEMICOLON,
+ BX_KEY_COMMA,
+ BX_KEY_EQUALS,
+ BX_KEY_PERIOD,
+ BX_KEY_SLASH,
+
+ // @ABCDEFG
+ BX_KEY_2,
+ BX_KEY_A,
+ BX_KEY_B,
+ BX_KEY_C,
+ BX_KEY_D,
+ BX_KEY_E,
+ BX_KEY_F,
+ BX_KEY_G,
+
+
+ // HIJKLMNO
+ BX_KEY_H,
+ BX_KEY_I,
+ BX_KEY_J,
+ BX_KEY_K,
+ BX_KEY_L,
+ BX_KEY_M,
+ BX_KEY_N,
+ BX_KEY_O,
+
+
+ // PQRSTUVW
+ BX_KEY_P,
+ BX_KEY_Q,
+ BX_KEY_R,
+ BX_KEY_S,
+ BX_KEY_T,
+ BX_KEY_U,
+ BX_KEY_V,
+ BX_KEY_W,
+
+ // XYZ[\]^_
+ BX_KEY_X,
+ BX_KEY_Y,
+ BX_KEY_Z,
+ BX_KEY_LEFT_BRACKET,
+ BX_KEY_BACKSLASH,
+ BX_KEY_RIGHT_BRACKET,
+ BX_KEY_6,
+ BX_KEY_MINUS,
+
+ // `abcdefg
+ BX_KEY_GRAVE,
+ BX_KEY_A,
+ BX_KEY_B,
+ BX_KEY_C,
+ BX_KEY_D,
+ BX_KEY_E,
+ BX_KEY_F,
+ BX_KEY_G,
+
+ // hijklmno
+ BX_KEY_H,
+ BX_KEY_I,
+ BX_KEY_J,
+ BX_KEY_K,
+ BX_KEY_L,
+ BX_KEY_M,
+ BX_KEY_N,
+ BX_KEY_O,
+
+ // pqrstuvw
+ BX_KEY_P,
+ BX_KEY_Q,
+ BX_KEY_R,
+ BX_KEY_S,
+ BX_KEY_T,
+ BX_KEY_U,
+ BX_KEY_V,
+ BX_KEY_W,
+
+ // xyz{|}~
+ BX_KEY_X,
+ BX_KEY_Y,
+ BX_KEY_Z,
+ BX_KEY_LEFT_BRACKET,
+ BX_KEY_BACKSLASH,
+ BX_KEY_RIGHT_BRACKET,
+ BX_KEY_GRAVE
+ };
+
+extern Bit8u graphics_snapshot[32 * 1024];
+
+
+static void create_internal_vga_font(void);
+static void xkeypress(KeySym keysym, int press_release);
+// extern "C" void select_visual(void);
+
+#define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad)>>3))
+
+
+#define MAX_VGA_COLORS 256
+
+unsigned long col_vals[MAX_VGA_COLORS]; // 256 VGA colors
+unsigned curr_foreground, curr_background;
+
+static unsigned x_tilesize, y_tilesize;
+
+
+// Try to allocate NCOLORS at once in the colormap provided. If it can
+// be done, return true. If not, return false. (In either case, free
+// up the color cells so that we don't add to the problem!) This is used
+// to determine whether Bochs should use a private colormap even when the
+// user did not specify it.
+static bx_bool
+test_alloc_colors (Colormap cmap, Bit32u n_tries) {
+ XColor color;
+ unsigned long pixel[MAX_VGA_COLORS];
+ bx_bool pixel_valid[MAX_VGA_COLORS];
+ Bit32u n_allocated = 0;
+ Bit32u i;
+ color.flags = DoRed | DoGreen | DoBlue;
+ for (i=0; i<n_tries; i++) {
+ // choose wierd color values that are unlikely to already be in the
+ // colormap.
+ color.red = ((i+41)%MAX_VGA_COLORS) << 8;
+ color.green = ((i+42)%MAX_VGA_COLORS) << 8;
+ color.blue = ((i+43)%MAX_VGA_COLORS) << 8;
+ pixel_valid[i] = false;
+ if (XAllocColor (bx_x_display, cmap, &color)) {
+ pixel[i] = color.pixel;
+ pixel_valid[i] = true;
+ n_allocated++;
+ }
+ }
+ BX_INFO (("test_alloc_colors: %d colors available out of %d colors tried", n_allocated, n_tries));
+ // now free them all
+ for (i=0; i<n_tries; i++) {
+ if (pixel_valid[i]) XFreeColors (bx_x_display, cmap, &pixel[i], 1, 0);
+ }
+ return (n_allocated == n_tries);
+}
+
+bx_x_gui_c::bx_x_gui_c () {
+}
+
+ void
+bx_x_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
+ unsigned headerbar_y)
+{
+ unsigned i;
+ int x, y; /* window position */
+ unsigned int border_width = 4; /* four pixels */
+#if BX_CPU_LEVEL < 2
+ char *window_name = "Bochs 8086 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 2
+ char *window_name = "Bochs 80286 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 3
+ char *window_name = "Bochs 80386 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 4
+ char *window_name = "Bochs 80486 emulator, http://bochs.sourceforge.net/";
+#else
+ char *window_name = "VTXen";
+#endif
+ char *icon_name = "Bochs";
+ Pixmap icon_pixmap;
+#if BX_HAVE_XPM_H
+ Pixmap icon_mask;
+#endif
+ XSizeHints size_hints;
+ char *display_name = NULL;
+ /* create GC for text and drawing */
+ unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */
+ XGCValues values;
+ Visual *default_visual;
+ int default_depth;
+ XEvent report;
+ XSetWindowAttributes win_attr;
+ unsigned long plane_masks_return[1];
+ XColor color;
+
+ put("XGUI");
+
+ x_tilesize = tilewidth;
+ y_tilesize = tileheight;
+ bx_headerbar_y = headerbar_y;
+
+ progname = argv[0];
+
+ /* connect to X server */
+ if ( (bx_x_display=XOpenDisplay(display_name)) == NULL )
+ {
+ BX_PANIC(("%s: cannot connect to X server %s",
+ progname, XDisplayName(display_name)));
+ }
+
+ /* get screen size from display structure macro */
+ bx_x_screen_num = DefaultScreen(bx_x_display);
+
+ /* Note that in a real application, x and y would default to 0
+ * but would be settable from the command line or resource database.
+ */
+ x = y = 0;
+
+
+ // Temporary values so we can create the window
+ font_width = 8;
+ font_height = 16;
+
+ dimension_x = text_cols * font_width;
+ dimension_y = text_rows * font_height + headerbar_y;
+
+ /* create opaque window */
+ win = XCreateSimpleWindow(bx_x_display, RootWindow(bx_x_display,bx_x_screen_num),
+ x, y,
+ dimension_x,
+ dimension_y,
+ border_width,
+ BlackPixel(bx_x_display, bx_x_screen_num),
+ BlackPixel(bx_x_display, bx_x_screen_num));
+
+ // (attempt to) enable backing store
+ win_attr.save_under=1;
+ win_attr.backing_store=Always;
+ XChangeWindowAttributes(bx_x_display,win,CWSaveUnder|CWBackingStore,&win_attr);
+
+ default_depth = DefaultDepth(bx_x_display, bx_x_screen_num);
+ default_visual = DefaultVisual(bx_x_display, bx_x_screen_num);
+
+ if (!bx_options.Oprivate_colormap->get ()) {
+ default_cmap = DefaultColormap(bx_x_display, bx_x_screen_num);
+ // try to use default colormap. If not enough colors are available,
+ // then switch to private colormap despite the user setting. There
+ // are too many cases when no colors are available and Bochs simply
+ // draws everything in black on black.
+ if (!test_alloc_colors (default_cmap, 16)) {
+ BX_ERROR (("I can't even allocate 16 colors! Switching to a private colormap"));
+ bx_options.Oprivate_colormap->set (1);
+ }
+ col_vals[0] = BlackPixel(bx_x_display, bx_x_screen_num);
+ col_vals[15] = WhitePixel(bx_x_display, bx_x_screen_num);
+ for (i = 1; i < MAX_VGA_COLORS; i++) {
+ if (i==15) continue;
+ col_vals[i] = col_vals[0];
+ }
+ }
+
+ if (bx_options.Oprivate_colormap->get ()) {
+ default_cmap = XCreateColormap(bx_x_display, DefaultRootWindow(bx_x_display),
+ default_visual, AllocNone);
+ if (XAllocColorCells(bx_x_display, default_cmap, False,
+ plane_masks_return, 0, col_vals, MAX_VGA_COLORS) == 0) {
+ BX_PANIC(("XAllocColorCells returns error. Maybe your screen does not support a private colormap?"));
+ }
+
+ win_attr.colormap = default_cmap;
+ XChangeWindowAttributes(bx_x_display, win, CWColormap, &win_attr);
+
+ color.flags = DoRed | DoGreen | DoBlue;
+
+ for (i=0; i < MAX_VGA_COLORS; i++) {
+ color.pixel = i;
+ if (i==15) {
+ color.red = 0xffff;
+ color.green = 0xffff;
+ color.blue = 0xffff;
+ }
+ else {
+ color.red = 0;
+ color.green = 0;
+ color.blue = 0;
+ }
+ XStoreColor(bx_x_display, default_cmap, &color);
+ }
+ }
+
+ // convenience variables which hold the black & white color indeces
+ black_pixel = col_vals[0];
+ white_pixel = col_vals[15];
+
+ BX_INFO(("font %u wide x %u high, display depth = %d",
+ (unsigned) font_width, (unsigned) font_height, default_depth));
+
+ //select_visual();
+
+
+ /* Get available icon sizes from Window manager */
+
+#if BX_HAVE_XPM_H
+ /* Create pixmap from XPM for icon */
+ XCreatePixmapFromData(bx_x_display, win, icon_bochs_xpm, &icon_pixmap, &icon_mask, NULL);
+#else
+ /* Create pixmap of depth 1 (bitmap) for icon */
+ icon_pixmap = XCreateBitmapFromData(bx_x_display, win,
+ (char *) bochs_icon_bits, bochs_icon_width, bochs_icon_height);
+#endif
+
+ /* Set size hints for window manager. The window manager may
+ * override these settings. Note that in a real
+ * application if size or position were set by the user
+ * the flags would be UPosition and USize, and these would
+ * override the window manager's preferences for this window. */
+ /* x, y, width, and height hints are now taken from
+ * the actual settings of the window when mapped. Note
+ * that PPosition and PSize must be specified anyway. */
+
+ size_hints.flags = PPosition | PSize | PMinSize | PMaxSize;
+ size_hints.max_width = size_hints.min_width = dimension_x;
+ size_hints.max_height = size_hints.min_height = dimension_y;
+
+ {
+ XWMHints wm_hints;
+ XClassHint class_hints;
+
+ /* format of the window name and icon name
+ * arguments has changed in R4 */
+ XTextProperty windowName, iconName;
+
+ /* These calls store window_name and icon_name into
+ * XTextProperty structures and set their other
+ * fields properly. */
+ if (XStringListToTextProperty(&window_name, 1, &windowName) == 0) {
+ BX_PANIC(("%s: structure allocation for windowName failed.",
+ progname));
+ }
+
+ if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0) {
+ BX_PANIC(("%s: structure allocation for iconName failed.",
+ progname));
+ }
+
+ wm_hints.initial_state = NormalState;
+ wm_hints.input = True;
+ wm_hints.icon_pixmap = icon_pixmap;
+#if BX_HAVE_XPM_H
+ wm_hints.icon_mask = icon_mask;
+ wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint;
+#else
+ wm_hints.flags = StateHint | IconPixmapHint | InputHint;
+#endif
+ class_hints.res_name = progname;
+ class_hints.res_class = "Bochs";
+
+ XSetWMProperties(bx_x_display, win, &windowName, &iconName,
+ argv, argc, &size_hints, &wm_hints,
+ &class_hints);
+ }
+
+ /* Select event types wanted */
+ XSelectInput(bx_x_display, win, ExposureMask | KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask | StructureNotifyMask | PointerMotionMask |
+ EnterWindowMask | LeaveWindowMask );
+
+
+ /* Create default Graphics Context */
+ gc = XCreateGC(bx_x_display, win, valuemask, &values);
+ gc_inv = XCreateGC(bx_x_display, win, valuemask, &values);
+ gc_headerbar = XCreateGC(bx_x_display, win, valuemask, &values);
+ gc_headerbar_inv = XCreateGC(bx_x_display, win, valuemask, &values);
+
+ XSetState(bx_x_display, gc, white_pixel, black_pixel, GXcopy,AllPlanes);
+
+ XSetState(bx_x_display, gc_inv, black_pixel, white_pixel, GXinvert,AllPlanes);
+
+ XSetState(bx_x_display, gc_headerbar, black_pixel, white_pixel, GXcopy,AllPlanes);
+
+ XSetState(bx_x_display, gc_headerbar_inv, white_pixel, black_pixel, GXcopy,AllPlanes);
+
+
+ /* Display window */
+ XMapWindow(bx_x_display, win);
+ XSync(bx_x_display, /* no discard */ 0);
+
+ BX_DEBUG(("waiting for MapNotify"));
+ while (1) {
+ XNextEvent(bx_x_display, &report);
+ if (report.type == MapNotify) break;
+ }
+ BX_DEBUG(("MapNotify found."));
+
+ // Create the VGA font
+ create_internal_vga_font();
+
+
+{
+ char *imagedata;
+
+ ximage = XCreateImage(bx_x_display, default_visual,
+ default_depth, // depth of image (bitplanes)
+ ZPixmap,
+ 0, // offset
+ NULL, // malloc() space after
+ x_tilesize, y_tilesize, // x & y size of image
+ 32, // # bits of padding
+ 0 ); // bytes_per_line, let X11 calculate
+ if (!ximage)
+ BX_PANIC(("vga: couldn't XCreateImage()"));
+
+ imDepth = default_depth;
+ imWide = ximage->bytes_per_line;
+ imBPP = ximage->bits_per_pixel;
+
+ imagedata = (char *) malloc( (size_t) (ximage->bytes_per_line * y_tilesize) );
+ if (!imagedata) BX_PANIC(("imagedata: malloc returned error"));
+
+ ximage->data = imagedata;
+
+ if (imBPP < imDepth) {
+ BX_PANIC(("vga_x: bits_per_pixel < depth ?"));
+ }
+
+ x_init_done = true;
+
+}
+
+ curr_background = 0;
+ XSetBackground(bx_x_display, gc, col_vals[curr_background]);
+ curr_foreground = 1;
+ XSetForeground(bx_x_display, gc, col_vals[curr_foreground]);
+ //XGrabPointer( bx_x_display, win, True, 0, GrabModeAsync, GrabModeAsync,
+ // win, None, CurrentTime );
+
+
+ XFlush(bx_x_display);
+
+ // loads keymap for x11
+ if(bx_options.keyboard.OuseMapping->get()) {
+ bx_keymap.loadKeymap(convertStringToXKeysym);
+ }
+}
+
+
+// This is called whenever the mouse_enabled parameter changes. It
+// can change because of a gui event such as clicking on the mouse-enable
+// bitmap or pressing the middle button, or from the configuration interface.
+// In all those cases, setting the parameter value will get you here.
+ void
+bx_x_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+ BX_DEBUG (("mouse_enabled=%d, x11 specific code", val?1:0));
+ if (val) {
+ BX_INFO(("[x] Mouse on"));
+ mouse_enable_x = current_x;
+ mouse_enable_y = current_y;
+ disable_cursor();
+ // Move the cursor to a 'safe' place
+ warp_cursor(warp_home_x-current_x, warp_home_y-current_y);
+ } else {
+ BX_INFO(("[x] Mouse off"));
+ enable_cursor();
+ warp_cursor(mouse_enable_x-current_x, mouse_enable_y-current_y);
+ }
+}
+
+ void
+create_internal_vga_font(void)
+{
+ // Default values
+ font_width=8;
+ font_height=16;
+
+ for(int i=0; i<256; i++) {
+ vgafont[i]=XCreateBitmapFromData(bx_x_display, win, (const char*)bx_vgafont[i].data,
+ font_width, font_height);
+ if(vgafont[i] == None)
+ BX_PANIC(("Can't create vga font [%d]", i));
+ }
+}
+
+ void
+bx_x_gui_c::handle_events(void)
+{
+ XEvent report;
+ XKeyEvent *key_event;
+ KeySym keysym;
+ XComposeStatus compose;
+ char buffer[MAX_MAPPED_STRING_LENGTH];
+ int bufsize = MAX_MAPPED_STRING_LENGTH;
+ int charcount;
+ bx_bool mouse_update;
+ int y, height;
+
+
+ XPointerMovedEvent *pointer_event;
+ XEnterWindowEvent *enter_event;
+ XLeaveWindowEvent *leave_event;
+ XButtonEvent *button_event;
+ XExposeEvent *expose_event;
+
+
+ //current_x = -1;
+ //current_y = -1;
+ mouse_update = 0;
+
+ while (XPending(bx_x_display) > 0) {
+ XNextEvent(bx_x_display, &report);
+ switch (report.type) {
+
+ case Expose:
+ expose_event = &report.xexpose;
+ /* Adjust y, and reduce height if it overlaps headerbar. */
+ y = expose_event->y - BX_HEADER_BAR_Y;
+ height = expose_event->height;
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+
+ DEV_vga_redraw_area(
+ (unsigned) expose_event->x,
+ y,
+ (unsigned) expose_event->width,
+ height);
+
+ /* Always draw headerbar, even if not touched by expose event.
+ * As a small optimization, only do it on last contigous expose.
+ */
+ if (expose_event->count == 0) {
+ show_headerbar();
+ }
+ break;
+
+ case ConfigureNotify:
+ BX_DEBUG(("ConfigureNotify Xevent"));
+ /* FIXME: It's not clear why we have to show the headerbar here.
+ * This should be forced by the following expose events.
+ */
+ show_headerbar();
+ break;
+
+ case ButtonPress:
+ button_event = (XButtonEvent *) &report;
+ BX_DEBUG(("xxx: buttonpress"));
+ if (button_event->y < BX_HEADER_BAR_Y) {
+ BX_DEBUG(("xxx: in headerbar"));
+ if (mouse_update) {
+ BX_DEBUG(("xxx: mouse_update=1"));
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ }
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+ headerbar_click(button_event->x, button_event->y);
+ break;
+ }
+ current_x = button_event->x;
+ current_y = button_event->y;
+ mouse_update = 1;
+ BX_DEBUG(("xxx: x,y=(%d,%d)", current_x, current_y));
+ switch (button_event->button) {
+ case Button1:
+ BX_DEBUG(("xxx: button1"));
+ mouse_button_state |= 0x01;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ case Button2:
+ BX_DEBUG(("XXX: button2"));
+
+ // (mch) Hack for easier mouse handling (toggle mouse enable)
+ toggle_mouse_enable();
+
+ //mouse_button_state |= ;
+ //send_keyboard_mouse_status();
+ //mouse_update = 0;
+ break;
+ case Button3:
+ BX_DEBUG(("xxx: button3"));
+ mouse_button_state |= 0x02;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ }
+ break;
+
+ case ButtonRelease:
+ button_event = (XButtonEvent *) &report;
+//BX_INFO(("xxx: buttonrelease"));
+ if (button_event->y < BX_HEADER_BAR_Y) {
+//BX_INFO(("xxx: in headerbar"));
+ if (mouse_update) {
+//BX_INFO(("xxx: mouse_update=1"));
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ }
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+ // ignore, in headerbar area
+ break;
+ }
+ current_x = button_event->x;
+ current_y = button_event->y;
+ mouse_update = 1;
+//BX_INFO(("xxx: x,y=(%d,%d)", current_x, current_y));
+ switch (button_event->button) {
+ case Button1:
+//BX_INFO(("xxx: button1"));
+ mouse_button_state &= ~0x01;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ case Button2:
+//BX_INFO(("xxx: button2"));
+ //mouse_button_state &= ~;
+ //send_keyboard_mouse_status();
+ //mouse_update = 0;
+ break;
+ case Button3:
+//BX_INFO(("xxx: button3"));
+ mouse_button_state &= ~0x02;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ }
+ break;
+
+ case KeyPress:
+ key_event = (XKeyEvent *) &report;
+ charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);
+ xkeypress(keysym, 0);
+ break;
+
+ case KeyRelease:
+ key_event = (XKeyEvent *) &report;
+ charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);
+ xkeypress(keysym, 1);
+ break;
+
+ case MotionNotify:
+ pointer_event = (XPointerMovedEvent *) &report;
+ current_x = pointer_event->x;
+ current_y = pointer_event->y;
+ mouse_update = 1;
+//BX_INFO(("xxx: motionNotify x,y=(%d,%d)", current_x, current_y));
+ break;
+
+ case EnterNotify:
+ enter_event = (XEnterWindowEvent *) &report;
+ prev_x = current_x = enter_event->x;
+ prev_y = current_y = enter_event->y;
+//BX_INFO(("xxx: enterNotify x,y=(%d,%d)", current_x, current_y));
+ break;
+
+ case LeaveNotify:
+ leave_event = (XLeaveWindowEvent *) &report;
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+//BX_INFO(("xxx: LeaveNotify x,y set to -1"));
+ break;
+
+ case MapNotify:
+ /* screen needs redraw, since X would have tossed previous
+ * requests before window mapped
+ */
+//BX_INFO(("xxx: mapnotify: found"));
+ //retval = 1;
+ break;
+
+ default:
+ // (mch) Ignore...
+ BX_DEBUG(("XXX: default Xevent type"));
+ /* all events selected by StructureNotifyMask are thrown away here,
+ * since nothing is done with them */
+ break;
+ } /* end switch */
+ } /* end while */
+
+ if (mouse_update) {
+ BX_DEBUG(("XXX: bottom, send status"));
+ send_keyboard_mouse_status();
+ }
+}
+
+
+ void
+send_keyboard_mouse_status(void)
+{
+ BX_DEBUG(("XXX: prev=(%d,%d) curr=(%d,%d)",
+ prev_x, prev_y, current_x, current_y));
+
+ if ( (prev_x!=-1) && (current_x!=-1) && (prev_y!=-1) && (current_y!=-1)) {
+ int dx, dy;
+
+ // (mch) consider warping here
+ dx = current_x - prev_x - warp_dx;
+ dy = -(current_y - prev_y - warp_dy);
+ warp_cursor(warp_home_x-current_x, warp_home_y-current_y);
+
+//BX_INFO(("xxx: MOUSE_MOTION: dx=%d, dy=%d", (int) dx, (int) dy));
+ DEV_mouse_motion (dx, dy, mouse_button_state);
+ //if (warped) {
+ // prev_x = current_x = -1;
+ // prev_y = current_y = -1;
+ // }
+ //else {
+ prev_x = current_x;
+ prev_y = current_y;
+ // }
+ }
+ else {
+ if ( (current_x!=-1) && (current_y!=-1)) {
+ prev_x = current_x;
+ prev_y = current_y;
+ }
+ else {
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+ }
+ }
+}
+
+ void
+bx_x_gui_c::flush(void)
+{
+ if (bx_x_display)
+ XFlush(bx_x_display);
+}
+
+
+ void
+xkeypress(KeySym keysym, int press_release)
+{
+ Bit32u key_event;
+
+ /* Old (no mapping) behavior */
+ if(!bx_options.keyboard.OuseMapping->get()){
+
+ // this depends on the fact that the X11 keysyms which
+ // correspond to the ascii characters space .. tilde
+ // are in consequtive order.
+ if ((keysym >= XK_space) && (keysym <= XK_asciitilde)) {
+ key_event = ascii_to_key_event[keysym - XK_space];
+ }
+ else switch (keysym) {
+ case XK_KP_1:
+#ifdef XK_KP_End
+ case XK_KP_End:
+#endif
+ key_event = BX_KEY_KP_END; break;
+
+ case XK_KP_2:
+#ifdef XK_KP_Down
+ case XK_KP_Down:
+#endif
+ key_event = BX_KEY_KP_DOWN; break;
+
+ case XK_KP_3:
+#ifdef XK_KP_Page_Down
+ case XK_KP_Page_Down:
+#endif
+ key_event = BX_KEY_KP_PAGE_DOWN; break;
+
+ case XK_KP_4:
+#ifdef XK_KP_Left
+ case XK_KP_Left:
+#endif
+ key_event = BX_KEY_KP_LEFT; break;
+
+ case XK_KP_5:
+#ifdef XK_KP_Begin
+ case XK_KP_Begin:
+#endif
+ key_event = BX_KEY_KP_5; break;
+
+ case XK_KP_6:
+#ifdef XK_KP_Right
+ case XK_KP_Right:
+#endif
+ key_event = BX_KEY_KP_RIGHT; break;
+
+ case XK_KP_7:
+#ifdef XK_KP_Home
+ case XK_KP_Home:
+#endif
+ key_event = BX_KEY_KP_HOME; break;
+
+ case XK_KP_8:
+#ifdef XK_KP_Up
+ case XK_KP_Up:
+#endif
+ key_event = BX_KEY_KP_UP; break;
+
+ case XK_KP_9:
+#ifdef XK_KP_Page_Up
+ case XK_KP_Page_Up:
+#endif
+ key_event = BX_KEY_KP_PAGE_UP; break;
+
+ case XK_KP_0:
+#ifdef XK_KP_Insert
+ case XK_KP_Insert:
+#endif
+ key_event = BX_KEY_KP_INSERT; break;
+
+ case XK_KP_Decimal:
+#ifdef XK_KP_Delete
+ case XK_KP_Delete:
+#endif
+ key_event = BX_KEY_KP_DELETE; break;
+
+#ifdef XK_KP_Enter
+ case XK_KP_Enter: key_event = BX_KEY_KP_ENTER; break;
+#endif
+
+ case XK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break;
+ case XK_KP_Add: key_event = BX_KEY_KP_ADD; break;
+
+ case XK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break;
+ case XK_KP_Divide: key_event = BX_KEY_KP_DIVIDE; break;
+
+
+ case XK_Up: key_event = BX_KEY_UP; break;
+ case XK_Down: key_event = BX_KEY_DOWN; break;
+ case XK_Left: key_event = BX_KEY_LEFT; break;
+ case XK_Right: key_event = BX_KEY_RIGHT; break;
+
+
+ case XK_Delete: key_event = BX_KEY_DELETE; break;
+ case XK_BackSpace: key_event = BX_KEY_BACKSPACE; break;
+ case XK_Tab: key_event = BX_KEY_TAB; break;
+#ifdef XK_ISO_Left_Tab
+ case XK_ISO_Left_Tab: key_event = BX_KEY_TAB; break;
+#endif
+ case XK_Return: key_event = BX_KEY_ENTER; break;
+ case XK_Escape: key_event = BX_KEY_ESC; break;
+ case XK_F1: key_event = BX_KEY_F1; break;
+ case XK_F2: key_event = BX_KEY_F2; break;
+ case XK_F3: key_event = BX_KEY_F3; break;
+ case XK_F4: key_event = BX_KEY_F4; break;
+ case XK_F5: key_event = BX_KEY_F5; break;
+ case XK_F6: key_event = BX_KEY_F6; break;
+ case XK_F7: key_event = BX_KEY_F7; break;
+ case XK_F8: key_event = BX_KEY_F8; break;
+ case XK_F9: key_event = BX_KEY_F9; break;
+ case XK_F10: key_event = BX_KEY_F10; break;
+ case XK_F11: key_event = BX_KEY_F11; break;
+ case XK_F12: key_event = BX_KEY_F12; break;
+ case XK_Control_L: key_event = BX_KEY_CTRL_L; break;
+#ifdef XK_Control_R
+ case XK_Control_R: key_event = BX_KEY_CTRL_R; break;
+#endif
+ case XK_Shift_L: key_event = BX_KEY_SHIFT_L; break;
+ case XK_Shift_R: key_event = BX_KEY_SHIFT_R; break;
+ case XK_Alt_L: key_event = BX_KEY_ALT_L; break;
+#ifdef XK_Alt_R
+ case XK_Alt_R: key_event = BX_KEY_ALT_R; break;
+#endif
+ case XK_Caps_Lock: key_event = BX_KEY_CAPS_LOCK; break;
+ case XK_Num_Lock: key_event = BX_KEY_NUM_LOCK; break;
+#ifdef XK_Scroll_Lock
+ case XK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break;
+#endif
+#ifdef XK_Print
+ case XK_Print: key_event = BX_KEY_PRINT; break;
+#endif
+#ifdef XK_Pause
+ case XK_Pause: key_event = BX_KEY_PAUSE; break;
+#endif
+
+ case XK_Insert: key_event = BX_KEY_INSERT; break;
+ case XK_Home: key_event = BX_KEY_HOME; break;
+ case XK_End: key_event = BX_KEY_END; break;
+ case XK_Page_Up: key_event = BX_KEY_PAGE_UP; break;
+ case XK_Page_Down: key_event = BX_KEY_PAGE_DOWN; break;
+
+ default:
+ BX_ERROR(( "xkeypress(): keysym %x unhandled!", (unsigned) keysym ));
+ return;
+ break;
+ }
+ }
+ else {
+ /* use mapping */
+ BXKeyEntry *entry = bx_keymap.findHostKey (keysym);
+ if (!entry) {
+ BX_ERROR(( "xkeypress(): keysym %x unhandled!", (unsigned) keysym ));
+ return;
+ }
+ key_event = entry->baseKey;
+ }
+
+ if (press_release)
+ key_event |= BX_KEY_RELEASED;
+
+ DEV_kbd_gen_scancode(key_event);
+}
+
+
+ void
+bx_x_gui_c::clear_screen(void)
+{
+ XClearArea(bx_x_display, win, 0, bx_headerbar_y, dimension_x, dimension_y-bx_headerbar_y, 0);
+}
+
+
+
+
+ void
+bx_x_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
+ unsigned long cursor_x, unsigned long cursor_y,
+ bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+ unsigned char *old_line, *new_line;
+ unsigned char cChar;
+ unsigned int curs, hchars, i, j, offset, rows, x, y, xc, yc, yc2;
+ unsigned new_foreground, new_background;
+ Bit8u cfwidth, cfheight, cfheight2, font_col, font_row, font_row2;
+ bx_bool force_update=0;
+ unsigned char cell[64];
+
+ UNUSED(nrows);
+ if (charmap_updated) {
+ BX_INFO(("charmap update. Font Height is %d",font_height));
+ for (unsigned c = 0; c<256; c++) {
+ if (char_changed[c]) {
+ XFreePixmap(bx_x_display, vgafont[c]);
+ bx_bool gfxchar = tm_info.line_graphics && ((c & 0xE0) == 0xC0);
+ j = 0;
+ memset(cell, 0, sizeof(cell));
+ for(i=0; i<font_height*2; i+=2) {
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x01)<<7);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x02)<<5);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x04)<<3);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x08)<<1);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x10)>>1);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x20)>>3);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x40)>>5);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x80)>>7);
+ if (gfxchar) {
+ cell[i+1] = (vga_charmap[(c<<5)+j] & 0x01);
+ }
+ j++;
+ }
+
+ vgafont[c]=XCreateBitmapFromData(bx_x_display, win,
+ (const char*)cell,
+ font_width, font_height);
+ if(vgafont[c] == None)
+ BX_PANIC(("Can't create vga font [%d]", c));
+ char_changed[c] = 0;
+ }
+ }
+ force_update = 1;
+ charmap_updated = 0;
+ }
+
+ if((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning)) {
+ force_update = 1;
+ h_panning = tm_info.h_panning;
+ v_panning = tm_info.v_panning;
+ }
+
+ // first invalidate character at previous and new cursor location
+ if ( (prev_cursor_y < text_rows) && (prev_cursor_x < text_cols) ) {
+ curs = prev_cursor_y * tm_info.line_offset + prev_cursor_x * 2;
+ old_text[curs] = ~new_text[curs];
+ }
+ if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < font_height) &&
+ (cursor_y < text_rows) && (cursor_x < text_cols)) {
+ curs = cursor_y * tm_info.line_offset + cursor_x * 2;
+ old_text[curs] = ~new_text[curs];
+ } else {
+ curs = 0xffff;
+ }
+
+ rows = text_rows;
+ if (v_panning) rows++;
+ y = 0;
+ do {
+ hchars = text_cols;
+ if (h_panning) hchars++;
+ if (v_panning) {
+ if (y == 0) {
+ yc = bx_headerbar_y;
+ font_row = v_panning;
+ cfheight = font_height - v_panning;
+ } else {
+ yc = y * font_height + bx_headerbar_y - v_panning;
+ font_row = 0;
+ if (rows == 1) {
+ cfheight = v_panning;
+ } else {
+ cfheight = font_height;
+ }
+ }
+ } else {
+ yc = y * font_height + bx_headerbar_y;
+ font_row = 0;
+ cfheight = font_height;
+ }
+ new_line = new_text;
+ old_line = old_text;
+ x = 0;
+ offset = y * tm_info.line_offset;
+ do {
+ if (h_panning) {
+ if (hchars > text_cols) {
+ xc = 0;
+ font_col = h_panning;
+ cfwidth = font_width - h_panning;
+ } else {
+ xc = x * font_width - h_panning;
+ font_col = 0;
+ if (hchars == 1) {
+ cfwidth = h_panning;
+ } else {
+ cfwidth = font_width;
+ }
+ }
+ } else {
+ xc = x * font_width;
+ font_col = 0;
+ cfwidth = font_width;
+ }
+ if ( force_update || (old_text[0] != new_text[0])
+ || (old_text[1] != new_text[1]) ) {
+
+ cChar = new_text[0];
+ new_foreground = new_text[1] & 0x0f;
+ new_background = (new_text[1] & 0xf0) >> 4;
+
+ XSetForeground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_foreground)]);
+ XSetBackground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_background)]);
+
+ XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col, font_row, cfwidth, cfheight,
+ xc, yc, 1);
+ if (offset == curs) {
+ XSetForeground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_background)]);
+ XSetBackground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_foreground)]);
+ if (font_row == 0) {
+ yc2 = yc + tm_info.cs_start;
+ font_row2 = tm_info.cs_start;
+ cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
+ } else {
+ if (v_panning > tm_info.cs_start) {
+ yc2 = yc;
+ font_row2 = font_row;
+ cfheight2 = tm_info.cs_end - v_panning + 1;
+ } else {
+ yc2 = yc + tm_info.cs_start - v_panning;
+ font_row2 = tm_info.cs_start;
+ cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
+ }
+ }
+ XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col, font_row2, cfwidth,
+ cfheight2, xc, yc2, 1);
+ }
+ }
+ x++;
+ new_text+=2;
+ old_text+=2;
+ offset+=2;
+ } while (--hchars);
+ y++;
+ new_text = new_line + tm_info.line_offset;
+ old_text = old_line + tm_info.line_offset;
+ } while (--rows);
+
+ prev_cursor_x = cursor_x;
+ prev_cursor_y = cursor_y;
+
+ XFlush(bx_x_display);
+}
+
+ int
+bx_x_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+ int len;
+ Bit8u *tmp = (Bit8u *)XFetchBytes (bx_x_display, &len);
+ // according to man XFetchBytes, tmp must be freed by XFree(). So allocate
+ // a new buffer with "new". The keyboard code will free it with delete []
+ // when the paste is done.
+ Bit8u *buf = new Bit8u[len];
+ memcpy (buf, tmp, len);
+ *bytes = buf;
+ *nbytes = len;
+ XFree (tmp);
+ return 1;
+}
+
+ int
+bx_x_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+ // this writes data to the clipboard.
+ BX_INFO (("storing %d bytes to X windows clipboard", len));
+ XSetSelectionOwner(bx_x_display, XA_PRIMARY, None, CurrentTime);
+ XStoreBytes (bx_x_display, (char *)text_snapshot, len);
+ return 1;
+}
+
+
+ void
+bx_x_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+ unsigned x, y;
+ unsigned color, offset;
+ Bit8u b0, b1, b2, b3;
+
+ Bit16u *tile16 = (Bit16u *)tile;
+ switch (vga_bpp) {
+ case 32: // 32 bits per pixel
+ if (ximage->byte_order == LSBFirst) {
+ memcpy(&ximage->data[0], tile, x_tilesize*y_tilesize*4);
+ }
+ else { // MSBFirst
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ offset = imWide*y + 4*x;
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*4 + 3];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*4 + 2];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*4 + 1];
+ ximage->data[offset + 3] = tile[(y*x_tilesize + x)*4];
+ }
+ }
+ }
+ break;
+ case 24: // 24 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ switch (imBPP) {
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 2];
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3 + 2];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3];
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 2];
+ ximage->data[offset + 3] = 0;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = 0;
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 2];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 3] = tile[(y*x_tilesize + x)*3];
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case 16: // 16 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ switch (imBPP) {
+ case 16: // 16 bits per pixel
+ offset = imWide*y + 2*x;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*2];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*2 + 1];
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*2 + 1];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*2];
+ }
+ break;
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x07e0) >> 3;
+ b2 = (tile16[y*x_tilesize + x] & 0xF800) >> 8;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b2;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b0;
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x07e0) >> 3;
+ b2 = (tile16[y*x_tilesize + x] & 0xF800) >> 8;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ ximage->data[offset + 3] = 0;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = 0;
+ ximage->data[offset + 1] = b2;
+ ximage->data[offset + 2] = b1;
+ ximage->data[offset + 3] = b0;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case 15: // 15 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ switch (imBPP) {
+ case 16: // 16 bits per pixel
+ offset = imWide*y + 2*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f);
+ b0 |= (tile16[y*x_tilesize + x] & 0x0060) << 1;
+ b1 = (tile16[y*x_tilesize + x] & 0x7f80) >> 7;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b1;
+ ximage->data[offset + 1] = b0;
+ }
+ break;
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x03e0) >> 2;
+ b2 = (tile16[y*x_tilesize + x] & 0x7c00) >> 7;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b2;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b0;
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x03e0) >> 2;
+ b2 = (tile16[y*x_tilesize + x] & 0x7c00) >> 7;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ ximage->data[offset + 3] = 0;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = 0;
+ ximage->data[offset + 1] = b2;
+ ximage->data[offset + 2] = b1;
+ ximage->data[offset + 3] = b0;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ default: // 8 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ color = col_vals[tile[y*x_tilesize + x]];
+ switch (imBPP) {
+ case 8: // 8 bits per pixel
+ ximage->data[imWide*y + x] = color;
+ break;
+ case 16: // 16 bits per pixel
+ offset = imWide*y + 2*x;
+ b0 = color >> 0;
+ b1 = color >> 8;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b1;
+ ximage->data[offset + 1] = b0;
+ }
+ break;
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ b0 = color >> 0;
+ b1 = color >> 8;
+ b2 = color >> 16;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b2;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b0;
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ b0 = color >> 0;
+ b1 = color >> 8;
+ b2 = color >> 16;
+ b3 = color >> 24;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ ximage->data[offset + 3] = b3;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b3;
+ ximage->data[offset + 1] = b2;
+ ximage->data[offset + 2] = b1;
+ ximage->data[offset + 3] = b0;
+ }
+ break;
+ default:
+ BX_PANIC(("X_graphics_tile_update: bits_per_pixel %u not implemented",
+ (unsigned) imBPP));
+ break;
+ }
+ }
+ }
+ }
+ XPutImage(bx_x_display, win, gc, ximage, 0, 0, x0, y0+bx_headerbar_y,
+ x_tilesize, y_tilesize);
+}
+
+
+ bx_bool
+bx_x_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+ // returns: 0=no screen update needed (color map change has direct effect)
+ // 1=screen updated needed (redraw using current colormap)
+ XColor color;
+
+ color.flags = DoRed | DoGreen | DoBlue;
+ color.red = red << 8;
+ color.green = green << 8;
+ color.blue = blue << 8;
+
+ if (bx_options.Oprivate_colormap->get ()) {
+ color.pixel = index;
+ XStoreColor(bx_x_display, default_cmap, &color);
+ return(0); // no screen update needed
+ }
+ else {
+ XAllocColor(bx_x_display, DefaultColormap(bx_x_display, bx_x_screen_num),
+ &color);
+ col_vals[index] = color.pixel;
+ return(1); // screen update needed
+ }
+}
+
+
+ void
+bx_x_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+ if ((bpp <= imBPP) && ((bpp == 8) || (bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32))) {
+ vga_bpp = bpp;
+ } else {
+ BX_PANIC(("%d bpp graphics mode not supported", bpp));
+ }
+ if (fheight > 0) {
+ font_height = fheight;
+ font_width = fwidth;
+ text_cols = x / font_width;
+ text_rows = y / font_height;
+ }
+ if ( (x != dimension_x) || (y != (dimension_y-bx_headerbar_y)) ) {
+ XSizeHints hints;
+ long supplied_return;
+
+ if ( XGetWMNormalHints(bx_x_display, win, &hints, &supplied_return) &&
+ supplied_return & PMaxSize ) {
+ hints.max_width = hints.min_width = x;
+ hints.max_height = hints.min_height = y+bx_headerbar_y;
+ XSetWMNormalHints(bx_x_display, win, &hints);
+ }
+ XResizeWindow(bx_x_display, win, x, y+bx_headerbar_y);
+ dimension_x = x;
+ dimension_y = y + bx_headerbar_y;
+ }
+}
+
+
+ void
+bx_x_gui_c::show_headerbar(void)
+{
+ unsigned xorigin;
+ int xleft, xright;
+
+ // clear header bar area to white
+ XFillRectangle(bx_x_display, win, gc_headerbar_inv, 0,0, dimension_x, bx_headerbar_y);
+
+ xleft = 0;
+ xright = dimension_x;
+ for (unsigned i=0; i<bx_headerbar_entries; i++) {
+ if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT) {
+ xorigin = bx_headerbar_entry[i].xorigin;
+ xleft += bx_headerbar_entry[i].xdim;
+ }
+ else {
+ xorigin = dimension_x - bx_headerbar_entry[i].xorigin;
+ xright = xorigin;
+ }
+ if (xright < xleft) break;
+ XCopyPlane(bx_x_display, bx_headerbar_entry[i].bitmap, win, gc_headerbar,
+ 0,0, bx_headerbar_entry[i].xdim, bx_headerbar_entry[i].ydim,
+ xorigin, 0, 1);
+ }
+}
+
+
+ unsigned
+bx_x_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+ if (bx_bitmap_entries >= BX_MAX_PIXMAPS) {
+ BX_PANIC(("x: too many pixmaps, increase BX_MAX_PIXMAPS"));
+ }
+
+ bx_bitmaps[bx_bitmap_entries].bmap =
+ XCreateBitmapFromData(bx_x_display, win, (const char *) bmap, xdim, ydim);
+ bx_bitmaps[bx_bitmap_entries].xdim = xdim;
+ bx_bitmaps[bx_bitmap_entries].ydim = ydim;
+ if (!bx_bitmaps[bx_bitmap_entries].bmap) {
+ BX_PANIC(("x: could not create bitmap"));
+ }
+ bx_bitmap_entries++;
+ return(bx_bitmap_entries-1); // return index as handle
+}
+
+
+ unsigned
+bx_x_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+ unsigned hb_index;
+
+ if ( (bx_headerbar_entries+1) > BX_MAX_HEADERBAR_ENTRIES )
+ BX_PANIC(("x: too many headerbar entries, increase BX_MAX_HEADERBAR_ENTRIES"));
+
+ bx_headerbar_entries++;
+ hb_index = bx_headerbar_entries - 1;
+
+ bx_headerbar_entry[hb_index].bitmap = bx_bitmaps[bmap_id].bmap;
+ bx_headerbar_entry[hb_index].xdim = bx_bitmaps[bmap_id].xdim;
+ bx_headerbar_entry[hb_index].ydim = bx_bitmaps[bmap_id].ydim;
+ bx_headerbar_entry[hb_index].alignment = alignment;
+ bx_headerbar_entry[hb_index].f = f;
+ if (alignment == BX_GRAVITY_LEFT) {
+ bx_headerbar_entry[hb_index].xorigin = bx_bitmap_left_xorigin;
+ bx_headerbar_entry[hb_index].yorigin = 0;
+ bx_bitmap_left_xorigin += bx_bitmaps[bmap_id].xdim;
+ }
+ else { // BX_GRAVITY_RIGHT
+ bx_bitmap_right_xorigin += bx_bitmaps[bmap_id].xdim;
+ bx_headerbar_entry[hb_index].xorigin = bx_bitmap_right_xorigin;
+ bx_headerbar_entry[hb_index].yorigin = 0;
+ }
+ return(hb_index);
+}
+
+ void
+bx_x_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+ unsigned xorigin;
+
+ bx_headerbar_entry[hbar_id].bitmap = bx_bitmaps[bmap_id].bmap;
+
+ if (bx_headerbar_entry[hbar_id].alignment == BX_GRAVITY_LEFT)
+ xorigin = bx_headerbar_entry[hbar_id].xorigin;
+ else
+ xorigin = dimension_x - bx_headerbar_entry[hbar_id].xorigin;
+ XCopyPlane(bx_x_display, bx_headerbar_entry[hbar_id].bitmap, win, gc_headerbar,
+ 0,0, bx_headerbar_entry[hbar_id].xdim, bx_headerbar_entry[hbar_id].ydim,
+ xorigin, 0, 1);
+}
+
+
+ void
+headerbar_click(int x, int y)
+{
+ int xorigin;
+
+ // assuming y is in bounds
+ UNUSED(y);
+ for (unsigned i=0; i<bx_headerbar_entries; i++) {
+ if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT)
+ xorigin = bx_headerbar_entry[i].xorigin;
+ else
+ xorigin = dimension_x - bx_headerbar_entry[i].xorigin;
+ if ( (x>=xorigin) && (x<(xorigin+int(bx_headerbar_entry[i].xdim))) ) {
+ bx_headerbar_entry[i].f();
+ return;
+ }
+ }
+}
+
+ void
+bx_x_gui_c::exit(void)
+{
+ if (!x_init_done) return;
+
+ // Delete the font bitmaps
+ for (int i=0; i<256; i++) {
+ //if (vgafont[i] != NULL)
+ XFreePixmap(bx_x_display,vgafont[i]);
+ }
+
+ if (bx_x_display)
+ XCloseDisplay (bx_x_display);
+ BX_INFO(("Exit."));
+}
+
+static void warp_cursor (int dx, int dy)
+{
+ if (bx_options.Omouse_enabled->get () &&
+ (warp_dx || warp_dy || dx || dy)
+ ) {
+ warp_dx = dx;
+ warp_dy = dy;
+ XWarpPointer(bx_x_display, None, None, 0, 0, 0, 0, dx, dy);
+ }
+}
+
+static void disable_cursor ()
+{
+ static Cursor cursor;
+ static unsigned cursor_created = 0;
+
+ static int shape_width = 16,
+ shape_height = 16,
+ mask_width = 16,
+ mask_height = 16;
+
+ static uint32 shape_bits[(16*16)/32] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ };
+ static uint32 mask_bits[(16*16)/32] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ };
+
+ if (!cursor_created) {
+ Pixmap shape, mask;
+ XColor white, black;
+ shape = XCreatePixmapFromBitmapData(bx_x_display,
+ RootWindow(bx_x_display,bx_x_screen_num),
+ (char*)shape_bits,
+ shape_width,
+ shape_height,
+ 1, 0, 1);
+ mask = XCreatePixmapFromBitmapData(bx_x_display,
+ RootWindow(bx_x_display,bx_x_screen_num),
+ (char*)mask_bits,
+ mask_width,
+ mask_height,
+ 1, 0, 1);
+ XParseColor(bx_x_display, default_cmap, "black", &black);
+ XParseColor(bx_x_display, default_cmap, "white", &white);
+ cursor = XCreatePixmapCursor(bx_x_display, shape, mask,
+ &white, &black, 1, 1);
+ cursor_created = 1;
+ }
+
+ XDefineCursor(bx_x_display, win, cursor);
+}
+
+static void enable_cursor ()
+{
+ XUndefineCursor(bx_x_display, win);
+}
+
+/* convertStringToXKeysym is a keymap callback
+ * used when reading the keymap file.
+ * It converts a Symblic String to a GUI Constant
+ *
+ * It returns a Bit32u constant or BX_KEYMAP_UNKNOWN if it fails
+ */
+static Bit32u convertStringToXKeysym (const char *string)
+{
+ if (strncmp ("XK_", string, 3) != 0)
+ return BX_KEYMAP_UNKNOWN;
+ KeySym keysym=XStringToKeysym(string+3);
+
+ // failure, return unknown
+ if(keysym==NoSymbol) return BX_KEYMAP_UNKNOWN;
+
+ return((Bit32u)keysym);
+}
+
+#if BX_USE_IDLE_HACK
+
+/* BX_USE_IDLE_HACK: a small idle hack by
+ * Roland.Mainz@informatik.med.uni-giessen.de to prevent bochs
+ * from consuming 100% CPU time even when it is not required (for
+ * example, the OS in the emulator calls HLT to wait for an interupt)
+ * pro:
+ * - no more 100% CPU usage
+ * contra:
+ * - we're sleeping too long
+ * - bochs still consumes ~10%-20% CPU time while executing an idle
+ * linux kernel
+ * - this is an hack
+ */
+
+/* XPeekEvent() with timeout
+ * (adopted from mozilla/gfx/src/xprint/xprintutil_printtofile.c#XNextEventTimeout())
+ */
+static
+Bool XPeekEventTimeout( Display *display, XEvent *event_return, struct timeval *timeout )
+{
+ int res;
+ fd_set readfds;
+ int display_fd = XConnectionNumber(display);
+
+ /* small shortcut... */
+ if( timeout == NULL )
+ {
+ XPeekEvent(display, event_return);
+ return(True);
+ }
+
+ FD_ZERO(&readfds);
+ FD_SET(display_fd, &readfds);
+
+ /* Note/bug: In the case of internal X events (like used to trigger callbacks
+ * registered by XpGetDocumentData()&co.) select() will return with "new info"
+ * - but XNextEvent() below processes these _internal_ events silently - and
+ * will block if there are no other non-internal events.
+ * The workaround here is to check with XEventsQueued() if there are non-internal
+ * events queued - if not select() will be called again - unfortunately we use
+ * the old timeout here instead of the "remaining" time... (this only would hurt
+ * if the timeout would be really long - but for current use with values below
+ * 1/2 secs it does not hurt... =:-)
+ */
+ while( XEventsQueued(display, QueuedAfterFlush) == 0 )
+ {
+ res = select(display_fd+1, &readfds, NULL, NULL, timeout);
+
+ switch(res)
+ {
+ case -1: /* select() error - should not happen */
+ perror("XPeekEventTimeout: select() failure");
+ return(False);
+ case 0: /* timeout */
+ return(False);
+ }
+ }
+
+ XPeekEvent(display, event_return);
+ return(True);
+}
+
+#if BX_USE_IDLE_HACK
+void bx_x_gui_c::sim_is_idle () {
+ XEvent dummy;
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1000; /* 1/1000 s */
+ XPeekEventTimeout(bx_x_display, &dummy, &timeout);
+}
+#endif
+#endif /* BX_USE_IDLE_HACK */
+
+#endif /* if BX_WITH_X11 */