/* * display.c: X11 display of frames * * Written by: Ullrich Hafner * * This file is part of FIASCO (Fractal Image And Sequence COdec) * Copyright (C) 1994-2000 Ullrich Hafner * * Based on mpeg2decode, (C) 1994, MPEG Software Simulation Group * and mpeg2play, (C) 1994 Stefan Eckart * * and tmndec (C) 1995, 1996 Telenor R&D, Norway */ /* * $Date: 2000/07/03 19:35:59 $ * $Author: hafner $ * $Revision: 5.2 $ * $State: Exp $ */ #include "config.h" #ifndef X_DISPLAY_MISSING #include #include #include #include #include #include "types.h" #include "macros.h" #include "display.h" #include "binerror.h" /***************************************************************************** shared memory functions (if USE_SHM is defined) *****************************************************************************/ #ifdef USE_SHM #ifdef HAVE_FEATURES_H #include #endif #include #include #include #include int XShmQueryExtension (Display *dpy); int XShmGetEventBase (Display *dpy); static int HandleXError (Display *dpy, XErrorEvent *event); static void InstallXErrorHandler (x11_info_t *xinfo); static void DeInstallXErrorHandler (x11_info_t *xinfo); static int shmem_flag; static XShmSegmentInfo shminfo1, shminfo2; static int gXErrorFlag; static int CompletionType = -1; static int HandleXError (Display *dpy, XErrorEvent *event) { gXErrorFlag = 1; return 0; } static void InstallXErrorHandler (x11_info_t *xinfo) { XSetErrorHandler (HandleXError); XFlush (xinfo->display); } static void DeInstallXErrorHandler (x11_info_t *xinfo) { XSetErrorHandler (NULL); XFlush (xinfo->display); } #endif /* USE_SHM */ /***************************************************************************** public code *****************************************************************************/ void display_image (unsigned x0, unsigned y0, x11_info_t *xinfo) /* * Display 'image' at pos ('x0', 'y0') in the current window * (given by 'xinfo->window'). * * No return value. */ { int byte_order_check = 1; /* * Always work in native bit and byte order. This tells Xlib to * reverse bit and byte order if necessary when crossing a * network. Frankly, this part of XImages is somewhat * underdocumented, so this may not be exactly correct. */ if (*(char *) & byte_order_check == 1) { xinfo->ximage->byte_order = LSBFirst; xinfo->ximage->bitmap_bit_order = LSBFirst; } else { xinfo->ximage->byte_order = MSBFirst; xinfo->ximage->bitmap_bit_order = MSBFirst; } /* Display dithered image */ #ifdef USE_SHM if (shmem_flag) { XEvent xev; XShmPutImage (xinfo->display, xinfo->window, xinfo->gc, xinfo->ximage, 0, 0, x0, y0, xinfo->ximage->width, xinfo->ximage->height, True); XFlush (xinfo->display); while (!XCheckTypedEvent (xinfo->display, CompletionType, &xev)) ; } else #endif /* USE_SHM */ { xinfo->ximage->data = (char *) xinfo->pixels; XPutImage (xinfo->display, xinfo->window, xinfo->gc, xinfo->ximage, 0, 0, x0, y0, xinfo->ximage->width, xinfo->ximage->height); } } void close_window (x11_info_t *xinfo) { #ifdef USE_SHM if (shmem_flag && xinfo->ximage) { XShmDetach (xinfo->display, &shminfo1); XDestroyImage (xinfo->ximage); xinfo->ximage = NULL; shmdt (shminfo1.shmaddr); } else #endif /* USE_SHM */ if (xinfo->ximage) { XDestroyImage (xinfo->ximage); xinfo->ximage = NULL; } if (xinfo->display) { XCloseDisplay (xinfo->display); xinfo->display = NULL; } } x11_info_t * open_window (const char *titlename, const char *iconname, unsigned width, unsigned height) /* * Open a X11 window of size 'width'x'height'. * If 'color' is false then allocate a colormap with grayscales. * Window and icon titles are given by 'titlename' and 'iconname', * respectively. * * Return value: * X11 info struct containing display, gc, window ID and colormap. */ { XVisualInfo visual_template; /* template for XGetVisualInfo() */ XVisualInfo visual_info; /* return value of XGetVisualInfo() */ int visual_n; /* # of matches of XGetVisualInfo */ XEvent xev; XSizeHints hint; XSetWindowAttributes xswa; unsigned int fg, bg; /* foreground and background color */ unsigned int mask; /* event mask */ x11_info_t *xinfo = calloc (1, sizeof (x11_info_t)); long visual_mask; if (!xinfo) error ("Out of memory"); /* * Initialization of display */ xinfo->display = XOpenDisplay (NULL); if (xinfo->display == NULL) error ("Can't open display.\n" "Make sure that your environment variable DISPLAY " "is set correctly."); xinfo->screen = DefaultScreen (xinfo->display); xinfo->gc = DefaultGC (xinfo->display, xinfo->screen); { unsigned depth [] = {32, 24, 16}; int class [] = {TrueColor, PseudoColor}; const char *class_text [] = {"TrueColor", "PseudoColor"}; Status found = 0; unsigned d, c; for (d = 0; !found && d < sizeof (depth) / sizeof (unsigned); d++) for (c = 0; !found && c < sizeof (class) / sizeof (int); c++) { found = XMatchVisualInfo (xinfo->display, xinfo->screen, depth [d], class [c], &visual_info); if (found) fprintf (stderr, "%s : %d bit colordepth.\n", class_text [c], depth [d]); } if (!found && fiasco_get_verbosity ()) error ("Can't find a 16/24/32 bit TrueColor/DirectColor display"); } /* Width and height of the display window */ hint.x = hint.y = 0; hint.min_width = hint.max_width = hint.width = width; hint.min_height = hint.max_height = hint.height = height; hint.flags = PSize | PMinSize | PMaxSize; /* Get some colors */ bg = WhitePixel (xinfo->display, xinfo->screen); fg = BlackPixel (xinfo->display, xinfo->screen); /* Make the window */ mask = CWBackPixel | CWBorderPixel; if (visual_info.depth >= 16) { mask |= CWColormap; xswa.colormap = XCreateColormap (xinfo->display, DefaultRootWindow (xinfo->display), visual_info.visual, AllocNone); } xswa.background_pixel = bg; xswa.border_pixel = fg; xinfo->window = XCreateWindow (xinfo->display, DefaultRootWindow (xinfo->display), 0, 0, width, height, 1, visual_info.depth, InputOutput, visual_info.visual, mask, &xswa); XSelectInput (xinfo->display, xinfo->window, StructureNotifyMask); /* Tell other applications about this window */ XSetStandardProperties (xinfo->display, xinfo->window, titlename, iconname, None, NULL, 0, &hint); /* Map window. */ XMapWindow (xinfo->display, xinfo->window); /* Wait for map. */ do { XNextEvent (xinfo->display, &xev); } while (xev.type != MapNotify || xev.xmap.event != xinfo->window); /* Allocate colors */ return xinfo; } void alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height) /* * Allocate ximage of size 'width'x'height'. * If USE_SHM is defined then use shared memory extensions. * * No return value. * * Side effects: * 'ximage->ximage' and 'ximage->pixels' are set to useful values. */ { char dummy; #ifdef USE_SHM if (XShmQueryExtension(xinfo->display)) { if (fiasco_get_verbosity ()) fprintf (stderr, "Trying shared memory.\n"); shmem_flag = 1; } else { shmem_flag = 0; if (fiasco_get_verbosity ()) fprintf (stderr, "Shared memory does not work on this system\n" "Reverting to normal Xlib.\n"); } if (shmem_flag) CompletionType = XShmGetEventBase (xinfo->display) + ShmCompletion; InstallXErrorHandler (xinfo); if (shmem_flag) { xinfo->ximage = XShmCreateImage (xinfo->display, DefaultVisual (xinfo->display, xinfo->screen), DefaultDepth (xinfo->display, xinfo->screen), ZPixmap, NULL, &shminfo1, width, height); /* If no go, then revert to normal Xlib calls. */ if (xinfo->ximage == NULL) { if (fiasco_get_verbosity ()) fprintf (stderr, "Shared memory error, disabling (Ximage error).\n"); goto shmemerror; } /* Success here, continue. */ shminfo1.shmid = shmget (IPC_PRIVATE, xinfo->ximage->bytes_per_line * xinfo->ximage->height, IPC_CREAT | 0777); if (shminfo1.shmid < 0) { XDestroyImage (xinfo->ximage); if (fiasco_get_verbosity ()) fprintf (stderr, "Shared memory error, disabling (seg id error).\n"); goto shmemerror; } shminfo1.shmaddr = (char *) shmat (shminfo1.shmid, 0, 0); shminfo2.shmaddr = (char *) shmat (shminfo2.shmid, 0, 0); if (shminfo1.shmaddr == ((char *) -1)) { XDestroyImage (xinfo->ximage); if (shminfo1.shmaddr != ((char *) -1)) shmdt (shminfo1.shmaddr); if (fiasco_get_verbosity ()) fprintf (stderr, "Shared memory error, disabling (address error).\n"); goto shmemerror; } xinfo->ximage->data = shminfo1.shmaddr; xinfo->pixels = (byte_t *) xinfo->ximage->data; shminfo1.readOnly = False; XShmAttach (xinfo->display, &shminfo1); XSync (xinfo->display, False); if (gXErrorFlag) { /* Ultimate failure here. */ XDestroyImage (xinfo->ximage); shmdt (shminfo1.shmaddr); if (fiasco_get_verbosity ()) fprintf (stderr, "Shared memory error, disabling.\n"); gXErrorFlag = 0; goto shmemerror; } else shmctl (shminfo1.shmid, IPC_RMID, 0); if (fiasco_get_verbosity ()) fprintf (stderr, "Sharing memory.\n"); } else { shmemerror: shmem_flag = 0; #endif /* USE_SHM */ xinfo->ximage = XCreateImage (xinfo->display, DefaultVisual (xinfo->display, xinfo->screen), DefaultDepth (xinfo->display, xinfo->screen), ZPixmap, 0, &dummy, width, height, 8, 0); xinfo->pixels = calloc (width * height, xinfo->ximage->depth <= 8 ? sizeof (byte_t) : (xinfo->ximage->depth <= 16 ? sizeof (u_word_t) : sizeof (unsigned int))); if (!xinfo->pixels) error ("Out of memory."); #ifdef USE_SHM } DeInstallXErrorHandler (xinfo); #endif /* USE_SHM */ } #endif /* not X_DISPLAY_MISSING */