"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 }