"Fossies" - the Fresh Open Source Software Archive

Member "xzgv-0.9.2/src/copymove.c" (3 Sep 2017, 10534 Bytes) of package /linux/misc/old/xzgv-0.9.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "copymove.c" see the Fossies "Dox" file reference documentation.

    1 /* xzgv v0.3 - picture viewer for X, with file selector.
    2  * Copyright (C) 1999 Russell Marks. See main.c for license details.
    3  *
    4  * copymove.c - code for file copy/move.
    5  *
    6  * Based on both gotodir.c and zgv's copymove.c.
    7  */
    8 
    9 #include <stdio.h>
   10 #include <string.h>
   11 #include <stdlib.h>
   12 #include <unistd.h>
   13 #include <sys/types.h>
   14 #include <sys/stat.h>
   15 #include <utime.h>
   16 #include <errno.h>
   17 #include <gtk/gtk.h>
   18 #include <gdk/gdkkeysyms.h>
   19 #include "backend.h"
   20 #include "main.h"
   21 
   22 #include "copymove.h"
   23 
   24 
   25 #define TRANSFER_BUF_SIZE   8192
   26 
   27 
   28 static GtkWidget *dir_win;
   29 static int cm_do_move;
   30 
   31 
   32 
   33 /* ------ actual copy/move file code ------ */
   34 
   35 
   36 static int cm_isdir(const char *filename)
   37 {
   38 struct stat sbuf;
   39 
   40 return(stat(filename,&sbuf)!=-1 && S_ISDIR(sbuf.st_mode));
   41 }
   42 
   43 
   44 /* check dstdir is a directory, and append src to it
   45  */
   46 char *make_dest(const char *src,const char *dstdir)
   47 {
   48 char *dst;
   49 
   50 if(!cm_isdir(dstdir) ||
   51    (dst=malloc(strlen(dstdir)+strlen(src)+2))==NULL)    /* +2 for / and NUL */
   52   return NULL;
   53 
   54 strcpy(dst,dstdir);
   55 strcat(dst,"/");
   56 if(strrchr(src,'/'))
   57   strcat(dst,strrchr(src,'/')+1);
   58 else
   59   strcat(dst,src);
   60 
   61 return dst;
   62 }
   63 
   64 
   65 /* copy or move file, returns 0 if failed
   66  * src must be in the current directory (though this isn't checked)
   67  * and dstdir must be a directory (fails if it isn't)
   68  */
   69 int copy_or_move(const char *src,const char *dstdir,int do_move)
   70 {
   71 char *dst = make_dest(src, dstdir);
   72 GFile *srcfile = g_file_new_for_path(src);
   73 GFile *dstfile = g_file_new_for_path(dst);
   74 return (do_move?g_file_move:g_file_copy)(srcfile, dstfile, 0, NULL, NULL, NULL, NULL);
   75 }
   76 
   77 
   78 
   79 
   80 /* ------ UI code ------ */
   81 
   82 
   83 /* see if we have either tagged files, or cursor on a file (not a dir). */
   84 int ok_for_copymove(void)
   85 {
   86 struct clist_data_tag *datptr;
   87 int f,t;
   88 
   89 if(!numrows) return(0);
   90 
   91 for(f=t=0;f<numrows;f++)
   92   if(get_tagged_state(f))
   93     t++;
   94 
   95 datptr=gtk_clist_get_row_data(GTK_CLIST(clist),GTK_CLIST(clist)->focus_row);
   96 
   97 return(t || !datptr->isdir);
   98 }
   99 
  100 
  101 
  102 /* returns window widget, and progbar in arg */
  103 static void make_progress_win(GtkWidget **progress_win_ret,
  104                               GtkWidget **progbar_ret)
  105 {
  106 GtkWidget *progress_win;
  107 GtkWidget *progbar,*button;
  108 
  109 progress_win=*progress_win_ret=gtk_dialog_new();
  110 
  111 /* set returned pointer to NULL when destroyed */
  112 gtk_signal_connect(GTK_OBJECT(progress_win),"destroy",
  113                    GTK_SIGNAL_FUNC(gtk_widget_destroyed),
  114                    progress_win_ret);
  115 
  116 gtk_container_set_border_width(
  117   GTK_CONTAINER(GTK_DIALOG(progress_win)->vbox),2);
  118 gtk_container_set_border_width(
  119   GTK_CONTAINER(GTK_DIALOG(progress_win)->action_area),0);
  120 
  121 gtk_window_set_title(GTK_WINDOW(progress_win),
  122                      cm_do_move?"Moving":"Copying");
  123 gtk_window_set_policy(GTK_WINDOW(progress_win),FALSE,TRUE,FALSE);
  124 gtk_widget_set_usize(progress_win,250,55);
  125 gtk_window_set_position(GTK_WINDOW(progress_win),GTK_WIN_POS_CENTER);
  126 gtk_window_set_modal(GTK_WINDOW(progress_win),TRUE);
  127 
  128 progbar=*progbar_ret=gtk_progress_bar_new();
  129 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progress_win)->vbox),
  130                    progbar,TRUE,TRUE,2);
  131 gtk_widget_show(progbar);
  132 
  133 button=gtk_button_new_with_label("Cancel");
  134 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progress_win)->action_area),
  135                    button,TRUE,TRUE,2);
  136 gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
  137                           GTK_SIGNAL_FUNC(gtk_widget_destroy),
  138                           GTK_OBJECT(progress_win));
  139 gtk_widget_grab_focus(button);
  140 gtk_widget_show(button);
  141 
  142 /* esc also aborts (even from main window!) */
  143 gtk_widget_add_accelerator(button,"clicked",mainwin_accel_group,
  144                            GDK_Escape,0,0);
  145 
  146 
  147 gtk_widget_show(progress_win);
  148 }
  149 
  150 
  151 /* do the copy/moves, showing how far we've got. */
  152 void cm_copymove_gotdir(const char *destdir)
  153 {
  154 static char buf[256];
  155 GtkWidget *progress_win,*progbar;
  156 int f,t,numtagged;
  157 int done;
  158 char *ptr;
  159 
  160 /* if by some miracle there are no files, don't bother ;-) */
  161 if(!numrows) return;
  162 
  163 /* stop any running thumbnail read. The caller rescans the dir after
  164  * we're done anyway.
  165  */
  166 if(thumbnail_read_running())
  167   stop_thumbnail_read();
  168 
  169 for(f=t=0;f<numrows;f++)
  170   if(get_tagged_state(f))
  171     t++;
  172 
  173 numtagged=t;
  174 if(t==0) numtagged=1;   /* used for progress bar, so fake it :-) */
  175 
  176 make_progress_win(&progress_win,&progbar);
  177 
  178 if(progress_win && mainwin)
  179   gtk_progress_configure(GTK_PROGRESS(progbar),0.,0.,(float)numtagged);
  180 
  181 /* do GTK+ update early */
  182 if(progress_win && mainwin)
  183   do_gtk_stuff();
  184 
  185 for(done=f=0;f<numrows;f++)
  186   {
  187   /* kludge for cursor file
  188    * may lead one to think the code
  189    * sucks in untold ways.
  190    *
  191    * "For example, er... where is Eric Cartman?"
  192    * "That's a haiku?"
  193    *        -- South Park
  194    */
  195   if(t==0)
  196     f=GTK_CLIST(clist)->focus_row;
  197   else
  198     if(!get_tagged_state(f)) continue;
  199   
  200   gtk_clist_get_text(GTK_CLIST(clist),f,SELECTOR_NAME_COL,&ptr);
  201   
  202   if(!copy_or_move(ptr,destdir,cm_do_move))
  203     {
  204     sprintf(buf,"Error %s ",cm_do_move?"moving":"copying");
  205     /* if it's a really big filename just say "file" :-) */
  206     strcat(buf,(strlen(ptr)>100)?"file":ptr);
  207     
  208     if(mainwin)
  209       {
  210       if(progress_win)
  211         gtk_widget_destroy(progress_win);
  212       
  213       error_dialog("xzgv error",buf);
  214       }
  215     
  216     return;
  217     }
  218   
  219   done++;
  220   
  221   /* update progress bar, and give it a chance to draw */
  222   if(progress_win && mainwin)
  223     {
  224     gtk_progress_set_value(GTK_PROGRESS(progbar),(float)done);
  225     do_gtk_stuff();
  226     }
  227   
  228   if(!progress_win || !mainwin)
  229     break;      /* they must have aborted */
  230 
  231   if(t==0) break;
  232   }
  233 
  234 /* if they decided to quit completely, take the hint :-) */
  235 if(!mainwin)
  236   return;
  237 
  238 /* if not already destroyed, blast window */
  239 if(progress_win)
  240   gtk_widget_destroy(progress_win);
  241 }
  242 
  243 
  244 /* XXX much of the following is the same as gotodir.c. Should merge
  245  * these together if reasonable.
  246  */
  247 
  248 static void cb_ok_button(GtkWidget *button,GtkWidget *entry)
  249 {
  250 const char *ptr=gtk_entry_get_text(GTK_ENTRY(entry));
  251 int isdir;
  252 
  253 if(!ptr || *ptr==0 || strcmp(ptr,".")==0)
  254   {
  255   gtk_widget_destroy(dir_win);
  256   return;
  257   }
  258 
  259 if(*ptr=='~' && getenv("HOME"))     /* kludge for home dir */
  260   ptr=g_strdup_printf("%s%s",getenv("HOME"),ptr+1);
  261 else
  262   ptr=g_strdup(ptr);    /* not needed but easier this way :-) */
  263 
  264 isdir=cm_isdir(ptr);
  265 
  266 /* now do the actual copy/move */
  267 if(isdir)
  268   cm_copymove_gotdir(ptr);
  269 
  270 free((void *)ptr);
  271 gtk_widget_destroy(dir_win);
  272 
  273 if(!isdir)
  274   {
  275   error_dialog("xzgv error","Directory not found!");
  276   return;
  277   }
  278 
  279 if(!cmdline_files)  /* don't update if run as `xzgv file(s)' */
  280   {
  281   /* unpredictable what'll happen to files in current dir; safest to
  282    * just always update. (Yes, even if copying, as we stopped thumbnail
  283    * update in cm_copymove_gotdir().) However, save pastpos first, so
  284    * we stand a decent chance of staying at a tolerably similar place
  285    * in the dir.
  286    */
  287   new_pastpos(GTK_CLIST(clist)->focus_row);
  288 
  289   reinit_dir(1,0);
  290   }
  291 }
  292 
  293 
  294 void cb_copymove_file_or_tagged_files(int do_move)
  295 {
  296 GtkWidget *vbox;
  297 GtkWidget *action_tbl,*ok_button,*cancel_button;
  298 GtkWidget *table;
  299 GtkWidget *label,*entry;
  300 static char cdir[1024],buf[1024];
  301 int tbl_row;
  302 
  303 if(!ok_for_copymove())
  304   {
  305   error_dialog("xzgv error","No files tagged and cursor not on a file");
  306   return;
  307   }
  308 
  309 cm_do_move=do_move;     /* save for later */
  310 
  311 getcwd(cdir,sizeof(cdir)-1);
  312 
  313 dir_win=gtk_dialog_new();
  314 
  315 gtk_window_set_title(GTK_WINDOW(dir_win),
  316                      do_move?"Move file(s) to dir":"Copy file(s) to dir");
  317 gtk_window_set_policy(GTK_WINDOW(dir_win),FALSE,TRUE,FALSE);
  318 gtk_window_set_position(GTK_WINDOW(dir_win),GTK_WIN_POS_CENTER);
  319 
  320 /* must be modal given the way we save static data like cm_do_move */
  321 gtk_window_set_modal(GTK_WINDOW(dir_win),TRUE);
  322 
  323 /* make a new vbox for the top part so we can get spacing more sane */
  324 vbox=gtk_vbox_new(FALSE,10);
  325 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dir_win)->vbox),
  326                    vbox,TRUE,TRUE,0);
  327 gtk_widget_show(vbox);
  328 
  329 gtk_container_set_border_width(GTK_CONTAINER(vbox),5);
  330 gtk_container_set_border_width(
  331   GTK_CONTAINER(GTK_DIALOG(dir_win)->action_area),5);
  332 
  333 /* add ok/cancel buttons */
  334 action_tbl=gtk_table_new(1,5,TRUE);
  335 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dir_win)->action_area),
  336                    action_tbl,TRUE,TRUE,0);
  337 gtk_widget_show(action_tbl);
  338 
  339 ok_button=gtk_button_new_with_label("Ok");
  340 gtk_table_attach_defaults(GTK_TABLE(action_tbl),ok_button, 1,2, 0,1);
  341 /* we connect the signal later, so we can refer to the text-entry */
  342 gtk_widget_show(ok_button);
  343 
  344 cancel_button=gtk_button_new_with_label("Cancel");
  345 gtk_table_attach_defaults(GTK_TABLE(action_tbl),cancel_button, 3,4, 0,1);
  346 gtk_signal_connect_object(GTK_OBJECT(cancel_button),"clicked",
  347                           GTK_SIGNAL_FUNC(gtk_widget_destroy),
  348                           GTK_OBJECT(dir_win));
  349 gtk_widget_show(cancel_button);
  350 
  351 
  352 table=gtk_table_new(2,3,TRUE);
  353 gtk_box_pack_start(GTK_BOX(vbox),table,TRUE,TRUE,0);
  354 gtk_table_set_col_spacings(GTK_TABLE(table),20);
  355 gtk_table_set_row_spacings(GTK_TABLE(table),8);
  356 gtk_container_set_border_width(GTK_CONTAINER(table),8);
  357 gtk_widget_show(table);
  358 
  359 #define DO_TBL_LEFT(table,row,name) \
  360   label=gtk_label_new(name);                \
  361   gtk_misc_set_alignment(GTK_MISC(label),1.,0.5);   \
  362   gtk_table_attach_defaults(GTK_TABLE(table),label, 0,1, (row),(row)+1); \
  363   gtk_widget_show(label)
  364 
  365 #define DO_TBL_RIGHT(table,row,name) \
  366   label=gtk_label_new(name);                \
  367   gtk_misc_set_alignment(GTK_MISC(label),0.,0.5);   \
  368   gtk_table_attach_defaults(GTK_TABLE(table),label, 1,3, (row),(row)+1); \
  369   gtk_widget_show(label)
  370 
  371 tbl_row=0;
  372 
  373 DO_TBL_LEFT(table,tbl_row,"Current dir:");
  374 DO_TBL_RIGHT(table,tbl_row,cdir);
  375 tbl_row++;
  376 
  377 DO_TBL_LEFT(table,tbl_row,"Target dir:");
  378 
  379 entry=gtk_entry_new_with_max_length(sizeof(buf)-1);
  380 gtk_table_attach_defaults(GTK_TABLE(table),entry, 1,3, tbl_row,tbl_row+1);
  381 gtk_widget_grab_focus(entry);
  382 gtk_widget_show(entry);
  383 gtk_signal_connect(GTK_OBJECT(entry),"activate",
  384                    GTK_SIGNAL_FUNC(cb_ok_button),GTK_OBJECT(entry));
  385 
  386 /* finally connect up the ok button */
  387 gtk_signal_connect(GTK_OBJECT(ok_button),"clicked",
  388                    GTK_SIGNAL_FUNC(cb_ok_button),GTK_OBJECT(entry));
  389 
  390 
  391 /* esc = cancel */
  392 gtk_widget_add_accelerator(cancel_button,"clicked",
  393                            mainwin_accel_group,
  394                            GDK_Escape,0,0);
  395 
  396 gtk_widget_add_accelerator(ok_button,"clicked",
  397                            mainwin_accel_group,
  398                            GDK_Return,0,0);
  399 
  400 
  401 gtk_widget_show(dir_win);
  402 
  403 /* that's it then; it's modal so we can just leave GTK+ to deal with things. */
  404 }