/* * xvmisc.c - random 'handy' routines used in XV * * Contains: * Window CreateWindow(name, clname, geom, w, h, fg, bg, usesize) * void CenterString(win, str, x, y) * void ULineString(win, str, x, y) * int StringWidth(str) * void FakeButtonPress(bptr) * void FakeKeyPress(win, keysym); * void GenExpose(win, x, y, w, h); * void RemapKeyCheck(ks, buf, stlen) * void xvDestroyImage(XImage *); * void DimRect(win, x, y, w, h, bg); * void Draw3dRect(win, x,y,w,h, inout, bwidth, hicol, locol); * void SetCropString() * void SetSelectionString() * void Warning() * void FatalError(str) * void Quit(int) * void LoadFishCursors() * void WaitCursor() * void SetCursors(int) * char *BaseName(char *) * void DrawTempGauge(win, x,y,w,h, percent, fg,bg,hi,lo, str) * void ProgressMeter(min, max, val, str); * void xvbcopy(src, dst, length) * int xvbcmp (s1, s2, length) * void xvbzero(s, length) * char *xv_strstr(s1, s2) * FILE *xv_fopen(str, str) * void xv_mktemp(str) * void Timer(milliseconds) */ #include "copyright.h" #define NEEDSTIME #include "xv.h" #include "bits/fc_left" #include "bits/fc_leftm" #include "bits/fc_left1" #include "bits/fc_left1m" #include "bits/fc_mid" #include "bits/fc_midm" #include "bits/fc_right1" #include "bits/fc_right1m" #include "bits/fc_right" #include "bits/fc_rightm" static void set_cursors PARM((Cursor, Cursor)); static Atom atom_DELWIN = 0; static Atom atom_PROTOCOLS = 0; /***************************************************/ void StoreDeleteWindowProp (win) Window win; { if (! atom_DELWIN) atom_DELWIN = XInternAtom (theDisp, "WM_DELETE_WINDOW", FALSE); /* the following fakes 'XSetWMProtocols(theDisp, win, &atom_DELWIN, 1);' */ if (! atom_PROTOCOLS) atom_PROTOCOLS = XInternAtom (theDisp, "WM_PROTOCOLS", False); if (atom_PROTOCOLS == None) return; XChangeProperty(theDisp, win, atom_PROTOCOLS, XA_ATOM, 32, PropModeReplace, (unsigned char *) &atom_DELWIN, 1); } /***************************************************/ Window CreateWindow(name,clname,geom,defw,defh,fg,bg,usesize) char *name, *clname, *geom; int defw,defh,usesize; unsigned long fg, bg; { Window win; XSetWindowAttributes xswa; unsigned long xswamask; XWMHints xwmh; XSizeHints hints; int i,x,y,w,h; XClassHint classh; /* note: if usesize, w,h are extracted from geom spec, otherwise defw,defh are used */ x = y = 1; i = XParseGeometry(geom,&x,&y, (unsigned int *) &w, (unsigned int *) &h); if ((i&XValue || i&YValue)) hints.flags = USPosition; else hints.flags = PPosition; if (!usesize || !(i&WidthValue)) w = defw; if (!usesize || !(i&HeightValue)) h = defh; hints.flags |= USSize | PWinGravity; hints.win_gravity = NorthWestGravity; if (i&XValue && i&XNegative) { hints.win_gravity = NorthEastGravity; x = dispWIDE - (w + 2 * bwidth) - abs(x); } if (i&YValue && i&YNegative) { hints.win_gravity = (hints.win_gravity == NorthWestGravity) ? SouthWestGravity : SouthEastGravity; y = dispHIGH - (h + 2 * bwidth) - abs(y); } #define VROOT_TRANS #ifdef VROOT_TRANS if (vrootW != rootW) { /* virtual window manager running */ int x1,y1; Window child; XTranslateCoordinates(theDisp, rootW, vrootW, x, y, &x1, &y1, &child); if (DEBUG) fprintf(stderr,"translate: %d,%d -> %d,%d\n",x,y,x1,y1); x = x1; y = y1; } #endif hints.x = x; hints.y = y; hints.width = w; hints.height = h; if (!usesize) { hints.min_width = w; hints.min_height = h; hints.max_width = w; hints.max_height = h; hints.flags |= PMaxSize | PMinSize; } xswa.background_pixel = bg; xswa.border_pixel = fg; xswa.colormap = theCmap; xswa.bit_gravity = StaticGravity; xswamask = CWBackPixel | CWBorderPixel | CWColormap; if (!usesize) xswamask |= CWBitGravity; win = XCreateWindow(theDisp, rootW, x, y, (u_int) w, (u_int) h, (u_int) bwidth, (int) dispDEEP, InputOutput, theVisual, xswamask, &xswa); if (!win) return(win); /* leave immediately if couldn't create */ xwmh.input = True; xwmh.flags = InputHint; if (iconPix) { xwmh.icon_pixmap = iconPix; xwmh.flags |= IconPixmapHint; } if (clname && strlen(clname)) { classh.res_name = "xv"; classh.res_class = clname; StoreDeleteWindowProp(win); } XmbSetWMProperties(theDisp, win, name, name, NULL, 0, &hints, &xwmh, clname ? &classh : NULL); return(win); } /**************************************************/ void DrawString(win,x,y,str) Window win; int x,y; char *str; { XDrawString(theDisp, win, theGC, x, y, str, (int) strlen(str)); } /**************************************************/ void CenterString(win,x,y,str) Window win; int x,y; char *str; { DrawString(win, CENTERX(mfinfo, x, str), CENTERY(mfinfo, y), str); } /**************************************************/ void ULineString(win,x,y,str) Window win; int x,y; char *str; { DrawString(win, x, y, str); XDrawLine(theDisp, win, theGC, x, y+DESCENT-1, x+StringWidth(str), y+DESCENT-1); } /**************************************************/ int StringWidth(str) char *str; { return(XTextWidth(mfinfo, str, (int) strlen(str))); } /**************************************************/ int CursorKey(ks, shift, dotrans) KeySym ks; int shift, dotrans; { /* called by the KeyPress/KeyRelease event handler to determine if a given keypress is a cursor key. More complex than you'd think, since certain Sun Keyboards generate a variety of odd keycodes, and not all keyboards *have* all these keys. Note that 'shifted' arrow keys are not translated to PageUp/Down, since it's up to the particular case whether that translation should occur */ /* if we don't have the new R5-R6 'XK_KP_*' cursor movement symbols, make them. */ #ifndef XK_KP_Up # define XK_KP_Up XK_Up # define XK_KP_Down XK_Down # define XK_KP_Left XK_Left # define XK_KP_Right XK_Right # define XK_KP_Prior XK_Prior # define XK_KP_Next XK_Next # define XK_KP_Home XK_Home # define XK_KP_End XK_End #endif int i = CK_NONE; if (ks==XK_Up || ks==XK_KP_Up || ks==XK_KP_8 || ks==XK_F28) i=CK_UP; else if (ks==XK_Down || ks==XK_KP_Down || ks==XK_KP_2 || ks==XK_F34) i=CK_DOWN; else if (ks==XK_Left || ks==XK_KP_Left || ks==XK_KP_4 || ks==XK_F30) i=CK_LEFT; else if (ks==XK_Right || ks==XK_KP_Right || ks==XK_KP_6 || ks==XK_F32) i=CK_RIGHT; else if (ks==XK_Prior || ks==XK_KP_Prior || ks==XK_KP_9 || ks==XK_F29) i=CK_PAGEUP; else if (ks==XK_Next || ks==XK_KP_Next || ks==XK_KP_3 || ks==XK_F35) i=CK_PAGEDOWN; else if (ks==XK_Home || ks==XK_KP_Home || ks==XK_KP_7 || ks==XK_F27) i=CK_HOME; else if (ks==XK_End || ks==XK_KP_End || ks==XK_KP_1 || ks==XK_F33) i=CK_END; else i = CK_NONE; if (dotrans && shift) { if (i==CK_PAGEUP) i=CK_HOME; else if (i==CK_PAGEDOWN) i=CK_END; else if (i==CK_UP) i=CK_PAGEUP; else if (i==CK_DOWN) i=CK_PAGEDOWN; } return i; } /***********************************/ void FakeButtonPress(bp) BUTT *bp; { /* called when a button keyboard equivalent has been pressed. 'fakes' a ButtonPress event in the button, which A) makes the button blink, and B) falls through to ButtonPress command dispatch code */ Window rW, cW; int x, y, rx, ry; unsigned int mask; XButtonEvent ev; ev.type = ButtonPress; ev.send_event = True; ev.display = theDisp; ev.window = bp->win; ev.root = rootW; ev.subwindow = (Window) NULL; ev.x = bp->x; ev.y = bp->y; ev.state = 0; ev.button = Button1; XSendEvent(theDisp, bp->win, False, NoEventMask, (XEvent *) &ev); /* if button1 is pressed, loop until RELEASED to avoid probs in BTTrack */ while (XQueryPointer(theDisp, rootW, &rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button1Mask)) break; /* button released */ } } /************************************************************************/ void FakeKeyPress(win, ksym) Window win; KeySym ksym; { XKeyEvent ev; ev.type = KeyPress; ev.send_event = True; ev.display = theDisp; ev.window = win; ev.root = rootW; ev.subwindow = (Window) NULL; ev.time = CurrentTime; ev.x = ev.y = ev.x_root = ev.y_root = 0; ev.state = 0; ev.keycode = XKeysymToKeycode(theDisp, ksym); ev.same_screen = True; XSendEvent(theDisp, win, False, NoEventMask, (XEvent *) &ev); XFlush(theDisp); } /***********************************/ void GenExpose(win, x, y, w, h) Window win; int x, y; unsigned int w, h; { /* generates an expose event on 'win' of the specified rectangle. Unlike XClearArea(), it doesn't clear the rectangular region */ XExposeEvent ev; ev.type = Expose; ev.send_event = True; ev.display = theDisp; ev.window = win; ev.x = x; ev.y = y; ev.width = w; ev.height = h; ev.count = 0; XSendEvent(theDisp, win, False, NoEventMask, (XEvent *) &ev); } /***********************************/ void RemapKeyCheck(ks, buf, stlen) KeySym ks; char *buf; int *stlen; { /* remap weirdo keysyms into normal key events */ if (ks == 0x1000ff00) { /* map 'Remove' key on DEC keyboards -> ^D */ buf[0] = '\004'; buf[1] = '\0'; *stlen = 1; } } /***********************************/ void xvDestroyImage(image) XImage *image; { /* called in place of XDestroyImage(). Explicitly destroys *BOTH* the data and the structure. XDestroyImage() doesn't seem to do this on all systems. Also, can be called with a NULL image pointer */ if (image) { /* free data by hand, since XDestroyImage is vague about it */ if (image->data) free(image->data); image->data = NULL; XDestroyImage(image); } } /***********************************/ void DimRect(win, x, y, w, h, bg) Window win; int x, y; u_int w, h; u_long bg; { /* stipple a rectangular region by drawing 'bg' where there's 1's in the stipple pattern */ XSetFillStyle (theDisp, theGC, FillStippled); XSetStipple (theDisp, theGC, dimStip); XSetForeground(theDisp, theGC, bg); XFillRectangle(theDisp, win, theGC, x, y, (u_int) w, (u_int) h); XSetFillStyle (theDisp, theGC, FillSolid); } /**************************************************/ void Draw3dRect(win, x,y,w,h, inout, bwidth, hi, lo, bg) Window win; int x,y,inout,bwidth; unsigned int w,h; unsigned long hi, lo, bg; { int i,r,x1,y1; x1 = x + (int) w; y1 = y + (int) h; if (ctrlColor) { /* draw top-left */ XSetForeground(theDisp, theGC, (inout==R3D_OUT) ? hi : lo); for (i=0; i"); } /**************************************************/ void SetSelectionString() { /* sets the Selection string in the info box to be correct. should be called whenever the selection may have changed */ if (HaveSelection()) { int x,y,w,h; GetSelRCoords(&x,&y,&w,&h); SetISTR(ISTR_SELECT, "%dx%d rectangle starting at %d,%d", w, h, x, y); } else SetISTR(ISTR_SELECT, ""); } /***********************************/ void Warning() { char *st; /* give 'em time to read message */ if (infoUp || ctrlUp || anyBrowUp) sleep(3); else { st = GetISTR(ISTR_INFO); OpenAlert(st); sleep(3); CloseAlert(); } } /***********************************/ void FatalError (identifier) char *identifier; { fprintf(stderr, "%s: %s\n",cmd, identifier); Quit(-1); } /***********************************/ void Quit(i) int i; { /* called when the program exits. frees everything explictly created EXCEPT allocated colors. This is used when 'useroot' is in operation, as we have to keep the alloc'd colors around, but we don't want anything else to stay */ #ifdef AUTO_EXPAND chdir(initdir); Vdsettle(); #endif if (!theDisp) exit(i); /* called before connection opened */ if (useroot && i==0) { /* save the root info */ SaveRootInfo(); /* kill the various windows, since we're in RetainPermanent mode now */ if (dirW) XDestroyWindow(theDisp, dirW); if (infoW) XDestroyWindow(theDisp, infoW); if (ctrlW) XDestroyWindow(theDisp, ctrlW); if (gamW) XDestroyWindow(theDisp, gamW); KillBrowseWindows(); if (psW) XDestroyWindow(theDisp, psW); #ifdef HAVE_JPEG if (jpegW) XDestroyWindow(theDisp, jpegW); #endif #ifdef HAVE_TIFF if (tiffW) XDestroyWindow(theDisp, tiffW); #endif #ifdef HAVE_PIC2 if (pic2W) XDestroyWindow(theDisp, pic2W); #endif /* HAVE_PIC2 */ #ifdef HAVE_PCD if (pcdW) XDestroyWindow(theDisp, pcdW); #endif /* HAVE_PCD */ #ifdef HAVE_MGCSFX if (mgcsfxW) XDestroyWindow(theDisp, mgcsfxW); #endif /* HAVE_MGCSFX */ #ifdef HAVE_PNG if (pngW) XDestroyWindow(theDisp, pngW); #endif /* if NOT using stdcmap for images, free stdcmap */ if (colorMapMode != CM_STDCMAP) { int j; for (j=0; j w) && numchars>0) numchars--; } if (numchars) tw = XTextWidth(mfinfo, str, numchars); XSetForeground(theDisp, theGC, fg); XDrawRectangle(theDisp, win, theGC, x,y, (u_int) w, (u_int) h); if (ctrlColor) { Draw3dRect(win, x+1,y+1, (u_int) w-2, (u_int) h-2, R3D_IN, 2, hi, lo, bg); maxwide = w-4; barwide = (int) (maxwide * ratio + 0.5); XSetForeground(theDisp, theGC, fg); XFillRectangle(theDisp,win,theGC, x+3, y+3, (u_int) barwide, (u_int) h-5); if (numchars) { /* do string */ if (barwide < maxwide) { XSetForeground(theDisp, theGC, bg); XFillRectangle(theDisp, win, theGC, x+3+barwide, y+3, (u_int) (maxwide-barwide), (u_int) (h-5)); } XSetFunction(theDisp, theGC, GXinvert); XSetPlaneMask(theDisp, theGC, fg ^ bg); XDrawString(theDisp, win, theGC, CENTERX(mfinfo, (x+w/2), str), CENTERY(mfinfo, (y+h/2)), str, numchars); XSetFunction(theDisp, theGC, GXcopy); XSetPlaneMask(theDisp, theGC, AllPlanes); } else if (barwide < maxwide) { XDrawLine(theDisp,win,theGC,x+3+barwide, y+h/2 + 0, x+w-3, y+h/2 + 0); XSetForeground(theDisp, theGC, lo); XDrawLine(theDisp,win,theGC,x+3+barwide, y+h/2 + 1, x+w-3, y+h/2 + 1); XSetForeground(theDisp, theGC, hi); XDrawLine(theDisp,win,theGC,x+3+barwide, y+h/2 + 2, x+w-3, y+h/2 + 2); XSetForeground(theDisp, theGC, bg); XFillRectangle(theDisp, win, theGC, x+3+barwide, y+3, (u_int) (maxwide-barwide), (u_int) (h/2 - 3)); XFillRectangle(theDisp, win, theGC, x+3+barwide, y+h/2 + 3, (u_int) (maxwide-barwide),(u_int)((h-3) - (h/2+3)) + 1); } } else { maxwide = w-1; barwide = (int) (maxwide * ratio + 0.5); XSetForeground(theDisp, theGC, fg); XFillRectangle(theDisp,win,theGC, x+1, y+1, (u_int) barwide, (u_int) h-1); if (numchars) { if (barwide < maxwide) { XSetForeground(theDisp, theGC, bg); XFillRectangle(theDisp, win, theGC, x+1+barwide, y+1, (u_int) (maxwide-barwide), (u_int) (h-1)); } XSetFunction(theDisp, theGC, GXinvert); XSetPlaneMask(theDisp, theGC, fg ^ bg); XDrawString(theDisp, win, theGC, CENTERX(mfinfo, (x+w/2), str), CENTERY(mfinfo, (y+h/2)), str, numchars); XSetFunction(theDisp, theGC, GXcopy); XSetPlaneMask(theDisp, theGC, AllPlanes); } else if (barwide < maxwide) { XDrawLine(theDisp, win, theGC, x+1+barwide, y+h/2, x+w-1, y+h/2); XSetForeground(theDisp, theGC, bg); XFillRectangle(theDisp, win, theGC, x+1+barwide, y+1, (u_int) (maxwide-barwide), (u_int) (h/2 - 1)); XFillRectangle(theDisp, win, theGC, x+1+barwide, y+h/2 + 1, (u_int)(maxwide-barwide),(u_int)(((h-1) - (h/2+1))+1)); } } XFlush(theDisp); } /***************************************************/ void ProgressMeter(min, max, val, str) int min, max, val; char *str; { /* called during 'long' operations (algorithms, smoothing, etc.) to give some indication that the program will ever finish. Draws a temperature gauge in either mainW (if not useRoot), or ctrlW. Tries to be clever: only draws gauge if it looks like the operation is going to take more than a few seconds. Calling with val == max removes the gauge. */ static int waiting = 0; static time_t lastTime = 0; time_t nowTime; double doneness; Window win; int xpos,ypos; if (useroot) { win=ctrlW; xpos=10; ypos=3; } else { win=mainW; xpos=5; ypos=5; } if (!win) return; if (min >= max) return; if (val==max && lastTime==0) return; /* already erased meter */ doneness = ((double) (val-min)) / ((double) (max - min)); time(&nowTime); if (lastTime == 0) { /* first time we're calling for this meter */ lastTime = nowTime; waiting = 1; } else if (waiting) { /* haven't drawn meter yet... */ if ((nowTime - lastTime >= 2) && doneness < .5) waiting = 0; } if (!waiting) { /* not waiting (or not waiting any longer) */ if (nowTime == lastTime && val= max) { /* remove temp gauge */ XClearArea(theDisp, win, xpos,ypos, 100+1,19+1, True); lastTime = 0; } } } /***************************************************/ void XVDeletedFile(fullname) char *fullname; { /* called whenever a file has been deleted. Updates browser & dir windows, if necessary */ BRDeletedFile(fullname); DIRDeletedFile(fullname); } /***************************************************/ void XVCreatedFile(fullname) char *fullname; { /* called whenever a file has been deleted. Updates browser & dir windows, if necessary */ BRCreatedFile(fullname); DIRCreatedFile(fullname); } /***************************************************/ void xvbcopy(src, dst, len) char *src, *dst; size_t len; { /* Modern OS's (Solaris, etc.) frown upon the use of bcopy(), * and only want you to use memcpy(). However, memcpy() is broken, * in the sense that it doesn't properly handle overlapped regions * of memory. This routine does, and also has its arguments in * the same order as bcopy() did, without using bcopy(). */ /* determine if the regions overlap * * 3 cases: src=dst, srcdst * * if src=dst, they overlap completely, but nothing needs to be moved * if srcdst then they overlap * if src>dst and srcdst) { /* do a backward copy */ src = src + len - 1; dst = dst + len - 1; for ( ; len>0; len--, src--, dst--) *dst = *src; } else { /* they either overlap (src>dst) or they don't overlap */ /* do a forward copy */ for ( ; len>0; len--, src++, dst++) *dst = *src; } } /***************************************************/ int xvbcmp (s1, s2, len) char *s1, *s2; size_t len; { for ( ; len>0; len--, s1++, s2++) { if (*s1 < *s2) return -1; else if (*s1 > *s2) return 1; } return 0; } /***************************************************/ void xvbzero(s, len) char *s; size_t len; { for ( ; len>0; len--) *s++ = 0; } /***************************************************/ void xv_getwd(buf, buflen) char *buf; size_t buflen; { /* gets the current working directory. No trailing '/' */ char *rv; #ifdef USE_GETCWD rv = (char *) getcwd(buf, buflen); #else rv = (char *) getwd(buf); #endif if (!rv || strlen(rv)==0) { if (((rv=(char *) getenv("PWD"))==NULL) && ((rv=(char *) getenv("cwd"))==NULL)) rv = "./"; strcpy(buf, rv); } #ifdef AUTO_EXPAND Vdtodir(buf); #endif } /***************************************************/ /* * Source code for the "strstr" library routine. * * Copyright 1988 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. */ char *xv_strstr(string, substring) char *string; /* String to search. */ char *substring; /* Substring to try to find in string. */ { register char *a, *b; /* First scan quickly through the two strings looking for a * single-character match. When it's found, then compare the * rest of the substring. */ b = substring; if (*b == 0) return string; for ( ; *string != 0; string += 1) { if (*string != *b) continue; a = string; while (1) { if (*b == 0) return string; if (*a++ != *b++) break; } b = substring; } return (char *) 0; } /***************************************************/ /***************************************************/ FILE *xv_fopen(fname, mode) char *fname, *mode; { FILE *fp; #ifndef VMS fp = fopen(fname, mode); #else fp = fopen(fname, mode, "ctx=stm"); #endif return fp; } /***************************************************/ void xv_mktemp(buf, fname) char *buf, *fname; { #ifndef VMS sprintf(buf, "%s/%s", tmpdir, fname); #else sprintf(buf, "Sys$Disk:[]%s", fname); #endif } /*******/ void Timer(msec) /* waits for 'n' milliseconds */ int msec; /*******/ { long usec; if (msec <= 0) return; usec = (long) msec * 1000; #ifdef VMS { float ftime; ftime = msec / 1000.0; lib$wait(&ftime); return; } #endif #ifdef sgi { float ticks_per_msec; long ticks; ticks_per_msec = (float) CLK_TCK / 1000.0; ticks = (long) ((float) msec * ticks_per_msec); sginap(ticks); return; } #endif #if defined(SVR4) || defined(sco) { struct pollfd dummy; poll(&dummy, 0, msec); return; } #endif #ifdef USLEEP usleep(usec); return; #endif #ifdef NOTIMER return; #endif #ifndef VMS { /* default Timer() method now uses 'select()', which probably works on all systems *anyhow* (except for VMS...) */ struct timeval time; time.tv_sec = usec / 1000000L; time.tv_usec = usec % 1000000L; select(0, XV_FDTYPE NULL, XV_FDTYPE NULL, XV_FDTYPE NULL, &time); } #endif /* VMS */ }