1 /* copyopwin.cc
2  * This file belongs to Worker, a file manager for UN*X/X11.
3  * Copyright (C) 2001-2014 Ralf Hoffmann.
4  * You can contact me at: ralf@boomerangsworld.de
5  *   or http://www.boomerangsworld.de/worker
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "worker.h"
23 #include "copyopwin.hh"
24 #include "aguix/util.h"
25 #include "aguix/lowlevelfunc.h"
26 #include "aguix/awindow.h"
27 #include "aguix/button.h"
28 #include "aguix/bevelbox.h"
29 #include "aguix/solidbutton.h"
30 #include "aguix/choosebutton.h"
31 #include "worker_locale.h"
32 #include "datei.h"
33 #include "pers_kvp.hh"
34 
35 #define HUMAN_READABLE_DIALOG 1
36 
CopyOpWin(AGUIX * taguix,bool _move)37 CopyOpWin::CopyOpWin( AGUIX*taguix, bool _move )
38 {
39   this->aguix=taguix;
40   copied_bytes_curfile=0;
41   bytes_curfile=0;
42   copied_bytes=0;
43   bytes=0;
44   copied_files=0;
45   files=0;
46   copied_dirs=0;
47   dirs=0;
48 
49   window=NULL;
50   melw = 0;
51   filenamespace[0] = 0;
52   filenamespace[1] = 0;
53   ismessage[0] = false;
54   ismessage[1] = false;
55 
56   update_sourcetext = false;
57   update_desttext = false;
58   update_filetext = false;
59   update_globtext = false;
60   update_files2gotext = false;
61   update_dirs2gotext = false;
62 
63   mintime = 1000000;
64   lastbytes = 0;
65   lastrate = 0.0;
66   lastbytes_global = 0;
67   lastrate_global = 0.0;
68 
69   glob_percent = 0;
70 
71   move = _move;
72 
73   lencalc = new AFontWidth( aguix, NULL );
74   memset( &stoptime, 0, sizeof( stoptime ) );
75   timer_stopped = false;
76 
77   gettimeofday( &last_update_time, NULL );
78   skipped_updates = 0;
79 
80   m_master_thread_id = std::this_thread::get_id();
81 
82   m_finished = false;
83   m_detached = false;
84 
85   int v = Worker::getPersKVPStore().getIntValue( "copy-keep-window" );
86 
87   // 0 is default for non-existing entry, 2 means enabled
88   if ( v == 0 ||
89        v == 2 ) {
90       m_keep_window = true;
91   } else {
92       m_keep_window = false;
93   }
94 
95   m_keep_window_cb = nullptr;
96 }
97 
~CopyOpWin()98 CopyOpWin::~CopyOpWin()
99 {
100   if(window!=NULL) close();
101   delete lencalc;
102 }
103 
104 int
open()105 CopyOpWin::open()
106 {
107   int w,h;
108   int tx,ty;
109   Text *ttext;
110 
111   close();
112   w=400;
113   h=10;
114   window = new AWindow( aguix,
115 			10, 10,
116 			w, h,
117 			( move == true ) ? catalog.getLocale( 299 ) : catalog.getLocale( 1249 ),
118                         AWindow::AWINDOW_NORMAL );
119   window->create();
120   tx=5;
121   ty=5;
122   sourcetext=(Text*)window->add(new Text(aguix,tx,ty,""));
123   ismessage[0] = true;
124   ty+=sourcetext->getHeight()+5;
125   desttext=(Text*)window->add(new Text(aguix,tx,ty,""));
126   ismessage[1] = true;
127   ty+=desttext->getHeight()+5;
128   fsb=(SolidButton*)window->add(new SolidButton(aguix,tx+1,ty+1,w-2*(tx+1),"","button-special1-fg", "button-special1-bg",0));
129   sbw=fsb->getWidth();
130   bb1=(BevelBox*)window->add(new BevelBox(aguix,tx,ty,w-2*tx,fsb->getHeight()+2,1));
131   fsb->toFront();
132   ty+=bb1->getHeight()+5;
133   tx=10;
134   filetext=(Text*)window->add(new Text(aguix,tx,ty,""));
135   ty+=filetext->getHeight()+5;
136 
137   ttext = (Text*)window->add( new Text( aguix, tx, ty, catalog.getLocale( 90 ) ) );
138   tx += ttext->getWidth() + 5;
139   fileavgtext = (Text*)window->add( new Text( aguix, tx, ty, "" ) );
140   ty += fileavgtext->getHeight() + 5;
141 
142   tx=5;
143   bb2=(BevelBox*)window->add(new BevelBox(aguix,tx,ty,w-2*tx,2,0));
144   ty+=bb2->getHeight()+5;
145 
146   ttext=(Text*)window->add(new Text(aguix,tx,ty,catalog.getLocale(118)));
147   tx+=ttext->getWidth()+5;
148   files2gotext=(Text*)window->add(new Text(aguix,tx,ty,""));
149   tx=5;
150   ty+=ttext->getHeight()+5;
151   ttext=(Text*)window->add(new Text(aguix,tx,ty,catalog.getLocale(119)));
152   tx+=ttext->getWidth()+5;
153   dirs2gotext=(Text*)window->add(new Text(aguix,tx,ty,""));
154   tx=5;
155   ty+=ttext->getHeight()+5;
156   gsb=(SolidButton*)window->add(new SolidButton(aguix,tx+1,ty+1,w-2*(tx+1),"","button-special1-fg", "button-special1-bg",0));
157   bb3=(BevelBox*)window->add(new BevelBox(aguix,tx,ty,w-2*tx,gsb->getHeight()+2,1));
158   gsb->toFront();
159   ty+=bb3->getHeight()+5;
160   tx=10;
161   ttext=(Text*)window->add(new Text(aguix,tx,ty,catalog.getLocale(120)));
162   tx+=ttext->getWidth()+5;
163   globtext=(Text*)window->add(new Text(aguix,tx,ty,""));
164   tx=5;
165   ty+=globtext->getHeight()+5;
166   ttext=(Text*)window->add(new Text(aguix,tx,ty,catalog.getLocale(121)));
167   tx+=ttext->getWidth()+5;
168   timetext=(Text*)window->add(new Text(aguix,tx,ty,""));
169   ty+=timetext->getHeight()+5;
170   tx=5;
171   bb4=(BevelBox*)window->add(new BevelBox(aguix,tx,ty,w-2*tx,2,0));
172   ty+=bb4->getHeight()+5;
173 
174   m_detach_b = (Button*)window->add( new Button( aguix, tx, ty, catalog.getLocale( 1039 ), 0 ) );
175 
176   m_keep_window_cb = (ChooseButton*)window->add( new ChooseButton( aguix, tx, ty,
177                                                                    m_keep_window,
178                                                                    catalog.getLocale( 1047 ),
179                                                                    LABEL_RIGHT, 0 ) );
180   m_keep_window_cb->hide();
181 
182   cb = (Button*)window->add( new Button( aguix, tx, ty, catalog.getLocale( 8 ), 0 ) );
183   cb->move( w - 5 - cb->getWidth(), cb->getY() );
184 
185   ty+=cb->getHeight()+5;
186   h=ty;
187   window->setDoTabCycling( true );
188   window->resize(w,h);
189   window->setMinSize(w,h);
190   //  window->setMaxSize(w,h);
191   window->centerScreen();
192   window->show();
193 
194   filenamespace[0] = w - window->getBorderWidth() - sourcetext->getX();
195   filenamespace[0] -= aguix->getTextWidth( catalog.getLocale( ( move == true ) ? 594 : 116 ) ) - 2 * aguix->getTextWidth( " " );
196   filenamespace[1] = w - window->getBorderWidth() - desttext->getX();
197   filenamespace[1] -= aguix->getTextWidth( catalog.getLocale( 117 ) ) - 2 * aguix->getTextWidth( " " );
198 
199   return 0;
200 }
201 
202 void
close()203 CopyOpWin::close()
204 {
205   if(window!=NULL) {
206     delete window;
207   }
208   window=NULL;
209 }
210 
211 void
starttimer()212 CopyOpWin::starttimer()
213 {
214     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
215 
216     gettimeofday( &starttime, NULL );
217     lasttime_global = starttime;
218 }
219 
220 void
set_files_to_copy(long nfiles)221 CopyOpWin::set_files_to_copy(long nfiles)
222 {
223     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
224 
225   if(nfiles>0) files=nfiles;
226   else files=0;
227   update_files2gotext=true;
228 }
229 
230 void
set_dirs_to_copy(long ndirs)231 CopyOpWin::set_dirs_to_copy(long ndirs)
232 {
233     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
234 
235   if(ndirs>0) dirs=ndirs;
236   else dirs=0;
237   update_dirs2gotext=true;
238 }
239 
240 void
set_bytes_to_copy(loff_t nbytes)241 CopyOpWin::set_bytes_to_copy(loff_t nbytes)
242 {
243     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
244 
245   if(nbytes>0) bytes=nbytes;
246   else bytes=0;
247   update_globtext=true;
248 }
249 
250 void
set_bytes_to_copy_curfile(loff_t nbytes)251 CopyOpWin::set_bytes_to_copy_curfile( loff_t nbytes )
252 {
253     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
254 
255   if ( nbytes > 0 ) bytes_curfile = nbytes;
256   else bytes_curfile = 0;
257   update_filetext = true;
258 }
259 
260 void
dir_finished()261 CopyOpWin::dir_finished()
262 {
263     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
264 
265   copied_dirs++;
266   update_dirs2gotext=true;
267 }
268 
269 void
file_finished()270 CopyOpWin::file_finished()
271 {
272     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
273 
274   // inc counter
275   copied_files++;
276   update_files2gotext=true;
277   if ( skipped_updates > 0 ) {
278     update_filetext = true;
279     update_globtext = true;
280   }
281 }
282 
283 void
add_curbytes_copied(loff_t nbytes)284 CopyOpWin::add_curbytes_copied( loff_t nbytes )
285 {
286     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
287 
288   if ( nbytes > 0 ) {
289     copied_bytes_curfile += nbytes;
290     copied_bytes += nbytes;
291   }
292 
293   struct timeval curtime;
294   gettimeofday( &curtime, NULL );
295   if ( ldiffgtod_m( &curtime, &last_update_time ) >= ( 1000 / UPDATES_PER_SECOND ) ) {
296     update_filetext = true;
297     update_globtext = true;
298     last_update_time = curtime;
299     skipped_updates = 0;
300   } else {
301     skipped_updates++;
302   }
303 }
304 
305 void
newfile(const std::string & name,const std::string & ndest)306 CopyOpWin::newfile( const std::string &name,
307                     const std::string &ndest )
308 {
309     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
310 
311     source = name;
312 
313     dest = ndest;
314 
315   gettimeofday( &filestarttime, NULL );
316   update_sourcetext=true;
317   update_desttext=true;
318   ismessage[0] = false;
319   ismessage[1] = false;
320   copied_bytes_curfile = 0;
321   update_filetext=true;
322 
323   lastbytes = 0;
324   lasttime = filestarttime;
325   lastrate = 0.0;
326 }
327 
328 int
redraw(bool skip_message_handling)329 CopyOpWin::redraw( bool skip_message_handling )
330 { /* this functions will redraw the window AND process events for this window
331    * returns values:
332    *  0 for regular exit
333    *  1 when clicked Cancel-Button or closed window
334    *  other not implemented */
335   int returnvalue=0;
336   long rtime, rtime_at_current_rate;
337   double drtime;
338   struct timeval curtime;
339   double difftime2, lastdiff2;
340   char tstr[1024],
341        *tstr2;
342   double rate;
343   int tw;
344   bool doresize = false;
345   int newglob_percent;
346   std::string copied_bytes_curfile_str,
347               bytes_curfile_str,
348               copied_bytes_str,
349               bytes_str;
350 
351   char *tstr3;
352 
353     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
354 
355   timerclear( &curtime );
356   if ( update_sourcetext == true ) {
357       if ( ismessage[0] == false ) {
358           tstr3 = Datei::shrinkFilename( source.c_str(), filenamespace[0], *lencalc );
359           if ( tstr3 == NULL)
360               tstr3 = dupstring( source.c_str() );
361           tstr2 = (char*)_allocsafe( strlen( catalog.getLocale( ( move == true ) ? 594 : 116 ) ) + strlen( tstr3 ) + 1 );
362           sprintf( tstr2, catalog.getLocale( ( move == true ) ? 594 : 116 ), tstr3 );
363           _freesafe( tstr3 );
364           sourcetext->setText(tstr2);
365           _freesafe(tstr2);
366           /* no need for explicit redraw */
367       } else {
368           sourcetext->setText( source.c_str() );
369       }
370       update_sourcetext = false;
371   }
372   if ( update_desttext == true ) {
373       if ( ismessage[1] == false ) {
374           tstr3 = Datei::shrinkFilename( dest.c_str(), filenamespace[1], *lencalc );
375           if ( tstr3 == NULL)
376               tstr3 = dupstring( dest.c_str() );
377           tstr2 = (char*)_allocsafe( strlen( catalog.getLocale( 117 ) ) + strlen( tstr3 ) + 1 );
378           sprintf( tstr2, catalog.getLocale( 117 ), tstr3 );
379           _freesafe(tstr3);
380           desttext->setText(tstr2);
381           _freesafe(tstr2);
382           // no need for explicit redraw
383       } else {
384           desttext->setText( dest.c_str() );
385       }
386       update_desttext = false;
387   }
388   if(update_filetext==true) {
389     if ( ! timerisset( &curtime ) ) gettimeofday( &curtime, NULL );
390     difftime2 = diffgtod( &curtime, &filestarttime );
391     lastdiff2 = diffgtod( &curtime, &lasttime );
392 
393     if ( lastdiff2 >= mintime ) {
394       lastrate = (double)( copied_bytes_curfile - lastbytes ) * 1000000.0 / lastdiff2;
395       lastbytes = copied_bytes_curfile;
396       lasttime = curtime;
397     }
398 
399     if ( HUMAN_READABLE_DIALOG ) {
400         copied_bytes_curfile_str = AGUIXUtils::bytes_to_human_readable_f( (double)copied_bytes_curfile,
401                                                                           1, ( lastrate > 0.0 ) ? 5 : 0,
402                                                                           AGUIXUtils::BM_SYSTEM_SETTING,
403                                                                           lastrate );
404         bytes_curfile_str = AGUIXUtils::bytes_to_human_readable_f( (double)bytes_curfile,
405                                                                    1, ( lastrate > 0.0 ) ? 5 : 0,
406                                                                    AGUIXUtils::BM_SYSTEM_SETTING,
407                                                                    lastrate );
408 
409         snprintf( tstr, sizeof( tstr ), "%s / %s @ %s/s",
410                   copied_bytes_curfile_str.c_str(),
411                   bytes_curfile_str.c_str(),
412                   AGUIXUtils::bytes_to_human_readable_f( lastrate ).c_str() );
413         tstr[ sizeof( tstr ) - 1 ] = '\0';
414     } else {
415         MakeLong2NiceStr( copied_bytes_curfile, copied_bytes_curfile_str );
416 
417         MakeLong2NiceStr( bytes_curfile, bytes_curfile_str );
418         snprintf( tstr, sizeof( tstr ), "%s / %s @ %.2f KB/s",
419                   copied_bytes_curfile_str.c_str(),
420                   bytes_curfile_str.c_str(),
421                   lastrate / 1024.0 );
422         tstr[ sizeof( tstr ) - 1 ] = '\0';
423     }
424 
425     filetext->setText(tstr);
426     tw = filetext->getX() + filetext->getWidth() + window->getBorderWidth();
427     if ( tw > melw ) {
428       melw = tw;
429       doresize = true;
430     }
431 
432     if(difftime2>0) {
433       rate = (double)copied_bytes_curfile * 1000000.0 / difftime2;
434     } else rate=0.0;
435 
436     if ( HUMAN_READABLE_DIALOG ) {
437         snprintf( tstr, sizeof( tstr ), "%s/s", AGUIXUtils::bytes_to_human_readable_f( rate ).c_str() );
438     } else {
439         snprintf( tstr, sizeof( tstr ), "%.2f KB/s", rate / 1024.0 );
440     }
441 
442     tstr[ sizeof( tstr ) - 1 ] = '\0';
443     fileavgtext->setText( tstr );
444 
445     int rate_precision = AGUIXUtils::calc_precision( rate * 100.0 / (double)bytes_curfile );
446     if ( rate_precision < 0 ) rate_precision = 0;
447 
448     if(bytes_curfile>0)
449       rate = (double)copied_bytes_curfile/(double)bytes_curfile;
450     else
451       rate=0.0;
452     if ( rate < 0.01 )
453       rate = 0.0;
454 
455     std::string fraction_str = AGUIXUtils::formatStringToString( "%%.%df %%%%",
456                                                                  rate_precision );
457 
458     snprintf( tstr, sizeof( tstr ), fraction_str.c_str(), rate * 100.0 );
459     tstr[ sizeof( tstr ) - 1 ] = '\0';
460     fsb->setText(tstr);
461     fsb->resize( w_max( (int)( sbw * rate ), 2 ), fsb->getHeight() );
462     update_filetext=false;
463   }
464   if(update_globtext==true) {
465     if ( ! timerisset( &curtime ) ) gettimeofday( &curtime, NULL );
466     difftime2 = diffgtod( &curtime, &starttime );
467     if(difftime2>0.0) {
468       rate = (double)copied_bytes * 1000000.0 / difftime2;
469     } else rate=0.0;
470 
471     double lastdiff_global = diffgtod( &curtime, &lasttime_global );
472 
473     if ( lastdiff_global >= 10.0 * mintime ) {
474       lastrate_global = (double)( copied_bytes - lastbytes_global ) * 1000000.0 / lastdiff_global;
475       lastbytes_global = copied_bytes;
476       lasttime_global = curtime;
477     }
478 
479     if ( HUMAN_READABLE_DIALOG ) {
480         copied_bytes_str = AGUIXUtils::bytes_to_human_readable_f( (double)copied_bytes,
481                                                                   1, ( rate > 0.0 ) ? 5 : 0,
482                                                                   AGUIXUtils::BM_SYSTEM_SETTING,
483                                                                   rate );
484 
485         bytes_str = AGUIXUtils::bytes_to_human_readable_f( (double)bytes,
486                                                            1, ( rate > 0.0 ) ? 5 : 0,
487                                                            AGUIXUtils::BM_SYSTEM_SETTING,
488                                                            rate );
489 
490         snprintf( tstr, sizeof( tstr ), "%s / %s @ %s/s", copied_bytes_str.c_str(), bytes_str.c_str(), AGUIXUtils::bytes_to_human_readable_f( rate ).c_str() );
491         tstr[ sizeof( tstr ) - 1 ] = '\0';
492     } else {
493         MakeLong2NiceStr( copied_bytes, copied_bytes_str );
494         MakeLong2NiceStr( bytes, bytes_str );
495         snprintf( tstr, sizeof( tstr ), "%s / %s @ %.2f KB/s", copied_bytes_str.c_str(), bytes_str.c_str(), rate / 1024.0 );
496         tstr[ sizeof( tstr ) - 1 ] = '\0';
497     }
498 
499     globtext->setText(tstr);
500     tw = globtext->getX() + globtext->getWidth() + window->getBorderWidth();
501     if ( tw > melw ) {
502       melw = tw;
503       doresize = true;
504     }
505 
506     int rate_precision = AGUIXUtils::calc_precision( rate * 100.0 / (double)bytes );
507     if ( rate_precision < 0 ) rate_precision = 0;
508 
509     if(bytes>0)
510         rate = (double)copied_bytes/(double)bytes;
511     else
512         rate=0.0;
513     if ( rate < 0.01 )
514         rate = 0.0;
515 
516     std::string fraction_str = AGUIXUtils::formatStringToString( "%%.%df %%%%",
517                                                                  rate_precision );
518 
519     snprintf( tstr, sizeof( tstr ), fraction_str.c_str(), rate * 100.0 );
520 
521     tstr[ sizeof( tstr ) - 1 ] = '\0';
522     gsb->setText(tstr);
523     gsb->resize( w_max( (int)( sbw * rate ), 2 ), gsb->getHeight() );
524 
525     newglob_percent = (int)( rate * 100.0 );
526     if ( newglob_percent != glob_percent ) {
527         glob_percent = newglob_percent;
528         tstr3 = (char*)_allocsafe( strlen( ( move == true ) ? catalog.getLocale( 299 ) : catalog.getLocale( 1249 ) ) +
529                                    strlen( " ( %)" ) +
530                                    A_BYTESFORNUMBER( glob_percent ) +
531                                    1 );
532         if ( ( glob_percent > 0 ) && ( glob_percent <= 100 ) ) {
533             sprintf( tstr3, "%s (%d %%)",
534                      ( move == true ) ? catalog.getLocale( 299 ) : catalog.getLocale( 1249 ),
535                      glob_percent );
536         } else {
537             sprintf( tstr3, "%s",
538                      ( move == true ) ? catalog.getLocale( 299 ) : catalog.getLocale( 1249 ) );
539         }
540         window->setTitle( tstr3 );
541         _freesafe( tstr3 );
542     }
543 
544     if(rate>0) {
545         drtime = difftime2 / rate;
546         drtime -= difftime2;
547         rtime = (long)( drtime / 1000000.0 );
548     } else
549         rtime = 700000;  // no rate available => no real time calculatable
550 
551     if ( lastrate_global != 0.0 ) {
552         double remaining_bytes = (double)bytes - (double)copied_bytes;
553         rtime_at_current_rate = remaining_bytes / lastrate_global;
554         rtime_at_current_rate++;
555     } else {
556         rtime_at_current_rate = 700000;
557     }
558 
559     rtime++; // add a second because the last second will shown as 0:00
560     // and at least I don't like this
561     if ( rtime > 604800 ) // more then 7 days
562         sprintf( tstr, "--:--" );
563     else
564         sprintf( tstr, "%ld:%02ld", rtime / 60, rtime % 60 );
565 
566     if ( rtime_at_current_rate <= 604800 &&
567          fabs( rtime - rtime_at_current_rate ) > 10.0 &&
568          fabs( rtime - rtime_at_current_rate ) / (double)rtime > 0.1 ) {
569         std::string alt_time_str = AGUIXUtils::formatStringToString( catalog.getLocale( 973 ),
570                                                                      tstr,
571                                                                      rtime_at_current_rate / 60,
572                                                                      rtime_at_current_rate % 60 );
573         timetext->setText( alt_time_str.c_str() );
574     } else {
575         timetext->setText(tstr);
576     }
577 
578     tw = timetext->getX() + timetext->getWidth() + window->getBorderWidth();
579     if ( tw > melw ) {
580         melw = tw;
581         doresize = true;
582     }
583 
584     update_globtext=false;
585   }
586   if(update_files2gotext==true) {
587     sprintf(tstr,"%ld",files-copied_files);
588     files2gotext->setText(tstr);
589     tw = files2gotext->getX() + files2gotext->getWidth() + window->getBorderWidth();
590     if ( tw > melw ) {
591       melw = tw;
592       doresize = true;
593     }
594 
595     update_files2gotext=false;
596   }
597   if(update_dirs2gotext==true) {
598     sprintf(tstr,"%ld",dirs-copied_dirs);
599     dirs2gotext->setText(tstr);
600     tw = dirs2gotext->getX() + dirs2gotext->getWidth() + window->getBorderWidth();
601     if ( tw > melw ) {
602       melw = tw;
603       doresize = true;
604     }
605 
606     update_dirs2gotext=false;
607   }
608   if ( doresize == true ) {
609     // only resize if window is smaller
610     if ( window->getWidth() < melw ) {
611       window->resize( melw, window->getHeight() );
612     }
613     // anyway the min size has changed so set it again
614     window->setMinSize( melw, bb4->getY() + bb4->getHeight() + 5 +cb->getHeight() + window->getBorderWidth() );
615   }
616 
617   //window->redraw();
618   aguix->Flush();
619 
620   if ( ! skip_message_handling ) {
621       /* update complete
622          now check for X-messages */
623       AGMessage *msg;
624       do {
625           msg=aguix->GetMessage( window );
626 
627           returnvalue |= handleMessage( msg );
628 
629           aguix->ReplyMessage(msg);
630       } while(msg!=NULL);
631   }
632 
633   return returnvalue;
634 }
635 
handleMessage(AGMessage * msg)636 int CopyOpWin::handleMessage( AGMessage *msg )
637 {
638     int returnvalue=0;
639 
640     if(msg!=NULL) {
641       switch(msg->type) {
642         case AG_CLOSEWINDOW:
643             if ( msg->closewindow.window == window->getWindow() ) {
644                 if ( m_finished ) {
645                     returnvalue = 4;
646                 } else {
647                     returnvalue = 1;
648                 }
649             }
650           break;
651         case AG_BUTTONCLICKED:
652             if ( msg->button.button == cb ) {
653                 if ( m_finished ) {
654                     returnvalue = 4;
655                 } else {
656                     returnvalue = 1;
657                 }
658             } else if ( msg->button.button == m_detach_b ) {
659                 returnvalue = 2;
660             }
661           break;
662         case AG_CHOOSECLICKED:
663             if ( msg->choose.button == m_keep_window_cb ) {
664                 m_keep_window = m_keep_window_cb->getState();
665 
666                 Worker::getPersKVPStore().setIntValue( "copy-keep-window",
667                                                        ( m_keep_window ? 2 : 1 ) );
668             }
669             break;
670         case AG_SIZECHANGED:
671           if ( msg->size.window == window->getWindow() ) {
672             std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
673 
674             bb1->resize( msg->size.neww - 2 * window->getBorderWidth(), bb1->getHeight() );
675             sbw = bb1->getWidth() - 2;
676             bb2->resize( msg->size.neww - 2 * window->getBorderWidth(), bb2->getHeight() );
677             bb3->resize( msg->size.neww - 2 * window->getBorderWidth(), bb3->getHeight() );
678             bb4->resize( msg->size.neww - 2 * window->getBorderWidth(), bb4->getHeight() );
679             cb->move( msg->size.neww -5 - cb->getWidth(),
680                       msg->size.newh - window->getBorderWidth() - cb->getHeight() );
681 
682             m_detach_b->move( 5,
683                               msg->size.newh - window->getBorderWidth() - m_detach_b->getHeight() );
684             m_keep_window_cb->move( 5,
685                                     msg->size.newh - window->getBorderWidth() - m_keep_window_cb->getHeight() );
686 
687             filenamespace[0] = msg->size.neww - window->getBorderWidth() - sourcetext->getX();
688             filenamespace[0] -= aguix->getTextWidth( catalog.getLocale( ( move == true ) ? 594 : 116 ) ) - 2 * aguix->getTextWidth( " " );
689             filenamespace[1] = msg->size.neww - window->getBorderWidth() - desttext->getX();
690             filenamespace[1] -= aguix->getTextWidth( catalog.getLocale( 117 ) ) - 2 * aguix->getTextWidth( " " );
691             update_sourcetext = true;
692             update_desttext = true;
693 
694             // now gsb and fsb are not scaled for new width
695             // but next call of redraw they will so this shouldn't hurt anybody
696             // but a solution would be to first react for messages and then redraw
697 
698             if ( m_finished ) {
699                 double rate = 0.0;
700 
701                 if ( bytes_curfile > 0 ) {
702                     rate = (double)copied_bytes_curfile / (double)bytes_curfile;
703                 }
704 
705                 fsb->resize( w_max( (int)( sbw * rate ), 2 ), fsb->getHeight() );
706 
707                 if ( bytes > 0 ) {
708                     rate = (double)copied_bytes / (double)bytes;
709                 } else {
710                     rate=0.0;
711                 }
712 
713                 gsb->resize( w_max( (int)( sbw * rate ), 2 ), gsb->getHeight() );
714             }
715           }
716           break;
717       }
718     }
719 
720   return returnvalue;
721 }
722 
723 void
setmessage(const std::string & msg,int line)724 CopyOpWin::setmessage( const std::string &msg, int line )
725 {
726     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
727 
728     switch(line) {
729         case 0:
730             source = msg;
731             ismessage[0] = true;
732             update_sourcetext = true;
733             break;
734         case 1:
735             dest = msg;
736             ismessage[1] = true;
737             update_desttext = true;
738             break;
739     }
740 }
741 
742 void
dec_file_counter(unsigned long f)743 CopyOpWin::dec_file_counter(unsigned long f)
744 {
745     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
746 
747   files-=f;
748   update_files2gotext=true;
749 }
750 
751 void
dec_dir_counter(unsigned long d)752 CopyOpWin::dec_dir_counter(unsigned long d)
753 {
754     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
755 
756   dirs-=d;
757   update_dirs2gotext=true;
758 }
759 
760 void
dec_byte_counter(loff_t b)761 CopyOpWin::dec_byte_counter(loff_t b)
762 {
763     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
764 
765   bytes-=b;
766   update_globtext=true;
767 }
768 
769 void
stoptimer()770 CopyOpWin::stoptimer()
771 {
772     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
773 
774   gettimeofday( &stoptime, NULL );
775   timer_stopped = true;
776 }
777 
778 void
conttimer()779 CopyOpWin::conttimer()
780 {
781   struct timeval curtime;
782   long s, us;
783 
784     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
785 
786   if ( timer_stopped == false ) return;
787 
788   gettimeofday( &curtime, NULL );
789 
790   s = curtime.tv_sec - stoptime.tv_sec;
791   us = curtime.tv_usec - stoptime.tv_usec;
792   if ( us < 0 ) {
793     s--;
794     us += 1000000;
795   }
796 
797   starttime.tv_sec += s;
798   starttime.tv_usec += us;
799   if ( starttime.tv_usec > 1000000 ) {
800     starttime.tv_sec++;
801     starttime.tv_usec -= 1000000;
802   }
803   filestarttime.tv_sec += s;
804   filestarttime.tv_usec += us;
805   if ( filestarttime.tv_usec > 1000000 ) {
806     filestarttime.tv_sec++;
807     filestarttime.tv_usec -= 1000000;
808   }
809 
810   lasttime_global.tv_sec += s;
811   lasttime_global.tv_usec += us;
812   if ( lasttime_global.tv_usec > 1000000 ) {
813       lasttime_global.tv_sec++;
814       lasttime_global.tv_usec -= 1000000;
815   }
816 }
817 
request_int(const char * title,const char * text,const char * buttons,Requester::request_flags_t flags)818 int CopyOpWin::request_int( const char *title,
819                             const char *text,
820                             const char *buttons,
821                             Requester::request_flags_t flags )
822 {
823   if ( window != NULL ) {
824     return window->request( title, text, buttons, flags );
825   } else {
826     return Worker::getRequester()->request( title, text, buttons, flags );
827   }
828 }
829 
string_request_int(const char * title,const char * lines,const char * default_str,const char * buttons,char ** return_str,Requester::request_flags_t flags)830 int CopyOpWin::string_request_int( const char *title,
831                                    const char *lines,
832                                    const char *default_str,
833                                    const char *buttons,
834                                    char **return_str,
835                                    Requester::request_flags_t flags )
836 {
837   if ( window != NULL ) {
838     return window->string_request( title, lines, default_str, buttons, return_str, flags );
839   } else {
840     return Worker::getRequester()->string_request( title, lines, default_str, buttons, return_str, flags );
841   }
842 }
843 
file_skipped(loff_t byteSum,bool subCopied)844 void CopyOpWin::file_skipped( loff_t byteSum, bool subCopied )
845 {
846     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
847 
848   if ( files > 0 ) files--;
849   if ( byteSum > 0 ) bytes -= byteSum;
850   if ( subCopied == true ) copied_bytes -= copied_bytes_curfile;
851   update_globtext = true;
852   update_files2gotext = true;
853 }
854 
update_file_status()855 void CopyOpWin::update_file_status()
856 {
857     std::unique_lock< std::recursive_mutex > lck( m_status_update_lock );
858 
859   if ( skipped_updates > 0 ) {
860     update_filetext = true;
861     update_globtext = true;
862   }
863 }
864 
master_process_request()865 void CopyOpWin::master_process_request()
866 {
867     std::unique_lock<std::mutex> lck( m_request_lock );
868 
869     if ( m_request ) {
870         process_request( *m_request );
871 
872         std::unique_lock<std::mutex> lck( m_response_lock );
873 
874         m_response = std::move( m_request );
875 
876         m_response_cond.notify_one();
877     }
878 }
879 
push_request(const BGCopyRequestMessage & msg)880 void CopyOpWin::push_request( const BGCopyRequestMessage &msg )
881 {
882     std::unique_lock<std::mutex> lck( m_request_lock );
883 
884     m_request = std::unique_ptr< BGCopyRequestMessage >( new BGCopyRequestMessage( msg ) );
885 }
886 
wait_for_response()887 BGCopyRequestMessage CopyOpWin::wait_for_response()
888 {
889     std::unique_lock<std::mutex> lck( m_response_lock );
890 
891     while ( ! m_response ) {
892         m_response_cond.wait( lck );
893     }
894 
895     BGCopyRequestMessage res = *m_response;
896 
897     m_response.reset();
898 
899     return res;
900 }
901 
request(const std::string & title,const std::string & text,const std::string & buttons,Requester::request_flags_t flags)902 int CopyOpWin::request( const std::string &title,
903                         const std::string &text,
904                         const std::string &buttons,
905                         Requester::request_flags_t flags )
906 {
907     BGCopyRequestMessage msg( title, text, buttons );
908 
909     if ( std::this_thread::get_id() == m_master_thread_id ) {
910         process_request( msg );
911 
912         return msg.getRes();
913     } else {
914         push_request( msg );
915 
916         return wait_for_response().getRes();
917     }
918 }
919 
string_request(const std::string & title,const std::string & lines,const std::string & default_str,const std::string & buttons,std::string & return_str,Requester::request_flags_t flags)920 int CopyOpWin::string_request( const std::string &title,
921                                const std::string &lines,
922                                const std::string &default_str,
923                                const std::string &buttons,
924                                std::string &return_str,
925                                Requester::request_flags_t flags )
926 {
927     BGCopyRequestMessage msg( title, lines, default_str, buttons, flags );
928 
929     if ( std::this_thread::get_id() == m_master_thread_id ) {
930         process_request( msg );
931 
932         return_str = msg.getResultString();
933 
934         return msg.getRes();
935     } else {
936         push_request( msg );
937 
938         auto res = wait_for_response();
939 
940         return_str = res.getResultString();
941 
942         return res.getRes();
943     }
944 }
945 
process_request(BGCopyRequestMessage & msg)946 void CopyOpWin::process_request( BGCopyRequestMessage &msg )
947 {
948     if ( msg.getType() == BGCopyRequestMessage::REGULAR_REQUEST ) {
949         msg.setRes( request_int( msg.getTitle().c_str(),
950                                  msg.getText().c_str(),
951                                  msg.getButtons().c_str() ) );
952     } else if ( msg.getType() == BGCopyRequestMessage::STRING_REQUEST ) {
953         char *result_string = NULL;
954         int res = string_request_int( msg.getTitle().c_str(),
955                                       msg.getText().c_str(),
956                                       msg.getDefaultString().c_str(),
957                                       msg.getButtons().c_str(),
958                                       &result_string,
959                                       msg.getFlags() );
960 
961         if ( result_string ) {
962             msg.setResultString( result_string );
963 
964             _freesafe( result_string );
965         }
966         msg.setRes( res );
967     } else {
968         throw 1;
969     }
970 }
971 
hide_detach_button()972 void CopyOpWin::hide_detach_button()
973 {
974     m_detach_b->hide();
975 
976     m_keep_window_cb->show();
977 
978     m_detached = true;
979 }
980 
getKeepWindow() const981 bool CopyOpWin::getKeepWindow() const
982 {
983     if ( ! m_detached ) return false;
984 
985     return m_keep_window;
986 }
987 
setFinished()988 void CopyOpWin::setFinished()
989 {
990     m_finished = true;
991 
992     if ( getKeepWindow() ) {
993         cb->setText( 0, catalog.getLocale( 633 ) );
994 
995         int tw = cb->getMaximumWidth();
996 
997         if ( tw > cb->getWidth() ) {
998             cb->resize( tw, cb->getHeight() );
999             cb->move( window->getWidth() - 5 - cb->getWidth(), cb->getY() );
1000         }
1001 
1002         setmessage( catalog.getLocale( 1046 ), 0 );
1003         setmessage( "", 1 );
1004 
1005         redraw();
1006     }
1007 }
1008