📄 zgv.c
字号:
/* zgv 5.5 - GIF, JPEG and PBM/PGM/PPM viewer, for VGA PCs running Linux. * Copyright (C) 1993-2001 Russell Marks. * * zgv.c - This provides the zgv file selector, and interfaces to the * vga display routines (vgadisp.c) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <stdio.h>#include <dirent.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <signal.h>#include <time.h>#include <setjmp.h>#include <pwd.h>#include <grp.h>#include <sys/param.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/file.h>#include <sys/ioctl.h>#include <sys/vt.h>#include <errno.h>#include <vga.h>#include <vgagl.h>#include <vgamouse.h>#include "zgv.h"#include "readgif.h"#include "vgadisp.h"#include "readnbkey.h"#include "font.h"#include "3deffects.h"#include "helppage.h"#include "rc_config.h"#include "rcfile.h"#include "readpnm.h" /* for the dithering - should be moved! */#include "resizepic.h"#include "copymove.h"#include "mousecur.h"#include "scrollbar.h"#include "rbmenu.h"#include "gnuhelp.h"#include "modesel.h"#include "magic.h"#define HOWFAR_LOADING_MSG "Reading - please wait"/* text used when copying >=2 files */#define HOWFAR_COPYING_MSG "Copying files - please wait"/* text used when moving >=2 files */#define HOWFAR_MOVING_MSG "Moving files - please wait"/* and deleting >=2 */#define HOWFAR_DELETING_MSG "Deleting files - please wait"char *zgvhelp[]= { " ", "? (question mark)\\this help page", " ", "up (also k or q)\\move file selection cursor up", "down (also j or a)\\move file selection cursor down", "left (also h or o)\\move file selection cursor left", "right (also l or p)\\move file selection cursor right", " ", "Enter\\display file or change directory", " ", "v\\visual selection mode on/off", "u\\create/update thumbnails in visual mode", "Ctrl-R\\update directory listing / redraw screen", "D or Delete\\delete file", " ", "Esc or x\\exit zgv", "" };struct rbm_data_tag filesel_menu_data[]= { /* 31 chars max for label text */ {1, "Quit zgv", RK_ESC }, /* stuff in draw_rb_menu which sets the active field of these * mode buttons assumes they are in *exactly* this order/position. * So don't change anything before the "Tag all" button without * thinking twice... or more. :-) */ {0,"-",0}, {1, "640x480x8", RK_F1 }, {1, "800x600x8", RK_F2 }, {1, "1024x768x8", RK_F3 }, {1, "1280x1024x8", RK_F4 }, {0,"-",0}, {1, "Tag all", 'T' }, {1, "Untag all", 'N' }, {0,"-",0}, {1, "Tag", 't' }, {1, "Untag", 'n' }, {1, "Toggle tag", ' ' }, {0,"-",0}, {1, "Copy files", 'C' }, {1, "Move files", 'M' }, {1, "Delete file", 'D' }, {1, "Slideshow", RK_TAB }, {1, " ...looping on/off", 'L' }, {1, " ...shuffle on/off", 'S' }, {0,"-",0}, {1, "Rescan dir", 'R'-0x40 }, {0,"-",0}, {1, "Show file info", ':' }, {1, "Thumbnails on/off", 'v' }, {1, " ...grey/colour", 'c' }, {0,"-",0}, {1, "Thumbnail update", 'u' }, {1, " ...for directories", 'd' }, {0,"-",0}, {1, "Sort by name", 128+'n' }, {1, " ...extension", 128+'e' }, {1, " ...file size", 128+'s' }, {1, " ...date/time", 128+'d' }, {0,"",0} };/* from 18-bit RGB (as used by VGA palette) to 3:3:2 palette index */#define MAKE332COL(r,g,b) (((r)>>3)*32+((g)>>3)*4+((b)>>4))/* colour indicies used for filenames-only selector */#define LIGHT 2#define DARK 1#define BLACK 15#define MIDGREY 3#define MARKEDCOL 14/* these relate to the size of each file's entry ("bar") onscreen */#define GDFYBIT 18#define BARWIDTH 126#define BAR_RESTRICT_WIDTH BARWIDTH-4#define DIR_OF_XPOS (100)#define DIR_OF_YPOS (12)#define DIR_OF_XSIZ (fs_scrnwide-DIR_OF_XPOS-10)#define COLS (fs_scrnwide-5)#define ROWS (fs_scrnhigh-10-yofs)#define XSIZ (COLS/BARWIDTH)#define YSIZ (ROWS/barheight)#define XSTARTPOS (4+(COLS%BARWIDTH)/2)#define XENDPOS (XSTARTPOS+COLS)#define fwinxpos(f) (XSTARTPOS+(((f)-1)/YSIZ)*BARWIDTH)#define fwinypos(f) (yofs+(ROWS%barheight)/2-cfg.scrollbar*9+ \ barheight*(((f)-1)%YSIZ))/* maximum no. of `past positions' in dirs to save. * if it runs out of space the oldest entries are lost. */#define MPPOSSIZ 256/* number of greyscales *less one* used in selector when in 640x480x16 mode */#define GREY_MAXVAL 10struct gifdir_tag { char name[256]; char isdir; /* 0=file, 1=dir. */ char xvw,xvh; /* xvpic width and height, zero if none */ char marked; off_t size; time_t mtime; int extofs; };int gifdirsiz;struct gifdir_tag *gifdir=NULL;int gifdir_byte_size=64*sizeof(struct gifdir_tag);int gifdir_byte_incr=32*sizeof(struct gifdir_tag);enum sorttypes { sort_name,sort_ext,sort_size,sort_mtime };/* this has to be global so we can use it in gcompare() */enum sorttypes filesel_sorttype=sort_name;int *slideshow_idx=NULL,slideshow_idx_size;int zgv_ttyfd,howfar_upto;jmp_buf setjmpbuf; /* in case someone aborts decompressing a file */static int xv332_how_far_xpos,xv332_how_far_ypos;static int one_file_only=0;int original_vt,separate_vt=0;int zgv_vt;int tagview_mode=0;int slider_drag=0; /* for scrollbar/mouse *//* for right-buttom menu */static int rb_ignore_first_left_click=0;static unsigned char *rb_save=NULL;static int rb_save_width,rb_save_height;int idx_light,idx_medium,idx_dark,idx_black,idx_marked;int idx_blacknz; /* idx_blacknz is always black, and always non-zero */ /* (it's needed for mouse cursor and buttons) */int updating_index=0;int gdfsiz=3; /* size of filename text in selector */int gdfofs=0;int barheight,yofs; /* height of cursor, and offset of selection bit *//* XXX this sgres stuff is bogus in the extreme */extern int sgres;int has_mouse=0;int current_colour=0; /* see zgv.h */struct pastpos_tag { int dev,inode,curent,startfrom; } pastpos[MPPOSSIZ];/* jpeg/png error messages are written into this */char jpeg_png_errmsg[JPEG_PNG_ERRMSG_SIZE];int fs_vgamode=G640x480x256; /* current video mode for selector */int fs_scrnwide,fs_scrnhigh; /* width/height of selector mode *//* stuff for checking old directories (to avoid symlink loops in * recursive update). */struct olddir_tag { dev_t device; ino_t inode; };static struct olddir_tag *olddirs=NULL;static int olddir_byte_size=64*sizeof(struct olddir_tag);static int olddir_byte_incr=32*sizeof(struct olddir_tag);static int num_olddirs=0;/* prototypes */int main(int argc,char *argv[]);void write_gifdir_name(int entry,char *str);void my_mouse_init(void);void openstdin_nonblocking(void);void writeppm(void);void load_one_file(char *filename);void copyfromconfig(void);void mainloop(void);void fix_startfrom(int curent,int *startfromp);int rename_file(int curent,int startfrom);static void draw_rb_menu(void);static void undraw_rb_menu(void);static int rb_menu_event(int *keyp);void new_pastpos(int curent, int startfrom);void get_pastpos(int *curentp,int *startfromp);int load_single_file(int curent, int do_howfar);int load_tagged_files(void);void delete_gifdir_element(int n);void copymovedel_file_or_tagged_files(int curent,int remove_from_array, int no_dir_prompt, int (*func_ptr)(char *,char *), char *msg_action,char *msg_acting, char *msg_acted,char *msg_howfar);int goto_named_dir(void);int permissiondenied(char *fname);void redrawall(int curent, int startfrom);void inithowfar(char *msg);void showhowfar(int sofar, int total);void smallhowfar(int sofar, int total);void showbar(int entnum, int selected, int startfrom);int centreseltxt(int x, int fsiz, char *str);void showgifdir(int startfrom,int unshow,int drawdirmsg,int do_one_only);int ispicture(char *filename);void readgifdir(int graphics_ok);void sort_files(void);int gcompare(void *gn1, void *gn2);void prettyfile(char *buf, struct gifdir_tag *gifdptr, int bufsize);void screenon(void);void screenoff(void);void cleartext(void);void showerrmessage(int errnumber);int delete_file(char *filename,int doprompt,int report_error);int delete_file_simple(char *filename,char *junk);void xv332_how_far(int sofar, int total);void clear_xvpic(int xpos, int ypos);int makexv332(char *filename, char *xvpicfn, unsigned int howfar);int makedirxv332(char *filename, char *xvpicfn, unsigned int howfar);void update_xvpics(int do_dirs_instead);void recursive_update(void);int fixvt(void);void switchback(void);void greyfix332(unsigned char **image, int w, int h, int xw7, int w8);void wait_for_foreground(void);void ctrlc(int foo);int make_slideshow_idx_array(void);void shuffle_slideshow_idx(void);void gifdir_init(void);int gifdir_resize_if_needed(int newent);int main(int argc,char *argv[]){int argsleft;if(fixvt()==0) { fprintf(stderr,"zgv: not running on console and no free VTs found.\n"); exit(1); }atexit(switchback); /* this gets called after svgalib stuff *//* this gets called after svgalib's ^C handler, on ^C */signal(SIGINT,ctrlc);vga_disabledriverreport(); /* quieten svgalib */vga_init();/* root permissions should now have been ditched *//* check modesel.c's mode array is valid & consistent (and quit if not) */check_modedesc_array();/* Temporary workaround for svgalib security problem --kvajk */{int fd=3; while(!fcntl(fd,F_SETFD,1)) fd++;}gifdir_init(); /* allocate initial memory for gifdir[] */srand(time(NULL)); /* in case we use shuffleslideshow */pixelsize=1;getconfig(); /* see rcfile.c... */argsleft=parsecommandline(argc,argv); /* ...for these two. */fixconfig(); /* deal with any bogus config settings */copyfromconfig();my_mouse_init();cleartext();/* do one-file-only if have one arg. *//* (does a chdir and carries on if it's a dir.) */if(argsleft==1) load_one_file(argv[argc-1]);/* do slideshow if more than one arg *//* XXX this should be shoved into a separate routine sometime */if(argsleft>1) { int i, entnum; struct stat buf; for(i=argc-argsleft,entnum=0;i<=argc-1;i++) if(stat(argv[i],&buf) != -1 && !S_ISDIR(buf.st_mode)) { entnum++; if(!gifdir_resize_if_needed(entnum)) fprintf(stderr,"zgv: out of memory\n"),exit(1); write_gifdir_name(entnum,argv[i]); gifdir[entnum].marked=1; gifdir[entnum].isdir=0; } gifdirsiz = entnum; one_file_only=1; openstdin_nonblocking(); screenon(); load_tagged_files(); screenoff(); exit(0); }/* normal zgv startup */cfg.errignore=0; /* don't ignore errs if using this way */openstdin_nonblocking();screenon();mainloop();screenoff();if(cfg.echotagged) { int f; for(f=1;f<=gifdirsiz;f++) if(gifdir[f].marked) printf("%s\n",gifdir[f].name); }exit(0);}/* write str to gifdir[entry].name checking buffer size */void write_gifdir_name(int entry,char *str){strncpy(gifdir[entry].name,str,sizeof(gifdir[entry].name)-1);gifdir[entry].name[sizeof(gifdir[entry].name)-1]=0;}void my_mouse_init(){int mouse_fd=-1;if(cfg.svgalib_mouse) { int svgalib_type=vga_getmousetype(); has_mouse=1; if(svgalib_type==MOUSE_NONE) { has_mouse=0; fprintf(stderr,"zgv: svgalib reports no mouse configured!\n" " (possibly an error in the config file?)\n" " carrying on anyway...\n"); sleep(3); /* bit annoying but it's an important problem! */ } else { mouse_fd=mouse_init_return_fd("/dev/mouse", svgalib_type,MOUSE_DEFAULTSAMPLERATE); if(mouse_fd==-1) has_mouse=0; } }if(has_mouse) { unsigned char c; struct timeval tv={0,50000}; fd_set fds; struct modedesc_tag *md_ptr; int found; /* ditch any byte which appears in next 1/20th-sec. * this is to workaround a problem with my `mouse' (a logitech trackball) * which sends a bogus `N' byte on initialisation for no obvious reason. * (This screws everything up because input is *meant* to be in packets * of 3 bytes!) * * 1/20-th sec is roughly five times as long as it should take, * so this should work unless the machine is impossibly overloaded. */ if(cfg.mousekludge) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -