diff -urN qemu-0.8.2/configure qemu-0.8.2-x/configure --- qemu-0.8.2/configure 2006-07-22 18:23:34.000000000 +0100 +++ qemu-0.8.2-x/configure 2006-08-24 14:24:33.000000000 +0100 @@ -492,6 +492,21 @@ fi # cross compilation fi # -z $sdl +########################################## +# X Probe + +x11=no +if test -z "$sdl" || test "$sdl" = "no"; then + x11=yes +fi + +if test "$x11" = "yes"; then + x11=no + if `pkg-config --exists x11 xext`; then + x11=yes + fi +fi + # Check if tools are available to build documentation. if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then build_docs="yes" @@ -540,6 +555,7 @@ if test "$sdl" != "no" ; then echo "SDL static link $sdl_static" fi +echo "X11 support $x11" echo "mingw32 support $mingw32" echo "Adlib support $adlib" echo "CoreAudio support $coreaudio" @@ -748,14 +764,14 @@ fi if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ - -a "$sdl" = "no" -a "$cocoa" = "no" ; then + -a "$sdl" = "no" -a "$x11" = "no" -a "$cocoa" = "no" ; then echo "ERROR: QEMU requires SDL or Cocoa for graphical output" echo "To build QEMU without graphical output configure with --disable-gfx-check" echo "Note that this will disable all output from the virtual graphics card." exit 1; fi -#echo "Creating $config_mak, $config_h and $target_dir/Makefile" +echo "Creating $config_mak, $config_h and $target_dir/Makefile" mkdir -p $target_dir mkdir -p $target_dir/fpu @@ -882,6 +898,14 @@ fi fi +# x11 +if test "$x11" = "yes"; then + echo "#define CONFIG_X11 1" >> $config_h + echo "CONFIG_X11=yes" >> $config_mak + echo "X11_LIBS=`pkg-config --libs x11 xext`" >> $config_mak + echo "X11_CFLAGS=`pkg-config --cflags x11 xext`" >> $config_mak +fi + if test "$cocoa" = "yes" ; then echo "#define CONFIG_COCOA 1" >> $config_h echo "CONFIG_COCOA=yes" >> $config_mak diff -urN qemu-0.8.2/Makefile.target qemu-0.8.2-x/Makefile.target --- qemu-0.8.2/Makefile.target 2006-07-22 18:23:34.000000000 +0100 +++ qemu-0.8.2-x/Makefile.target 2006-08-23 14:47:17.000000000 +0100 @@ -376,6 +376,9 @@ ifdef CONFIG_SDL VL_OBJS+=sdl.o endif +ifdef CONFIG_X11 +VL_OBJS+=x.o +endif VL_OBJS+=vnc.o ifdef CONFIG_COCOA VL_OBJS+=cocoa.o @@ -426,7 +429,7 @@ endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a - $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(X11_LIBS) $(COCOA_LIBS) $(VL_LIBS) cocoa.o: cocoa.m $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< @@ -434,6 +437,10 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< +x.o: x.c keymaps.c + $(CC) $(CFLAGS) $(DEFINES) $(X11_CFLAGS) -c -o $@ $< + + vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff -urN qemu-0.8.2/vl.c qemu-0.8.2-x/vl.c --- qemu-0.8.2/vl.c 2006-07-22 18:23:34.000000000 +0100 +++ qemu-0.8.2-x/vl.c 2006-09-29 18:58:26.000000000 +0100 @@ -5217,6 +5217,9 @@ #ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n" #endif +#if defined(CONFIG_X11) + "-parent xid Use pre-existing window as qemu output window\n" +#endif #ifdef TARGET_I386 "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" @@ -5302,6 +5305,8 @@ QEMU_OPTION_smp, QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, + + QEMU_OPTION_parent_xid, }; typedef struct QEMUOption { @@ -5361,6 +5366,9 @@ #if defined(TARGET_PPC) || defined(TARGET_SPARC) { "g", 1, QEMU_OPTION_g }, #endif +#if defined(CONFIG_X11) + { "parent", HAS_ARG, QEMU_OPTION_parent_xid }, +#endif { "localtime", 0, QEMU_OPTION_localtime }, { "std-vga", 0, QEMU_OPTION_std_vga }, { "monitor", 1, QEMU_OPTION_monitor }, @@ -5608,6 +5616,10 @@ char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; +#if defined(CONFIG_X11) + unsigned long parent_xid = 0; +#endif + LIST_INIT (&vm_change_state_head); #ifndef _WIN32 { @@ -6021,6 +6033,11 @@ case QEMU_OPTION_no_acpi: acpi_enabled = 0; break; +#if defined(CONFIG_X11) + case QEMU_OPTION_parent_xid: + parent_xid = strtol(optarg, NULL, 0); + break; +#endif } } } @@ -6142,6 +6159,8 @@ sdl_display_init(ds, full_screen); #elif defined(CONFIG_COCOA) cocoa_display_init(ds, full_screen); +#elif defined(CONFIG_X11) + x_display_init(ds, full_screen, parent_xid); #else dumb_display_init(ds); #endif diff -urN qemu-0.8.2/vl.h qemu-0.8.2-x/vl.h --- qemu-0.8.2/vl.h 2006-07-22 18:23:34.000000000 +0100 +++ qemu-0.8.2-x/vl.h 2006-09-29 18:35:32.000000000 +0100 @@ -767,6 +767,9 @@ /* vnc.c */ void vnc_display_init(DisplayState *ds, int display); +/* x.c */ +void x_display_init(DisplayState *ds, int display, unsigned long parent_xid); + /* ide.c */ #define MAX_DISKS 4 diff -urN qemu-0.8.2/x.c qemu-0.8.2-x/x.c --- qemu-0.8.2/x.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.8.2-x/x.c 2006-09-29 18:35:02.000000000 +0100 @@ -0,0 +1,451 @@ +#include "vl.h" + +#include +#include +#include +#include +#include + +#include +#include + +typedef struct XHostScreen +{ + Display *xdpy; + int xscreen; + Visual *xvisual; + Window xwin, xwinroot; + GC xgc; + int xdepth; + XImage *ximg; + int xwin_width, xwin_height; + Bool use_fullscreen; + Bool have_shm; + unsigned char *fb_data; + unsigned long cmap[256]; + XShmSegmentInfo shminfo; +} +XHostScreen; + +static XHostScreen *xscreen; +static int trapped_error_code = 0; +static int (*old_error_handler) (Display *d, XErrorEvent *e); + +static void +x_update(DisplayState *ds, int x, int y, int w, int h); + +static int +error_handler(Display *display, + XErrorEvent *error) +{ + trapped_error_code = error->error_code; + return 0; +} + +static void +x_errors_trap(void) +{ + trapped_error_code = 0; + old_error_handler = XSetErrorHandler(error_handler); +} + +static int +x_errors_untrap(void) +{ + XSetErrorHandler(old_error_handler); + return trapped_error_code; +} + +static void +x_update(DisplayState *ds, int x, int y, int w, int h) +{ + if (xscreen->have_shm) + { + XShmPutImage(xscreen->xdpy, xscreen->xwin, xscreen->xgc, xscreen->ximg, + x, y, x, y, w, h, False); + } + else + { + XPutImage(xscreen->xdpy, xscreen->xwin, xscreen->xgc, xscreen->ximg, + x, y, x, y, w, h); + } + + XSync(xscreen->xdpy, False); +} + +static void +x_resize(DisplayState *ds, int w, int h) +{ + Bool shm_success = False; + int bitmap_pad; + XSizeHints *size_hints; + + if (xscreen->ximg != NULL) + { + if (xscreen->have_shm) + { + XShmDetach(xscreen->xdpy, &xscreen->shminfo); + XDestroyImage (xscreen->ximg); + shmdt(xscreen->shminfo.shmaddr); + shmctl(xscreen->shminfo.shmid, IPC_RMID, 0); + } + else + { + if (xscreen->ximg->data) + { + free(xscreen->ximg->data); + xscreen->ximg->data = NULL; + } + + XDestroyImage(xscreen->ximg); + } + } + + if (xscreen->have_shm) + { + xscreen->ximg = XShmCreateImage(xscreen->xdpy, + xscreen->xvisual, + xscreen->xdepth, + ZPixmap, + NULL, + &xscreen->shminfo, + w, h ); + + xscreen->shminfo.shmid + = shmget(IPC_PRIVATE, + xscreen->ximg->bytes_per_line * h, + IPC_CREAT|0777); + xscreen->shminfo.shmaddr = xscreen->ximg->data + = shmat(xscreen->shminfo.shmid, 0, 0); + + if (xscreen->ximg->data == (char *)-1) + { + xscreen->have_shm = False; + XDestroyImage(xscreen->ximg); + shmctl(xscreen->shminfo.shmid, IPC_RMID, 0); + } + else + { + xscreen->shminfo.readOnly = False; + XShmAttach(xscreen->xdpy, &xscreen->shminfo); + shm_success = True; + } + } + + if (!shm_success) + { + bitmap_pad = ( xscreen->xdepth > 16 ) ? + 32 : (( xscreen->xdepth > 8 )? 16 : 8 ); + + xscreen->ximg = XCreateImage( xscreen->xdpy, + xscreen->xvisual, + xscreen->xdepth, + ZPixmap, 0, 0, + w, + h, + bitmap_pad, + 0); + + xscreen->ximg->data + = malloc( xscreen->ximg->bytes_per_line * h ); + } + + XResizeWindow(xscreen->xdpy, xscreen->xwin, w, h); + + /* Ask the WM to keep our size static */ + size_hints = XAllocSizeHints(); + size_hints->max_width = size_hints->min_width = w; + size_hints->max_height = size_hints->min_height = h; + size_hints->flags = PMinSize|PMaxSize; + XSetWMNormalHints(xscreen->xdpy, xscreen->xwin, size_hints); + XFree(size_hints); + + XMapWindow(xscreen->xdpy, xscreen->xwin); + + XSync(xscreen->xdpy, False); + + xscreen->xwin_width = w; + xscreen->xwin_height = h; + + if (1) // (ds->depth == xscreen->xdepth) + { + ds->data = xscreen->ximg->data; + } + else + { + xscreen->fb_data = malloc(w*h*(ds->depth>>3)); + ds->data = xscreen->fb_data; + } + + ds->linesize = xscreen->ximg->bytes_per_line; + ds->depth = (xscreen->xdepth >= 24) ? 32 : xscreen->xdepth; + ds->bgr = 0; + +#if 0 + if (ds->depth == 32 && screen->format->Rshift == 0) { + ds->bgr = 1; + } else { + ds->bgr = 0; + } +#endif + + ds->width = w; + ds->height = h; + +} + +static void +x_refresh(DisplayState *ds) +{ + vga_hw_update(); +} + +static int +x_listen_poll(void *opaque) +{ + return XPending(xscreen->xdpy); +} + +static void +x_grab(void) +{ + static Bool grab = False; + + if (!grab) + { + if (XGrabPointer (xscreen->xdpy, xscreen->xwin, + True, + NoEventMask, + GrabModeAsync, + GrabModeAsync, + xscreen->xwin, None, CurrentTime) == 0 + && XGrabKeyboard (xscreen->xdpy, xscreen->xwin, True, + GrabModeAsync, + GrabModeAsync, + CurrentTime) == 0) + { + grab = True; + XStoreName(xscreen->xdpy, xscreen->xwin, + "QEmu (ctrl+shift releases mouse and keyboard )"); + } + } + else + { + XUngrabPointer (xscreen->xdpy, CurrentTime); + XUngrabKeyboard (xscreen->xdpy, CurrentTime); + grab = False; + XStoreName(xscreen->xdpy, xscreen->xwin, + "QEmu (ctrl+shift grabs mouse and keyboard )"); + } +} + +static void +x_listen_read(void *opaque) +{ + XEvent xev; + DisplayState *ds = opaque; + Bool grabbed = False; + static int last_x = 0, last_y = 0, button_state = 0, state; + + if (XPending(xscreen->xdpy)) + { + XNextEvent(xscreen->xdpy, &xev); + + switch (xev.type) + { + case EnterNotify: + case LeaveNotify: + break; + case FocusIn: + if (!kbd_mouse_is_absolute()) + x_grab(); + break; + case FocusOut: + break; + case Expose: + while (XCheckTypedWindowEvent(xscreen->xdpy, xev.xexpose.window, + Expose, &xev)); + x_update(ds, 0, 0, + xscreen->xwin_width, + xscreen->xwin_height); + break; + case KeyRelease: + if ((XKeycodeToKeysym(xscreen->xdpy, + xev.xkey.keycode,0) == XK_Shift_L + || XKeycodeToKeysym(xscreen->xdpy, + xev.xkey.keycode,0) == XK_Shift_R) + && (xev.xkey.state & ControlMask)) + { + x_grab(); + break; + } + case KeyPress: + { + int keycode = xev.xkey.keycode-8; /* X adds 8 to keycode */ + + /* FIXME: LUT needed here me thinks */ + + if (keycode & 0x80) /* Extended */ + kbd_put_keycode(0xe0); + + if (xev.type == KeyPress) + kbd_put_keycode(keycode & 0x7f); + else + kbd_put_keycode(keycode | 0x80); + } + break; + case ButtonPress: + case ButtonRelease: + case MotionNotify: + { + int ev_state, ev_x, ev_y, dx, dy; + + state = 0; + + if (xev.type == MotionNotify) + { + ev_state = xev.xmotion.state; + ev_x = xev.xmotion.x; + ev_y = xev.xmotion.y; + + if (ev_state & Button1Mask) + state |= MOUSE_EVENT_LBUTTON; + if (ev_state & Button2Mask) + state |= MOUSE_EVENT_RBUTTON; + if (ev_state & Button3Mask) + state |= MOUSE_EVENT_MBUTTON; + + /* Touchscreen dont send motion notifys */ + if (kbd_mouse_is_absolute() && state == 0) + break; + } + else + { + ev_state = xev.xbutton.state; + ev_x = xev.xbutton.x; + ev_y = xev.xbutton.y; + + if (xev.type == ButtonPress) + { + if (xev.xbutton.button == Button1) + state |= MOUSE_EVENT_LBUTTON; + if (xev.xbutton.state == Button1) + state |= MOUSE_EVENT_RBUTTON; + if (xev.xbutton.state & Button3) + state |= MOUSE_EVENT_MBUTTON; + } + } + + if (kbd_mouse_is_absolute()) + { + dx = ev_x * 0x7FFF / xscreen->xwin_width; + dy = ev_y * 0x7FFF / xscreen->xwin_height; + } + else + { + dx = ev_x - last_x; + dy = ev_y - last_y; + } + + kbd_mouse_event(dx, dy, 0, state); + + last_x = ev_x; + last_y = ev_y; + } + break; + default: + break; + + } + } + return; +} + +void +x_display_init(DisplayState *ds, int full_screen, unsigned long parent_xid) +{ + Cursor empty_cursor; + Pixmap cursor_pxm; + XColor col; + XSetWindowAttributes attr; + + xscreen = malloc(sizeof(XHostScreen)); + memset(xscreen, 0, sizeof(XHostScreen)); + + if ((xscreen->xdpy = XOpenDisplay(getenv("DISPLAY"))) == NULL) + { + fprintf(stderr, "\nqemu cannot open host display. Is DISPLAY set?\n"); + exit(-1); + } + + xscreen->xscreen = DefaultScreen(xscreen->xdpy); + xscreen->xwinroot = RootWindow(xscreen->xdpy, xscreen->xscreen); + xscreen->xgc = XCreateGC(xscreen->xdpy, xscreen->xwinroot, 0, NULL); + xscreen->xdepth = DefaultDepth(xscreen->xdpy, xscreen->xscreen); + xscreen->xvisual = DefaultVisual(xscreen->xdpy, xscreen->xscreen); + + attr.event_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask + |KeyPressMask|KeyReleaseMask|ExposureMask + |FocusChangeMask|EnterWindowMask|LeaveWindowMask; + + xscreen->xwin = XCreateWindow(xscreen->xdpy, + xscreen->xwinroot, + 0,0,640,480, + 0, + CopyFromParent, + CopyFromParent, + CopyFromParent, + CWEventMask, + &attr); + + xscreen->have_shm = True; + + if (!XShmQueryExtension(xscreen->xdpy) || getenv("QEMU_X_NO_SHM")) + { + xscreen->have_shm = False; + } + else + { + XShmSegmentInfo shminfo; + + shminfo.shmid=shmget(IPC_PRIVATE, 1, IPC_CREAT|0777); + shminfo.shmaddr=shmat(shminfo.shmid,0,0); + shminfo.readOnly=True; + + x_errors_trap(); + + XShmAttach(xscreen->xdpy, &shminfo); + XSync(xscreen->xdpy, False); + + if (x_errors_untrap()) + { + fprintf(stderr, "QEmu unable to use SHM XImages\n"); + xscreen->have_shm = False; + } + + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + } + + if (!kbd_mouse_is_absolute()) + { + /* Only hide cursor if were not a touchscreen */ + cursor_pxm = XCreatePixmap (xscreen->xdpy, xscreen->xwinroot, 1, 1, 1); + memset (&col, 0, sizeof (col)); + empty_cursor = XCreatePixmapCursor (xscreen->xdpy, + cursor_pxm, cursor_pxm, + &col, &col, 1, 1); + XDefineCursor (xscreen->xdpy, xscreen->xwin, empty_cursor); + XFreePixmap (xscreen->xdpy, cursor_pxm); + } + + ds->dpy_update = x_update; + ds->dpy_resize = x_resize; + ds->dpy_refresh = x_refresh; + + if ((qemu_set_fd_handler2 (ConnectionNumber(xscreen->xdpy), + x_listen_poll, x_listen_read, NULL, ds)) == -1) + exit(-1); + + x_resize(ds, 640, 480); +}