f.file.cc (fotoxx-23.0) | : | f.file.cc (fotoxx-23.1) | ||
---|---|---|---|---|
/******************************************************************************* * | /******************************************************************************* * | |||
Fotoxx edit photos and manage collections | Fotoxx - edit photos and manage collections | |||
Copyright 2007-2023 Michael Cornelison | Copyright 2007-2023 Michael Cornelison | |||
source code URL: https://kornelix.net | source code URL: https://kornelix.net | |||
contact: mkornelix@gmail.com | contact: mkornelix@gmail.com | |||
This program is free software: you can redistribute it and/or modify | 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 | it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation, either version 3 of the License, or | the Free Software Foundation, either version 3 of the License, or | |||
(at your option) any later version. See https://www.gnu.org/licenses | (at your option) any later version. See https://www.gnu.org/licenses | |||
skipping to change at line 93 | skipping to change at line 93 | |||
#define EX extern // disable extern declarations | #define EX extern // disable extern declarations | |||
#include "fotoxx.h" // (variables in fotoxx.h are refs) | #include "fotoxx.h" // (variables in fotoxx.h are refs) | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// start a new parallel session of fotoxx | // start a new parallel session of fotoxx | |||
// new window is slightly down and right from old window | // new window is slightly down and right from old window | |||
// args = optional command line args | // args = optional command line args | |||
// current file is appended if it exists | // current file is appended if it exists | |||
void m_new_session(GtkWidget *, cchar *) | void m_new_session(GtkWidget *, ch *) | |||
{ | { | |||
char *pp; | ch *pp; | |||
int cc; | int cc; | |||
F1_help_topic = "new session"; | F1_help_topic = "new session"; | |||
Plog(1,"m_new_session \n"); | Plog(1,"m_new_session \n"); | |||
if (curr_file) { | if (curr_file) { | |||
cc = strlen(curr_file); | cc = strlen(curr_file); | |||
pp = (char *) zmalloc(cc+100,"new-session"); | pp = (ch *) zmalloc(cc+100,"new-session"); | |||
repl_1str(curr_file,pp+1,"\"","\\\""); // replace embedded " with \" 22.30 | repl_1str(curr_file,pp+1,"\"","\\\""); // replace embedded " with \" 22.30 | |||
pp[0] = '"'; | pp[0] = '"'; | |||
cc = strlen(pp); // add " at both ends | cc = strlen(pp); // add " at both ends | |||
pp[cc] = '"'; | pp[cc] = '"'; | |||
pp[cc+1] = 0; | pp[cc+1] = 0; | |||
new_session(pp); | new_session(pp); | |||
zfree(pp); | zfree(pp); | |||
} | } | |||
else new_session(0); | else new_session(0); | |||
return; | return; | |||
} | } | |||
// callable new session function | // callable new session function | |||
void new_session(cchar *args) | void new_session(ch *args) | |||
{ | { | |||
int cc, xx, yy, ww, hh; | int cc, xx, yy, ww, hh; | |||
char progexe[300]; | ch progexe[300]; | |||
// do before new session: | // do before new session: | |||
zdialog_inputs("save"); // save dialog inputs | zdialog_inputs("save"); // save dialog inputs | |||
zdialog_geometry("save"); // save dialogs position/size | zdialog_geometry("save"); // save dialogs position/size | |||
gallery_memory("save"); // save recent gallery positions | gallery_memory("save"); // save recent gallery positions | |||
save_params(); // save state for next session | save_params(); // save state for next session | |||
gtk_window_get_position(MWIN,&xx,&yy); // get window position and size | gtk_window_get_position(MWIN,&xx,&yy); // get window position and size | |||
gtk_window_get_size(MWIN,&ww,&hh); | gtk_window_get_size(MWIN,&ww,&hh); | |||
xx += 100; // shift down and right | xx += 100; // shift down and right | |||
yy += 100; | yy += 100; | |||
skipping to change at line 151 | skipping to change at line 151 | |||
if (! args) args = ""; | if (! args) args = ""; | |||
zshell("log ack","%s -c %d %d %d %d %s &",progexe,xx,yy,ww,hh,args); | zshell("log ack","%s -c %d %d %d %d %s &",progexe,xx,yy,ww,hh,args); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// find and open an image file using a file open dialog | // find and open an image file using a file open dialog | |||
void m_open_file(GtkWidget *, cchar *) | void m_open_file(GtkWidget *, ch *) | |||
{ | { | |||
int err; | int err; | |||
F1_help_topic = "open image file"; | F1_help_topic = "open image file"; | |||
Plog(1,"m_open_file \n"); | Plog(1,"m_open_file \n"); | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
err = f_open(0,0,0,1,0); | err = f_open(0,0,0,1,0); | |||
if (err) return; | if (err) return; | |||
m_viewmode(0,"F"); // file view mode | m_viewmode(0,"F"); // file view mode | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// open the previous file opened (not the same as toolbar [prev] button) | // open the previous file opened (not the same as toolbar [prev] button) | |||
// repeated use will alternate the two most recent files | // repeated use will alternate the two most recent files | |||
void m_cycle2files(GtkWidget *, cchar *) | void m_cycle2files(GtkWidget *, ch *) | |||
{ | { | |||
FILE *fid; | FILE *fid; | |||
char *file, buff[XFCC]; | ch *file, buff[XFCC]; | |||
int Nth = 0, err; | int Nth = 0, err; | |||
float gzoom; | float gzoom; | |||
F1_help_topic = "cycle 2"; | F1_help_topic = "cycle 2"; | |||
Plog(1,"m_cycle2files \n"); | Plog(1,"m_cycle2files \n"); | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
m_viewmode(0,"F"); | m_viewmode(0,"F"); | |||
skipping to change at line 213 | skipping to change at line 213 | |||
Cstate->fzoom = gzoom; // keep same image scale | Cstate->fzoom = gzoom; // keep same image scale | |||
Fpaint2(); | Fpaint2(); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// open the 2nd previous file opened | // open the 2nd previous file opened | |||
// repeated use will alternate the 3 most recent files | // repeated use will alternate the 3 most recent files | |||
void m_cycle3files(GtkWidget *, cchar *) | void m_cycle3files(GtkWidget *, ch *) | |||
{ | { | |||
FILE *fid; | FILE *fid; | |||
char *file, buff[XFCC]; | ch *file, buff[XFCC]; | |||
int Nth = 0, err; | int Nth = 0, err; | |||
float gzoom; | float gzoom; | |||
F1_help_topic = "cycle 3"; | F1_help_topic = "cycle 3"; | |||
Plog(1,"m_cycle3files \n"); | Plog(1,"m_cycle3files \n"); | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
m_viewmode(0,"F"); | m_viewmode(0,"F"); | |||
skipping to change at line 267 | skipping to change at line 267 | |||
namespace view360 | namespace view360 | |||
{ | { | |||
void show(); | void show(); | |||
void * show_thread(void *arg); | void * show_thread(void *arg); | |||
void mouse(); | void mouse(); | |||
void KB_func(int key); | void KB_func(int key); | |||
void quit(); | void quit(); | |||
PXB *filepxb, *viewpxb; | PXB *filepxb, *viewpxb; | |||
PIXBUF *viewpixbuf; | PIXBUF *viewpixbuf; | |||
char *filename = 0; | ch *filename = 0; | |||
int Frecalc; | int Frecalc; | |||
int fww, fhh; // file dimensions | int fww, fhh; // file dimensions | |||
int dww, dhh; // window dimensions | int dww, dhh; // window dimensions | |||
int pdww, pdhh; | int pdww, pdhh; | |||
int cx, cy; | int cx, cy; | |||
float *Fx, *Fy, zoom; | float *Fx, *Fy, zoom; | |||
zdialog *zd; | zdialog *zd; | |||
} | } | |||
// menu function | // menu function | |||
void m_view360(GtkWidget *, const char *) | void m_view360(GtkWidget *, ch *) | |||
{ | { | |||
using namespace view360; | using namespace view360; | |||
F1_help_topic = "view 360° pano"; | F1_help_topic = "view 360° pano"; | |||
Plog(1,"m_view360 \n"); | Plog(1,"m_view360 \n"); | |||
if (Fblock("view360","block edits")) return; // check pend, block | if (Fblock("view360","block edits")) return; // check pend, block | |||
if (clicked_file) { // use clicked file if present | if (clicked_file) { // use clicked file if present | |||
skipping to change at line 546 | skipping to change at line 546 | |||
gdk_window_thaw_updates(gdkwin); | gdk_window_thaw_updates(gdkwin); | |||
Fpaint2(); | Fpaint2(); | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// rename menu function | // rename menu function | |||
// activate rename dialog, stuff data from current or clicked file | // activate rename dialog, stuff data from current or clicked file | |||
// dialog remains active when new file is opened | // dialog remains active when new file is opened | |||
char rename_old[200] = ""; | ch rename_old[200] = ""; | |||
// base names only | // base names only | |||
char rename_new[200] = ""; | ch rename_new[200] = ""; | |||
char rename_prev[200] = ""; | ch rename_prev[200] = ""; | |||
char *rename_file = 0; | ch *rename_file = 0; | |||
void m_rename(GtkWidget *, cchar *menu) | void m_rename(GtkWidget *, ch *menu) | |||
{ | { | |||
int rename_dialog_event(zdialog *zd, cchar *event); | int rename_dialog_event(zdialog *zd, ch *event); | |||
char *pdir, *pfile, *pext; | ch *pdir, *pfile, *pext; | |||
F1_help_topic = "rename"; | F1_help_topic = "rename"; | |||
Plog(1,"m_rename \n"); | Plog(1,"m_rename \n"); | |||
if (rename_file) zfree(rename_file); | if (rename_file) zfree(rename_file); | |||
rename_file = 0; | rename_file = 0; | |||
if (clicked_file) { // use clicked file if present | if (clicked_file) { // use clicked file if present | |||
rename_file = clicked_file; | rename_file = clicked_file; | |||
skipping to change at line 630 | skipping to change at line 630 | |||
strncpy0(rename_old,pfile,199); | strncpy0(rename_old,pfile,199); | |||
strncpy0(rename_new,pfile,199); | strncpy0(rename_new,pfile,199); | |||
zdialog_stuff(zd,"oldname",rename_old); // current file name | zdialog_stuff(zd,"oldname",rename_old); // current file name | |||
zdialog_stuff(zd,"newname",rename_new); // entered file name (same) | zdialog_stuff(zd,"newname",rename_new); // entered file name (same) | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int rename_dialog_event(zdialog *zd, cchar *event) | int rename_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
char *pp, *pdir, *pfile, *pext, suffix[16]; | ch *pp, *pdir, *pfile, *pext, suffix[16]; | |||
char *newfile = 0, *nextfile = 0, namever[200]; | ch *newfile = 0, *nextfile = 0, namever[200]; | |||
int nseq, digits, ccp, ccn, ccx, err, Fkeep; | int nseq, digits, ccp, ccn, ccx, err, Fkeep; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (strmatch(event,"prev")) // previous name >> new name | if (strmatch(event,"prev")) // previous name >> new name | |||
{ | { | |||
if (! *rename_prev) return 1; | if (! *rename_prev) return 1; | |||
if (! rename_file) return 1; | if (! rename_file) return 1; | |||
pp = strrchr(rename_prev,'.'); | pp = strrchr(rename_prev,'.'); | |||
skipping to change at line 709 | skipping to change at line 709 | |||
parsefile(rename_file,&pdir,&pfile,&pext); // existing /folders/file.ext | parsefile(rename_file,&pdir,&pfile,&pext); // existing /folders/file.ext | |||
zdialog_fetch(zd,"newname",rename_new,194); // new file name from user | zdialog_fetch(zd,"newname",rename_new,194); // new file name from user | |||
ccp = strlen(pdir); // length of /folders/ | ccp = strlen(pdir); // length of /folders/ | |||
ccn = strlen(rename_new); // length of file | ccn = strlen(rename_new); // length of file | |||
if (pext) ccx = strlen(pext); // length of .ext | if (pext) ccx = strlen(pext); // length of .ext | |||
else ccx = 0; | else ccx = 0; | |||
newfile = (char *) zmalloc(ccp + ccn + ccx + 1,"rename"); // put it all together | newfile = (ch *) zmalloc(ccp + ccn + ccx + 1,"rename"); // put it all together | |||
strncpy(newfile,rename_file,ccp); // /folders.../newfilename.ext | strncpy(newfile,rename_file,ccp); // /folders.../newfilename.ext | |||
strcpy(newfile+ccp,rename_new); | strcpy(newfile+ccp,rename_new); | |||
if (ccx) strcpy(newfile+ccp+ccn,pext); | if (ccx) strcpy(newfile+ccp+ccn,pext); | |||
if (regfile(newfile)) { // check if new name exists | if (regfile(newfile)) { // check if new name exists | |||
zmessageACK(Mwin,"output file exists"); | zmessageACK(Mwin,"output file exists"); | |||
zfree(newfile); | zfree(newfile); | |||
newfile = 0; | newfile = 0; | |||
return 1; | return 1; | |||
} | } | |||
if (FGWM == 'F') | if (FGWM == 'F') | |||
nextfile = gallery(0,"get",curr_file_posn+1); // save next file, before rename | nextfile = gallery(0,"getR",curr_file_posn+1); // save next file, before rename 23.1 | |||
else nextfile = 0; | else nextfile = 0; | |||
if (Fblock("rename","block edits")) return 1; // check pend, block | if (Fblock("rename","block edits")) return 1; // check pend, block | |||
err = rename(rename_file,newfile); // rename the file | err = rename(rename_file,newfile); // rename the file | |||
if (err) { | if (err) { | |||
zmessageACK(Mwin,"file error: %s",strerror(errno)); | zmessageACK(Mwin,"file error: %s",strerror(errno)); | |||
Fblock("rename",0); | Fblock("rename",0); | |||
goto KILL; | goto KILL; | |||
} | } | |||
skipping to change at line 764 | skipping to change at line 764 | |||
} | } | |||
Fblock("rename",0); | Fblock("rename",0); | |||
zdialog_fetch(zd,"keepopen",Fkeep); | zdialog_fetch(zd,"keepopen",Fkeep); | |||
if (Fkeep) { // keep dialog open | if (Fkeep) { // keep dialog open | |||
if (FGWM == 'F' && nextfile) { | if (FGWM == 'F' && nextfile) { | |||
f_open(nextfile); // will call m_rename() | f_open(nextfile); // will call m_rename() | |||
gtk_window_present(MWIN); // keep focus on main window | gtk_window_present(MWIN); // keep focus on main window | |||
} | } | |||
if (nextfile) zfree(nextfile); | ||||
nextfile = 0; | ||||
if (newfile) zfree(newfile); | if (newfile) zfree(newfile); | |||
newfile = 0; | newfile = 0; | |||
return 1; | return 1; | |||
} | } | |||
else { // close dialog | else { // close dialog | |||
f_open(newfile); // open renamed file | f_open(newfile); // open renamed file | |||
goto KILL; | goto KILL; | |||
} | } | |||
KILL: | KILL: | |||
if (nextfile) zfree(nextfile); | ||||
nextfile = 0; | ||||
if (newfile) zfree(newfile); | if (newfile) zfree(newfile); | |||
newfile = 0; | newfile = 0; | |||
zdialog_free(zd); // kill dialog | zdialog_free(zd); // kill dialog | |||
zd_rename = 0; | zd_rename = 0; | |||
return 1; | return 1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// show and change file permissions | // show and change file permissions | |||
char *permissions_file = 0; | ch *permissions_file = 0; | |||
void m_permissions(GtkWidget *, cchar *menu) | void m_permissions(GtkWidget *, ch *menu) | |||
{ | { | |||
int permissions_dialog_event(zdialog *zd, cchar *event); | int permissions_dialog_event(zdialog *zd, ch *event); | |||
char permissions[100]; | ch permissions[100]; | |||
cchar *pp; | ch *pp; | |||
STATB statB; | STATB statB; | |||
int ftype; | int ftype; | |||
F1_help_topic = "permissions"; | F1_help_topic = "permissions"; | |||
Plog(1,"m_permissions \n"); | Plog(1,"m_permissions \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (permissions_file) zfree(permissions_file); | if (permissions_file) zfree(permissions_file); | |||
skipping to change at line 907 | skipping to change at line 903 | |||
if (pp) zdialog_stuff(zd,"permgrp",pp); | if (pp) zdialog_stuff(zd,"permgrp",pp); | |||
pp = substring(permissions,',',3); | pp = substring(permissions,',',3); | |||
if (pp) zdialog_stuff(zd,"permoth",pp); | if (pp) zdialog_stuff(zd,"permoth",pp); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int permissions_dialog_event(zdialog *zd, cchar *event) | int permissions_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int Fkeep; | int Fkeep; | |||
mode_t mode; | mode_t mode; | |||
char permown[20], permgrp[20], permoth[20]; | ch permown[20], permgrp[20], permoth[20]; | |||
char permissions[100]; | ch permissions[100]; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat == 0) return 1; // wait for dialog finished | if (zd->zstat == 0) return 1; // wait for dialog finished | |||
if (zd->zstat != 1) goto KILL; // [cancel] or [x] | if (zd->zstat != 1) goto KILL; // [cancel] or [x] | |||
zdialog_fetch(zd,"permown",permown,20); // [apply] | zdialog_fetch(zd,"permown",permown,20); // [apply] | |||
zdialog_fetch(zd,"permgrp",permgrp,20); // construct permissions string | zdialog_fetch(zd,"permgrp",permgrp,20); // construct permissions string | |||
zdialog_fetch(zd,"permoth",permoth,20); // e.g. "read+write, read only, no access" | zdialog_fetch(zd,"permoth",permoth,20); // e.g. "read+write, read only, no access" | |||
snprintf(permissions,100,"%s, %s, %s",permown,permgrp,permoth); | snprintf(permissions,100,"%s, %s, %s",permown,permgrp,permoth); | |||
skipping to change at line 948 | skipping to change at line 944 | |||
return 1; | return 1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Remove alpha channel if present | // Remove alpha channel if present | |||
// RGB pixels are reduced according to alpha channel value | // RGB pixels are reduced according to alpha channel value | |||
// RGBout = RGBin * (alpha/255) | // RGBout = RGBin * (alpha/255) | |||
// Transparent margins (e.g. panorama images) will become black. | // Transparent margins (e.g. panorama images) will become black. | |||
void m_remove_alpha(GtkWidget *, cchar *) | void m_remove_alpha(GtkWidget *, ch *) | |||
{ | { | |||
int remove_alpha_dialog_event(zdialog *zd, cchar *event); | int remove_alpha_dialog_event(zdialog *zd, ch *event); | |||
int ftype; | int ftype; | |||
char *pp; | ch *pp; | |||
F1_help_topic = "remove alpha"; | F1_help_topic = "remove alpha"; | |||
Plog(1,"m_remove_alpha \n"); | Plog(1,"m_remove_alpha \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
if (! curr_file) return; | if (! curr_file) return; | |||
ftype = image_file_type(curr_file); | ftype = image_file_type(curr_file); | |||
if (ftype != IMAGE) return; | if (ftype != IMAGE) return; | |||
skipping to change at line 1020 | skipping to change at line 1016 | |||
else | else | |||
zdialog_stuff(zd,"labpresent","not present"); | zdialog_stuff(zd,"labpresent","not present"); | |||
zdialog_present(zd); | zdialog_present(zd); | |||
return; | return; | |||
} | } | |||
// dialog event and completion function | // dialog event and completion function | |||
int remove_alpha_dialog_event(zdialog *zd, cchar *event) | int remove_alpha_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int zstat = zd->zstat; | int zstat = zd->zstat; | |||
if (! E0pxm) goto KILL; | if (! E0pxm) goto KILL; | |||
if (strmatch(event,"escape")) zstat = -2; // escape key | if (strmatch(event,"escape")) zstat = -2; // escape key | |||
if (! zstat) return 1; // wait for dialog completion | if (! zstat) return 1; // wait for dialog completion | |||
if (zstat == 1) // [remove] | if (zstat == 1) // [remove] | |||
skipping to change at line 1072 | skipping to change at line 1068 | |||
// Fack: failure will cause a popup ACK dialog. | // Fack: failure will cause a popup ACK dialog. | |||
// fzoom: keep current zoom level and position, otherwise fit window. | // fzoom: keep current zoom level and position, otherwise fit window. | |||
// | // | |||
// Following are set: curr_file_type, curr_file_bpc, curr_file_size. | // Following are set: curr_file_type, curr_file_bpc, curr_file_size. | |||
// Returns: 0 = OK, +N = error. | // Returns: 0 = OK, +N = error. | |||
// errors: 1 reentry | // errors: 1 reentry | |||
// 2 curr. edit function cannot be restarted or canceled | // 2 curr. edit function cannot be restarted or canceled | |||
// 3 file not found or user cancel | // 3 file not found or user cancel | |||
// 4 unsupported file type or PXB_load() failure | // 4 unsupported file type or PXB_load() failure | |||
int f_open(cchar *filespec, int Nth, int Fkeep, int Fack, int fzoom) | int f_open(ch *filespec, int Nth, int Fkeep, int Fack, int fzoom) | |||
{ | { | |||
PXB *tempxb = 0; | PXB *tempxb = 0; | |||
int fposn, retcode = 0; | int fposn, retcode = 0; | |||
FTYPE ftype; | FTYPE ftype; | |||
static int Freent = 0; | static int Freent = 0; | |||
char *pp, *file; | ch *pp, *file; | |||
void (*editfunc)(GtkWidget *, cchar *); | void (*editfunc)(GtkWidget *, ch *); | |||
if (Freent++) { // stop re-entry | if (Freent++) { // stop re-entry | |||
Plog(0,"f_open() re-entry \n"); | Plog(0,"f_open() re-entry \n"); | |||
goto ret1; | goto ret1; | |||
} | } | |||
poptext_killnow(); // kill pending popup message | poptext_killnow(); // kill pending popup message | |||
if (CEF && ! CEF->Frestart) goto ret2; // edit function not restartable | if (CEF && ! CEF->Frestart) goto ret2; // edit function not restartable | |||
skipping to change at line 1150 | skipping to change at line 1146 | |||
curr_file = file; // new current file | curr_file = file; // new current file | |||
Fpxb = tempxb; // pixmap for current image | Fpxb = tempxb; // pixmap for current image | |||
strcpy(curr_file_type,f_load_type); // set curr_file_xxx from f_load_xxx | strcpy(curr_file_type,f_load_type); // set curr_file_xxx from f_load_xxx | |||
curr_file_bpc = f_load_bpc; | curr_file_bpc = f_load_bpc; | |||
curr_file_size = f_load_size; | curr_file_size = f_load_size; | |||
load_filemeta(curr_file); // load metadata used by fotoxx | load_filemeta(curr_file); // load metadata used by fotoxx | |||
Fexif_edithist = 0; // no edit history data loaded | Fmeta_edithist = 0; // no edit history data loaded | |||
Fupright = Flevel = 0; // file not uprighted or levelled | Fupright = Flevel = 0; // file not uprighted or levelled | |||
if (ftype == RAW) Fupright = 1; // assume RAW loaders do upright | if (ftype == RAW) Fupright = 1; // assume RAW loaders do upright | |||
fposn = file_position(file,Nth); // file position in gallery list | fposn = file_position(file,Nth); // file position in gallery list | |||
if (fposn < 0) { // not there | if (fposn < 0) { // not there | |||
gallery(curr_file,"init",0); // generate new gallery list | gallery(curr_file,"init",0); // generate new gallery list | |||
gallery(0,"sort",-2); // recall sort and position | gallery(0,"sort",-2); // recall sort and position | |||
gallery(curr_file,"paint",0); // position at curr. file | gallery(curr_file,"paint",0); // position at curr. file | |||
fposn = file_position(curr_file,0); // position and count in gallery list | fposn = file_position(curr_file,0); // position and count in gallery list | |||
skipping to change at line 1176 | skipping to change at line 1172 | |||
zoomx = zoomy = 0; // no zoom center | zoomx = zoomy = 0; // no zoom center | |||
} | } | |||
add_recent_file(curr_file); // most recent file opened | add_recent_file(curr_file); // most recent file opened | |||
if (zd_rename) m_rename(0,0); // update active rename dialog | if (zd_rename) m_rename(0,0); // update active rename dialog | |||
if (zd_permissions) m_permissions(0,0); // " permissions dialog | if (zd_permissions) m_permissions(0,0); // " permissions dialog | |||
if (zd_remove_alpha) m_remove_alpha(0,0); // " remove_alpha dialog | if (zd_remove_alpha) m_remove_alpha(0,0); // " remove_alpha dialog | |||
if (zd_copymove) m_copy_move(0,0); // " copy/move dialog | if (zd_copymove) m_copy_move(0,0); // " copy/move dialog | |||
if (zd_deltrash) m_delete_trash(0,0); // " delete/trash dialog | if (zd_deltrash) m_delete_trash(0,0); // " delete/trash dialog | |||
if (zd_metaview) meta_view(0); // " EXIF/IPTC data view window | if (zd_metaview) meta_view(0); // " metadata view window | |||
if (zd_editmeta) m_meta_edit_main(0,0); // " edit metadata dialog | if (zd_editmeta) m_meta_edit_main(0,0); // " edit metadata dialog | |||
if (zd_editanymeta) m_meta_edit_any(0,0); // " edit any metadata dialog | if (zd_editanymeta) m_meta_edit_any(0,0); // " edit any metadata dialog | |||
if (zd_deletemeta) m_meta_delete(0,0); // " delete metadata dialog | if (zd_deletemeta) m_meta_delete(0,0); // " delete metadata dialog | |||
if (Fcaps) meta_show_caps(1); // show captions on current image | if (Fcaps) meta_show_caps(1); // show captions on current image | |||
if (editfunc) editfunc(0,0); // restart edit function | if (editfunc) editfunc(0,0); // restart edit function | |||
if (ftype == VIDEO) // offer to play video file | if (ftype == VIDEO) // offer to play video file | |||
zmessage_post_bold(Mwin,"20/30",3,"VIDEO press P to play"); | zmessage_post_bold(Mwin,"20/30",3,"VIDEO press P to play"); | |||
skipping to change at line 1246 | skipping to change at line 1242 | |||
} | } | |||
curr_file_posn = fposn; // keep track of file position | curr_file_posn = fposn; // keep track of file position | |||
strcpy(curr_file_type,f_save_type); // set curr_file_xxx from f_save_xxx | strcpy(curr_file_type,f_save_type); // set curr_file_xxx from f_save_xxx | |||
curr_file_bpc = f_save_bpc; | curr_file_bpc = f_save_bpc; | |||
curr_file_size = f_save_size; | curr_file_size = f_save_size; | |||
zoomx = zoomy = 0; // no zoom center | zoomx = zoomy = 0; // no zoom center | |||
if (FGWM == 'F') set_mwin_title(); // set win title from curr_file info | if (FGWM == 'F') set_mwin_title(); // set win title from curr_file info | |||
if (zd_metaview) meta_view(0); // update EXIF/IPTC view window | if (zd_metaview) meta_view(0); // update meta view window | |||
return 0; | return 0; | |||
} | } | |||
/******************************************************************************* * | /******************************************************************************* * | |||
Remove a file and clean up index, thumbnails, gallery, curr_file. | Remove a file and clean up index, thumbnails, gallery, curr_file. | |||
Albums must be handled separately via album_purge_replace(). | Albums must be handled separately via album_purge_replace(). | |||
'opt' is "delete" or "trash". | 'opt' is "delete" or "trash". | |||
trash logic: Move target file to ~/Desktop/ first, then move to trash. | trash logic: Move target file to ~/Desktop/ first, then move to trash. | |||
Gnome trash fails for files on mounted volumes. | Gnome trash fails for files on mounted volumes. | |||
Returns 0 if OK, else error code. | Returns 0 if OK, else error code. | |||
****/ | ****/ | |||
int f_remove(cchar *file, cchar *opt) | int f_remove(ch *file, ch *opt) | |||
{ | { | |||
int err, Nth; | int err, Nth; | |||
char *currfile = 0; | ch *cfile = 0; | |||
char trashfile[400] = "~/Desktop/"; | ch trashfile[400] = "~/Desktop/"; | |||
cchar *pp; | ch *pp; | |||
GFile *gfile; | GFile *gfile; | |||
GError *gerror = 0; | GError *gerror = 0; | |||
int gstat; | int gstat; | |||
if (*opt == 'd') // delete | if (*opt == 'd') // delete | |||
{ | { | |||
err = remove(file); | err = remove(file); | |||
if (err && errno != ENOENT) { // OK if already deleted | if (err && errno != ENOENT) { // OK if already deleted | |||
zmessageACK(Mwin,"delete %s \n %s",file,strerror(errno)); | zmessageACK(Mwin,"delete %s \n %s",file,strerror(errno)); | |||
return err; | return err; | |||
skipping to change at line 1318 | skipping to change at line 1314 | |||
} | } | |||
delete_image_index(file); // delete file in image index | delete_image_index(file); // delete file in image index | |||
delete_thumbfile(file); // delete thumbnail file and cache | delete_thumbfile(file); // delete thumbnail file and cache | |||
Nth = file_position(file,0); // find in gallery list | Nth = file_position(file,0); // find in gallery list | |||
if (Nth >= 0) gallery(0,"delete",Nth); // delete from gallery list | if (Nth >= 0) gallery(0,"delete",Nth); // delete from gallery list | |||
if (curr_file && strmatch(file,curr_file)) { // current file was removed | if (curr_file && strmatch(file,curr_file)) { // current file was removed | |||
free_resources(); | free_resources(); | |||
currfile = gallery(0,"get",curr_file_posn); | cfile = gallery(0,"getR",curr_file_posn); | |||
// new current file = next | // new current file = next 23.1 | |||
if (currfile) { | if (cfile) f_open(cfile); | |||
f_open(currfile); | ||||
zfree(currfile); | ||||
} | ||||
else { | else { | |||
Nth = curr_file_posn - 1; | Nth = curr_file_posn - 1; | |||
if (Nth >= navi::Gfolders && Nth < navi::Gfiles) { // no next, try previous 22.35 | if (Nth >= navi::Gfolders && Nth < navi::Gfiles) { // no next, try previous 22.35 | |||
currfile = gallery(0,"get",curr_file_posn - 1); | cfile = gallery(0,"getR",curr_file_posn - 1); | |||
if (currfile) { | // 23.1 | |||
f_open(currfile); | if (cfile) f_open(cfile); | |||
zfree(currfile); | ||||
} | ||||
} | } | |||
} | } | |||
} | } | |||
if (! currfile && FGWM == 'F') m_blank_window(0,0); // 22.35 | if (! cfile && FGWM == 'F') m_blank_window(0,0); // 22.35 | |||
return 0; | return 0; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Function to preload image files hopefully ahead of need. | // Function to preload image files hopefully ahead of need. | |||
// Usage: f_preload(next) | // Usage: f_preload(next) | |||
// next = -1 / +1 to read previous / next image file in curr. gallery | // next = -1 / +1 to read previous / next image file in curr. gallery | |||
// preload_file will be non-zero if and when preload_pxb is available. | // preload_file will be non-zero if and when preload_pxb is available. | |||
void f_preload(int next, int Flast) | void f_preload(int next, int Flast) | |||
{ | { | |||
int fd; | int fd; | |||
char *file; | ch *file; | |||
if (! curr_file) return; | if (! curr_file) return; | |||
file = prev_next_file(next,Flast); | file = prev_next_file(next,Flast); | |||
if (! file) return; | if (! file) return; | |||
if (strmatch(file,curr_file)) { | if (strmatch(file,curr_file)) return; | |||
zfree(file); | ||||
return; | ||||
} | ||||
fd = open(file,O_RDONLY); | fd = open(file,O_RDONLY); | |||
if (fd >= 0) { | if (fd >= 0) { | |||
posix_fadvise(fd,0,0,POSIX_FADV_WILLNEED); // preload file in kernel cache | posix_fadvise(fd,0,0,POSIX_FADV_WILLNEED); // preload file in kernel cache | |||
close(fd); | close(fd); | |||
} | } | |||
zfree(file); | ||||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Open previous or next file in current gallery list, | // Open previous or next file in current gallery list, | |||
// or jump to previous or next gallery when at the limits. | // or jump to previous or next gallery when at the limits. | |||
// index is -1 / +1 for prev / next file. | // index is -1 / +1 for prev / next file. | |||
// Fjump: jump to last file version, jump to prev/next folder. | // Fjump: jump to last file version, jump to prev/next folder. | |||
void x_prev_next(int index, int Fjump) | void x_prev_next(int index, int Fjump) | |||
{ | { | |||
using namespace navi; | using namespace navi; | |||
char *newfile = 0, *newgallery = 0; | ch *newfile = 0, *newgallery = 0; | |||
int err, Nth = 0; | int err, Nth = 0; | |||
static int xbusy = 0, jumpswitch = 0; | static int xbusy = 0, jumpswitch = 0; | |||
static zdialog *zd = 0; | static zdialog *zd = 0; | |||
cchar *mess1 = "Previous gallery"; | ch *mess1 = "Previous gallery"; | |||
cchar *mess2 = "Next gallery"; | ch *mess2 = "Next gallery"; | |||
cchar *mess3 = "Start of gallery"; | ch *mess3 = "Start of gallery"; | |||
cchar *mess4 = "End of gallery"; | ch *mess4 = "End of gallery"; | |||
if (! curr_file) return; | if (! curr_file) return; | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (zd && zdialog_valid2(zd,"post")) zdialog_free(zd); // clear prior popup message | if (zd && zdialog_valid2(zd,"post")) zdialog_free(zd); // clear prior popup message | |||
zd = 0; | zd = 0; | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
if (xbusy) return; // avoid "function busy" | if (xbusy) return; // avoid "function busy" | |||
skipping to change at line 1427 | skipping to change at line 1413 | |||
if (index == -1) zd = zmessage_post_bold(Mwin,"5/5",3,mess3,0); // notify gallery start/end | if (index == -1) zd = zmessage_post_bold(Mwin,"5/5",3,mess3,0); // notify gallery start/end | |||
if (index == +1) zd = zmessage_post_bold(Mwin,"5/5",3,mess4,0); | if (index == +1) zd = zmessage_post_bold(Mwin,"5/5",3,mess4,0); | |||
jumpswitch = 0; | jumpswitch = 0; | |||
} | } | |||
if (Fjump && jumpswitch) { // jump to prev/next gallery | if (Fjump && jumpswitch) { // jump to prev/next gallery | |||
jumpswitch = 0; | jumpswitch = 0; | |||
newgallery = prev_next_gallery(index); | newgallery = prev_next_gallery(index); | |||
if (! newgallery) goto returnx; | if (! newgallery) goto returnx; | |||
gallery(newgallery,"init",0); // load gallery | gallery(newgallery,"init",0); // load gallery | |||
zfree(newgallery); | ||||
gallery(0,"sort",-2); // preserve sort | gallery(0,"sort",-2); // preserve sort | |||
if (Gfiles - Gfolders > 0) { // at least one image file present | if (Gfiles - Gfolders > 0) { // at least one image file present | |||
if (index == +1) Nth = Gfolders; // get first or last image file | if (index == +1) Nth = Gfolders; // get first or last image file | |||
if (index == -1) Nth = Gfiles - 1; | if (index == -1) Nth = Gfiles - 1; | |||
newfile = gallery(0,"get",Nth); | newfile = gallery(0,"getR",Nth); // 23.1 | |||
err = f_open(newfile,Nth,0,1,0); // open image or RAW file | err = f_open(newfile,Nth,0,1,0); // open image or RAW file | |||
if (! err) gallery(newfile,"paint",Nth); | if (! err) gallery(newfile,"paint",Nth); | |||
if (! err) f_preload(index,Fjump); // preload next image | if (! err) f_preload(index,Fjump); // preload next image | |||
goto returnx; | goto returnx; | |||
} | } | |||
else { // no image files in gallery | else { // no image files in gallery | |||
gallery(0,"paint",0); | gallery(0,"paint",0); | |||
m_viewmode(0,"G"); | m_viewmode(0,"G"); | |||
free_resources(); | free_resources(); | |||
} | } | |||
} | } | |||
else if (Fjump) jumpswitch = 1; // hesitate once, jump next time | else if (Fjump) jumpswitch = 1; // hesitate once, jump next time | |||
returnx: | returnx: | |||
if (newfile) zfree(newfile); | ||||
if (newgallery) zfree(newgallery); | ||||
zmainloop(); // refresh window (holding arrow key) | zmainloop(); // refresh window (holding arrow key) | |||
xbusy = 0; | xbusy = 0; | |||
return; | return; | |||
} | } | |||
void m_prev(GtkWidget *, cchar *menu) | void m_prev(GtkWidget *, ch *menu) | |||
{ | { | |||
Plog(1,"m_prev \n"); | Plog(1,"m_prev \n"); | |||
if (menu) x_prev_next(-1,1); // jump option | if (menu) x_prev_next(-1,1); // jump option | |||
else x_prev_next(-1,0); // search from curr_file -1 | else x_prev_next(-1,0); // search from curr_file -1 | |||
return; // to first file | return; // to first file | |||
} | } | |||
void m_next(GtkWidget *, cchar *menu) | void m_next(GtkWidget *, ch *menu) | |||
{ | { | |||
Plog(1,"m_next \n"); | Plog(1,"m_next \n"); | |||
if (menu) x_prev_next(+1,1); // jump option | if (menu) x_prev_next(+1,1); // jump option | |||
else x_prev_next(+1,0); // search from curr_file +1 | else x_prev_next(+1,0); // search from curr_file +1 | |||
return; // to last file | return; // to last file | |||
} | } | |||
void m_prev_next(GtkWidget *, cchar *menu) // left/right mouse click >> | void m_prev_next(GtkWidget *, ch *menu) // left/right mouse click >> | |||
{ // previous/next image file | { // previous/next image file | |||
int button = zfuncs::vmenuclickbutton; | int button = zfuncs::vmenuclickbutton; | |||
if (button == 1) m_prev(0,0); | if (button == 1) m_prev(0,0); | |||
else m_next(0,0); | else m_next(0,0); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// zoom in/out - left/right mouse click on zoom button or F-view image | // zoom in/out - left/right mouse click on zoom button or F-view image | |||
void m_zoom_menu(GtkWidget *, cchar *menu) // left/right mouse click | void m_zoom_menu(GtkWidget *, ch *menu) // left/right mouse click | |||
{ | { | |||
F1_help_topic = "zoom"; | F1_help_topic = "zoom"; | |||
int button = zfuncs::vmenuclickbutton; | int button = zfuncs::vmenuclickbutton; | |||
if (FGWM == 'G') { // G view, larger/smaller thumbnails | if (FGWM == 'G') { // G view, larger/smaller thumbnails | |||
if (button == 1) navi::menufuncx(0,"Zoom+"); | if (button == 1) navi::menufuncx(0,"Zoom+"); | |||
else navi::menufuncx(0,"Zoom-"); | else navi::menufuncx(0,"Zoom-"); | |||
} | } | |||
skipping to change at line 1505 | skipping to change at line 1490 | |||
else m_zoom(0,"Zoom-"); | else m_zoom(0,"Zoom-"); | |||
} | } | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// create a new blank image file with desired background color | // create a new blank image file with desired background color | |||
void m_blank_image(GtkWidget *, cchar *pname) | void m_blank_image(GtkWidget *, ch *pname) | |||
{ | { | |||
char color[20], fname[100], fext[8], *filespec; | ch color[20], fname[100], fext[8], *filespec; | |||
int zstat, err, cc, ww, hh, RGB[3]; | int zstat, err, cc, ww, hh, RGB[3]; | |||
zdialog *zd; | zdialog *zd; | |||
cchar *pp; | ch *pp; | |||
char *curr_folder = 0; | ch *curr_folder = 0; | |||
F1_help_topic = "blank image"; | F1_help_topic = "blank image"; | |||
Plog(1,"m_blank_image \n"); | Plog(1,"m_blank_image \n"); | |||
if (navi::gallerytype == FOLDER) curr_folder = navi::galleryname; | if (navi::gallerytype == FOLDER) curr_folder = navi::galleryname; | |||
else curr_folder = topfolders[0]; | else curr_folder = topfolders[0]; | |||
if (! curr_folder) { | if (! curr_folder) { | |||
Plog(0,"no top image folders defined \n"); // should not happen | Plog(0,"no top image folders defined \n"); // should not happen | |||
return; | return; | |||
skipping to change at line 1618 | skipping to change at line 1603 | |||
Fblock("blank_image",0); | Fblock("blank_image",0); | |||
return; | return; | |||
} | } | |||
// function to create a new blank image file | // function to create a new blank image file | |||
// file extension must be one of: .jpg .tif .png | // file extension must be one of: .jpg .tif .png | |||
// RGB args are in the range 0 - 255 | // RGB args are in the range 0 - 255 | |||
// if file exists it is overwritten | // if file exists it is overwritten | |||
// returns 0 if OK, 1 if file exists, +N if error | // returns 0 if OK, 1 if file exists, +N if error | |||
int create_blank_file(cchar *file, int ww, int hh, int RGB[3]) | int create_blank_file(ch *file, int ww, int hh, int RGB[3]) | |||
{ | { | |||
cchar *pp; | ch *pp; | |||
cchar *fext; | ch *fext; | |||
int cstat; | int cstat; | |||
PXB *tempxb; | PXB *tempxb; | |||
GError *gerror = 0; | GError *gerror = 0; | |||
uint8 *pixel; | uint8 *pixel; | |||
if (regfile(file)) { | if (regfile(file)) { | |||
zmessageACK(Mwin,"output file exists"); // file already exists | zmessageACK(Mwin,"output file exists"); // file already exists | |||
return 1; | return 1; | |||
} | } | |||
skipping to change at line 1666 | skipping to change at line 1651 | |||
} | } | |||
PXB_free(tempxb); | PXB_free(tempxb); | |||
return 0; | return 0; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// blank or restore window | // blank or restore window | |||
void m_blank_window(GtkWidget *, cchar *menu) | void m_blank_window(GtkWidget *, ch *menu) | |||
{ | { | |||
static int Fblank = 0; | static int Fblank = 0; | |||
static char *savefile = 0; | static ch *savefile = 0; | |||
F1_help_topic = "blank window"; | F1_help_topic = "blank window"; | |||
Plog(1,"m_blank_window \n"); | Plog(1,"m_blank_window \n"); | |||
if (FGWM != 'F') m_viewmode(0,"F"); // insure file view mode | if (FGWM != 'F') m_viewmode(0,"F"); // insure file view mode | |||
if (Fblock("blank_window","block edits")) return; // check pend, block | if (Fblock("blank_window","block edits")) return; // check pend, block | |||
if (! Fblank) | if (! Fblank) | |||
skipping to change at line 1703 | skipping to change at line 1688 | |||
Fblank = 1 - Fblank; | Fblank = 1 - Fblank; | |||
Fblock("blank_window",0); | Fblock("blank_window",0); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// animate given GIF file if possible | // animate given GIF file if possible | |||
void play_gif(cchar *file) | void play_gif(ch *file) | |||
{ | { | |||
int gif_animations_dialog_event(zdialog *, cchar *event); | int gif_animations_dialog_event(zdialog *, ch *event); | |||
FILE *fid; | FILE *fid; | |||
char command[300], buff[20] = "", *pp = 0; | ch command[300], buff[20] = "", *pp = 0; | |||
zdialog *zd; | zdialog *zd; | |||
GtkWidget *image; | GtkWidget *image; | |||
GdkPixbufAnimation *animation; | GdkPixbufAnimation *animation; | |||
snprintf(command,300,"exiftool -s3 -framecount \"%s\"",file); | snprintf(command,300,"exiftool -s3 -framecount \"%s\"",file); | |||
fid = popen(command,"r"); | fid = popen(command,"r"); | |||
if (fid) { | if (fid) { | |||
pp = fgets(buff,20,fid); | pp = fgets(buff,20,fid); | |||
pclose(fid); | pclose(fid); | |||
} | } | |||
skipping to change at line 1734 | skipping to change at line 1719 | |||
animation = gdk_pixbuf_animation_new_from_file(curr_file,0); | animation = gdk_pixbuf_animation_new_from_file(curr_file,0); | |||
gtk_image_set_from_animation(GTK_IMAGE(image),animation); | gtk_image_set_from_animation(GTK_IMAGE(image),animation); | |||
zdialog_run(zd,gif_animations_dialog_event,"desktop"); | zdialog_run(zd,gif_animations_dialog_event,"desktop"); | |||
zdialog_can_focus(zd,0); | zdialog_can_focus(zd,0); | |||
return; | return; | |||
} | } | |||
// dialog event and completion function | // dialog event and completion function | |||
int gif_animations_dialog_event(zdialog *zd, cchar *event) | int gif_animations_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) zdialog_free(zd); | if (zd->zstat) zdialog_free(zd); | |||
return 1; | return 1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// copy or move an image file to a new location | // copy or move an image file to a new location | |||
namespace copymove_names | namespace copymove_names | |||
{ | { | |||
char *sorcfile = 0; | ch *sorcfile = 0; | |||
// source file full name | // source file full name | |||
char *destname = 0; | ch *destname = 0; | |||
// destination file base name | // destination file base name | |||
char *destfile = 0; | ch *destfile = 0; | |||
// destination file full name | // destination file full name | |||
char *nextfile = 0; | ch *nextfile = 0; | |||
// next file in source gallery | // next file in source gallery | |||
} | } | |||
// menu function | // menu function | |||
void m_copy_move(GtkWidget *, cchar *) // overhauled 22.14 | void m_copy_move(GtkWidget *, ch *) // overhauled 22.14 | |||
{ | { | |||
using namespace copymove_names; | using namespace copymove_names; | |||
int copymove_dialog_event(zdialog *zd, cchar *event); | int copymove_dialog_event(zdialog *zd, ch *event); | |||
cchar *title = "Copy or Move Image File"; | ch *title = "Copy or Move Image File"; | |||
char *pp; | ch *pp; | |||
F1_help_topic = "copy/move"; | F1_help_topic = "copy/move"; | |||
Plog(1,"m_copy_move \n"); | Plog(1,"m_copy_move \n"); | |||
if (sorcfile) zfree(sorcfile); | if (sorcfile) zfree(sorcfile); | |||
sorcfile = 0; | sorcfile = 0; | |||
if (clicked_file) { // use clicked file if present | if (clicked_file) { // use clicked file if present | |||
sorcfile = clicked_file; | sorcfile = clicked_file; | |||
skipping to change at line 1864 | skipping to change at line 1849 | |||
return; | return; | |||
} | } | |||
if (copymove_loc) zdialog_stuff(zd,"copymove_loc",copymove_loc); // last used copy-to location 22.18 | if (copymove_loc) zdialog_stuff(zd,"copymove_loc",copymove_loc); // last used copy-to location 22.18 | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int copymove_dialog_event(zdialog *zd, cchar *event) | int copymove_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
using namespace copymove_names; | using namespace copymove_names; | |||
int Fcopy, Fmove, Fnext; | int Fcopy, Fmove, Fnext; | |||
char *pp, *pext; | ch *pp, *pext; | |||
char copyloc[XFCC]; | ch copyloc[XFCC]; | |||
int cc, err, Fkeep, Nth; | int cc, err, Fkeep, Nth; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (strmatch(event,"Browse")) { // browse for new location | if (strmatch(event,"Browse")) { // browse for new location | |||
pp = zgetfile("Select folder",MWIN,"folder",copymove_loc); | pp = zgetfile("Select folder",MWIN,"folder",copymove_loc); | |||
if (! pp) return 1; | if (! pp) return 1; | |||
if (copymove_loc) zfree(copymove_loc); // save new copymove location 22.18 | if (copymove_loc) zfree(copymove_loc); // save new copymove location 22.18 | |||
copymove_loc = pp; | copymove_loc = pp; | |||
zdialog_stuff(zd,"copymove_loc",copymove_loc); | zdialog_stuff(zd,"copymove_loc",copymove_loc); | |||
skipping to change at line 1918 | skipping to change at line 1903 | |||
zdialog_fetch(zd,"copymove_loc",copyloc,XFCC); // get move-to location from dialog | zdialog_fetch(zd,"copymove_loc",copyloc,XFCC); // get move-to location from dialog | |||
if (! dirfile(copyloc)) { // check for valid folder | if (! dirfile(copyloc)) { // check for valid folder | |||
zmessageACK(Mwin,"new location is not a folder"); | zmessageACK(Mwin,"new location is not a folder"); | |||
return 1; | return 1; | |||
} | } | |||
zstrcopy(copymove_loc,copyloc,"copy-move"); // save new copymove location 22.18 | zstrcopy(copymove_loc,copyloc,"copy-move"); // save new copymove location 22.18 | |||
if (destname) zfree(destname); | if (destname) zfree(destname); | |||
destname = (char *) zmalloc(200,"copy-move"); // get dest file name | destname = (ch *) zmalloc(200,"copy-move"); // get dest file name | |||
zdialog_fetch(zd,"destname",destname,190); | zdialog_fetch(zd,"destname",destname,190); | |||
if (*destname <= ' ' || strchr(destname,'/')) { // 22.18 | if (*destname <= ' ' || strchr(destname,'/')) { // 22.18 | |||
zmessageACK(Mwin,"new file name is invalid"); | zmessageACK(Mwin,"new file name is invalid"); | |||
return 1; | return 1; | |||
} | } | |||
pext = strrchr(destname,'.'); // find dest file .ext | pext = strrchr(destname,'.'); // find dest file .ext | |||
if (! pext || strlen(pext) > 8) | if (! pext || strlen(pext) > 8) | |||
pext = destname + strlen(destname); // try to skip over '.' in file name | pext = destname + strlen(destname); // try to skip over '.' in file name | |||
if (strlen(pext) > 3 && pext[1] == 'v') | if (strlen(pext) > 3 && pext[1] == 'v') | |||
pext = destname + strlen(destname); // try to skip over version number | pext = destname + strlen(destname); // try to skip over version number | |||
*pext = 0; | *pext = 0; | |||
pp = strrchr(sorcfile,'.'); | pp = strrchr(sorcfile,'.'); | |||
if (pp && strlen(pp) < 9) strcpy(pext,pp); // copy source file .ext to dest file | if (pp && strlen(pp) < 9) strcpy(pext,pp); // copy source file .ext to dest file | |||
cc = strlen(copymove_loc) + strlen(destname) + 2; // new file = copymove_loc/destname.ext | cc = strlen(copymove_loc) + strlen(destname) + 2; // new file = copymove_loc/destname.ext | |||
if (destfile) zfree(destfile); | if (destfile) zfree(destfile); | |||
destfile = (char *) zmalloc(cc,"copy-move"); | destfile = (ch *) zmalloc(cc,"copy-move"); | |||
*destfile = 0; | *destfile = 0; | |||
strncatv(destfile,cc,copymove_loc,"/",destname,0); | strncatv(destfile,cc,copymove_loc,"/",destname,0); | |||
if (strmatch(sorcfile,destfile)) { // block copy to self | if (strmatch(sorcfile,destfile)) { // block copy to self | |||
zmessageACK(Mwin,"cannot copy a file to itself"); | zmessageACK(Mwin,"cannot copy a file to itself"); | |||
return 1; | return 1; | |||
} | } | |||
if (regfile(destfile)) { // if new file exists | if (regfile(destfile)) { // if new file exists | |||
int yn = zmessageYN(Mwin,"output file exists, overwrite?"); // optionally overwrite file | int yn = zmessageYN(Mwin,"output file exists, overwrite?"); // optionally overwrite file | |||
skipping to change at line 2021 | skipping to change at line 2006 | |||
} | } | |||
else gtk_window_present(MWIN); // keep focus on main window | else gtk_window_present(MWIN); // keep focus on main window | |||
return 1; | return 1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// copy selected image file to the desktop | // copy selected image file to the desktop | |||
void m_copyto_desktop(GtkWidget *, cchar *) | void m_copyto_desktop(GtkWidget *, ch *) | |||
{ | { | |||
char *file, *pp, newfile[XFCC]; | ch *file, *pp, newfile[XFCC]; | |||
int err; | int err; | |||
F1_help_topic = "copy to desktop"; | F1_help_topic = "copy to desktop"; | |||
Plog(1,"m_copyto_desktop \n"); | Plog(1,"m_copyto_desktop \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
file = clicked_file; | file = clicked_file; | |||
if (! file) file = curr_file; | if (! file) file = curr_file; | |||
if (! file) return; | if (! file) return; | |||
snprintf(newfile,100,"%s/%s",getenv("HOME"),desktopname); // locale specific desktop name | snprintf(newfile,XFCC,"%s/%s",getenv("HOME"),desktopname); // locale specific desktop name | |||
pp = strrchr(file,'/'); | pp = strrchr(file,'/'); | |||
if (! pp) return; | if (! pp) return; | |||
strncatv(newfile,XFCC,pp,0); // new desktop file name | strncatv(newfile,XFCC,pp,0); // new desktop file name | |||
if (regfile(newfile)) { // check if file exists | if (regfile(newfile)) { // check if file exists | |||
int yn = zmessageYN(Mwin,"output file exists, overwrite?"); // confirm overwrite | int yn = zmessageYN(Mwin,"output file exists, overwrite?"); // confirm overwrite | |||
if (! yn) goto cleanup; | if (! yn) goto cleanup; | |||
} | } | |||
if (curr_file && strmatch(file,curr_file) // current file is copied | if (curr_file && strmatch(file,curr_file) // current file is copied | |||
skipping to change at line 2070 | skipping to change at line 2055 | |||
cleanup: | cleanup: | |||
if (clicked_file) zfree(clicked_file); | if (clicked_file) zfree(clicked_file); | |||
clicked_file = 0; | clicked_file = 0; | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// copy selected image file to the clipboard | // copy selected image file to the clipboard | |||
void m_copyto_clip(GtkWidget *, cchar *) | void m_copyto_clip(GtkWidget *, ch *) | |||
{ | { | |||
int file_copytoclipboard(char *file); | int file_copytoclipboard(ch *file); | |||
char tempfile[200]; | ch tempfile[200]; | |||
int err; | int err; | |||
F1_help_topic = "copy to clipboard"; | F1_help_topic = "copy to clipboard"; | |||
Plog(1,"m_copyto_clip \n"); | Plog(1,"m_copyto_clip \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (clicked_file) { | if (clicked_file) { | |||
file_copytoclipboard(clicked_file); // get file behind thumbnail | file_copytoclipboard(clicked_file); // get file behind thumbnail | |||
skipping to change at line 2111 | skipping to change at line 2096 | |||
remove(tempfile); | remove(tempfile); | |||
return; | return; | |||
} | } | |||
// copy an image file to the clipboard (as pixbuf) | // copy an image file to the clipboard (as pixbuf) | |||
// any prior clipboard image is replaced | // any prior clipboard image is replaced | |||
// supports copy/paste to other apps (not used within fotoxx) | // supports copy/paste to other apps (not used within fotoxx) | |||
// returns 1 if OK, else 0 | // returns 1 if OK, else 0 | |||
int file_copytoclipboard(char *file) | int file_copytoclipboard(ch *file) | |||
{ | { | |||
GtkClipboard *clipboard; | GtkClipboard *clipboard; | |||
PIXBUF *pixbuf; | PIXBUF *pixbuf; | |||
GError *gerror = 0; | GError *gerror = 0; | |||
pixbuf = gdk_pixbuf_new_from_file(file,&gerror); | pixbuf = gdk_pixbuf_new_from_file(file,&gerror); | |||
if (! pixbuf) return 0; | if (! pixbuf) return 0; | |||
clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | |||
if (! clipboard) return 0; | if (! clipboard) return 0; | |||
skipping to change at line 2138 | skipping to change at line 2123 | |||
g_object_unref(pixbuf); | g_object_unref(pixbuf); | |||
return 1; | return 1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Delete or Trash an image file. | // Delete or Trash an image file. | |||
// Use the Linux standard trash function. | // Use the Linux standard trash function. | |||
// If not available, show diagnostic and do nothing. | // If not available, show diagnostic and do nothing. | |||
char *deltrash_file = 0; | ch *deltrash_file = 0; | |||
void m_delete_trash(GtkWidget *, cchar *) // combined delete/trash function | void m_delete_trash(GtkWidget *, ch *) // combined delete/trash function | |||
{ | { | |||
int delete_trash_dialog_event(zdialog *zd, cchar *event); | int delete_trash_dialog_event(zdialog *zd, ch *event); | |||
cchar *title = "Delete/Trash Image File"; | ch *title = "Delete/Trash Image File"; | |||
F1_help_topic = "delete/trash"; | F1_help_topic = "delete/trash"; | |||
Plog(1,"m_delete_trash \n"); | Plog(1,"m_delete_trash \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (deltrash_file) zfree(deltrash_file); | if (deltrash_file) zfree(deltrash_file); | |||
deltrash_file = 0; | deltrash_file = 0; | |||
skipping to change at line 2194 | skipping to change at line 2179 | |||
zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); | zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); | |||
zdialog_add_widget(zd,"check","keepopen","hb2","keep this dialog open","sp ace=3"); | zdialog_add_widget(zd,"check","keepopen","hb2","keep this dialog open","sp ace=3"); | |||
zdialog_resize(zd,300,0); | zdialog_resize(zd,300,0); | |||
zdialog_restore_inputs(zd); | zdialog_restore_inputs(zd); | |||
zdialog_run(zd,delete_trash_dialog_event,"parent"); // run dialog | zdialog_run(zd,delete_trash_dialog_event,"parent"); // run dialog | |||
} | } | |||
if (deltrash_file) | if (deltrash_file) | |||
{ | { | |||
char *pp = strrchr(deltrash_file,'/'); | ch *pp = strrchr(deltrash_file,'/'); | |||
if (pp) pp++; | if (pp) pp++; | |||
else pp = deltrash_file; | else pp = deltrash_file; | |||
zdialog_stuff(zd_deltrash,"file",pp); | zdialog_stuff(zd_deltrash,"file",pp); | |||
if (FGWM == 'G') f_open(deltrash_file,0,0,1,0); // show or highlight gallery 22.18 | if (FGWM == 'G') f_open(deltrash_file,0,0,1,0); // show or highlight gallery 22.18 | |||
} | } | |||
else zdialog_stuff(zd_deltrash,"file",""); | else zdialog_stuff(zd_deltrash,"file",""); | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int delete_trash_dialog_event(zdialog *zd, cchar *event) | int delete_trash_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int err = 0, yn = 0; | int err = 0, yn = 0; | |||
int ftype, Fkeep; | int ftype, Fkeep; | |||
STATB statB; | STATB statB; | |||
cchar *opt = 0; | ch *opt = 0; | |||
char *pp; | ch *pp; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat == 0) return 1; // wait for dialog finished | if (zd->zstat == 0) return 1; // wait for dialog finished | |||
if (zd->zstat == 1) goto PREP; // [delete] button | if (zd->zstat == 1) goto PREP; // [delete] button | |||
if (zd->zstat == 2) goto PREP; // [trash] button | if (zd->zstat == 2) goto PREP; // [trash] button | |||
goto EXIT; // [cancel] or [x] | goto EXIT; // [cancel] or [x] | |||
PREP: | PREP: | |||
skipping to change at line 2286 | skipping to change at line 2271 | |||
gallery(0,"sort",-2); // recall sort and position | gallery(0,"sort",-2); // recall sort and position | |||
gallery(0,"paint",-1); // paint | gallery(0,"paint",-1); // paint | |||
} | } | |||
if (FGWM == 'F') m_next(0,0); // file view mode, open next image | if (FGWM == 'F') m_next(0,0); // file view mode, open next image | |||
zdialog_fetch(zd,"keepopen",Fkeep); // keep going if wanted | zdialog_fetch(zd,"keepopen",Fkeep); // keep going if wanted | |||
if (! Fkeep) goto EXIT; | if (! Fkeep) goto EXIT; | |||
zd->zstat = 0; // keep dialog active | zd->zstat = 0; // keep dialog active | |||
gtk_window_present(MWIN); // keep focus on main window 22.14 | gtk_window_present(MWIN); // keep focus on main window 22.14 | |||
zdialog_stuff(zd_deltrash,"file",""); // set no next file in dialog | zdialog_stuff(zd_deltrash,"file",""); // set no next file in dialog | |||
if (deltrash_file) zfree(deltrash_file); | if (deltrash_file) zfree(deltrash_file); | |||
deltrash_file = 0; | deltrash_file = 0; | |||
if (! curr_file) goto EXIT; // no current file | if (! curr_file) goto EXIT; // no current file | |||
deltrash_file = zstrdup(curr_file,"delete-trash"); // default delete new current file 22.30 | deltrash_file = zstrdup(curr_file,"delete-trash"); // default delete new current file 22.30 | |||
pp = strrchr(deltrash_file,'/'); | pp = strrchr(deltrash_file,'/'); | |||
if (pp) pp++; | if (pp) pp++; | |||
skipping to change at line 2321 | skipping to change at line 2306 | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Select an Adobe document file and convert all pages into jpeg image files. | // Select an Adobe document file and convert all pages into jpeg image files. | |||
// The image files are named InputFileName-N.jpg where N is the page number. | // The image files are named InputFileName-N.jpg where N is the page number. | |||
// File types recognized: | // File types recognized: | |||
// .pdf portable document format | // .pdf portable document format | |||
// .ps .eps postscript | // .ps .eps postscript | |||
// .psd photoshop image file | // .psd photoshop image file | |||
void m_convert_adobe(GtkWidget *, cchar *) // 22.20 | void m_convert_adobe(GtkWidget *, ch *) // 22.20 | |||
{ | { | |||
char *pp, *infile = 0, *outfile = 0; | ch *pp, *infile = 0, *outfile = 0; | |||
zdialog *zd = 0; | zdialog *zd = 0; | |||
int err; | int err; | |||
F1_help_topic = "convert adobe"; | F1_help_topic = "convert adobe"; | |||
Plog(1,"convert adobe \n"); | Plog(1,"convert adobe \n"); | |||
if (Fblock(0,"blocked edits")) return; // check nothing pending | if (Fblock(0,"blocked edits")) return; // check nothing pending | |||
pp = 0; | pp = 0; | |||
skipping to change at line 2397 | skipping to change at line 2382 | |||
if (zd) zdialog_free(zd); | if (zd) zdialog_free(zd); | |||
if (infile) zfree(infile); | if (infile) zfree(infile); | |||
if (outfile) zfree(outfile); | if (outfile) zfree(outfile); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// set current file as desktop wallpaper (GNOME only) | // set current file as desktop wallpaper (GNOME only) | |||
void m_wallpaper(GtkWidget *, cchar *) | void m_wallpaper(GtkWidget *, ch *) | |||
{ | { | |||
cchar * key = "gsettings set org.gnome.desktop.background"; | ch * key = "gsettings set org.gnome.desktop.background"; | |||
cchar * id = "picture-uri"; | ch * id = "picture-uri"; | |||
F1_help_topic = "set wallpaper"; | F1_help_topic = "set wallpaper"; | |||
Plog(1,"m_wallpaper \n"); | Plog(1,"m_wallpaper \n"); | |||
if (! curr_file) return; | if (! curr_file) return; | |||
zshell("ack","%s %s \"file://%s\" ",key,id,curr_file); | zshell("ack","%s %s \"file://%s\" ",key,id,curr_file); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// print image file | // print image file | |||
void m_print(GtkWidget *, cchar *) // use GTK print | void m_print(GtkWidget *, ch *) // use GTK print | |||
{ | { | |||
int print_addgrid(PXB *Ppxb); | int print_addgrid(PXB *Ppxb); | |||
int pstat; | int pstat; | |||
char *printfile = 0; | ch *printfile = 0; | |||
PXB *Ppxb = 0; | PXB *Ppxb = 0; | |||
GError *gerror = 0; | GError *gerror = 0; | |||
F1_help_topic = "print"; | F1_help_topic = "print"; | |||
Plog(1,"m_print \n"); | Plog(1,"m_print \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (clicked_file) Ppxb = PXB_load(clicked_file,1); // clicked thumbnail | if (clicked_file) Ppxb = PXB_load(clicked_file,1); // clicked thumbnail | |||
skipping to change at line 2521 | skipping to change at line 2506 | |||
memset(pix,0,9); | memset(pix,0,9); | |||
} | } | |||
} | } | |||
return 1; | return 1; | |||
} | } | |||
// print calibrated image | // print calibrated image | |||
// menu function calling print_calibrated() in f.tools.cc | // menu function calling print_calibrated() in f.tools.cc | |||
void m_print_calibrated(GtkWidget *, cchar *) | void m_print_calibrated(GtkWidget *, ch *) | |||
{ | { | |||
Plog(1,"m_print_calibrated \n"); | Plog(1,"m_print_calibrated \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
print_calibrated(); | print_calibrated(); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Quit menu function | // Quit menu function | |||
// Click on window [x] button (delete event) also comes here. | // Click on window [x] button (delete event) also comes here. | |||
// User can bail out if unsaved edit, open dialog, running function, or second thoughts. | // User can bail out if unsaved edit, open dialog, running function, or second thoughts. | |||
void m_quit(GtkWidget *, cchar *) | void m_quit(GtkWidget *, ch *) | |||
{ | { | |||
zdialog *zd; | zdialog *zd; | |||
int yn, nn, ii; | int yn, nn, ii; | |||
char quitmess[100] = ""; | ch quitmess[100] = ""; | |||
Plog(1,"m_quit \n"); | Plog(1,"m_quit \n"); | |||
if (Fblock("quit","edits")) return; // unsaved edits, user bailout | if (Fblock("quit","edits")) return; // unsaved edits, user bailout | |||
if (zfuncs::zdialog_busy) { | if (zfuncs::zdialog_busy) { | |||
for (int ii = 0; ii < zfuncs::zdialog_count; ii++) { // loop pending dialogs | for (int ii = 0; ii < zfuncs::zdialog_count; ii++) { // loop pending dialogs | |||
zd = zfuncs::zdialog_list[ii]; | zd = zfuncs::zdialog_list[ii]; | |||
if (strmatch(zd->title,"userguide")) continue; // omit this dialog | if (strmatch(zd->title,"userguide")) continue; // omit this dialog | |||
zdialog_show(zd,1); // un-hide minimized dialog | zdialog_show(zd,1); // un-hide minimized dialog | |||
yn = zmessageYN(Mwin,"Kill active dialog? %s",zd->title); // allow user bailout | yn = zmessageYN(Mwin,"Kill active dialog? %s",zd->title); // allow user bailout | |||
if (! yn) return; | if (! yn) return; | |||
zdialog_send_event(zd,"cancel"); | zdialog_send_event(zd,"escape"); // kill dialog 23.1 | |||
zmainsleep(0.1); | zmainsleep(0.1); | |||
} | } | |||
} | } | |||
if (Fblock(0,"blocked quiet") || Ffuncbusy) { // something is still running | if (Fblock(0,"blocked quiet") || Ffuncbusy) { // something is still running | |||
yn = zmessageYN(Mwin,"Kill busy function?"); | yn = zmessageYN(Mwin,"Kill busy function?"); | |||
if (! yn) return; | if (! yn) return; | |||
Fescape = 2; | Fescape = 1; | |||
// tell it to exit | // tell it to exit | |||
for (ii = 0; ii < 20; ii++) { // allow 2 secs. | for (ii = 0; ii < 20; ii++) { // allow 2 secs. | |||
if (Fblock(0,"blocked quiet") || Ffuncbusy) | if (Fblock(0,"blocked quiet") || Ffuncbusy) | |||
zmainsleep(0.1); | zmainsleep(0.1); | |||
else break; | else break; | |||
} | } | |||
if (ii == 20) Plog(1,"busy function will be killed \n"); | if (ii == 20) Plog(0,"busy function will be killed \n"); | |||
// still running | // still running | |||
else Plog(1,"busy function quit \n"); | ||||
Fescape = 0; | ||||
} | } | |||
if (! Faskquit) goto quitxx; // no "ask to quit" option | if (! Faskquit) goto quitxx; // no "ask to quit" option | |||
strncatv(quitmess,100," ","Quit Fotoxx?"," ",0); | strncatv(quitmess,100," ","Quit Fotoxx?"," ",0); | |||
nn = zdialog_choose2(Mwin,"parent",quitmess,"Yes","No",0); // get button or KB key input | nn = zdialog_choose2(Mwin,"parent",quitmess,"Yes","No",0); // get button or KB key input | |||
if (nn == 1) goto quitxx; // [Yes] button | if (nn == 1) goto quitxx; // [Yes] button | |||
if (nn == 2 || nn == -1) return; // [No] or [x] button | if (nn == 2 || nn == -1) return; // [No] or [x] button | |||
nn = toupper(nn); | nn = toupper(nn); | |||
skipping to change at line 2598 | skipping to change at line 2582 | |||
quitxx: | quitxx: | |||
Plog(1,"Quit Fotoxx\n"); | Plog(1,"Quit Fotoxx\n"); | |||
quitxx(); // does not return | quitxx(); // does not return | |||
} | } | |||
// used also for main window destroy event | // used also for main window destroy event | |||
// does not return | // does not return | |||
void quitxx() | void quitxx() | |||
{ | { | |||
Fshutdown++; | Fshutdown = 1; | |||
Fescape = 1; | ||||
// stop long-running funcs | ||||
gtk_window_get_position(MWIN,&mwgeom[0],&mwgeom[1]); // save main window position and size | gtk_window_get_position(MWIN,&mwgeom[0],&mwgeom[1]); // save main window position and size | |||
gtk_window_get_size(MWIN,&mwgeom[2],&mwgeom[3]); // for next session | gtk_window_get_size(MWIN,&mwgeom[2],&mwgeom[3]); // for next session | |||
zdialog_inputs("save"); // save dialog inputs | zdialog_inputs("save"); // save dialog inputs | |||
zdialog_geometry("save"); // save dialogs position/size | zdialog_geometry("save"); // save dialogs position/size | |||
gallery_memory("save"); // save recent gallery positions | gallery_memory("save"); // save recent gallery positions | |||
free_resources(); // free memory | free_resources(); // free memory | |||
showz_docfile(0,0,"quit"); // close userguide window | showz_docfile(0,0,"quit"); // close userguide window | |||
zshell(0,"rm -R -f %s",temp_folder); // delete temp files | zshell(0,"rm -R -f %s",temp_folder); // delete temp files | |||
save_params(); // save state for next session | save_params(); // save state for next session | |||
fflush(null); // flush stdout, stderr | fflush(null); // flush stdout, stderr | |||
zexit(0,"Fotoxx exit"); | zexit(0,"Fotoxx exit"); | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// help menu function | // help menu function | |||
void m_help(GtkWidget *, cchar *menu) | void m_help(GtkWidget *, ch *menu) | |||
{ | { | |||
Plog(1,"m_help \n"); | Plog(1,"m_help \n"); | |||
F1_help_topic = "help menu"; | F1_help_topic = "help menu"; | |||
if (! *menu) { | if (! *menu) { | |||
showz_docfile(Mwin,"userguide","help menu"); | showz_docfile(Mwin,"userguide","help menu"); | |||
return; | return; | |||
} | } | |||
skipping to change at line 2679 | skipping to change at line 2664 | |||
if (strmatch(menu,"Home Page")) | if (strmatch(menu,"Home Page")) | |||
showz_html("https://kornelix.net"); | showz_html("https://kornelix.net"); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// save (modified) image file to disk | // save (modified) image file to disk | |||
void m_file_save(GtkWidget *, cchar *menu) | void m_file_save(GtkWidget *, ch *menu) | |||
{ | { | |||
int file_save_dialog_event(zdialog *zd, cchar *event); | int file_save_dialog_event(zdialog *zd, ch *event); | |||
cchar *pp; | ch *pp; | |||
zdialog *zd; | zdialog *zd; | |||
F1_help_topic = "file save"; | F1_help_topic = "file save"; | |||
Plog(1,"m_file_save \n"); | Plog(1,"m_file_save \n"); | |||
if (FGWM != 'F' && FGWM != 'G') return; | if (FGWM != 'F' && FGWM != 'G') return; | |||
if (! curr_file) { | if (! curr_file) { | |||
if (zd_filesave) zdialog_free(zd_filesave); | if (zd_filesave) zdialog_free(zd_filesave); | |||
skipping to change at line 2753 | skipping to change at line 2738 | |||
pp = strrchr(curr_file,'/'); | pp = strrchr(curr_file,'/'); | |||
if (pp) zdialog_stuff(zd,"filename",pp+1); | if (pp) zdialog_stuff(zd,"filename",pp+1); | |||
zdialog_run(zd,file_save_dialog_event,"mouse"); | zdialog_run(zd,file_save_dialog_event,"mouse"); | |||
return; | return; | |||
} | } | |||
// dialog event and completion function | // dialog event and completion function | |||
int file_save_dialog_event(zdialog *zd, cchar *event) | int file_save_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
char *RP = 0, *newfilename = 0; | ch *RP = 0, *newfilename = 0; | |||
char temp[8]; | ch temp[8]; | |||
int err; | int err; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) goto retx; // cancel | if (zd->zstat) goto retx; // cancel | |||
if (! zstrstr("newvers newfile replace",event)) return 1; // ignore other events | if (! zstrstr("newvers newfile replace",event)) return 1; // ignore other events | |||
if (Fblock(0,"blocked")) return 1; // check nothing pending | if (Fblock(0,"blocked")) return 1; // check nothing pending | |||
if (strmatch(event,"newvers")) // save as new version | if (strmatch(event,"newvers")) // save as new version | |||
{ | { | |||
skipping to change at line 2821 | skipping to change at line 2806 | |||
retx: | retx: | |||
if (RP) zfree(RP); | if (RP) zfree(RP); | |||
if (newfilename) zfree(newfilename); | if (newfilename) zfree(newfilename); | |||
zdialog_free(zd); // kill dialog | zdialog_free(zd); // kill dialog | |||
zd_filesave = 0; | zd_filesave = 0; | |||
return 1; | return 1; | |||
} | } | |||
// menu entry for KB shortcut Save File (replace) | // menu entry for KB shortcut Save File (replace) | |||
void m_file_save_replace(GtkWidget *, cchar *menu) | void m_file_save_replace(GtkWidget *, ch *menu) | |||
{ | { | |||
int err; | int err; | |||
char *RP; | ch *RP; | |||
Plog(1,"m_file_save_replace \n"); | Plog(1,"m_file_save_replace \n"); | |||
RP = f_realpath(curr_file); // use real path | RP = f_realpath(curr_file); // use real path | |||
if (! RP) { | if (! RP) { | |||
zmessageACK(Mwin,"file not found: %s",curr_file); | zmessageACK(Mwin,"file not found: %s",curr_file); | |||
return; | return; | |||
} | } | |||
err = f_save(RP,curr_file_type,curr_file_bpc,0,1); // save file | err = f_save(RP,curr_file_type,curr_file_bpc,0,1); // save file | |||
if (! err) f_open_saved(); // open saved file with edit hist | if (! err) f_open_saved(); // open saved file with edit hist | |||
zfree(RP); | zfree(RP); | |||
return; | return; | |||
} | } | |||
// menu entry for KB shortcut Save File Version | // menu entry for KB shortcut Save File Version | |||
void m_file_save_version(GtkWidget *, cchar *menu) | void m_file_save_version(GtkWidget *, ch *menu) | |||
{ | { | |||
char *newfilename = 0, *RP = 0; | ch *newfilename = 0, *RP = 0; | |||
char newfiletype[8]; | ch newfiletype[8]; | |||
int err; | int err; | |||
Plog(1,"m_file_save_version \n"); | Plog(1,"m_file_save_version \n"); | |||
RP = f_realpath(curr_file); // use real path | RP = f_realpath(curr_file); // use real path | |||
if (! RP) { | if (! RP) { | |||
zmessageACK(Mwin,"file not found: %s",curr_file); | zmessageACK(Mwin,"file not found: %s",curr_file); | |||
return; | return; | |||
} | } | |||
skipping to change at line 2876 | skipping to change at line 2861 | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Save current image to specified file (same or new). | // Save current image to specified file (same or new). | |||
// Update image index file and thumbnail file. | // Update image index file and thumbnail file. | |||
// Set f_save_type, f_save_bpc, f_save_size | // Set f_save_type, f_save_bpc, f_save_size | |||
// Returns 0 if OK, else +N. | // Returns 0 if OK, else +N. | |||
// If Fack is true, failure will cause a popup ACK dialog. | // If Fack is true, failure will cause a popup ACK dialog. | |||
int f_save(char *outfile, cchar *outype, int outbpc, int qual, int Fack) | int f_save(ch *outfile, ch *outype, int outbpc, int qual, int Fack) | |||
{ | { | |||
cchar *exifkey[5], *exifdata[5]; | ch *metakey[5], *metadata[5]; | |||
char *ppv[1], *tempfile, *pext, *outfile2; | ch *ppv[1], *tempfile, *pext, *outfile2; | |||
int nkeys, err, cc1, cc2, cc3, ii; | int nkeys, err, cc1, cc2, cc3, ii; | |||
int Fmod, Fcopy, Ftransp, Fnewfile; | int Fmod, Fcopy, Ftransp, Fnewfile; | |||
int px, py; | int px, py; | |||
void (*editfunc)(GtkWidget *, cchar *); | void (*editfunc)(GtkWidget *, ch *); | |||
STATB statB; | STATB statB; | |||
cchar *warnalpha = "Transparency map will be lost.\n" | ch *warnalpha = "Transparency map will be lost.\n" | |||
"save to TIFF or PNG file to retain."; | "save to TIFF or PNG file to retain."; | |||
if (! curr_file) return 1; | if (! curr_file) return 1; | |||
if (strmatch(outype,"RAW")) { // disallow saving as RAW type | if (strmatch(outype,"RAW")) { // disallow saving as RAW type | |||
zmessageACK(Mwin,"cannot save as RAW type"); | zmessageACK(Mwin,"cannot save as RAW type"); | |||
return 1; | return 1; | |||
} | } | |||
Fmod = 0; | Fmod = 0; | |||
skipping to change at line 2991 | skipping to change at line 2976 | |||
if (! strstr("tif png",outype)) outbpc = 8; // force bpc 8 if 16 not supported | if (! strstr("tif png",outype)) outbpc = 8; // force bpc 8 if 16 not supported | |||
err = PXM_save(E0pxm,tempfile,outbpc,qual,Fack); | err = PXM_save(E0pxm,tempfile,outbpc,qual,Fack); | |||
if (err) { | if (err) { | |||
remove(tempfile); // failure, clean up | remove(tempfile); // failure, clean up | |||
zfree(tempfile); | zfree(tempfile); | |||
zfree(outfile2); | zfree(outfile2); | |||
return 1; | return 1; | |||
} | } | |||
cc1 = 0; // exif_edithist[] text cc | cc1 = 0; // meta_edithist[] text cc | |||
if (Fexif_edithist) cc1 = exif_edithist_cc0; // exif_edithist at file open | if (Fmeta_edithist) cc1 = meta_edithist_cc0; // meta_edithist at file open | |||
else { | else { | |||
exifkey[0] = exif_edithist_key; | metakey[0] = (ch *) meta_edithist_key; | |||
exif_get(curr_file,&exifkey[0],ppv,1); | meta_get1(curr_file,metakey,ppv,1); | |||
// get edits made before | // get edits made before | |||
if (ppv[0]) { // this file was opened | if (ppv[0]) { // this file was opened | |||
strncpy0(exif_edithist,ppv[0],exif_maxcc-2); | strncpy0(meta_edithist,ppv[0],metadataXcc-2); | |||
zfree(ppv[0]); | zfree(ppv[0]); | |||
cc1 = strlen(exif_edithist); | cc1 = strlen(meta_edithist); | |||
exif_edithist_cc0 = cc1; | meta_edithist_cc0 = cc1; | |||
// edit hist cc when file was opened | // edit hist cc when file was opened | |||
} // (not updated for new edits) | } // (not updated for new edits) | |||
Fexif_edithist = 1; // history is loaded | Fmeta_edithist = 1; // history is loaded | |||
} | } | |||
for (ii = 1; ii <= URS_pos; ii++) // append edits from undo/redo stack | for (ii = 1; ii <= URS_pos; ii++) // append edits from undo/redo stack | |||
{ // (omit index 0 = initial image) | { // (omit index 0 = initial image) | |||
cc2 = strlen(URS_menu[ii]); | cc2 = strlen(URS_menu[ii]); | |||
cc3 = strlen(URS_parms[ii]); | cc3 = strlen(URS_parms[ii]); | |||
if (cc1 + 7 + cc2 + cc3 + 5 > exif_maxcc) break; | if (cc1 + 7 + cc2 + cc3 + 5 > metadataXcc) break; | |||
// no more room | // no more room | |||
strcpy(exif_edithist+cc1,Frelease); | strcpy(meta_edithist+cc1,Frelease); | |||
cc1 += strlen(Frelease); // append "Fotoxx-nn.n:Menu:parms|" | cc1 += strlen(Frelease); // append "Fotoxx-nn.n:Menu:parms|" | |||
exif_edithist[cc1] = ';'; | meta_edithist[cc1] = ';'; | |||
cc1++; | cc1++; | |||
strcpy(exif_edithist+cc1,URS_menu[ii]); | strcpy(meta_edithist+cc1,URS_menu[ii]); | |||
cc1 += cc2; | cc1 += cc2; | |||
if (cc3) { | if (cc3) { | |||
strcpy(exif_edithist+cc1,": "); | strcpy(meta_edithist+cc1,": "); | |||
cc1 += 2; | cc1 += 2; | |||
strcpy(exif_edithist+cc1,URS_parms[ii]); | strcpy(meta_edithist+cc1,URS_parms[ii]); | |||
cc1 += cc3; | cc1 += cc3; | |||
} | } | |||
exif_edithist[cc1++] = '|'; | meta_edithist[cc1++] = '|'; | |||
} | } | |||
if (CEF && CEF->Fmods) // append active edit function | if (CEF && CEF->Fmods) // append active edit function | |||
{ | { | |||
cc2 = strlen(CEF->menuname); | cc2 = strlen(CEF->menuname); | |||
cc3 = strlen(CEF->edit_hist); // 23.0 | cc3 = strlen(CEF->edit_hist); // 23.0 | |||
if (cc1 + 7 + cc2 + cc3 + 5 < exif_maxcc) { | if (cc1 + 7 + cc2 + cc3 + 5 < metadataXcc) { | |||
strcpy(exif_edithist+cc1,"Fotoxx:"); | strcpy(meta_edithist+cc1,"Fotoxx:"); | |||
cc1 += 7; // append "Fotoxx:Menu:parms|" | cc1 += 7; // append "Fotoxx:Menu:parms|" | |||
strcpy(exif_edithist+cc1,CEF->menuname); | strcpy(meta_edithist+cc1,CEF->menuname); | |||
if (cc3) { | if (cc3) { | |||
cc1 += cc2; | cc1 += cc2; | |||
strcpy(exif_edithist+cc1,": "); | strcpy(meta_edithist+cc1,": "); | |||
cc1 += 2; | cc1 += 2; | |||
strcpy(exif_edithist+cc1,CEF->edit_hist); | strcpy(meta_edithist+cc1,CEF->edit_hist); | |||
cc1 += cc3; | cc1 += cc3; | |||
} | } | |||
exif_edithist[cc1++] = '|'; | meta_edithist[cc1++] = '|'; | |||
} | } | |||
} | } | |||
exif_edithist[cc1] = 0; | meta_edithist[cc1] = 0; | |||
nkeys = 0; | nkeys = 0; | |||
if (Fupright) { // image was uprighted | if (Fupright) { // image was uprighted | |||
exifkey[nkeys] = exif_orientation_key; | metakey[nkeys] = meta_orientation_key; | |||
// remove EXIF orientation | // remove metadata orientation | |||
exifdata[nkeys] = ""; | metadata[nkeys] = ""; | |||
nkeys++; | nkeys++; | |||
} | } | |||
if (Flevel) { // image was levelled | if (Flevel) { // image was levelled | |||
exifkey[nkeys] = exif_rollangle_key; | metakey[nkeys] = meta_rollangle_key; | |||
// remove EXIF rollangle | // remove metadata rollangle | |||
exifdata[nkeys] = "0"; | metadata[nkeys] = "0"; // "" | |||
// "" fails, use "0" | fails, use "0" | |||
nkeys++; | nkeys++; | |||
} | } | |||
if (cc1) { // prior and/or curr. edit history | if (cc1) { // prior and/or curr. edit history | |||
exifkey[nkeys] = exif_edithist_key; | metakey[nkeys] = meta_edithist_key; | |||
// add to EXIF | // add to metadata | |||
exifdata[nkeys] = exif_edithist; | metadata[nkeys] = meta_edithist; | |||
nkeys++; | nkeys++; | |||
} | } | |||
err = exif_copy(curr_file,tempfile,exifkey,exifdata,nkeys); // copy all EXIF/IPTC data to | err = meta_copy(curr_file,tempfile,metakey,metadata,nkeys); // copy all metadata to | |||
if (err) { // temp file with above revisions | if (err) { // temp file with above revisions | |||
if (Fack) zmessageACK(Mwin,"Unable to copy EXIF/IPTC data"); | if (Fack) zmessageACK(Mwin,"Unable to copy metadata"); | |||
else Plog(1,"Unable to copy EXIF/IPTC data \n"); | else Plog(1,"Unable to copy metadata \n"); | |||
} | } | |||
err = rename(tempfile,outfile2); // rename temp file to output file | err = rename(tempfile,outfile2); // rename temp file to output file | |||
if (err) { | if (err) { | |||
if (Fack) zmessageACK(Mwin,strerror(err)); | if (Fack) zmessageACK(Mwin,strerror(err)); | |||
remove(tempfile); // delete temp file | remove(tempfile); // delete temp file | |||
zfree(tempfile); | zfree(tempfile); | |||
zfree(outfile2); | zfree(outfile2); | |||
return 2; // could not save | return 2; // could not save | |||
} | } | |||
skipping to change at line 3136 | skipping to change at line 3121 | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// save (modified) image to new file name or type | // save (modified) image to new file name or type | |||
// confirm if overwrite of existing file | // confirm if overwrite of existing file | |||
// returns 0 if OK, 1 if cancel or error | // returns 0 if OK, 1 if cancel or error | |||
GtkWidget *saveas_fchooser; | GtkWidget *saveas_fchooser; | |||
int f_save_as() | int f_save_as() | |||
{ | { | |||
int f_save_as_dialog_event(zdialog *zd, cchar *event); | int f_save_as_dialog_event(zdialog *zd, ch *event); | |||
zdialog *zd; | zdialog *zd; | |||
char *save_folder = 0; | ch *save_folder = 0; | |||
cchar *type; | ch *type; | |||
char *newfile, *fname; | ch *newfile, *fname; | |||
char *outfile = 0, *outfile2 = 0, *pp, *pext; | ch *outfile = 0, *outfile2 = 0, *pp, *pext; | |||
char permissions[100]; | ch permissions[100]; | |||
int ii, zstat, err, bpc; | int ii, zstat, err, bpc; | |||
int jpgqual = jpeg_def_quality; | int jpgqual = jpeg_def_quality; | |||
int mkcurr = 0; | int mkcurr = 0; | |||
STATB statB; | STATB statB; | |||
mode_t mode; | mode_t mode; | |||
/*** | /*** | |||
_____________________________________________________ | _____________________________________________________ | |||
| Save as New File Name or Type | | | Save as New File Name or Type | | |||
| ________________________________________________ | | | ________________________________________________ | | |||
skipping to change at line 3346 | skipping to change at line 3331 | |||
} | } | |||
if (mkcurr) f_open_saved(); // open saved file with edit hist 22.1 | if (mkcurr) f_open_saved(); // open saved file with edit hist 22.1 | |||
zfree(outfile); | zfree(outfile); | |||
return 0; | return 0; | |||
} | } | |||
// dialog event and completion function | // dialog event and completion function | |||
int f_save_as_dialog_event(zdialog *zd, cchar *event) | int f_save_as_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int ii, err; | int ii, err; | |||
char *filespec, *filename, *pp; | ch *filespec, *filename, *pp; | |||
char oldperms[100], newperms[100]; | ch oldperms[100], newperms[100]; | |||
char ext[4]; | ch ext[4]; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (zd->zstat) return 1; // [ OK ] or [cancel] | if (zd->zstat) return 1; // [ OK ] or [cancel] | |||
if (strmatch(event,"jpgqual")) { // if jpg quality edited, set jpg .ext | if (strmatch(event,"jpgqual")) { // if jpg quality edited, set jpg .ext | |||
zdialog_stuff(zd,"jpg",1); | zdialog_stuff(zd,"jpg",1); | |||
event = "jpg"; | event = "jpg"; | |||
} | } | |||
skipping to change at line 3418 | skipping to change at line 3403 | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// get real path for filename possibly having symlinks | // get real path for filename possibly having symlinks | |||
// all folders in input filename path must exist | // all folders in input filename path must exist | |||
// final file name need not exist (f_save() caller) | // final file name need not exist (f_save() caller) | |||
// returns real path or null if error | // returns real path or null if error | |||
// returned path is subject for zfree() | // returned path is subject for zfree() | |||
char * f_realpath(cchar * infile) | ch * f_realpath(ch * infile) | |||
{ | { | |||
int cc; | int cc; | |||
char *pp, *RP, *outfile; | ch *pp, *RP, *outfile; | |||
char tempfile[XFCC]; | ch tempfile[XFCC]; | |||
RP = realpath(infile,null); // try full file path | RP = realpath(infile,null); // try full file path | |||
if (RP) { | if (RP) { | |||
outfile = zstrdup(RP,"realpath"); // OK | outfile = zstrdup(RP,"realpath"); // OK | |||
free(RP); | free(RP); | |||
return outfile; | return outfile; | |||
} | } | |||
strcpy(tempfile,infile); // fail, try folders only | strcpy(tempfile,infile); // fail, try folders only | |||
pp = strrchr(tempfile + 2,'/'); | pp = strrchr(tempfile + 2,'/'); | |||
skipping to change at line 3453 | skipping to change at line 3438 | |||
return outfile; | return outfile; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// get the root name of an image file, without version and extension | // get the root name of an image file, without version and extension | |||
// /.../filename.V03.png --> /.../filename | // /.../filename.V03.png --> /.../filename | |||
// returned root name has extra length to add .vNN.exxxxt | // returned root name has extra length to add .vNN.exxxxt | |||
// returned root name is subject for zfree() | // returned root name is subject for zfree() | |||
char * file_rootname(cchar *file) | ch * file_rootname(ch *file) | |||
{ | { | |||
char *rootname, *pp1, *pp2; | ch *rootname, *pp1, *pp2; | |||
rootname = zstrdup(file,"rootname",16); | rootname = zstrdup(file,"rootname",16); | |||
pp1 = strrchr(rootname,'/'); // find file .ext | pp1 = strrchr(rootname,'/'); // find file .ext | |||
if (! pp1) pp1 = rootname; | if (! pp1) pp1 = rootname; | |||
pp2 = strrchr(pp1,'.'); // pp2 --> .ext or ending null | pp2 = strrchr(pp1,'.'); // pp2 --> .ext or ending null | |||
if (! pp2) pp2 = pp1 + strlen(pp1); | if (! pp2) pp2 = pp1 + strlen(pp1); | |||
if (pp2[-4] == '.' && pp2[-3] == 'v' && // look for .vNN.ext | if (pp2[-4] == '.' && pp2[-3] == 'v' && // look for .vNN.ext | |||
pp2[-2] >= '0' && pp2[-2] <= '9' && | pp2[-2] >= '0' && pp2[-2] <= '9' && | |||
pp2[-1] >= '0' && pp2[-1] <= '9') pp2 -= 4; // pp2 --> .ext or .vNN.ext | pp2[-1] >= '0' && pp2[-1] <= '9') pp2 -= 4; // pp2 --> .ext or .vNN.ext | |||
skipping to change at line 3478 | skipping to change at line 3463 | |||
return rootname; | return rootname; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// return base name for given file = original file name /.../filename.ext | // return base name for given file = original file name /.../filename.ext | |||
// returns null if base file does not exist. | // returns null if base file does not exist. | |||
// returned base name has extra length to add .vNN.exxxxt | // returned base name has extra length to add .vNN.exxxxt | |||
// returned base name is subject for zfree() | // returned base name is subject for zfree() | |||
char * file_basename(cchar *file) | ch * file_basename(ch *file) | |||
{ | { | |||
char *rootname, **flist, *pp = 0; | ch *rootname, **flist, *pp = 0; | |||
int ii, cc, nf; | int ii, cc, nf; | |||
flist = file_all_versions(file,nf); // get base file and all versions | flist = file_all_versions(file,nf); // get base file and all versions | |||
if (! nf) return 0; | if (! nf) return 0; | |||
rootname = file_rootname(file); | rootname = file_rootname(file); | |||
cc = strlen(rootname); | cc = strlen(rootname); | |||
zfree(rootname); | zfree(rootname); | |||
for (ii = 0; ii < nf; ii++) | for (ii = 0; ii < nf; ii++) | |||
skipping to change at line 3514 | skipping to change at line 3499 | |||
return pp; | return pp; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Get all versions of a given file name in sequence, including base file. | // Get all versions of a given file name in sequence, including base file. | |||
// Returned list of file names is subject for zfree() | // Returned list of file names is subject for zfree() | |||
// (each returned flist[*] member and flist itself) | // (each returned flist[*] member and flist itself) | |||
// returns null if nothing found | // returns null if nothing found | |||
char ** file_all_versions(cchar *file, int &NF) | ch ** file_all_versions(ch *file, int &NF) | |||
{ | { | |||
int file_comp_versions(cchar *f1, cchar *f2); | int file_comp_versions(ch *f1, ch *f2); | |||
char **flist1, **flist2, *rootname; | ch **flist1, **flist2, *rootname; | |||
char *pext, *pvers; | ch *pext, *pvers; | |||
int ii, jj, err, cc1, cc2; | int ii, jj, err, cc1, cc2; | |||
rootname = file_rootname(file); // /.../fname.vNN.ext --> /.../fname | rootname = file_rootname(file); // /.../fname.vNN.ext --> /.../fname | |||
if (! rootname) return 0; | if (! rootname) return 0; | |||
cc1 = strlen(rootname); // file cc without .vNN.ext | cc1 = strlen(rootname); // file cc without .vNN.ext | |||
strcpy(rootname + cc1,".*"); | strcpy(rootname + cc1,".*"); | |||
err = zfind(rootname,flist1,NF); // find /.../fname.* | err = zfind(rootname,flist1,NF); // find /.../fname.* | |||
zfree(rootname); | zfree(rootname); | |||
if (err || NF < 1) return 0; | if (err || NF < 1) return 0; | |||
flist2 = (char **) zmalloc(NF * sizeof(char *),"file-vers"); // scan for valid versions | flist2 = (ch **) zmalloc(NF * sizeof(ch *),"file-vers"); // scan for valid versions | |||
for (ii = jj = 0; ii < NF; ii++) // validate fname.ext or fname.vNN.ext 22.20 | for (ii = jj = 0; ii < NF; ii++) // validate fname.ext or fname.vNN.ext 22.20 | |||
{ | { | |||
if (image_file_type(flist1[ii]) > VIDEO) continue; // not image file | if (image_file_type(flist1[ii]) > VIDEO) continue; // not image file | |||
pext = strrchr(flist1[ii],'.'); // get file .ext | pext = strrchr(flist1[ii],'.'); // get file .ext | |||
if (! pext) continue; | if (! pext) continue; | |||
cc2 = pext - flist1[ii]; // file cc without .ext | cc2 = pext - flist1[ii]; // file cc without .ext | |||
if (cc2 > cc1) { // version present? .vNN.ext | if (cc2 > cc1) { // version present? .vNN.ext | |||
cc2 -= 4; | cc2 -= 4; | |||
skipping to change at line 3570 | skipping to change at line 3555 | |||
if (NF > 99) { // screen out problem file | if (NF > 99) { // screen out problem file | |||
zmessageACK(Mwin,"file: %s \n exceed 99 versions",file); | zmessageACK(Mwin,"file: %s \n exceed 99 versions",file); | |||
zfree(flist2); | zfree(flist2); | |||
return 0; | return 0; | |||
} | } | |||
HeapSort(flist2,NF,file_comp_versions); // sort in base, version order | HeapSort(flist2,NF,file_comp_versions); // sort in base, version order | |||
return flist2; | return flist2; | |||
} | } | |||
int file_comp_versions(cchar *f1, cchar *f2) | int file_comp_versions(ch *f1, ch *f2) | |||
{ | { | |||
f1 = strrchr(f1,'.'); // find .ext in file f1 | f1 = strrchr(f1,'.'); // find .ext in file f1 | |||
if (! f1) return -1; // f1 has no .ext | if (! f1) return -1; // f1 has no .ext | |||
f2 = strrchr(f2,'.'); | f2 = strrchr(f2,'.'); | |||
if (! f2) return +1; // f2 has no .ext | if (! f2) return +1; // f2 has no .ext | |||
f1 -= 4; // point to '.v' in filename.vNN.ext | f1 -= 4; // point to '.v' in filename.vNN.ext | |||
if (! strmatchN(f1,".v",2)) return -1; // f1 not a version | if (! strmatchN(f1,".v",2)) return -1; // f1 not a version | |||
f2 -= 4; | f2 -= 4; | |||
if (! strmatchN(f2,".v",2)) return +1; // f2 not a version | if (! strmatchN(f2,".v",2)) return +1; // f2 not a version | |||
return strcmp(f1,f2); // compare versions | return strcmp(f1,f2); // compare versions | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Get next available version /.../filename.vNN.ext for given file. | // Get next available version /.../filename.vNN.ext for given file. | |||
// Returns "/.../filename.v01.ext" if no versions are found. | // Returns "/.../filename.v01.ext" if no versions are found. | |||
// Returns null if bad file name or 99 versions already exist. | // Returns null if bad file name or 99 versions already exist. | |||
// Returned file name is subject for zfree(). | // Returned file name is subject for zfree(). | |||
char * file_new_version(cchar *file) | ch * file_new_version(ch *file) | |||
{ | { | |||
char *retname, *pp, pext[8]; | ch *retname, *pp, pext[8]; | |||
char **flist = 0; | ch **flist = 0; | |||
int ii, cc, NF = 0, vers; | int ii, cc, NF = 0, vers; | |||
pp = (char *) strrchr(file,'/'); // find .ext for file | pp = (ch *) strrchr(file,'/'); // find .ext for file | |||
if (! pp) return 0; | if (! pp) return 0; | |||
pp = strrchr(pp,'.'); | pp = strrchr(pp,'.'); | |||
if (pp) strncpy0(pext,pp,8); | if (pp) strncpy0(pext,pp,8); | |||
else strcpy(pext,".jpg"); | else strcpy(pext,".jpg"); | |||
flist = file_all_versions(file,NF); // get base file and all versions | flist = file_all_versions(file,NF); // get base file and all versions | |||
if (! NF) { // nothing exists | if (! NF) { // nothing exists | |||
retname = file_rootname(file); // get /.../filename | retname = file_rootname(file); // get /.../filename | |||
retname = zstrdup(retname,"new-version",12); | retname = zstrdup(retname,"new-version",12); | |||
cc = strlen(retname); | cc = strlen(retname); | |||
skipping to change at line 3655 | skipping to change at line 3640 | |||
return retname; | return retname; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Get the newest version /.../filename.vNN.ext for the given file. | // Get the newest version /.../filename.vNN.ext for the given file. | |||
// Returns unversioned file /.../filename.ext if found by itself. | // Returns unversioned file /.../filename.ext if found by itself. | |||
// Returns null if bad file name. | // Returns null if bad file name. | |||
// Returned file name is subject for zfree(). | // Returned file name is subject for zfree(). | |||
char * file_newest_version(cchar *file) | ch * file_newest_version(ch *file) | |||
{ | { | |||
char *retname; | ch *retname; | |||
char **flist; | ch **flist; | |||
int ii, NF; | int ii, NF; | |||
flist = file_all_versions(file,NF); // get base file and all versions | flist = file_all_versions(file,NF); // get base file and all versions | |||
if (! NF) return 0; | if (! NF) return 0; | |||
retname = zstrdup(flist[NF-1],"new-version",12); // get last version found | retname = zstrdup(flist[NF-1],"new-version",12); // get last version found | |||
for (ii = 0; ii < NF; ii++) // free memory | for (ii = 0; ii < NF; ii++) // free memory | |||
zfree(flist[ii]); | zfree(flist[ii]); | |||
zfree(flist); | zfree(flist); | |||
return retname; | return retname; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Get the prior version /.../filename.vNN.ext for the given file. | // Get the prior version /.../filename.vNN.ext for the given file. | |||
// Returns unversioned file /.../filename.ext if no prior .vNN found. | // Returns unversioned file /.../filename.ext if no prior .vNN found. | |||
// Returns null if bad file name or no prior version. | // Returns null if bad file name or no prior version. | |||
char * file_prior_version(cchar *file) | ch * file_prior_version(ch *file) | |||
{ | { | |||
char *retname; | ch *retname; | |||
char **flist; | ch **flist; | |||
int ii, NF; | int ii, NF; | |||
flist = file_all_versions(file,NF); // get base file and all versions | flist = file_all_versions(file,NF); // get base file and all versions | |||
if (! NF) return 0; | if (! NF) return 0; | |||
for (ii = 0; ii < NF; ii++) // find input file in list | for (ii = 0; ii < NF; ii++) // find input file in list | |||
if (strmatch(file,flist[ii])) break; | if (strmatch(file,flist[ii])) break; | |||
if (ii == 0) return 0; // input is base file (no prior) | if (ii == 0) return 0; // input is base file (no prior) | |||
if (ii == NF) return 0; // should not happen | if (ii == NF) return 0; // should not happen | |||
skipping to change at line 3707 | skipping to change at line 3692 | |||
zfree(flist[ii]); | zfree(flist[ii]); | |||
zfree(flist); | zfree(flist); | |||
return retname; | return retname; | |||
} | } | |||
/******************************************************************************* * | /******************************************************************************* * | |||
Find all image files within given path. | Find all image files within given path. | |||
int find_imagefiles(cchar *folder, int flags, char **&flist, int &NF) | int find_imagefiles(ch *folder, int flags, ch **&flist, int &NF) | |||
folder folder path to search | folder folder path to search | |||
flags sum of the following: | flags sum of the following: | |||
1 include image files (+RAW +video) | 1 include image files (+RAW +video) | |||
2 include thumbnails | 2 include thumbnails | |||
4 include hidden files | 4 include hidden files | |||
8 include folders | 8 include folders | |||
16 recurse folders | 16 recurse folders | |||
32 omit symlinks | 32 omit symlinks | |||
NF count of files returned | NF count of files returned | |||
flist list of files returned | flist list of files returned | |||
Returns 0 if OK, +N if error (errno is set). | Returns 0 if OK, +N if error (errno is set). | |||
flist and flist[*] are subjects for zfree(). | flist and flist[*] are subjects for zfree(). | |||
******************************************************************************** */ | ******************************************************************************** */ | |||
namespace find_imagefiles_names | namespace find_imagefiles_names | |||
{ | { | |||
char **fif_filelist; // list of filespecs returned | ch **fif_filelist; // list of filespecs returned | |||
int fif_max; // filelist slots allocated | int fif_max; // filelist slots allocated | |||
int fif_count; // filelist slots filled | int fif_count; // filelist slots filled | |||
} | } | |||
int find_imagefiles(cchar *folder, int flags, char **&flist, int &NF, int Finit) | int find_imagefiles(ch *folder, int flags, ch **&flist, int &NF, int Finit) | |||
{ | { | |||
using namespace find_imagefiles_names; | using namespace find_imagefiles_names; | |||
int globflags, Fimages, Fthumbs, Fdirs, Frecurse, Fnolinks; | int globflags, Fimages, Fthumbs, Fdirs, Frecurse, Fnolinks; | |||
int err1, err2, cc; | int err1, err2, cc; | |||
FTYPE ftype; | FTYPE ftype; | |||
char *file, *mfolder, **templist; | ch *file, *mfolder, **templist; | |||
glob_t globdata; | glob_t globdata; | |||
STATB statB; | STATB statB; | |||
if (Finit) { // initial call | if (Finit) { // initial call | |||
spinlock(1); // prevent reentrance | spinlock(1); // prevent reentrance | |||
fif_max = fif_count = 0; | fif_max = fif_count = 0; | |||
} | } | |||
globflags = GLOB_NOSORT; | globflags = GLOB_NOSORT; | |||
Fimages = Fthumbs = Fdirs = Frecurse = Fnolinks = 0; | Fimages = Fthumbs = Fdirs = Frecurse = Fnolinks = 0; | |||
skipping to change at line 3806 | skipping to change at line 3791 | |||
if (ftype == OTHER) continue; // unknown file type | if (ftype == OTHER) continue; // unknown file type | |||
if (ftype == FDIR && ! Fdirs) continue; | if (ftype == FDIR && ! Fdirs) continue; | |||
if (ftype == THUMB && ! Fthumbs) continue; | if (ftype == THUMB && ! Fthumbs) continue; | |||
if (ftype == IMAGE || ftype == RAW || ftype == VIDEO) | if (ftype == IMAGE || ftype == RAW || ftype == VIDEO) | |||
if (! Fimages) continue; | if (! Fimages) continue; | |||
if (fif_count == fif_max) { // output list is full | if (fif_count == fif_max) { // output list is full | |||
if (fif_max == 0) { | if (fif_max == 0) { | |||
fif_max = 1000; // initial space, 1000 files | fif_max = 1000; // initial space, 1000 files | |||
cc = fif_max * sizeof(char *); | cc = fif_max * sizeof(ch *); | |||
fif_filelist = (char **) zmalloc(cc,"find-files"); | fif_filelist = (ch **) zmalloc(cc,"find-files"); | |||
} | } | |||
else { | else { | |||
templist = fif_filelist; // expand by 2x each time needed | templist = fif_filelist; // expand by 2x each time needed | |||
cc = fif_max * sizeof(char *); | cc = fif_max * sizeof(ch *); | |||
fif_filelist = (char **) zmalloc(cc+cc,"find-files"); | fif_filelist = (ch **) zmalloc(cc+cc,"find-files"); | |||
memcpy(fif_filelist,templist,cc); | memcpy(fif_filelist,templist,cc); | |||
memset(fif_filelist+fif_max,0,cc); | memset(fif_filelist+fif_max,0,cc); | |||
zfree(templist); | zfree(templist); | |||
fif_max *= 2; | fif_max *= 2; | |||
} | } | |||
} | } | |||
fif_filelist[fif_count] = zstrdup(file,"find-files"); // add file to output list | fif_filelist[fif_count] = zstrdup(file,"find-files"); // add file to output list | |||
fif_count += 1; | fif_count += 1; | |||
} | } | |||
skipping to change at line 3847 | skipping to change at line 3832 | |||
} | } | |||
errno = err2; // return err1 and preserve errno | errno = err2; // return err1 and preserve errno | |||
return err1; | return err1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// test if a file exists, is a regular file | // test if a file exists, is a regular file | |||
int regfile(cchar *file, struct stat *statb) | int regfile(ch *file, struct stat *statb) | |||
{ | { | |||
STATB statB; | STATB statB; | |||
int err; | int err; | |||
err = stat(file,&statB); | err = stat(file,&statB); | |||
if (err) return 0; | if (err) return 0; | |||
if (! S_ISREG(statB.st_mode)) return 0; | if (! S_ISREG(statB.st_mode)) return 0; | |||
if (statb) *statb = statB; | if (statb) *statb = statB; | |||
return 1; | return 1; | |||
} | } | |||
// test if a file exists, is a directory/folder | // test if a file exists, is a directory/folder | |||
int dirfile(cchar *file, struct stat *statb) | int dirfile(ch *file, struct stat *statb) | |||
{ | { | |||
STATB statB; | STATB statB; | |||
int err; | int err; | |||
err = stat(file,&statB); | err = stat(file,&statB); | |||
if (err) return 0; | if (err) return 0; | |||
if (! S_ISDIR(statB.st_mode)) return 0; | if (! S_ISDIR(statB.st_mode)) return 0; | |||
if (statb) *statb = statB; | if (statb) *statb = statB; | |||
return 1; | return 1; | |||
} | } | |||
// test if file exists, is a regular file, and read or write permission | // test if file exists, is a regular file, and read or write permission | |||
// rw: 'r' or read or 'w' for write or ' ' for file exists only | // rw: 'r' or read or 'w' for write or ' ' for file exists only | |||
// returns 0 if file does not exist, is not a regular file, or access is not pe rmitted | // returns 0 if file does not exist, is not a regular file, or access is not pe rmitted | |||
// returns 1 if all is OK | // returns 1 if all is OK | |||
int hasperm(cchar *file, cchar rw) | int hasperm(ch *file, ch rw) | |||
{ | { | |||
STATB statB; | STATB statB; | |||
if (! regfile(file,&statB)) return 0; | if (! regfile(file,&statB)) return 0; | |||
if (rw == 'r' && ! (S_IRUSR & statB.st_mode)) return 0; | if (rw == 'r' && ! (S_IRUSR & statB.st_mode)) return 0; | |||
if (rw == 'w' && ! (S_IWUSR & statB.st_mode)) return 0; | if (rw == 'w' && ! (S_IWUSR & statB.st_mode)) return 0; | |||
return 1; | return 1; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Show a permissions setting, edit and return changed permissions. | // Show a permissions setting, edit and return changed permissions. | |||
// 'fname' is a file name or permission category, e.g. 'default' | // 'fname' is a file name or permission category, e.g. 'default' | |||
// Permissions are strings: "read+write", "read only", "no access". | // Permissions are strings: "read+write", "read only", "no access". | |||
// 'p1' and 'p2' are input and output permissions strings, which are | // 'p1' and 'p2' are input and output permissions strings, which are | |||
// any combination of three of the above strings, comma separated, | // any combination of three of the above strings, comma separated, | |||
// which define the access permissions for user, group, other. | // which define the access permissions for user, group, other. | |||
// p1 and p2 are char[100] strings to allow for fat translations. | // p1 and p2 are char[100] strings to allow for fat translations. | |||
// Returns 1 if user cancel or error, 0 if changes were made OK. | // Returns 1 if user cancel or error, 0 if changes were made OK. | |||
int set_permissions(GtkWidget *parent, cchar *fname, cchar *p1, char *p2) | int set_permissions(GtkWidget *parent, ch *fname, ch *p1, ch *p2) | |||
{ | { | |||
char operm[50], gperm[50], wperm[50]; | ch operm[50], gperm[50], wperm[50]; | |||
const char *pp; | ch *pp; | |||
zdialog *zd; | zdialog *zd; | |||
int zstat; | int zstat; | |||
/*** | /*** | |||
________________________________ | ________________________________ | |||
| permissions | | | permissions | | |||
| | | | | | |||
| owner [read+write |v] | | | owner [read+write |v] | | |||
| group [read only |v] | | | group [read only |v] | | |||
| other [no access |v] | | | other [no access |v] | | |||
skipping to change at line 3976 | skipping to change at line 3961 | |||
snprintf(p2,100,"%s, %s, %s",operm,gperm,wperm); // output permissions | snprintf(p2,100,"%s, %s, %s",operm,gperm,wperm); // output permissions | |||
zdialog_free(zd); | zdialog_free(zd); | |||
return 0; // normal return | return 0; // normal return | |||
} | } | |||
// convert between permission formats | // convert between permission formats | |||
// string: "read+write, read only, no access" | // string: "read+write, read only, no access" | |||
// mode_t: bitmap of permissions, e.g. 0640 | // mode_t: bitmap of permissions, e.g. 0640 | |||
int conv_permissions(cchar *perms, mode_t &mode) // string permissions to mode_t | int conv_permissions(ch *perms, mode_t &mode) // string permissions to mode_t | |||
{ | { | |||
int err = 0; | int err = 0; | |||
cchar *pp; | ch *pp; | |||
mode = 0; | mode = 0; | |||
pp = substring(perms,',',1); | pp = substring(perms,',',1); | |||
if (pp) { | if (pp) { | |||
if (strmatch(pp,"read+write")) mode += S_IRUSR + S_IWUSR; | if (strmatch(pp,"read+write")) mode += S_IRUSR + S_IWUSR; | |||
else if (strmatch(pp,"read only")) mode += S_IRUSR; | else if (strmatch(pp,"read only")) mode += S_IRUSR; | |||
else if (strmatch(pp,"no access")); | else if (strmatch(pp,"no access")); | |||
else err = 1; | else err = 1; | |||
} | } | |||
skipping to change at line 4013 | skipping to change at line 3998 | |||
if (strmatch(pp,"read+write")) mode += S_IROTH + S_IWOTH; | if (strmatch(pp,"read+write")) mode += S_IROTH + S_IWOTH; | |||
else if (strmatch(pp,"read only")) mode += S_IROTH; | else if (strmatch(pp,"read only")) mode += S_IROTH; | |||
else if (strmatch(pp,"no access")); | else if (strmatch(pp,"no access")); | |||
else err = 1; | else err = 1; | |||
} | } | |||
else err = 1; | else err = 1; | |||
return err; | return err; | |||
} | } | |||
int conv_permissions(mode_t mode, char *perms) // mode_t to string permissions | int conv_permissions(mode_t mode, ch *perms) // mode_t to string permissions | |||
{ | { | |||
int err = 0; | int err = 0; | |||
*perms = 0; | *perms = 0; | |||
if (mode & S_IRUSR && mode & S_IWUSR) strcat(perms,"read+write"); | if (mode & S_IRUSR && mode & S_IWUSR) strcat(perms,"read+write"); | |||
else if (mode & S_IRUSR) strcat(perms,"read only"); | else if (mode & S_IRUSR) strcat(perms,"read only"); | |||
else strcat(perms,"no access"); | else strcat(perms,"no access"); | |||
strcat(perms,", "); | strcat(perms,", "); | |||
End of changes. 175 change blocks. | ||||
251 lines changed or deleted | 238 lines changed or added |