2006-08-20 22:43:09 +04:00
/*
* $ Id $
*
* EFiler - EDE File Manager
* Part of Equinox Desktop Environment ( EDE ) .
2007-08-03 13:59:31 +04:00
* Copyright ( c ) 2000 - 2007 EDE Authors .
2006-08-20 22:43:09 +04:00
*
* This program is licenced under terms of the
* GNU General Public Licence version 2 or newer .
* See COPYING for details .
*/
2006-08-21 23:27:22 +04:00
2007-07-16 11:35:32 +04:00
# include <string.h>
# include <dirent.h>
# include <sys/stat.h>
2007-08-01 22:04:35 +04:00
# include <sys/time.h> // timer in cb_open
# include <sys/resource.h> // for core dumps
2007-07-18 22:09:06 +04:00
2007-08-03 22:31:27 +04:00
// for application icon:
# include <X11/xpm.h>
# include <FL/x.H>
# include "efiler.xpm"
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
# include <Fl/Fl.H>
2007-07-17 23:16:39 +04:00
# include <Fl/Fl_Double_Window.H>
# include <Fl/Fl_Menu_Bar.H>
# include <Fl/Fl_File_Chooser.H> // for fl_dir_chooser, used in "Open location"
2007-07-16 11:35:32 +04:00
# include <Fl/filename.H>
2007-08-01 22:04:35 +04:00
# include <Fl/Fl_File_Input.H> // location bar
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
# include <edelib/Nls.h>
# include <edelib/MimeType.h>
# include <edelib/String.h>
2007-07-18 22:09:06 +04:00
# include <edelib/StrUtil.h>
2007-07-17 23:16:39 +04:00
# include <edelib/Run.h>
2006-08-20 22:43:09 +04:00
2007-07-23 23:59:48 +04:00
# include "EDE_FileView.h" // our file view widget
2007-08-01 22:04:35 +04:00
# include "EDE_DirTree.h" // directory tree
2007-07-23 23:59:48 +04:00
# include "Util.h" // ex-edelib
2007-08-03 13:59:31 +04:00
# include "ede_ask.h" // replacement for fl_ask
2007-08-20 16:16:10 +04:00
//#include "Ask.h"
2007-07-23 23:59:48 +04:00
# include "fileops.h" // file operations
2007-08-01 22:04:35 +04:00
# include "filesystem.h" // filesystem support
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
Fl_Window * win ;
2007-07-16 11:35:32 +04:00
FileDetailsView * view ;
2007-07-17 23:16:39 +04:00
Fl_Menu_Bar * main_menu ;
Fl_Box * statusbar ;
2007-08-01 22:04:35 +04:00
DirTree * dirtree ;
Fl_Tile * tile ;
Fl_Group * location_bar ;
Fl_File_Input * location_input ;
Fl_Menu_Button * context_menu ;
2007-07-17 23:16:39 +04:00
char current_dir [ FL_PATH_MAX ] ;
2007-07-16 11:35:32 +04:00
bool showhidden ;
bool semaphore ;
bool dirsfirst ;
bool ignorecase ;
2007-08-01 22:04:35 +04:00
bool showtree ;
bool showlocation ;
int tree_width ;
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
// constants
const int default_window_width = 600 ;
const int default_window_height = 400 ;
const int menubar_height = 30 ;
2007-08-01 22:04:35 +04:00
const int location_bar_height = 40 ;
2007-07-17 23:16:39 +04:00
const int statusbar_height = 24 ;
const int statusbar_width = 400 ;
2007-08-01 22:04:35 +04:00
int default_tree_width = 150 ;
2007-07-18 22:09:06 +04:00
2007-08-20 16:16:10 +04:00
/*-----------------------------------------------------------------
Some improvements to Fl_File_Input , that should be added
upstream :
* enable to set shortcut in label ( STR 1770 for Fl_Input_ )
* navigate using Ctrl + arrow ( here we jump to dir . sep . )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
class My_File_Input : public Fl_File_Input {
int shortcut_ ;
public :
My_File_Input ( int X , int Y , int W , int H , const char * label = 0 ) : Fl_File_Input ( X , Y , W , H , label ) {
set_flag ( SHORTCUT_LABEL ) ;
shortcut_ = 0 ;
}
int shortcut ( ) const { return shortcut_ ; }
void shortcut ( int s ) { shortcut_ = s ; }
int handle ( int e ) {
if ( e = = FL_SHORTCUT ) {
if ( ! ( shortcut ( ) ? Fl : : test_shortcut ( shortcut ( ) ) : test_shortcut ( ) ) ) return 0 ;
if ( Fl : : visible_focus ( ) & & handle ( FL_FOCUS ) ) Fl : : focus ( this ) ;
return 1 ;
}
if ( e = = FL_KEYDOWN ) {
if ( Fl : : event_state ( FL_CTRL ) ) {
const char * v = value ( ) ;
if ( Fl : : event_key ( ) = = FL_Left ) {
for ( uint i = position ( ) - 2 ; i > = 0 ; i - - )
if ( v [ i ] = = ' / ' ) {
if ( Fl : : event_state ( FL_SHIFT ) )
position ( i + 1 , mark ( ) ) ;
else
position ( i + 1 , i + 1 ) ;
break ;
}
return 1 ; // don't go out
}
if ( Fl : : event_key ( ) = = FL_Right ) {
for ( uint i = position ( ) + 1 ; i < strlen ( v ) ; i + + )
if ( v [ i ] = = ' / ' ) {
if ( Fl : : event_state ( FL_SHIFT ) )
position ( i + 1 , mark ( ) ) ;
else
position ( i + 1 , i + 1 ) ;
break ;
}
return 1 ; // don't go out
}
}
}
return Fl_File_Input : : handle ( e ) ;
}
} ;
2007-07-18 22:09:06 +04:00
2007-08-03 13:59:31 +04:00
2007-07-18 22:09:06 +04:00
/*-----------------------------------------------------------------
" Simple opener " - keep a list of openers in text file
This is just a temporary fix so that efiler works atm .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// These variables are global to save time on construction/destruction
edelib : : MimeType mime_resolver ;
struct stat stat_buffer ;
2007-07-17 23:16:39 +04:00
struct sopeners {
char * type ;
char * opener ;
sopeners * next ;
} * openers = 0 ;
char * simpleopener ( const char * mimetype ) {
sopeners * p ;
if ( ! openers ) {
FILE * fp = fopen ( " openers.txt " , " r " ) ;
2007-08-03 13:59:31 +04:00
if ( ! fp ) { ede_alert ( _ ( " File openers.txt not found " ) ) ; return 0 ; }
2007-07-17 23:16:39 +04:00
char buf [ FL_PATH_MAX * 2 ] ;
while ( ! feof ( fp ) ) {
fgets ( ( char * ) & buf , FL_PATH_MAX * 2 , fp ) ;
if ( buf [ 0 ] = = ' \0 ' | | buf [ 1 ] = = ' \0 ' | | buf [ 0 ] = = ' # ' ) continue ;
buf [ strlen ( buf ) - 1 ] = ' \0 ' ;
char * tmp = strstr ( buf , " || " ) ;
2007-07-27 12:36:05 +04:00
if ( ! tmp ) continue ; // malformatted opener
2007-07-17 23:16:39 +04:00
* tmp = ' \0 ' ;
sopeners * q = new sopeners ;
q - > type = strdup ( buf ) ;
q - > opener = strdup ( tmp + 2 ) ;
//fprintf (stderr, "Found type: '%s' opener: '%s'\n",q->type,q->opener);
q - > next = 0 ;
if ( ! openers ) openers = q ;
else p - > next = q ;
p = q ;
}
fclose ( fp ) ;
}
p = openers ;
char * result = 0 ; int topscore = 0 ;
while ( p ! = 0 ) {
int score = strlen ( p - > type ) ;
if ( strncmp ( p - > type , mimetype , score ) = = 0 & & score > topscore ) {
topscore = score ;
result = p - > opener ;
}
p = p - > next ;
}
return result ;
}
2007-07-18 22:09:06 +04:00
/*-----------------------------------------------------------------
LoadDir ( )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-07-16 11:35:32 +04:00
// modification of versionsort which ignores case
int myversionsort ( const void * a , const void * b ) {
struct dirent * * ka = ( struct dirent * * ) a ;
struct dirent * * kb = ( struct dirent * * ) b ;
2007-07-18 22:09:06 +04:00
char * ma = strdup ( ( * ka ) - > d_name ) ;
char * mb = strdup ( ( * kb ) - > d_name ) ;
edelib : : str_tolower ( ( unsigned char * ) ma ) ; edelib : : str_tolower ( ( unsigned char * ) mb ) ;
2007-07-16 11:35:32 +04:00
int k = strverscmp ( ma , mb ) ;
free ( ma ) ; free ( mb ) ;
return k ;
2006-08-20 22:43:09 +04:00
}
2006-08-30 13:20:54 +04:00
2007-08-20 16:16:10 +04:00
// Return a string describing permissions relative to the current user
const char * permission_text ( mode_t mode , uid_t uid , gid_t gid ) {
static uid_t uuid = getuid ( ) ;
static gid_t ugid = getgid ( ) ;
// use geteuid() and getegid()? what's the difference?
if ( S_ISDIR ( mode ) ) {
// Directory
if ( uid = = uuid ) {
if ( ! ( mode & S_IXUSR ) )
return _ ( " Can't enter directory " ) ;
if ( ! ( mode & S_IRUSR ) )
return _ ( " Can't list directory " ) ;
if ( ! ( mode & S_IWUSR ) )
return _ ( " Can't add, delete, rename files " ) ; // shorter description?
return _ ( " Full permissions " ) ;
} else if ( gid = = ugid ) {
if ( ! ( mode & S_IXGRP ) )
return _ ( " Can't enter directory " ) ;
if ( ! ( mode & S_IRGRP ) )
return _ ( " Can't list directory " ) ;
if ( ! ( mode & S_IWGRP ) )
return _ ( " Can't add, delete, rename files " ) ;
return _ ( " Full permissions " ) ;
} else {
if ( ! ( mode & S_IXOTH ) )
return _ ( " Can't enter directory " ) ;
if ( ! ( mode & S_IROTH ) )
return _ ( " Can't list directory " ) ;
if ( ! ( mode & S_IWOTH ) )
return _ ( " Can't add, delete, rename files " ) ;
return _ ( " Full permissions " ) ;
}
} else {
// Regular file (anything else should have similar permissions)
if ( uid = = uuid ) {
if ( ( mode & S_IXUSR ) & & ( mode & S_IRUSR ) & & ( mode & S_IWUSR ) )
return _ ( " Read, write, execute " ) ;
if ( ( mode & S_IRUSR ) & & ( mode & S_IWUSR ) )
return _ ( " Read, write " ) ;
if ( ( mode & S_IXUSR ) & & ( mode & S_IRUSR ) )
return _ ( " Read only, execute " ) ;
if ( ( mode & S_IRUSR ) )
return _ ( " Read only " ) ;
// ignore weird permissions such as "write only"
return _ ( " Not readable " ) ;
} else if ( gid = = ugid ) {
if ( ( mode & S_IXGRP ) & & ( mode & S_IRGRP ) & & ( mode & S_IWGRP ) )
return _ ( " Read, write, execute " ) ;
if ( ( mode & S_IRGRP ) & & ( mode & S_IWGRP ) )
return _ ( " Read, write " ) ;
if ( ( mode & S_IXGRP ) & & ( mode & S_IRGRP ) )
return _ ( " Read only, execute " ) ;
if ( ( mode & S_IRGRP ) )
return _ ( " Read only " ) ;
return _ ( " Not readable " ) ;
} else {
if ( ( mode & S_IXOTH ) & & ( mode & S_IROTH ) & & ( mode & S_IWOTH ) )
return _ ( " Read, write, execute " ) ;
if ( ( mode & S_IROTH ) & & ( mode & S_IWOTH ) )
return _ ( " Read, write " ) ;
if ( ( mode & S_IXOTH ) & & ( mode & S_IROTH ) )
return _ ( " Read only, execute " ) ;
if ( ( mode & S_IROTH ) )
return _ ( " Read only " ) ;
return _ ( " Not readable " ) ;
}
}
}
2006-08-20 22:43:09 +04:00
void loaddir ( const char * path ) {
2007-07-17 23:16:39 +04:00
if ( semaphore ) return ; // Prevent loaddir to interrupt previous loaddir - that can result in crash
semaphore = true ;
2007-07-16 11:35:32 +04:00
char old_dir [ FL_PATH_MAX ] ;
2007-07-17 23:16:39 +04:00
strncpy ( old_dir , current_dir , strlen ( current_dir ) ) ; // Restore olddir in case of error
2006-08-20 22:43:09 +04:00
2007-08-20 16:16:10 +04:00
// Sometimes path is just a pointer to current_dir
char * tmpath = strdup ( path ) ;
2006-08-20 22:43:09 +04:00
// Set current_dir
2007-08-01 22:04:35 +04:00
// fl_filename_isdir() thinks that / isn't a dir :(
if ( strcmp ( path , " / " ) = = 0 | | fl_filename_isdir ( path ) ) {
2007-08-20 16:16:10 +04:00
if ( path [ 0 ] = = ' ~ ' ) { // Expand tilde
2007-08-20 22:34:22 +04:00
snprintf ( current_dir , FL_PATH_MAX , " %s/%s " , getenv ( " HOME " ) , tmpath + 1 ) ;
2007-08-20 16:16:10 +04:00
} else if ( path [ 0 ] ! = ' / ' ) { // Relative path
2007-08-20 22:34:22 +04:00
snprintf ( current_dir , FL_PATH_MAX , " %s/%s " , getenv ( " PWD " ) , tmpath ) ;
2007-08-20 16:16:10 +04:00
} else {
if ( path ! = current_dir ) strncpy ( current_dir , tmpath , strlen ( tmpath ) + 1 ) ;
}
} else {
2007-08-20 22:34:22 +04:00
ede_alert ( tsprintf ( _ ( " Directory not found: %s " ) , path ) ) ;
free ( tmpath ) ;
semaphore = false ;
return ;
2007-08-20 16:16:10 +04:00
}
2007-08-20 22:34:22 +04:00
2007-08-20 16:16:10 +04:00
free ( tmpath ) ;
2007-07-16 11:35:32 +04:00
2006-08-20 22:43:09 +04:00
// Trailing slash should always be there
if ( current_dir [ strlen ( current_dir ) - 1 ] ! = ' / ' ) strcat ( current_dir , " / " ) ;
2007-07-16 11:35:32 +04:00
// Compact dotdot (..)
2007-08-20 16:16:10 +04:00
while ( char * tmp = strstr ( current_dir , " /../ " ) ) {
2007-07-16 11:35:32 +04:00
char * tmp2 = tmp + 4 ;
tmp - - ;
while ( tmp ! = current_dir & & * tmp ! = ' / ' ) tmp - - ;
tmp + + ;
while ( * tmp2 ! = ' \0 ' ) * tmp + + = * tmp2 + + ;
* tmp = ' \0 ' ;
}
2007-08-20 16:16:10 +04:00
// List all files in directory
2007-07-16 11:35:32 +04:00
int size = 0 ;
2007-08-03 13:59:31 +04:00
dirent * * files ;
2007-07-16 11:35:32 +04:00
if ( ignorecase )
size = scandir ( current_dir , & files , 0 , myversionsort ) ;
else
size = scandir ( current_dir , & files , 0 , versionsort ) ;
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
if ( size < 1 ) { // there should always be . and ..
2007-08-03 13:59:31 +04:00
ede_alert ( _ ( " Permission denied! " ) ) ;
2007-08-20 16:16:10 +04:00
// edelib::fl_alert(_("Permission denied!"));
2007-07-16 11:35:32 +04:00
strncpy ( current_dir , old_dir , strlen ( current_dir ) ) ;
2007-07-17 23:16:39 +04:00
semaphore = false ;
2007-07-16 11:35:32 +04:00
return ;
}
2006-08-20 22:43:09 +04:00
2007-08-03 13:59:31 +04:00
// Ok, now we know everything is fine...
// Update directory tree
dirtree - > set_current ( current_dir ) ;
location_input - > value ( current_dir ) ;
2007-07-16 11:35:32 +04:00
// set window label
2007-08-01 22:04:35 +04:00
// copy_label() is a method that calls strdup() and later free()
win - > copy_label ( tsprintf ( _ ( " %s - File manager " ) , current_dir ) ) ;
statusbar - > copy_label ( tsprintf ( _ ( " Scanning directory %s... " ) , current_dir ) ) ;
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
view - > clear ( ) ;
2006-08-30 13:20:54 +04:00
2007-08-01 22:04:35 +04:00
fprintf ( stderr , " Size: %d \n " , size ) ;
2007-07-16 11:35:32 +04:00
FileItem * * item_list = new FileItem * [ size ] ;
int fsize = 0 ;
2006-08-20 22:43:09 +04:00
2007-07-16 11:35:32 +04:00
for ( int i = 0 ; i < size ; i + + ) {
2006-08-20 22:43:09 +04:00
char * n = files [ i ] - > d_name ; //shortcut
2007-07-27 12:36:05 +04:00
if ( i > 0 ) free ( files [ i - 1 ] ) ; // see scandir(3)
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
// don't show . (current directory)
2007-07-16 11:35:32 +04:00
if ( strcmp ( n , " . " ) = = 0 ) continue ;
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
// hide files with dot except .. (up directory)
2007-07-16 11:35:32 +04:00
if ( ! showhidden & & ( n [ 0 ] = = ' . ' ) & & ( strcmp ( n , " .. " ) ! = 0 ) ) continue ;
2006-08-20 22:43:09 +04:00
// hide files ending with tilde (backup) - NOTE
if ( ! showhidden & & ( n [ strlen ( n ) - 1 ] = = ' ~ ' ) ) continue ;
2007-07-16 11:35:32 +04:00
char fullpath [ FL_PATH_MAX ] ;
2007-07-17 23:16:39 +04:00
snprintf ( fullpath , FL_PATH_MAX - 1 , " %s%s " , current_dir , n ) ;
2007-07-16 11:35:32 +04:00
2007-07-23 23:59:48 +04:00
if ( stat ( fullpath , & stat_buffer ) ) continue ; // happens when user has traverse but not read privilege
2007-07-16 11:35:32 +04:00
FileItem * item = new FileItem ;
item - > name = n ;
item - > realpath = fullpath ;
2007-07-18 22:09:06 +04:00
item - > date = nice_time ( stat_buffer . st_mtime ) ;
2007-08-20 16:16:10 +04:00
item - > permissions = permission_text ( stat_buffer . st_mode , stat_buffer . st_uid , stat_buffer . st_gid ) ;
2007-07-16 11:35:32 +04:00
if ( strcmp ( n , " .. " ) = = 0 ) {
item - > icon = " undo " ;
item - > description = " Go up " ;
item - > size = " " ;
2007-07-18 22:09:06 +04:00
} else if ( S_ISDIR ( stat_buffer . st_mode ) ) { // directory
2007-07-16 11:35:32 +04:00
item - > icon = " folder " ;
item - > description = " Directory " ;
// item->name += "/";
item - > size = " " ;
2007-08-01 22:04:35 +04:00
item - > realpath + = " / " ;
2007-07-16 11:35:32 +04:00
} else {
item - > icon = " unknown " ;
item - > description = " Unknown " ;
2007-07-18 22:09:06 +04:00
item - > size = nice_size ( stat_buffer . st_size ) ;
2006-08-30 13:20:54 +04:00
}
2007-07-16 11:35:32 +04:00
item_list [ fsize + + ] = item ;
2006-08-30 13:20:54 +04:00
}
2007-07-27 12:36:05 +04:00
free ( files [ size - 1 ] ) ; free ( files ) ; // see scandir(3)
2006-08-30 13:20:54 +04:00
2007-07-17 23:16:39 +04:00
// Populate view
2007-07-23 23:59:48 +04:00
for ( int i = 0 ; i < fsize ; i + + )
if ( item_list [ i ] - > description = = " Go up " )
view - > add ( item_list [ i ] ) ;
2007-07-16 11:35:32 +04:00
if ( dirsfirst ) {
2007-07-23 23:59:48 +04:00
for ( int i = 0 ; i < fsize ; i + + )
if ( item_list [ i ] - > description = = " Directory " )
2007-07-16 11:35:32 +04:00
view - > add ( item_list [ i ] ) ;
for ( int i = 0 ; i < fsize ; i + + )
if ( item_list [ i ] - > description ! = " Directory " & & item_list [ i ] - > description ! = " Go up " )
view - > add ( item_list [ i ] ) ;
2006-08-30 13:20:54 +04:00
} else {
2007-07-16 11:35:32 +04:00
for ( int i = 0 ; i < fsize ; i + + )
2007-07-23 23:59:48 +04:00
if ( item_list [ i ] - > description ! = " Go up " )
view - > add ( item_list [ i ] ) ;
2007-07-16 11:35:32 +04:00
}
view - > redraw ( ) ;
Fl : : check ( ) ;
2006-08-30 13:20:54 +04:00
2007-07-16 11:35:32 +04:00
// Update mime types - can be slow...
for ( int i = 0 ; i < fsize ; i + + ) {
if ( item_list [ i ] - > description ! = " Directory " & & item_list [ i ] - > description ! = " Go up " ) {
mime_resolver . set ( item_list [ i ] - > realpath . c_str ( ) ) ;
edelib : : String desc , icon ;
desc = mime_resolver . comment ( ) ;
2007-07-18 22:09:06 +04:00
// First letter of desc should be upper case:
2007-07-23 23:59:48 +04:00
if ( desc . length ( ) > 0 & & desc [ 0 ] > = ' a ' & & desc [ 0 ] < = ' z ' ) desc [ 0 ] = desc [ 0 ] - ' a ' + ' A ' ;
2007-07-16 11:35:32 +04:00
icon = mime_resolver . icon_name ( ) ;
if ( desc ! = " " | | icon ! = " " ) {
if ( desc ! = " " ) item_list [ i ] - > description = desc ;
if ( icon ! = " " ) item_list [ i ] - > icon = icon ;
fprintf ( stderr , " ICON: %s !!!!! \n " , icon . c_str ( ) ) ;
view - > update ( item_list [ i ] ) ;
2006-08-30 13:20:54 +04:00
}
2007-07-16 11:35:32 +04:00
Fl : : check ( ) ;
2006-08-30 13:20:54 +04:00
}
}
2007-07-16 11:35:32 +04:00
// Cleanup
for ( int i = 0 ; i < fsize ; i + + ) delete item_list [ i ] ;
delete [ ] item_list ;
2007-07-17 23:16:39 +04:00
semaphore = false ;
2007-07-23 23:59:48 +04:00
// Get partition size and free space
2007-08-01 22:04:35 +04:00
double totalsize , freesize ;
if ( fs_usage ( current_dir , totalsize , freesize ) ) {
double percent = ( totalsize - freesize ) / totalsize * 100 ;
char * tmp = strdup ( nice_size ( totalsize ) ) ; // nice_size() operates on a static char buffer, we can't use two calls in the same command
statusbar - > copy_label ( tsprintf ( _ ( " Filesystem %s, Size %s, Free %s (%4.1f%% used) " ) , find_fs_for ( current_dir ) , tmp , nice_size ( freesize ) , percent ) ) ;
2007-07-18 22:09:06 +04:00
free ( tmp ) ;
} else
statusbar - > label ( _ ( " Error reading filesystem information! " ) ) ;
2007-07-17 23:16:39 +04:00
}
/*-----------------------------------------------------------------
2007-08-03 13:59:31 +04:00
Main menu and other callbacks
2007-07-17 23:16:39 +04:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-08-20 16:16:10 +04:00
// This callback is called by doubleclicking on file list, by main menu and context menu
2007-07-16 11:35:32 +04:00
void open_cb ( Fl_Widget * w , void * data ) {
fprintf ( stderr , " cb \n " ) ;
2007-08-20 16:16:10 +04:00
2007-08-01 22:04:35 +04:00
if ( Fl : : event_clicks ( ) | | Fl : : event_key ( ) = = FL_Enter | | w = = main_menu | | w = = context_menu ) {
2007-08-20 16:16:10 +04:00
2007-07-16 11:35:32 +04:00
fprintf ( stderr , " enter \n " ) ;
2007-07-18 22:09:06 +04:00
//if (Fl::event_clicks()) fprintf(stderr, "clicks\n");
//if (Fl::event_key()==FL_Enter) fprintf(stderr, "ekey\n");
2007-07-17 23:16:39 +04:00
static timeval tm = { 0 , 0 } ;
timeval newtm ;
gettimeofday ( & newtm , 0 ) ;
if ( newtm . tv_sec - tm . tv_sec < 1 | | ( newtm . tv_sec - tm . tv_sec = = 1 & & newtm . tv_usec < tm . tv_usec ) ) return ; // no calling within 1 second
tm = newtm ;
2007-08-01 22:04:35 +04:00
if ( view - > get_focus ( ) = = 0 ) return ; // This can happen while efiler is loading
2007-07-17 23:16:39 +04:00
2007-08-01 22:04:35 +04:00
char * path = ( char * ) view - > path ( view - > get_focus ( ) ) ;
2007-07-16 11:35:32 +04:00
fprintf ( stderr , " Path: %s (ev %d) \n " , path , Fl : : event ( ) ) ;
2006-08-20 22:43:09 +04:00
2007-07-18 22:09:06 +04:00
if ( stat ( path , & stat_buffer ) ) return ; // error
if ( S_ISDIR ( stat_buffer . st_mode ) ) { // directory
2007-07-16 11:35:32 +04:00
loaddir ( path ) ;
2007-07-17 23:16:39 +04:00
return ;
}
2006-08-20 22:43:09 +04:00
2007-08-20 16:16:10 +04:00
// Find opener
2007-07-17 23:16:39 +04:00
mime_resolver . set ( path ) ;
char * opener = simpleopener ( mime_resolver . type ( ) . c_str ( ) ) ;
// dump core
struct rlimit * rlim = ( struct rlimit * ) malloc ( sizeof ( struct rlimit ) ) ;
getrlimit ( RLIMIT_CORE , rlim ) ;
rlim_t old_rlimit = rlim - > rlim_cur ; // keep previous rlimit
rlim - > rlim_cur = RLIM_INFINITY ;
setrlimit ( RLIMIT_CORE , rlim ) ;
2007-08-01 22:04:35 +04:00
const char * o2 = tsprintf ( opener , path ) ; // opener should contain %s
2007-07-17 23:16:39 +04:00
fprintf ( stderr , " run_program: %s \n " , o2 ) ;
2007-07-27 12:36:05 +04:00
2007-07-17 23:16:39 +04:00
if ( opener ) {
int k = edelib : : run_program ( o2 , false ) ; fprintf ( stderr , " retval: %d \n " , k ) ;
} else
2007-08-20 16:16:10 +04:00
statusbar - > copy_label ( tsprintf ( _ ( " No program to open %s! " ) , fl_filename_name ( path ) ) ) ;
2007-07-17 23:16:39 +04:00
rlim - > rlim_cur = old_rlimit ;
setrlimit ( RLIMIT_CORE , rlim ) ;
2007-07-27 12:36:05 +04:00
free ( rlim ) ;
2007-07-17 23:16:39 +04:00
2006-08-26 13:06:13 +04:00
}
2007-07-17 23:16:39 +04:00
} // open_cb
2007-08-03 13:59:31 +04:00
// Main menu callbacks
2007-08-20 16:16:10 +04:00
void new_cb ( Fl_Widget * , void * ) {
// FIXME: use program path
edelib : : run_program ( tsprintf ( " efiler %s " , current_dir ) , false ) ;
2006-08-26 13:06:13 +04:00
}
2006-08-20 22:43:09 +04:00
2007-08-20 16:16:10 +04:00
void quit_cb ( Fl_Widget * , void * ) { win - > hide ( ) ; }
2007-07-17 23:16:39 +04:00
void cut_cb ( Fl_Widget * , void * ) { do_cut_copy ( false ) ; }
void copy_cb ( Fl_Widget * , void * ) { do_cut_copy ( true ) ; }
2007-08-01 22:04:35 +04:00
void paste_cb ( Fl_Widget * , void * ) { Fl : : paste ( * view , 1 ) ; } // view->handle() will call do_paste()
2007-07-23 23:59:48 +04:00
void delete_cb ( Fl_Widget * , void * ) { do_delete ( ) ; }
2007-07-17 23:16:39 +04:00
2007-08-01 22:04:35 +04:00
void showtree_cb ( Fl_Widget * , void * ) {
showtree = ! showtree ;
if ( ! showtree ) {
tree_width = dirtree - > w ( ) ;
2007-08-20 16:16:10 +04:00
tile - > position ( default_tree_width , 1 , 1 , 1 ) ; // NOTE this doesn't always work!
2007-08-01 22:04:35 +04:00
fprintf ( stderr , " Hide tree: %d \n " , tree_width ) ;
} else {
int currentw = dirtree - > w ( ) ;
tile - > position ( currentw , 1 , tree_width , 1 ) ;
fprintf ( stderr , " Show tree: %d %d \n " , currentw , tree_width ) ;
}
}
2007-07-17 23:16:39 +04:00
void refresh_cb ( Fl_Widget * , void * ) {
loaddir ( current_dir ) ;
}
2007-08-01 22:04:35 +04:00
void locationbar_cb ( Fl_Widget * , void * ) {
showlocation = ! showlocation ;
if ( showlocation ) {
location_bar - > show ( ) ;
location_bar - > resize ( 0 , menubar_height , win - > w ( ) , location_bar_height ) ;
tile - > resize ( 0 , menubar_height + location_bar_height , win - > w ( ) , win - > h ( ) - menubar_height - location_bar_height - statusbar_height ) ;
2007-08-20 16:16:10 +04:00
// win->resizable(tile); // win keeps old tile size...
2007-08-01 22:04:35 +04:00
win - > redraw ( ) ;
} else {
location_bar - > hide ( ) ;
// location_bar->resize(0, menubar_height, win->w(), 0);
tile - > resize ( 0 , menubar_height , win - > w ( ) , win - > h ( ) - menubar_height - statusbar_height ) ;
win - > redraw ( ) ;
2007-08-20 16:16:10 +04:00
win - > resizable ( tile ) ;
win - > redraw ( ) ;
2007-08-01 22:04:35 +04:00
}
}
void showhidden_cb ( Fl_Widget * , void * ) {
showhidden = ! showhidden ;
dirtree - > show_hidden ( showhidden ) ;
dirtree - > reload ( ) ;
loaddir ( current_dir ) ;
}
void case_cb ( Fl_Widget * , void * ) {
ignorecase = ! ignorecase ;
dirtree - > ignore_case ( ignorecase ) ;
dirtree - > reload ( ) ;
loaddir ( current_dir ) ;
}
2007-07-17 23:16:39 +04:00
2007-08-20 16:16:10 +04:00
void dirsfirst_cb ( Fl_Widget * , void * ) {
dirsfirst = ! dirsfirst ;
loaddir ( current_dir ) ;
}
2007-07-17 23:16:39 +04:00
2007-08-03 13:59:31 +04:00
// dummy callbacks - TODO
2007-07-17 23:16:39 +04:00
void ow_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; } // make a list of openers
void pref_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
2007-08-20 16:16:10 +04:00
void iconsview_cb ( Fl_Widget * , void * ) {
//fprintf(stderr, "callback\n");
2007-08-20 22:34:22 +04:00
view - > type ( FILE_ICON_VIEW ) ;
2007-08-20 16:16:10 +04:00
loaddir ( current_dir ) ;
}
void listview_cb ( Fl_Widget * , void * ) {
//fprintf(stderr, "callback\n");
2007-08-20 22:34:22 +04:00
view - > type ( FILE_DETAILS_VIEW ) ;
2007-08-20 16:16:10 +04:00
loaddir ( current_dir ) ;
}
2007-07-17 23:16:39 +04:00
void about_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
void aboutede_cb ( Fl_Widget * , void * ) { fprintf ( stderr , " callback \n " ) ; }
2006-08-30 13:20:54 +04:00
2006-08-20 22:43:09 +04:00
2007-08-01 22:04:35 +04:00
// Directory tree callback
2007-08-20 22:34:22 +04:00
void tree_cb ( Fl_Widget * , void * ) {
if ( Fl : : event_clicks ( ) | | Fl : : event_key ( ) = = FL_Enter | | Fl : : event_key ( ) = = FL_KP_Enter ) {
2007-08-01 22:04:35 +04:00
int selected = dirtree - > get_focus ( ) ;
loaddir ( ( char * ) dirtree - > data ( selected ) ) ;
}
}
2007-08-03 13:59:31 +04:00
// This callback handles location input: changing the directory, autocomplete
// and callbacks for shortcut buttons
// location_input is set to FL_WHEN_CHANGED
void location_input_cb ( Fl_Widget * , void * ) {
2007-08-20 16:16:10 +04:00
if ( Fl : : event_key ( ) = = FL_Enter | | Fl : : event ( ) = = FL_RELEASE )
// second event is click on button
2007-08-03 13:59:31 +04:00
loaddir ( location_input - > value ( ) ) ;
2007-08-20 16:16:10 +04:00
if ( Fl : : event ( ) = = FL_KEYDOWN & & Fl : : event_key ( ) ! = FL_BackSpace & & Fl : : event_key ( ) ! = FL_Delete ) {
// Pressing a key in Fl_Input will automatically replace selection with that char
2007-08-03 13:59:31 +04:00
// So there are really two possibilities:
// 1. Cursor is at the end, we add autocomplete stuff at cursor pos
// 2. Cursor is in the middle, we do nothing
const char * loc = location_input - > value ( ) ; // shortcut
if ( strlen ( loc ) < 1 | | loc [ strlen ( loc ) - 1 ] = = ' / ' ) return ;
2007-08-03 22:43:40 +04:00
uint pos = location_input - > position ( ) ;
2007-08-03 13:59:31 +04:00
if ( pos ! = strlen ( loc ) ) return ; // cursor in the middle
int mark = location_input - > mark ( ) ;
// To avoid scandir, we will use view contents
if ( ( strlen ( loc ) > strlen ( current_dir ) ) & & ( ! strchr ( loc + strlen ( current_dir ) , ' / ' ) ) ) {
int i ;
for ( i = 1 ; i < = view - > size ( ) ; i + + ) {
const char * p = view - > path ( i ) ;
if ( ( p [ strlen ( p ) - 1 ] = = ' / ' ) & & ( strncmp ( loc , p , strlen ( loc ) ) = = 0 ) )
break ;
}
if ( i < = view - > size ( ) ) {
location_input - > replace ( pos , mark , view - > path ( i ) + pos ) ;
location_input - > position ( pos ) ;
location_input - > mark ( strlen ( view - > path ( i ) ) ) ;
}
// else beep(); ??
} else {
// sigh, we need to scandir....
char * k ;
if ( ! ( k = strrchr ( loc , ' / ' ) ) ) return ;
char * updir = strdup ( loc ) ;
updir [ k - loc + 1 ] = ' \0 ' ;
dirent * * files ;
int size = scandir ( updir , & files , 0 , versionsort ) ;
if ( size < 1 ) { free ( updir ) ; return ; }
int i ;
char p [ FL_PATH_MAX ] ;
for ( i = 0 ; i < size ; i + + ) {
snprintf ( p , FL_PATH_MAX - 1 , " %s%s " , updir , files [ i ] - > d_name ) ;
struct stat buf ;
if ( stat ( p , & buf ) ) continue ; // happens when user has traverse but not read privilege
if ( S_ISDIR ( buf . st_mode ) ) {
strcat ( p , " / " ) ;
if ( strncmp ( loc , p , strlen ( loc ) ) = = 0 )
break ;
}
free ( files [ i ] ) ;
}
free ( files ) ; free ( updir ) ;
if ( i < size ) {
location_input - > replace ( pos , mark , p + pos ) ;
location_input - > position ( pos ) ;
location_input - > mark ( strlen ( p ) ) ;
}
// else beep(); ??
}
}
}
2007-08-20 16:16:10 +04:00
// TODO: move this to view
// every item should have own context menu defined
2007-08-01 22:04:35 +04:00
Fl_Menu_Item context_menu_definition [ ] = {
{ _ ( " &Open " ) , 0 , open_cb } ,
{ _ ( " Open &with... " ) , 0 , ow_cb , 0 , FL_MENU_DIVIDER } ,
{ _ ( " &Cut " ) , 0 , cut_cb } ,
{ _ ( " Co&py " ) , 0 , copy_cb } ,
{ _ ( " Pa&ste " ) , 0 , paste_cb } ,
{ _ ( " &Delete " ) , 0 , delete_cb , 0 , FL_MENU_DIVIDER } ,
{ _ ( " P&references... " ) , 0 , pref_cb } ,
{ 0 }
} ;
// Right click - show context menu
void context_cb ( Fl_Widget * , void * ) {
context_menu - > popup ( ) ;
context_menu - > value ( - 1 ) ;
}
2006-08-20 22:43:09 +04:00
2006-08-30 13:20:54 +04:00
/*-----------------------------------------------------------------
GUI design
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2006-08-20 22:43:09 +04:00
2007-07-17 23:16:39 +04:00
// Main window menu - definition
Fl_Menu_Item main_menu_definition [ ] = {
{ _ ( " &File " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &Open " ) , FL_CTRL + ' o ' , open_cb } ,
{ _ ( " Open &with... " ) , 0 , ow_cb , 0 , FL_MENU_DIVIDER } ,
2007-08-01 22:04:35 +04:00
// {_("Open &location"), 0, location_cb, 0,FL_MENU_DIVIDER},
2007-07-23 23:59:48 +04:00
{ _ ( " &New window " ) , FL_CTRL + ' n ' , new_cb , 0 , FL_MENU_DIVIDER } ,
2007-07-17 23:16:39 +04:00
{ _ ( " &Quit " ) , FL_CTRL + ' q ' , quit_cb } ,
{ 0 } ,
{ _ ( " &Edit " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &Cut " ) , FL_CTRL + ' x ' , cut_cb } ,
{ _ ( " C&opy " ) , FL_CTRL + ' c ' , copy_cb } ,
{ _ ( " &Paste " ) , FL_CTRL + ' v ' , paste_cb } ,
{ _ ( " &Rename " ) , FL_F + 2 , 0 } , // no callback - view handles this
{ _ ( " &Delete " ) , FL_Delete , delete_cb , 0 , FL_MENU_DIVIDER } ,
{ _ ( " Pre&ferences " ) , FL_CTRL + ' p ' , pref_cb } ,
{ 0 } ,
{ _ ( " &View " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &Icons " ) , FL_F + 8 , iconsview_cb , 0 , FL_MENU_RADIO } , // coming soon
2007-08-20 22:34:22 +04:00
{ _ ( " &Detailed list " ) , 0 , listview_cb , 0 , FL_MENU_RADIO | FL_MENU_VALUE | FL_MENU_DIVIDER } ,
2007-08-01 22:04:35 +04:00
{ _ ( " Directory &tree " ) , FL_F + 9 , showtree_cb , 0 , FL_MENU_TOGGLE | FL_MENU_VALUE } ,
{ _ ( " &Location bar " ) , FL_F + 10 , locationbar_cb , 0 , FL_MENU_TOGGLE | FL_MENU_VALUE } ,
2007-08-20 16:16:10 +04:00
{ _ ( " &Hidden files " ) , 0 , showhidden_cb , 0 , FL_MENU_TOGGLE | FL_MENU_DIVIDER } ,
2007-07-17 23:16:39 +04:00
{ _ ( " &Refresh " ) , FL_F + 5 , refresh_cb } ,
2007-08-20 16:16:10 +04:00
{ _ ( " &Sort " ) , 0 , 0 , 0 , FL_SUBMENU } ,
2007-07-17 23:16:39 +04:00
{ _ ( " &Case sensitive " ) , 0 , case_cb , 0 , FL_MENU_TOGGLE } ,
2007-07-23 23:59:48 +04:00
{ _ ( " D&irectories first " ) , 0 , dirsfirst_cb , 0 , FL_MENU_TOGGLE | FL_MENU_VALUE } ,
2007-07-17 23:16:39 +04:00
{ 0 } ,
{ 0 } ,
{ _ ( " &Help " ) , 0 , 0 , 0 , FL_SUBMENU } ,
{ _ ( " &About File Manager " ) , 0 , about_cb } , // coming soon
{ _ ( " &About EDE " ) , 0 , aboutede_cb } , // coming soon
{ 0 } ,
{ 0 }
} ;
// Main program
2007-08-20 16:16:10 +04:00
extern int FL_NORMAL_SIZE ;
2006-08-20 22:43:09 +04:00
int main ( int argc , char * * argv ) {
2007-08-03 13:59:31 +04:00
// Parse command line - this must come first
int unknown = 0 ;
Fl : : args ( argc , argv , unknown ) ;
if ( unknown = = argc )
2007-08-20 22:34:22 +04:00
snprintf ( current_dir , FL_PATH_MAX , getenv ( " HOME " ) ) ;
2007-08-03 13:59:31 +04:00
else {
if ( strcmp ( argv [ unknown ] , " --help " ) = = 0 ) {
2007-08-20 16:16:10 +04:00
printf ( _ ( " EFiler - EDE File Manager \n Part of Equinox Desktop Environment (EDE). \n Copyright (c) 2000-2007 EDE Authors. \n \n This program is licenced under terms of the \n GNU General Public Licence version 2 or newer. \n See COPYING for details. \n \n " ) ) ;
printf ( _ ( " Usage: \n \t efiler [OPTIONS] [PATH] \n \n " ) ) ;
2007-08-03 13:59:31 +04:00
printf ( " %s \n " , Fl : : help ) ;
return 1 ;
}
strncpy ( current_dir , argv [ unknown ] , strlen ( argv [ unknown ] ) + 1 ) ;
}
2007-07-16 11:35:32 +04:00
fl_register_images ( ) ;
edelib : : IconTheme : : init ( " crystalsvg " ) ;
2007-07-17 23:16:39 +04:00
2007-08-03 13:59:31 +04:00
FL_NORMAL_SIZE = 12 ;
fl_message_font ( FL_HELVETICA , 12 ) ;
2007-07-17 23:16:39 +04:00
2007-08-20 16:16:10 +04:00
// Main GUI design
2007-07-17 23:16:39 +04:00
win = new Fl_Double_Window ( default_window_width , default_window_height ) ;
2007-07-16 11:35:32 +04:00
// win->color(FL_WHITE);
win - > begin ( ) ;
2007-07-17 23:16:39 +04:00
main_menu = new Fl_Menu_Bar ( 0 , 0 , default_window_width , menubar_height ) ;
main_menu - > menu ( main_menu_definition ) ;
2007-08-01 22:04:35 +04:00
location_bar = new Fl_Group ( 0 , menubar_height , default_window_width , location_bar_height ) ;
location_bar - > begin ( ) ;
2007-08-20 16:16:10 +04:00
location_input = new My_File_Input ( 70 , menubar_height + 2 , default_window_width - 200 , location_bar_height - 5 , _ ( " L&ocation: " ) ) ;
2007-08-01 22:04:35 +04:00
location_input - > align ( FL_ALIGN_LEFT ) ;
location_input - > callback ( location_input_cb ) ;
2007-08-03 13:59:31 +04:00
location_input - > when ( FL_WHEN_ENTER_KEY_CHANGED ) ;
2007-08-01 22:04:35 +04:00
location_bar - > end ( ) ;
2007-08-20 16:16:10 +04:00
location_bar - > box ( FL_UP_BOX ) ;
2007-08-01 22:04:35 +04:00
location_bar - > resizable ( location_input ) ;
tile = new Fl_Tile ( 0 , menubar_height + location_bar_height , default_window_width , default_window_height - menubar_height - location_bar_height - statusbar_height ) ;
tile - > begin ( ) ;
dirtree = new DirTree ( 0 , menubar_height + location_bar_height , default_tree_width , default_window_height - menubar_height - location_bar_height - statusbar_height ) ;
2007-08-20 22:34:22 +04:00
dirtree - > when ( FL_WHEN_ENTER_KEY_ALWAYS | FL_WHEN_RELEASE_ALWAYS ) ;
2007-08-01 22:04:35 +04:00
dirtree - > callback ( tree_cb ) ;
view = new FileDetailsView ( 150 , menubar_height + location_bar_height , default_window_width - default_tree_width , default_window_height - menubar_height - location_bar_height - statusbar_height ) ;
view - > callback ( open_cb ) ;
2007-08-20 16:16:10 +04:00
// callbacks for file ops
2007-08-01 22:04:35 +04:00
view - > rename_callback ( do_rename ) ;
view - > paste_callback ( do_paste ) ;
view - > context_callback ( context_cb ) ;
tile - > end ( ) ;
2007-07-17 23:16:39 +04:00
Fl_Group * sbgroup = new Fl_Group ( 0 , default_window_height - statusbar_height , default_window_width , statusbar_height ) ;
statusbar = new Fl_Box ( 2 , default_window_height - statusbar_height + 2 , statusbar_width , statusbar_height - 4 ) ;
statusbar - > box ( FL_DOWN_BOX ) ;
statusbar - > align ( FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP ) ;
2007-08-20 16:16:10 +04:00
statusbar - > label ( _ ( " EFiler is starting... " ) ) ;
2007-07-17 23:16:39 +04:00
Fl_Box * filler = new Fl_Box ( statusbar_width + 2 , default_window_height - statusbar_height + 2 , default_window_width - statusbar_width , statusbar_height - 4 ) ;
sbgroup - > end ( ) ;
sbgroup - > resizable ( filler ) ;
2006-08-26 13:06:13 +04:00
2007-08-01 22:04:35 +04:00
context_menu = new Fl_Menu_Button ( 0 , 0 , 0 , 0 ) ;
context_menu - > type ( Fl_Menu_Button : : POPUP3 ) ;
context_menu - > menu ( context_menu_definition ) ;
context_menu - > box ( FL_NO_BOX ) ;
2006-08-20 22:43:09 +04:00
win - > end ( ) ;
2007-08-01 22:04:35 +04:00
win - > resizable ( tile ) ;
// win->resizable(view);
2007-08-03 22:31:27 +04:00
2007-08-20 16:16:10 +04:00
// Set application (window manager) icon
// FIXME: due to fltk bug this icon doesn't have transparency
2007-08-03 22:31:27 +04:00
fl_open_display ( ) ;
Pixmap p , mask ;
XpmCreatePixmapFromData ( fl_display , DefaultRootWindow ( fl_display ) , efiler_xpm , & p , & mask , NULL ) ;
win - > icon ( ( char * ) p ) ;
2007-07-16 11:35:32 +04:00
2007-07-17 23:16:39 +04:00
// TODO remember previous configuration
2007-08-01 22:04:35 +04:00
showhidden = false ; dirsfirst = true ; ignorecase = true ; semaphore = false ; showtree = true ; showlocation = true ;
tree_width = default_tree_width ;
2006-08-20 22:43:09 +04:00
2007-08-20 16:16:10 +04:00
win - > show ( argc , argv ) ;
view - > take_focus ( ) ;
2007-08-01 22:04:35 +04:00
dirtree - > init ( ) ;
2007-08-20 22:34:22 +04:00
dirtree - > show_hidden ( showhidden ) ;
dirtree - > ignore_case ( ignorecase ) ;
2007-08-03 13:59:31 +04:00
loaddir ( current_dir ) ;
2007-08-20 16:16:10 +04:00
2007-07-16 11:35:32 +04:00
return Fl : : run ( ) ;
2006-08-20 22:43:09 +04:00
}