This is getx11.c in view mode; [Download] [Up]
/* * This software is copyrighted as noted below. It may be freely copied, * modified, and redistributed, provided that the copyright notices are * preserved on all copies. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * You may not include this software in a program or other software product * without supplying the source, or without informing the end-user that the * source is available for no extra charge. * * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. */ /* * getx11.c - Put RLE images on X display. * * Author: Spencer W. Thomas (x10) * Computer Science Dept. * University of Utah * Date: Thu Feb 20 1986 * Copyright (c) 1986, University of Utah * * Modified: Andrew F. Vesper (x 11) * High Performance Workstations * Digital Equipment Corp * Date: Fri, Aug 7, 1987 * Thu, Jan 14, 1988 * Copyright (c) 1987,1988, Digital Equipment Corporation * * Modified: Martin R. Friedmann (better X11, flipbook, mag, pix_info) * Dept of Electrical Engineering and Computer Science * University of Michigan * Date: Tue, Nov 14, 1989 * Copyright (c) 1989, University of Michigan */ #include "getx11.h" /* Make Sys V macros map to BSD macros */ #ifndef _tolower #define _tolower tolower #define _toupper toupper #endif /* must be able to fit 3 * log2 (MAXIMUM_LEVELS) bits in a 32 bit word */ #define DEFAULT_LEVELS 240 #define MAXIMUM_LEVELS 1024 #define icon_name "getx11" /* number of scan lines to be drawn in incremental mode */ #define LINES_DRAWN 10 static int get_pic (); static void update_pic(); extern void init_color(), find_appropriate_visual(), determine_icon_size(); extern void create_windows(), set_watch_cursor(), map_rgb_to_bw(); extern void map_rgb_to_rgb(), set_circle_cursor(), check_pixmap_allocation(); extern void set_timer(), wait_timer(), set_left_ptr_cursor(); extern void MapPixWindow(), DrawPixWindow(), UnmapPixWindow(); extern void DrawSpeedWindow(); /* * Global variables */ double display_gamma = 2.5; /* default gamma for display */ int iflag = 0; int red_shift; int green_shift; int blue_shift; Pixel red_mask; Pixel green_mask; Pixel blue_mask; Pixel pixel_base; Pixel black_pixel; Pixel white_pixel; char *progname = NULL; Display *dpy = NULL; Window root_window = NULL; int screen = 0; Boolean debug_flag = False; /* set if debug mode -D */ Boolean verbose_flag = False; /* set if verbose mode -v */ int jump_flag = 0, stingy_flag = 0; int specified_levels = 0; int no_color_ref_counts = 0; static struct { CONST_DECL char *string; int type; } visual_type_table[] = { { "staticgray", StaticGray}, { "grayscale", GrayScale}, { "staticgrey", StaticGray}, { "greyscale", GrayScale}, { "staticcolor", StaticColor}, { "pseudocolor", PseudoColor}, { "truecolor", TrueColor}, { "directcolor", DirectColor} }; image_information *img_info = NULL; void init_img_info( i ) image_information *i; { i->window = i->icn_window = NULL; i->pixmap = i->icn_pixmap = NULL; i->pix_info_window = NULL; i->gc = i->icn_gc = NULL; i->image = i->icn_image = NULL; i->colormap = NULL; i->visual_class = -1; i->pixmap_failed = False; i->filename = NULL; i->img_num = 0; i->title = NULL; i->fd = stdin; i->img_channels = 0; i->dpy_channels = 0; i->scan_data = NULL; i->map_scanline = NULL; i->MAG_scanline = NULL; i->gamma = 0.0; i->x = i->y = 0; i->w = i->h = 0; i->icn_w = i->icn_h = 0; i->icn_factor = 1; i->mag_x = i->mag_x = 0; i->mag_w = i->mag_h = 0; i->mag_fact = 1; i->save_mag_fact = 1; i->mag_mode = False; i->mag_pixmap = NULL; i->binary_img = False; i->dither_img = False; i->mono_img = False; i->rw_cmap = False; i->sep_colors = False; i->mono_color = False; i->color_dpy = True; i->in_cmap = NULL; i->ncmap = 0; i->cmlen = 0; i->modN = NULL; i->divN = NULL; i->dm16 = NULL; i->pixel_table = NULL; } /***************************************************************** * TAG( main ) * * Usage: * getx11 [-F] [-D] [-d display] [-= window-geometry] [-l levels] [-z] * [-{iI} gamma] [-g gamma] [-x visualtype] [-n] [-b] [-m] * [-v] [files] * Inputs: * -F: Dont fork after putting image on screen. * -D: Debug mode: print input file as read. * -b: bitonal; binary black and white * -m: Black & white: reduce color images to monochrome before * display. Advantage is that smoother shading can * be achieved. * -v: Print verbose information. * -d display: Specify display name. * -= window_geometry: * Specify window geometry (but min size set by file). * -i gamma: Specify gamma of image. (default 1.0) * -I gamma: Specify gamma of display image was computed for. * -g gamma: Specify gamma of display. (default 2.5) * -V vis_type: Specify visual type to be used (string or int, 0 to 5) * -l levels: number of levels to display of each color * -z: hold all output, then blast it all out at once * -n: Do not dither * * file: Input Run Length Encoded file. Uses stdin if not * specified. * * getx11 will also read picture comments from the input file to determine * the image gamma. These are * * image_gamma= gamma of image (equivalent to -i) * display_gamma= gamma of display image was computed for. * * Any command line arguments override the values in the file. * * Outputs: * Puts image on screen. * Assumptions: * Input file is in RLE format. * Algorithm: * [None] */ void main (argc, argv) int argc; char ** argv; { char ** infnames = NULL; char * display_name = NULL; char * window_geometry = NULL; int n_malloced, num_imgs = 0, using_stdin; int levels; int nfile = 0, forkflg = 0, dflag = 0, gflag = 0, wflag = 0; int vflag = 0, aflag = 0, bin_flag = 0, mono_flag = 0; int tflag = 0; int flip_book = 0; int flip_book_frams_sec = 30; char *vis_type = NULL, *title_string = NULL; int visual_type = -1; int status, done = 0, rle_cnt = -1; image_information *img, *previous_img; double image_gamma = 0.0; /* default gamma for image */ progname = argv[0]; if ( scanargs( argc, argv, "% =%-window-geometry!s a%- d%-display!s D%- f%- \n\ g%-gamma!F iI%-gamma!F j%- m%-maxframes/sec%d n%-levels!d \n\ s%- t%-title!s v%- wW%- x%-visual!s file%*s", &wflag, &window_geometry, &aflag, &dflag, &display_name, &debug_flag, &forkflg, &gflag, &display_gamma, &iflag, &image_gamma, &jump_flag, &flip_book, &flip_book_frams_sec, &specified_levels, &specified_levels, &stingy_flag, &tflag, &title_string, &verbose_flag, &bin_flag, &vflag, &vis_type, &nfile, &infnames ) == 0 ) exit(1); /* Check for -w instead of -W. */ if ( bin_flag == 2 ) { bin_flag = 0; mono_flag = 1; } using_stdin = ( nfile ? False : True ); n_malloced = ( using_stdin ? 1 : nfile ); img_info = (image_information *)malloc(n_malloced * sizeof(image_information) ); if ( img_info == NULL ){ perror("malloc returned NULL"); exit (1); } if ( vflag != 0) { if (isdigit (vis_type[0]) ) { visual_type = atoi (vis_type); } else { register char *ptr; register int i; visual_type = 9999; for (ptr = vis_type; *ptr != '\0'; ptr++) { if (isupper(*ptr)) *ptr = _tolower(*ptr); } for (i = 0; i < COUNT_OF (visual_type_table); i++) { if (strcmp (visual_type_table[i].string, vis_type) == 0) { visual_type = visual_type_table[i].type; break; } } } if ( visual_type < 0 || visual_type > 5 ) { fprintf ( stderr, "Bad visual type %s, ignoring request\n", vis_type); visual_type = -1; } } levels = specified_levels; if (levels == 0) levels = DEFAULT_LEVELS; /* default starting point */ if (levels > MAXIMUM_LEVELS) levels = MAXIMUM_LEVELS; /* * open the display */ if (display_name == NULL || *display_name == '\0') display_name = getenv("DISPLAY"); dpy = XOpenDisplay(display_name); /* Work around bug in X11/NeWS server colormap allocation. */ if (strcmp("X11/NeWS - Sun Microsystems Inc.", ServerVendor(dpy)) == 0 && VendorRelease(dpy) == 2000) no_color_ref_counts = True; if (dpy == NULL) { fprintf(stderr, "%s: Cant open display %s\n", progname, (display_name == NULL) ? "" : display_name); exit(1); } /* * For each file, display it. */ do { if ( num_imgs >= n_malloced ) img_info = (image_information *) realloc( img_info, ++n_malloced * sizeof(image_information) ); if ( img_info == 0 ) { fprintf(stderr, "%s: Out of memory!\n", progname); exit( RLE_NO_SPACE ); } img = &img_info[num_imgs]; init_img_info( img ); /* we need pixmaps for movie mode... */ if ( stingy_flag && !flip_book ) img_info[0].pixmap_failed = True; if ( iflag == 2 && image_gamma != 0.0 ) img->gamma = 1.0 / image_gamma; else if ( iflag == 1 ) img->gamma = image_gamma; img->binary_img = ( bin_flag ? True : False ); img->mono_img = ( mono_flag || bin_flag ? True : False ); if ( img->mono_img ) img->color_dpy = False; img->dither_img = ( aflag == 0 ); img->visual_class = visual_type; img->lvls = levels; img->lvls_squared = levels * levels; if ( img->mono_img ) img->dpy_channels = 1; if ( flip_book && img != &img_info[0] ) { previous_img = img - 1; #define INHERIT( thing ) img->thing = previous_img->thing INHERIT(window); INHERIT(icn_window); INHERIT(icn_pixmap); INHERIT(gc); INHERIT(icn_gc); INHERIT(pixmap_failed); INHERIT(divN); INHERIT(modN); INHERIT(dm16); INHERIT(pixel_table); INHERIT(lvls); INHERIT(lvls_squared); INHERIT(colormap); INHERIT(visual_class); INHERIT(dpy_depth); INHERIT(dpy_channels); INHERIT(sep_colors); INHERIT(rw_cmap); INHERIT(dither_img); INHERIT(color_dpy); INHERIT(mono_img); INHERIT(binary_img); #undef INHERIT } else previous_img = NULL; if ( !using_stdin ) { /* rle_cnt will be set to -1 when it is time to open a new * file. */ if ( rle_cnt < 0 ) { if ( strcmp( *infnames, "-" ) == 0 ) { img->filename = "Standard Input"; img->fd = stdin; } else { img->filename = *infnames; img->fd = rle_open_f_noexit( "getx11", img->filename, "r"); if (img->fd == NULL) { if ( nfile == 1 ) exit (1); else { nfile--; infnames++; continue; } } } rle_cnt = 0; } else { /* Safe to copy from previous image because this is at * least the second one in this file. */ img->filename = img[-1].filename; img->fd = img[-1].fd; } } else { img->filename = "Standard Input"; img->fd = stdin; if ( rle_cnt < 0 ) rle_cnt = 0; } img->img_num = rle_cnt; if ( tflag && title_string ) img->title = title_string; status = get_pic( img, window_geometry, previous_img ); switch (status){ case SUCCESS: num_imgs++; rle_cnt++; break; case MALLOC_FAILURE: case RLE_NO_SPACE: fprintf(stderr,"%s: Out of Memory! Trying to continue\n",progname); if ( !using_stdin ) { fclose( img->fd ); nfile--; infnames++; } rle_cnt = -1; break; case RLE_EMPTY: case RLE_EOF: case RLE_NOT_RLE: if ( status == RLE_NOT_RLE || rle_cnt == 0 ) rle_get_error( status, progname, img->filename ); if ( using_stdin ) done = 1; else { fclose( img->fd ); nfile--; infnames++; if ( nfile == 0 ) done = 1; } rle_cnt = -1; break; case FATAL_FAILURE: if ( flip_book ) fprintf(stderr,"%s: Cannot flip-book, sorry...\n", progname); exit(1); break; } } while( !done ); #ifdef unix if ( ! forkflg ) { if ( fork() == 0 ) { close( 0 ); close( 1 ); close( 2 ); /* Set process group to avoid signals under sh. */ #ifdef SYS_V_SETPGRP (void)setpgrp(); #else (void)setpgrp( 0, getpid() ); #endif update_pic ( img_info, num_imgs, flip_book, flip_book_frams_sec ); } else exit( 0 ); } else #endif update_pic ( img_info, num_imgs, flip_book, flip_book_frams_sec ); XCloseDisplay( dpy ); } /* returns how many lines it blitted */ void handle_exposure( img, x, y, width, height, img_h ) register image_information *img; int x, y, width, height, img_h; { /* * If window has been resized (bigger), dont bother redrawing * the area outside the image. */ if (x < 0) { width -= x; x = 0; } /* if the image has not yet read itself in, dont blit any of it */ /* instead clear out that top portion of the window(not needed oh well) */ if (y < img->h - img_h ) { XClearArea( dpy, img->window, x, y, width, img->h - img_h - y, False ); height -= img->h - img_h - y; y = img->h - img_h; } if ( height <= 0 ) return; if (y + height >= img->h) height = img->h - y; /* * if bitmap, round beginning pixel to beginning of word */ if ( img->binary_img ) { int offset = x % BitmapPad (dpy); x -= offset; width += offset; } if (x + width >= img->w) width = img->w - x; if ( width <= 0 || height <= 0 ) return; if ( img->refresh_pixmap ) XCopyArea(dpy, img->refresh_pixmap, img->window, img->gc, x, y, width, height, x, y ); else XPutImage(dpy, img->window, img->gc, img->image, x, y, x, y, width, height ); return; } /* * Read an image from the input file and display it. */ static int get_pic( img, window_geometry, previous_img ) register image_information *img, *previous_img; char *window_geometry; { int image_xmax, image_ymax; int y; unsigned char *save_scan[3], *read_scan[3]; register int i; register int image_y; register int next_y, y_base, lines_buffered; int rle_err; extern void choose_scanline_converter(); extern XImage * get_X_image(); extern int eq_cmap(); extern void get_dither_colors(); /* * Read setup info from file. */ rle_dflt_hdr.rle_file = img->fd; if ( (rle_err = rle_get_setup(&rle_dflt_hdr)) < 0) return ( rle_err ); /* XXX if ( debug_flag ) rle_debug( 1 ); else rle_debug (0); */ image_xmax = rle_dflt_hdr.xmax; image_ymax = rle_dflt_hdr.ymax; img->x = rle_dflt_hdr.xmin; img->y = rle_dflt_hdr.ymin; img->w = image_xmax - rle_dflt_hdr.xmin + 1; img->h = image_ymax - rle_dflt_hdr.ymin + 1; img->mag_w = img->w; img->mag_h = img->h; rle_dflt_hdr.xmin = 0; rle_dflt_hdr.xmax = img->w - 1; /* Were only interested in R, G, & B */ RLE_CLR_BIT(rle_dflt_hdr, RLE_ALPHA); for (i = 3; i < rle_dflt_hdr.ncolors; i++) RLE_CLR_BIT(rle_dflt_hdr, i); img->dpy_channels = img->img_channels = (rle_dflt_hdr.ncolors > 3 ) ? 3 : rle_dflt_hdr.ncolors; if ( img->img_channels == 1 ) img->mono_img = True; if ( img->mono_img ) img->dpy_channels = 1; if ( !previous_img ) /* find a suitable visual for the image */ find_appropriate_visual( img ); if ( img->img_channels < img->dpy_channels ) fprintf(stderr, "%s: dpy_channels > img_channels, %d > %d\n", progname, img->dpy_channels, img->img_channels); get_dither_colors( img ); if ( !previous_img ) /* Get X color map */ init_color( img ); if ( !img->title ) if ( (img->title = rle_getcom("image_title", &rle_dflt_hdr )) == NULL && (img->title = rle_getcom("IMAGE_TITLE", &rle_dflt_hdr )) == NULL && (img->title = rle_getcom("title", &rle_dflt_hdr )) == NULL && (img->title = rle_getcom("TITLE", &rle_dflt_hdr )) == NULL ) { if ( img->img_num > 0 ) { img->title = (char *)malloc( strlen( img->filename ) + 8 ); sprintf( img->title, "%s(%d)", img->filename, img->img_num + 1 ); } else img->title = img->filename; } /* * Here if we are flip_booking we gotta get nasty here... img->w, img->h * and img->img_channels must match for well surely be screwed if they * dont match up and we flip_book */ if ( previous_img ) { if ( img->w != previous_img->w || img->h != previous_img->h || img->img_channels != previous_img->img_channels ) { fprintf( stderr, "%s: Images %s and %s dont match in size or channels\n", progname, previous_img->title, img->title ); return( FATAL_FAILURE ); } if ((img->mono_color && !eq_cmap(previous_img->in_cmap, previous_img->cmlen, img->in_cmap, img->cmlen))) { fprintf( stderr, "%s: Images %s and %s have different colormaps\n", progname, previous_img->title, img->title ); return( FATAL_FAILURE ); } } /* * Here we have to conserve memory on the client side and not allocate a * new Ximage structure with associated memory for image data. Also, if * the server was unable to supply us with a pixmap in previous_img, then * we need to save the XImage there... */ if ( !previous_img || previous_img->pixmap == NULL ) { if ( !img->image ) img->image = get_X_image( img, img->w+1, img->h ); if ( img->image == NULL ) { perror("problem getting XImage"); return( MALLOC_FAILURE ); } } else img->image = previous_img->image; /* only dick with the icon if we are not flip_booking */ if ( !previous_img ) { determine_icon_size( img->w, img->h, &img->icn_w, &img->icn_h, &img->icn_factor); if ( !img->icn_image ) img->icn_image = get_X_image( img, img->icn_w, img->icn_h ); if ( img->icn_image == NULL ) { perror("malloc for fancy icon"); return ( MALLOC_FAILURE ); } } /* * Get image and icon windows of the right size */ create_windows( img, window_geometry ); set_watch_cursor( img->window ); if ( !img->map_scanline ) choose_scanline_converter( img ); /* * If we are going to display a 2 or 3 channel image in one channel (-w) * we have to copy the data anyway, so we will always read it into the * same spot, and map it into a saved_data array with only one color per * scanline this saves memory. * * read_scan[] is the scan data that we read into with rle_getrow. If the * number of image channels is equal to that which is displayed, we will * not mallocate new memory for it, but we will move it throughout the * saved_data along with save_scan. * * save_scan[] is the pointer to the current line in img->saved_data that * we are saving rle_getrows into. * * If we cant malloc the memory for the save_scan[] or we are doing * flip_book, then we dont want to malloc the memory for this thing. */ /* * Set up for rle_getrow. Pretend image x origin is 0. */ /* get img->h rows mem. SAVED_RLE_ROW uses scan_data to calc address!! */ img->scan_data = NULL; /* if we are flip_booking dont mess with this one huh? */ if ( !previous_img ){ img->scan_data = (unsigned char *) malloc ( SAVED_RLE_ROW( img, img->h ) ); if (img->scan_data == NULL) perror ("malloc for scanline buffer failed"); /* use the macro to point us to the last line... start saving here */ save_scan[0] = SAVED_RLE_ROW( img, img->h - 1 ); for (i = 1; i < img->img_channels; i++) save_scan[i] = save_scan[i - 1] + img->w; } /* get one line of scan data for reading if we are doing monochrome */ if ( img->mono_img || img->scan_data == NULL ) { read_scan[0] = (unsigned char *) malloc ( img->w * img->img_channels ); if ( read_scan[0] == NULL ) { perror ("malloc for read_scan buffer failed"); return ( MALLOC_FAILURE ); } for (i = 1; i < img->img_channels; i++) read_scan[i] = read_scan[i - 1] + img->w; } else read_scan[0] = save_scan[0], read_scan[1] = save_scan[1], read_scan[2] = save_scan[2]; if (img->scan_data == NULL) save_scan[0] = read_scan[0], save_scan[1] = read_scan[1], save_scan[2] = read_scan[2]; /* * For each scan line, read it, save it, dither it and display it. */ next_y = img->h - 1; y_base = next_y; lines_buffered = 0; while ((image_y = rle_getrow(&rle_dflt_hdr, read_scan)) <= rle_dflt_hdr.ymax ) { y = image_ymax - image_y; if ( img->mono_img ) map_rgb_to_bw ( img, read_scan, save_scan[0] ); else map_rgb_to_rgb ( img, read_scan, save_scan ); (*img->map_scanline) (img, save_scan, img->dpy_channels, img->w, 1, y, img->image); /* Subsample image to create icon */ if ( !previous_img && y % img->icn_factor == 0 ) (*img->map_scanline)( img, save_scan, img->dpy_channels, img->icn_w, img->icn_factor, y / img->icn_factor, img->icn_image); next_y = y - 1; while ( XPending( dpy ) ) { XEvent event; XNextEvent(dpy, &event); if (event.type == Expose) { image_information *eimg; /* get the right window bro.... */ for (eimg = img_info; eimg <= img; eimg++ ) if ( eimg->window == event.xany.window ) break; if (previous_img) eimg = img; /*flip_book override */ if (eimg <= img) /* protect against screwy window */ handle_exposure(eimg, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height, (eimg == img) ? image_y : eimg->h ); } XFlush(dpy); } if (++lines_buffered >= LINES_DRAWN||(img->fd == stdin && !jump_flag)){ y_base -= lines_buffered - 1; XPutImage( dpy, img->pixmap?img->pixmap:img->window, img->gc, img->image, 0, y_base, 0, y_base, img->w,lines_buffered); if ( img->pixmap ) XCopyArea( dpy, img->pixmap, img->window, img->gc, 0, y_base, img->w, lines_buffered, 0, y_base ); y_base = next_y; lines_buffered = 0; } if ( img->scan_data ) { /* move scan up one line */ save_scan[0] = SAVED_RLE_ROW ( img, next_y ); for( i = 1; i < img->img_channels; i++ ) save_scan[i] = save_scan[i - 1] + img->w; } /* * remember? if were saving more than one channel then we dont need * to move the data after we read it... So kludge read_scan ... */ if ( !img->mono_img && img->scan_data ) read_scan[0] = save_scan[0], read_scan[1] = save_scan[1], read_scan[2] = save_scan[2]; if ( img->scan_data == NULL) save_scan[0] = read_scan[0], save_scan[1] = read_scan[1], save_scan[2] = read_scan[2]; } if ( lines_buffered > 0 ) { y_base -= lines_buffered - 1; XPutImage( dpy, img->pixmap?img->pixmap:img->window, img->gc, img->image, 0, y_base, 0, y_base, img->w, lines_buffered ); if ( img->pixmap ) XCopyArea( dpy, img->pixmap, img->window, img->gc, 0, y_base, img->w, lines_buffered, 0, y_base ); } if ( !previous_img && img->icn_pixmap ) { XPutImage( dpy, img->icn_pixmap, img->icn_gc, img->icn_image, 0, 0, 0, 0, img->icn_w, img->icn_h ); XClearWindow( dpy, img->icn_window ); } set_circle_cursor( img->window ); /* free this if we mallocated it */ if ( img->mono_img || !img->scan_data ) free ( read_scan[0] ); return (SUCCESS); } /* * Track events & redraw image when necessary. */ /* now thats my kinda action! */ #define ACTION_MAGNIFY 0 #define ACTION_UNMAGNIFY 1 #define ACTION_PAN 2 #define ACTION_SWITCH_MAG_MODE 3 #define ACTION_FLIP_FORWARD 4 #define ACTION_FLIP_STEP 5 #define ACTION_FLIP_BACKWARD 6 #define ACTION_FLIP_SPEED 7 #define ACTION_PIXEL_INFO 8 #define ACTION_CYCLE 9 #define ACTION_CYCLE_TO_AND_FRO 10 #define ACTION_DEFAULT ACTION_PAN /* define what to do on mouse buttons */ static int button_action[3][2] = { ACTION_MAGNIFY, ACTION_PIXEL_INFO, ACTION_PAN, ACTION_SWITCH_MAG_MODE, ACTION_UNMAGNIFY, ACTION_PIXEL_INFO }; /* define what to do on flip_book mouse buttons */ static int flip_action[3][2] = { ACTION_FLIP_BACKWARD, ACTION_CYCLE, ACTION_FLIP_STEP, ACTION_FLIP_SPEED, ACTION_FLIP_FORWARD, ACTION_CYCLE_TO_AND_FRO }; static void mag_pan( img, action, bx, by, new_mag_fact ) image_information *img; int action, bx, by, new_mag_fact; { Boolean fast_pan = False; Boolean redraw = False; Boolean redither = False; int ix = img->mag_x + bx / img->mag_fact; int iy = img->mag_y + by / img->mag_fact; int omag_x, omag_y; /* perhaps we could re-open the img->filename to do this... */ /* but NAHHHHHHH */ if ( img->scan_data == NULL ) return; switch ( action ) { /* * Normalize has to switch the current mag factor with 1 if they * differ... It also remembers the old mag_x and mag_y and stuff. It * should use the pixmaps to refresh, so that it will be fast when * toggeling in this mode... */ case ACTION_SWITCH_MAG_MODE: if ( img->mag_fact == img->save_mag_fact ) return; else { if ( img->mag_fact == 1 ) { img->mag_mode = True; img->mag_fact = img->save_mag_fact; img->mag_x = img->save_mag_x; img->mag_y = img->save_mag_y; img->mag_w = img->save_mag_w; img->mag_h = img->save_mag_h; img->save_mag_x = 0; img->save_mag_y = 0; img->save_mag_w = img->w; img->save_mag_h = img->h; img->save_mag_fact = 1; img->refresh_pixmap = img->mag_pixmap; } else { img->mag_mode = False; img->save_mag_x = img->mag_x; img->save_mag_y = img->mag_y; img->save_mag_w = img->mag_w; img->save_mag_h = img->mag_h; img->save_mag_fact = img->mag_fact; img->mag_x = 0; img->mag_y = 0; img->mag_w = img->w; img->mag_h = img->h; img->mag_fact = 1; img->refresh_pixmap = img->pixmap; } redraw = True; } break; case ACTION_MAGNIFY: case ACTION_UNMAGNIFY: img->mag_fact = new_mag_fact; if ( img->mag_fact <= 1 ) { img->mag_fact = 1; img->mag_x = 0; img->mag_y = 0; img->mag_w = img->w; img->mag_h = img->h; img->refresh_pixmap = img->pixmap; if ( img->mag_mode ) redraw = True; img->mag_mode = False; break; } else img->mag_mode = True; img->mag_x = ix - ((img->w / 2)/img->mag_fact); img->mag_y = iy - ((img->h / 2)/img->mag_fact); img->mag_w = img->w/img->mag_fact; img->mag_h = img->h/img->mag_fact; if ( !img->mag_pixmap && !img->pixmap_failed && !stingy_flag ) { img->mag_pixmap = XCreatePixmap(dpy, img->window, img->w, img->h, img->dpy_depth ); check_pixmap_allocation( img ); } img->refresh_pixmap = img->mag_pixmap; redither = True; redraw = True; break; case ACTION_PAN: do { fast_pan = img->mag_mode; /* are we REALLY just panning around? */ omag_x = img->mag_x; omag_y = img->mag_y; if ( !img->mag_mode ) { img->mag_fact = img->save_mag_fact; img->save_mag_fact = 1; } if ( img->mag_fact > 1 ) img->mag_mode = True; else return; img->refresh_pixmap = img->mag_pixmap; img->mag_x = ix - ((img->w / 2)/img->mag_fact); img->mag_y = iy - ((img->h / 2)/img->mag_fact); /* Isnt this always like this? */ img->mag_w = img->w/img->mag_fact; img->mag_h = img->h/img->mag_fact; redither = True; redraw = True; } while (0); break; } /* check bounds */ if ( img->mag_x < 0 ) img->mag_x = 0; if ( img->mag_y < 0 ) img->mag_y = 0; if ( img->mag_x + img->mag_w > img->w ) { img->mag_x = img->w - img->mag_w; if ( img->mag_w * img->mag_fact < img->w ) img->mag_x -= 1; } if ( img->mag_y + img->mag_h > img->h ) { img->mag_y = img->h - img->mag_h; if ( img->mag_h * img->mag_fact < img->h ) img->mag_y -= 1; } /* check bounds */ if ( img->mag_x < 0 ) img->mag_x = 0; if ( img->mag_y < 0 ) img->mag_y = 0; /* let the suckers know that we are thinking */ set_watch_cursor( img->window ); /* * Some could argue that this fast_pan shit is a waste of time, but it * does speed things up a bunch, and its really hard to understand. * Sorry, no fancy pictures in the comments. Just code. We figure out * which rectangle is blt-able. We blt it on the server side, and on the * client side (my fancy XCopyImage) and then MAG_scanline the exposed * area and XPutImage that stuff too... Dont change it cuz its right. */ if ( fast_pan ) { int width, hight; int src_x, src_y, dst_x, dst_y; int pwidth = omag_x - img->mag_x; int phight = omag_y - img->mag_y; pwidth = img->mag_w - (( pwidth < 0 ) ? - pwidth : pwidth); phight = img->mag_h - (( phight < 0 ) ? - phight : phight); /* * pwidth and phight now contain the size of the non-changing * (BLT-able) portion of the viewport in rle_pixel space. */ width = pwidth * img->mag_fact + (img->w - img->mag_w * img->mag_fact); hight = phight * img->mag_fact + (img->h - img->mag_h * img->mag_fact); /* Now we compute the src_xy and dst_xy for the pixel copy */ if ( omag_x < img->mag_x ) { dst_x = 0; src_x = img->w - width;} else { src_x = 0; dst_x = img->w - width;} if ( omag_y < img->mag_y ) { dst_y = 0; src_y = img->h - hight;} else { src_y = 0; dst_y = img->h - hight;} /* subtract partial pixels if we are going right */ if ( omag_x < img->mag_x ) width -= img->w - img->mag_w * img->mag_fact; /* subtract partial pixels if we are going down */ if ( omag_y < img->mag_y ) hight -= img->h - img->mag_h * img->mag_fact; if ( src_x == dst_x && src_y == dst_y ) { redraw = False; redither = False; } else { /* XCopyImage is only implemented for 8 and 32 bit image pixels */ if (img->refresh_pixmap && XCopyImage(img->image, src_x, src_y, width, hight, dst_x, dst_y)) { XCopyArea ( dpy, img->refresh_pixmap, img->refresh_pixmap, img->gc, src_x, src_y, width, hight, dst_x, dst_y ); if ( dst_y ) { (*img->MAG_scanline)(img, img->mag_x, img->mag_y, img->mag_fact, 0, 0, img->w, dst_y, img->image ); XPutImage( dpy, img->refresh_pixmap, img->gc, img->image, 0, 0, 0, 0, img->w, dst_y); } else { if (hight < img->h) { (*img->MAG_scanline) (img, img->mag_x, img->mag_y + phight, img->mag_fact, 0, hight, img->w, img->h - hight, img->image ); XPutImage(dpy, img->refresh_pixmap, img->gc, img->image, 0, hight, 0, hight, img->w, img->h - hight ); } } if ( dst_x ) { if (hight && width < img->w) { (*img->MAG_scanline) (img, img->mag_x, img->mag_y + ((dst_y) ? img->mag_h - phight: 0), img->mag_fact, 0, dst_y, img->w - width, hight, img->image ); XPutImage(dpy, img->refresh_pixmap, img->gc,img->image, 0, dst_y, 0, dst_y, img->w - width, hight ); } } else { if (hight && width < img->w) { (*img->MAG_scanline) (img, img->mag_x + pwidth, img->mag_y + ((dst_y) ? img->mag_h - phight: 0), img->mag_fact, width, dst_y, img->w - width, hight, img->image ); XPutImage(dpy, img->refresh_pixmap, img->gc, img->image, width, dst_y, width, dst_y, img->w - width, hight ); } } /* * We already redithered... If XCopyImage failed we arent * here and we have to redither the whole thing below. */ redither = False; } } } /* redither the whole thing */ if ( redither || ( redraw && !img->refresh_pixmap ) ) { (*img->MAG_scanline)(img, img->mag_x, img->mag_y, img->mag_fact, 0, 0, img->w, img->h, img->image ); XPutImage( dpy, (img->refresh_pixmap?img->refresh_pixmap:img->window), img->gc, img->image, 0, 0, 0, 0, img->w, img->h ); } if ( redraw && img->refresh_pixmap ) XCopyArea( dpy, img->refresh_pixmap, img->window, img->gc, 0, 0, img->w, img->h, 0, 0 ); set_circle_cursor( img->window ); } image_information *action_flip_forward( img, img_info, flip_book_udelay, n, mask, event, found_event ) image_information *img, *img_info; int flip_book_udelay, n; unsigned long mask; XEvent *event; Boolean *found_event; { if (mask) *found_event = False; if ( img == &img_info[n - 1] ) img = &img_info[0]; for ( ; img < &img_info[n]; img++ ) { set_timer( flip_book_udelay ); handle_exposure(img, 0, 0, img->w, img->h, img->h); if (img->fd != stdin && flip_book_udelay ) /* as fast as possible */ XStoreName(dpy, img->window, img->title); XFlush( dpy ); if (mask && XCheckMaskEvent(dpy, mask, event )){ *found_event = True; break; } wait_timer(); } if (mask && *found_event) return img; else return img - 1; } image_information *action_flip_backward( img, img_info, flip_book_udelay, n, mask, event, found_event ) image_information *img, *img_info; int flip_book_udelay, n; unsigned long mask; XEvent *event; Boolean *found_event; { if (mask) *found_event = False; if ( img == img_info ) img = &img_info[n - 1]; for ( ; img >= &img_info[0]; img-- ) { set_timer( flip_book_udelay ); handle_exposure(img, 0, 0, img->w, img->h, img->h); if (img->fd != stdin && flip_book_udelay ) /* as fast as possible */ XStoreName(dpy, img->window, img->title); XFlush( dpy ); if (mask && XCheckMaskEvent(dpy, mask, event )){ *found_event = True; break; } wait_timer(); } if (mask && *found_event) return img; else return img + 1; } image_information *action_flip_book_cycle( img, img_info, n, flip_forward, flip_book_udelay ) image_information *img, *img_info; int n, flip_book_udelay; Boolean flip_forward; { int found_event; XEvent event; do { img = (* (flip_forward ? action_flip_forward : action_flip_backward)) (img, img_info, flip_book_udelay, n, ButtonPressMask|KeyPressMask, &event, &found_event); XSync(dpy, False); } while ( !found_event ); return img; } static void update_pic( img_info, n, flip_book, flip_book_frams_sec ) image_information *img_info; int n, flip_book_frams_sec; Boolean flip_book; { int i; XEvent event; int action; register image_information *img; int found_event; /* variables to use for flip_book mode */ image_information *flip_frame = NULL; Boolean flip_forward = True; Window dead_window; int flip_book_udelay = 0; if ( flip_book ) flip_frame = img_info; while (n) { XNextEvent(dpy, &event); if ( flip_book ){ /* all windows are the same! */ flip_book_udelay = (flip_book_frams_sec) ? 1000000 / flip_book_frams_sec : 0; img = flip_frame; } else for ( img = img_info; img < &img_info[n]; img++ ) if ( img->window == event.xany.window ) break; switch (event.type) { case ButtonPress: i = event.xbutton.button - Button1; if (i < 0 || i > COUNT_OF(button_action) ) action = ACTION_DEFAULT; else if ( flip_book ) action = flip_action[i][event.xbutton.state & ShiftMask]; else action = button_action[i][event.xbutton.state & ShiftMask]; switch (action) { case ACTION_PIXEL_INFO: if ( img->scan_data ) do {/* X calls by John Bradley, U of Penn, hacked up by mrf.... */ Boolean first = 1; int lx = 0, ly = 0; set_left_ptr_cursor( img->window ); MapPixWindow ( img, (event.xbutton.y > img->h/2)); while (1) { /* loop until button released */ Window foo,poo; int rx, ry, x, y; unsigned int mask; if (XQueryPointer(dpy, img->window, &foo, &poo, &rx, &ry, &x, &y, &mask)) { if (!(mask&(Button1Mask|Button2Mask|Button3Mask))) break; /* released */ x /= img->mag_fact; y /= img->mag_fact; x += img->mag_x; y += img->mag_y; /* wait for new pixel */ if ((first || x != lx || y != ly) && (x >= 0 && x < img->w && y >= 0 && y < img->h)) { DrawPixWindow( img, x, y ); first = 0; lx = x; ly = y; } } else break; } set_circle_cursor( img->window ); UnmapPixWindow ( img ); } while (0); continue; case ACTION_FLIP_SPEED: if (flip_book) do {/* X calls by John Bradley, U of Penn, hacked up by mrf.... */ Boolean first = 1; int height = DisplayHeight(dpy, screen)/4; /* use DH/4 */ int s, ly = 0; s = flip_book_frams_sec; MapPixWindow ( img, True ); while (1) { /* loop until button released */ Window foo,poo; int rx, ry, x, y, inc; unsigned int mask; if (XQueryPointer(dpy, img->window, &foo, &poo, &rx, &ry, &x, &y, &mask)) { if (!(mask&(Button1Mask|Button2Mask|Button3Mask))) break; /* released */ if ( first ) ly = y; inc = (ly - y) * 100 / height; /* wait for new pixel */ if ((first || flip_book_frams_sec + inc != s ) ) { s = flip_book_frams_sec + inc; s = (s < 0) ? 0 : s; s = (s > 100) ? 100 : s; DrawSpeedWindow( img, s ); first = 0; } } else break; } flip_book_frams_sec = s; UnmapPixWindow ( img ); } while (0); continue; case ACTION_FLIP_BACKWARD: if ( flip_book ) { img = action_flip_backward(img, img_info, flip_book_udelay, n, ButtonPressMask|KeyPressMask, &event, &found_event); flip_frame = img; flip_forward = False; } continue; case ACTION_FLIP_FORWARD: if ( flip_book ) { img = action_flip_forward (img, img_info, flip_book_udelay, n, ButtonPressMask|KeyPressMask, &event, &found_event); flip_frame = img; flip_forward = True; } continue; case ACTION_FLIP_STEP: /* step flip_book in current direction. */ if ( flip_book ) { if ( flip_forward ) { if ( flip_frame == &img_info[n-1] ) img = flip_frame = img_info; else img = flip_frame = flip_frame + 1; } else { if ( flip_frame == img_info ) img = flip_frame = &img_info[n-1]; else img = flip_frame = flip_frame - 1; } handle_exposure(img, 0, 0, img->w, img->h, img->h); XStoreName(dpy, img->window, img->title); } continue; /* cycle in the current (flip_forward) direction */ case ACTION_CYCLE: if ( flip_book ) { flip_frame = img = action_flip_book_cycle ( img, img_info, n, flip_forward, flip_book_udelay ); } continue; case ACTION_CYCLE_TO_AND_FRO: if ( flip_book ) { do { img = (* (flip_forward ? action_flip_forward : action_flip_backward)) (img, img_info, flip_book_udelay, n, ButtonPressMask |KeyPressMask, &event, &found_event); if (!found_event){ flip_forward = !flip_forward; if ( n > 1 ) img = (flip_forward) ? img + 1 : img - 1; } XSync(dpy, False); } while( !found_event ); flip_frame = img; } continue; case ACTION_MAGNIFY: mag_pan ( img, action, event.xbutton.x, event.xbutton.y, img->mag_fact + 1 ); continue; case ACTION_UNMAGNIFY: mag_pan ( img, action, event.xbutton.x, event.xbutton.y, img->mag_fact - 1 ); continue; case ACTION_SWITCH_MAG_MODE: mag_pan ( img, action, event.xbutton.x, event.xbutton.y, img->mag_fact ); continue; case ACTION_PAN: mag_pan ( img, action, event.xbutton.x, event.xbutton.y, img->mag_fact ); continue; default: continue; } break; /* not reached */ case Expose: handle_exposure(img, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height, img->h ); continue; case NoExpose: continue; case KeyPress: { char string[256]; char *symstr, *XKeysymToString( ); KeySym keysym; int length; XComposeStatus stat; Boolean handled_key = True; Boolean shifted_key; length = XLookupString( &event, string, 256, &keysym, &stat ); string [length] = '\0'; symstr = XKeysymToString( keysym ); shifted_key = event.xkey.state & ShiftMask; if ( length == 1 && (string[0] == 'q' || string[0] == 'Q' || string[0] == '\003' )) /* q, Q or ^C */ break; if ( length == 1 ) switch (string[0]) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': mag_pan ( img, ACTION_MAGNIFY, img->w/2, img->h/2, atoi(string)); break; /* back and forth mode */ case 'b': if ( flip_book ) { do { img = (* (flip_forward ? action_flip_forward : action_flip_backward)) (img, img_info, flip_book_udelay, n, ButtonPressMask |KeyPressMask, &event, &found_event); if (!found_event){ flip_forward = !flip_forward; if ( n > 1 ) img = (flip_forward) ? img + 1 : img - 1; } XSync(dpy, False); } while( !found_event ); flip_frame = img; } break; case 'c': case 'C': if ( flip_book ) { flip_forward = (string[0] == 'c'); flip_frame = img = action_flip_book_cycle (img, img_info, n, flip_forward, flip_book_udelay); } break; case ' ': /* step flip_book in current direction. */ if ( flip_book ) { if ( flip_forward ) { if ( flip_frame == &img_info[n-1] ) img = flip_frame = img_info; else img = flip_frame = flip_frame + 1; } else { if ( flip_frame == img_info ) img = flip_frame = &img_info[n-1]; else img = flip_frame = flip_frame - 1; } handle_exposure(img, 0, 0, img->w, img->h, img->h); XStoreName(dpy, img->window, img->title); } break; case 'i': case 'I': /* Install/deinstall colormap. * Should only do this if no window manager * running, but that's hard to tell. Let user * deal with it... */ if ( img->colormap ) if ( string[0] == 'i' ) XInstallColormap( dpy, img->colormap ); else XUninstallColormap( dpy, img->colormap ); break; default: handled_key = False; } else handled_key = False; DPRINTF(stderr, "%s %x, %s String '%s' - %d\n", symstr, keysym, ( shifted_key )? "shifted":"unshifted", string, length ); if ( !handled_key ) { /* GACK! the F28-34 keysyms are for the suns! */ /* on the DECs they are Left Right Up and Down w/ShiftMask */ /* on the ardent they are KP_4 KP_6 KP_8 KP_2 w/ShiftMask */ /* insert your favorite shifted arrow keysyms here! */ if ( !strcmp( symstr, "Left" ) || !strcmp( symstr, "F30" ) ) mag_pan( img, ACTION_PAN, (shifted_key ? 0 : img->w/4), img->h/2, img->mag_fact); if ( !strcmp( symstr, "Up" ) || !strcmp( symstr, "F28" ) ) mag_pan( img, ACTION_PAN, img->w/2, (shifted_key ? 0 : img->h/4), img->mag_fact); if ( !strcmp( symstr, "Right" ) || !strcmp( symstr, "F32" ) ) mag_pan( img, ACTION_PAN, (shifted_key ? img->w-1 : img->w/2 + img->w/4), img->h/2, img->mag_fact); if ( !strcmp( symstr, "Down" ) || !strcmp( symstr, "F34" ) ) mag_pan( img, ACTION_PAN, img->w/2, (shifted_key ? img->h-1 : img->h/2 + img->h/4), img->mag_fact); } continue; } case MappingNotify: XRefreshKeyboardMapping( &event.xmapping ); continue; default: fprintf(stderr, "%s: Event type %x?\n", progname, event.type); break; } /* exit this window */ if (img->scan_data) free ( img->scan_data ); if (img->icn_image) XDestroyImage( img->icn_image ); if (img->image) XDestroyImage( img->image ); if (img->pixmap) XFreePixmap( dpy, img->pixmap ); if (img->mag_pixmap) XFreePixmap( dpy, img->mag_pixmap ); if (img->icn_pixmap) XFreePixmap( dpy, img->icn_pixmap ); if (img->icn_gc) XFreeGC( dpy, img->icn_gc ); if (img->gc) XFreeGC( dpy, img->gc ); if (img->icn_window) XDestroyWindow ( dpy, img->icn_window ); dead_window = img->window; if (img->window) XDestroyWindow ( dpy, img->window ); n--; if ( n ) /* pack imgs in there good */ for ( ; img < &img_info[n]; img++ ) *img = *(img+1); else break; /* flipbook only has one window, so if its dead_window then die too */ if ( img_info[0].window == dead_window ) break; } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.