📄 zgv.c
字号:
FD_ZERO(&fds); FD_SET(mouse_fd,&fds); select(mouse_fd+1,&fds,NULL,NULL,&tv); if(FD_ISSET(mouse_fd,&fds)) read(mouse_fd,&c,1); } /* set scaling of mouse x/y. Default is 16, which gives a fast-ish * mouse on my trackball, and a slower but acceptable result with * another mouse I tried. */ mouse_setscale(cfg.mousescale); /* set mouse pos to centre of screen - we only do this once */ found=0; for(md_ptr=modedesc;md_ptr->mode;md_ptr++) if(fs_vgamode==md_ptr->mode) { mouse_setposition(md_ptr->width/2,md_ptr->height/2); found=1; break; } if(!found) { fprintf(stderr, "zgv: " "unknown file-sel video mode, can't correctly init mouse position\n"); mouse_setposition(320,240); /* should at least be onscreen :-) */ /* not desperately nasty though, so carry on. */ } /* not too nice not having scrollbar if using mouse, so force it on. */ cfg.scrollbar=1; }}void openstdin_nonblocking(){zgv_ttyfd=fileno(stdin);fcntl(zgv_ttyfd,F_SETFL,O_NONBLOCK);}/* write PPM of image to stdout (for `-w') */void writeppm(){int c,x,y;printf("P6\n%d %d\n255\n",width,height);for(y=0;y<height;y++) for(x=0;x<width;x++) if(pixelsize==1) { /* lookup index in palette */ c=theimage[y*width+x]; putchar(image_palette[ 0+c]); putchar(image_palette[256+c]); putchar(image_palette[512+c]); } else { /* just copy */ putchar(theimage[(y*width+x)*3+2]); putchar(theimage[(y*width+x)*3+1]); putchar(theimage[(y*width+x)*3 ]); }}void load_one_file(char *filename){static hffunc hf;struct stat sbuf;/* before we load it, see if it's a directory. If so, we run zgv with * much the same result as typing '( cd whatever;zgv )'. */if(stat(filename,&sbuf)!=-1 && S_ISDIR(sbuf.st_mode)) { chdir(filename); return; }if(cfg.writefile) cfg.onefile_progress=0; openstdin_nonblocking(); /* we hadn't done this yet */one_file_only=1;if(cfg.onefile_progress) { screenon(); inithowfar(HOWFAR_LOADING_MSG); hf=showhowfar; }else { hf=NULL; if(!cfg.writefile) fprintf(stderr,"Loading..."); }if(cfg.onefile_progress && hf!=NULL) vga_runinbackground(1); if(cfg.writefile) pixelsize=3; /* 24-bit output preferred *//* save context for possible abort (if using showhowfar) */if(setjmp(setjmpbuf)) { /* if we get here, someone aborted loading a file. */ wait_for_foreground(); screenoff(); exit(0); }if(readpicture(filename,hf,!cfg.writefile,0,NULL,NULL)!=_PIC_OK) { if(cfg.onefile_progress) screenoff(); fprintf(stderr,"\rzgv: error loading file.\n"); exit(1); }else { if(hf==NULL && !cfg.writefile) fprintf(stderr,"\r \r"); }/* restore_mouse_pos is unimportant for a one-file situation, so we skip it. */if(cfg.writefile) { writeppm(); /* pointless really, but might as well... */ free(theimage); free(image_palette); }else { wait_for_foreground(); screenoff(); }exit(0);}void copyfromconfig(){curvgamode=cfg.videomode;zoom=cfg.zoom;vkludge=cfg.vkludge;brightness=cfg.brightness;contrast=cfg.contrast;picgamma=cfg.initial_picgamma;virtual=(curvgamode==G320x400x256 || curvgamode==G360x480x256);fs_vgamode=cfg.fs_startmode;/* if we don't have or don't allow the mode, use 640x480x8. */if(!vga_hasmode(fs_vgamode) || !cfg.mode_allowed[fs_vgamode]) fs_vgamode=G640x480x256;/* now make it 640x480x4 (which also locks it in that mode) * if force16fs, or if 640x480x8 and we don't have it (or don't allow it). */if(cfg.force16fs || (fs_vgamode==G640x480x256 && (!vga_hasmode(fs_vgamode) || !cfg.mode_allowed[fs_vgamode]))) fs_vgamode=G640x480x16;}/* make `rw-r--r--'-style permission string from mode. */char *make_perms_string(int mode){static char buf[10];int f,shift,submode;char *execptr;strcpy(buf,"---------");for(f=0,shift=6;f<3;f++,shift-=3) { /* first do basic `rwx' bit. */ submode=((mode>>shift)&7); if(submode&4) buf[f*3+0]='r'; if(submode&2) buf[f*3+1]='w'; if(submode&1) buf[f*3+2]='x'; execptr=buf+f*3+2; /* apply any setuid/setgid/sticky bits */ switch(f) { case 0: if(mode&04000) *execptr=((*execptr=='x')?'s':'S'); break; case 1: if(mode&02000) *execptr=((*execptr=='x')?'s':'S'); break; case 2: if(mode&01000) *execptr=((*execptr=='x')?'t':'T'); break; } }return(buf);}/* this does the stat() itself, as it may be called from vgadisp.c. * width/height are zero if we should read the thumbnail to get them. * if need_redraw_ptr is non-NULL, it gets set to 1 when a screen redraw * is needed on return (only possible when called from the viewer). */void file_details(char *filename,int w,int h,int *need_redraw_ptr){static char buf[2048];struct tm *ctime;struct stat sbuf;struct passwd *pwptr=NULL;struct group *grptr=NULL;int gotdim=1,dim_from_pic=1;if(need_redraw_ptr) *need_redraw_ptr=0;if(stat(filename,&sbuf)==-1) return;/* this should be a can't happen, I think... */if((ctime=localtime(&sbuf.st_mtime))==NULL) return;/* try reading dimensions from thumbnail if needed */if(!w || !h) { FILE *tn; char *ptr; dim_from_pic=0; if((ptr=strrchr(filename,'/'))==NULL) snprintf(buf,sizeof(buf),".xvpics/%s",filename); else { buf[sizeof(buf)-1]=0; strncpy(buf,filename,sizeof(buf)-1); snprintf(buf+strlen(buf),sizeof(buf)-1-strlen(buf), ".xvpics/%s",ptr+1); } gotdim=0; if((tn=fopen(buf,"rb"))!=NULL) { fgets(buf,sizeof(buf),tn); /* lose first line */ fgets(buf,sizeof(buf),tn); /* this may be "#IMGINFO:123x456 <type>" */ while(buf[0]=='#') { if(sscanf(buf,"#IMGINFO:%dx%d",&w,&h)==2) { gotdim=1; break; } /* otherwise try another comment line */ fgets(buf,sizeof(buf),tn); } fclose(tn); } }if(!gotdim) w=h=0;pwptr=getpwuid(sbuf.st_uid);grptr=getgrgid(sbuf.st_gid);/* given the 7 field values, msgbox() does most of the work. */snprintf(buf,sizeof(buf), "%s\n" "%dk\n" "%d-%02d-%02d %02d:%02d\n" "%s (%o)\n" "%s\n" "%s\n" "%c%d x %d\n", filename, (int)(sbuf.st_size+1023)/1024, 1900+ctime->tm_year,ctime->tm_mon+1,ctime->tm_mday, ctime->tm_hour,ctime->tm_min, make_perms_string(sbuf.st_mode&07777),sbuf.st_mode&07777, pwptr?pwptr->pw_name:"unknown", grptr?grptr->gr_name:"unknown", dim_from_pic?'p':'t', /* bit of a kludge :-/ */ w,h);msgbox(zgv_ttyfd,buf,MSGBOXTYPE_FILEDETAILS, idx_light,idx_dark,idx_black);if(need_redraw_ptr) *need_redraw_ptr=!msgbox_did_restore();}void file_count(void){char buf[128];int f,tagged=0,files=0;for(f=1;f<=gifdirsiz;f++) { if(!gifdir[f].isdir) files++; if(gifdir[f].marked) tagged++; }if(!files) { msgbox(zgv_ttyfd,"No files",MSGBOXTYPE_OK,idx_light,idx_dark,idx_black); return; }if(tagged) snprintf(buf,sizeof(buf), "%d file%s (%d tagged)", files,files>1?"s":"",tagged);else snprintf(buf,sizeof(buf), "%d file%s (none tagged)", files,files>1?"s":"");msgbox(zgv_ttyfd,buf,MSGBOXTYPE_OK,idx_light,idx_dark,idx_black);}int tagged_count(void){int f,tagged=0;for(f=1;f<=gifdirsiz;f++) if(gifdir[f].marked) tagged++;return(tagged);}void mainloop(){int quit,key,curent; /* quit, key pressed, current entry */int oldent,startfrom,oldstart,f,markchange;int rb_menu_mode=0;int pending_mouse_viewsel=0;int tmpkey;/* blank out past-positions array */for(f=0;f<MPPOSSIZ;f++) pastpos[f].dev=-1,pastpos[f].inode=-1;quit=0; curent=1; oldent=1;startfrom=1;readgifdir(1);showgifdir(startfrom,0,1,0);showbar(curent,1,startfrom);while(!quit) { oldent=curent; markchange=0; key=mousecur_wait_for_keys_or_mouse(zgv_ttyfd); /* convert xzgv-ish keypresses */ if(cfg.xzgvkeys) { switch(key) { case ' ': key=RK_ENTER; break; case '-': key='n'; break; case '=': key='t'; break; case '-'+128: key='N'; break; case '='+128: key='T'; break; case 'N'-0x40: key='R'; break; case 'D'-0x40: key=RK_DELETE; break; case 'Q'-0x40: key=RK_ESC; break; case 'q': key=RK_ESC; break; } } if(rb_menu_mode) { /* we deal with keys ourselves... */ if(key==RK_ESC || key=='x') { rb_menu_mode=0; undraw_rb_menu(); continue; } /* but mouse dealt with by this. if not clicked an entry, skip * rest of loop. */ if(rb_menu_event(&key)) /* returns non-zero if should stay in menu */ continue; /* otherwise restore saved area of screen, and do action in (faked) key */ rb_menu_mode=0; undraw_rb_menu(); goto parsekey; /* skip normal mouse stuff just in case */ } /* grok mouse movements and buttons */ if(has_mouse) { int mx=mouse_getx(),my=mouse_gety(); int mbuttons=mouse_getbutton(); int mleft_start=is_start_click_left(); int mleft=is_end_click_left(),mright=is_end_click_right(); if(slider_drag) { /* the usual way of dragging a slider is (I think) that the (in this * case) horiz. pos. of the slider and the mouse pointer should (where * `physically' possible) stay constant relative to each other. * But the way zgv does it is to treat the mouse pointer's position * on the scrollbar as a place to move the file cursor to, despite * the relative position. This is a little odd, but I quite like it. :-) * * Anyway, the calculations are similar to those used by scrollbar.c * to draw the slider, so we let that take care of it... */ curent=scrollbar_conv_drag_to_curent(mx,gifdirsiz); } else /* not dragging slider */ { /* we're only interested in the mouse if: * - have released right button * - pending_mouse_viewsel is set and have released left * - we're on the scrollbar and have pressed the left button * - we're on the file area and have pressed left * (sets pending_mouse_viewsel) * - we're on the current-directory bit and have released left */ /* if right button released, get the right-button menu. */ if(mright) { rb_menu_mode=1; pending_mouse_viewsel=0; /* cancel any pending view */ draw_rb_menu(); /* if left mouse button is depressed now (poor thing :-)) * we should set flag to ignore first end-left-click. */ rb_ignore_first_left_click=((mbuttons&MOUSE_LEFTBUTTON)?1:0); continue; /* skip rest of main loop */ } /* this comes early (before other mleft-testing stuff) * so we can be sure that the end click doesn't do something * else as well. */ if(mleft && pending_mouse_viewsel) { pending_mouse_viewsel=0; key=RK_ENTER; /* fake a key to view current */ mleft=0; /* make sure it doesn't match stuff below :-) */ } if(cfg.scrollbar) { /* check for scrollbar. This is actually a bit complicated * button-wise due to dragging etc., so we check for mouse being * in it first. * my is tested first as that's more likely to fail quickly if not * in scrollbar area. */ if(my>=SCRLBAR_YPOS && my<SCRLBAR_YPOS+SCRLBAR_HEIGHT && mx>=SCRLBAR_XPOS && mx<SCRLBAR_XPOS+SCRLBAR_WIDTH) { int slid_xpos= scrollbar_slider_xpos(); int slid_width=scrollbar_slider_width(); /* so we're here then. where we are determines which button * states we care about. here's the list: * - for arrows, end of left click (XXX this isn't ideal!) * - for scrollbar but not slider, end of left click (ditto) * - for scrollbar slider, start of left click puts us * in slider_drag mode, end of left click leaves it. * (end of click isn't tested here though; it's tested above by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -