Adding dfm back in
This commit is contained in:
parent
2608c5241f
commit
f368f2a98e
@ -928,6 +928,18 @@ rxvt()
|
||||
cd $tmpdir
|
||||
}
|
||||
|
||||
# Tiny file manager with terminal like key combos
|
||||
dfm()
|
||||
{
|
||||
cd $systemdir/dfm
|
||||
|
||||
make
|
||||
|
||||
make install
|
||||
|
||||
cd $tmpdir
|
||||
}
|
||||
|
||||
jwm()
|
||||
{
|
||||
cd $systemdir/jwm
|
||||
|
45
system/dfm/Makefile
Normal file
45
system/dfm/Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
CC = cc
|
||||
CFLAGS = -std=c99 -D_GNU_SOURCE -g -O2 -pthread -Wall -pedantic `pkg-config --cflags --libs gtk+-2.0 gthread-2.0` -export-dynamic
|
||||
|
||||
PREFIX = /freon
|
||||
|
||||
SRC = dfm.c
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: clean dfm
|
||||
|
||||
.c.o:
|
||||
@echo CC $<
|
||||
@${CC} -c ${CFLAGS} $<
|
||||
|
||||
$(OBJ): config.h version.h
|
||||
|
||||
dfm: ${OBJ}
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJ) $(CFLAGS)
|
||||
|
||||
config:
|
||||
@echo creating default config.h from config.ex.h
|
||||
@cp config.ex.h config.h
|
||||
|
||||
clean:
|
||||
@echo cleaning directory
|
||||
@rm -f dfm ${OBJ} *.gch version.h
|
||||
|
||||
install: all
|
||||
@echo installing dfm to ${PREFIX}/bin
|
||||
@mkdir -p ${PREFIX}/bin
|
||||
@cp -f dfm ${PREFIX}/bin
|
||||
@chmod 755 ${PREFIX}/bin/dfm
|
||||
|
||||
uninstall:
|
||||
@echo removing dfm from ${PREFIX}/bin
|
||||
@rm -f ${PREFIX}/dfm
|
||||
|
||||
version.h:
|
||||
@echo "#ifndef _VERSION_H_" > version.h
|
||||
@echo "#define _VERSION_H_" >> version.h
|
||||
@echo -n "#define VERSION \"" >> version.h
|
||||
@git show -s --pretty=format:"dfm commit %h (%ai)\"%n" >> version.h
|
||||
@echo "#endif" >> version.h
|
||||
|
||||
.PHONY: clean
|
17
system/dfm/README
Normal file
17
system/dfm/README
Normal file
@ -0,0 +1,17 @@
|
||||
dfm
|
||||
===
|
||||
simple gtk+ file manager
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
Create configuration file with:
|
||||
|
||||
make config
|
||||
|
||||
And edit config.h
|
||||
|
||||
Installation
|
||||
------------
|
||||
Create a configuration file, and then run the following to build and install:
|
||||
|
||||
make clean install
|
65
system/dfm/config.ex.h
Normal file
65
system/dfm/config.ex.h
Normal file
@ -0,0 +1,65 @@
|
||||
#define MODKEY GDK_CONTROL_MASK
|
||||
|
||||
/* Terminal command */
|
||||
#define TERMINAL (char *[]){ "urxvt", NULL }
|
||||
|
||||
/* Bookmarks */
|
||||
static const char *bookmarks[] = {
|
||||
"/",
|
||||
"/root"
|
||||
};
|
||||
|
||||
/* Time format */
|
||||
static const char *timefmt = "%Y-%m-%d %H:%M:%S";
|
||||
|
||||
/* Poll time for directory updating (in seconds) */
|
||||
static const int polltime = 1;
|
||||
|
||||
/* Command to be executed when activating a file */
|
||||
static const char *filecmd[] = { "/bin/sh", "-c",
|
||||
"executor \"$DFM_PATH\"", NULL };
|
||||
|
||||
/* Key bindings */
|
||||
static Key keys[] = {
|
||||
|
||||
/* Movement */
|
||||
{ MODKEY, GDK_j, move_cursor, { .i = DOWN } },
|
||||
{ MODKEY, GDK_k, move_cursor, { .i = UP } },
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_j, move_cursor, { .i = PAGEDOWN } },
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_k, move_cursor, { .i = PAGEUP } },
|
||||
{ MODKEY, GDK_g, move_cursor, { .i = HOME } },
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_g, move_cursor, { .i = END } },
|
||||
|
||||
/* Spawn new window */
|
||||
{ MODKEY, GDK_w, newwin, { 0 } },
|
||||
|
||||
/* Go up one level */
|
||||
{ MODKEY, GDK_h, set_path, { .v = ".." } },
|
||||
{ 0, GDK_BackSpace, set_path, { .v = ".." } },
|
||||
|
||||
/* Terminal launch */
|
||||
{ MODKEY, GDK_x, dir_exec, { .v = TERMINAL } },
|
||||
|
||||
/* Make directory */
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_m, make_dir, { .i = 0755 } },
|
||||
|
||||
{ MODKEY, GDK_m, mv, { 0 } },
|
||||
|
||||
/* Set path */
|
||||
{ MODKEY, GDK_l, set_path, { 0 } },
|
||||
|
||||
/* Preferences */
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_h, toggle_pref, { .i = DOTFILES } },
|
||||
|
||||
/* Bookmarks */
|
||||
{ MODKEY, GDK_1, bookmark, { .i = 0 } },
|
||||
{ MODKEY, GDK_2, bookmark, { .i = 1 } },
|
||||
{ MODKEY, GDK_3, bookmark, { .i = 2 } },
|
||||
{ MODKEY, GDK_4, bookmark, { .i = 3 } },
|
||||
{ MODKEY, GDK_5, bookmark, { .i = 4 } },
|
||||
{ MODKEY, GDK_6, bookmark, { .i = 5 } },
|
||||
{ MODKEY, GDK_7, bookmark, { .i = 6 } },
|
||||
{ MODKEY, GDK_8, bookmark, { .i = 7 } },
|
||||
{ MODKEY, GDK_9, bookmark, { .i = 8 } },
|
||||
{ MODKEY, GDK_0, bookmark, { .i = 9 } }
|
||||
};
|
65
system/dfm/config.h
Normal file
65
system/dfm/config.h
Normal file
@ -0,0 +1,65 @@
|
||||
#define MODKEY GDK_CONTROL_MASK
|
||||
|
||||
/* Terminal command */
|
||||
#define TERMINAL (char *[]){ "rxvt", NULL }
|
||||
|
||||
/* Bookmarks */
|
||||
static const char *bookmarks[] = {
|
||||
"/",
|
||||
"/root"
|
||||
};
|
||||
|
||||
/* Time format */
|
||||
static const char *timefmt = "%Y-%m-%d %H:%M:%S";
|
||||
|
||||
/* Poll time for directory updating (in seconds) */
|
||||
static const int polltime = 1;
|
||||
|
||||
/* Command to be executed when activating a file */
|
||||
static const char *filecmd[] = { "/bin/sh", "-c",
|
||||
"executor \"$DFM_PATH\"", NULL };
|
||||
|
||||
/* Key bindings */
|
||||
static Key keys[] = {
|
||||
|
||||
/* Movement */
|
||||
{ MODKEY, GDK_j, move_cursor, { .i = DOWN } },
|
||||
{ MODKEY, GDK_k, move_cursor, { .i = UP } },
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_j, move_cursor, { .i = PAGEDOWN } },
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_k, move_cursor, { .i = PAGEUP } },
|
||||
{ MODKEY, GDK_g, move_cursor, { .i = HOME } },
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_g, move_cursor, { .i = END } },
|
||||
|
||||
/* Spawn new window */
|
||||
{ MODKEY, GDK_w, newwin, { 0 } },
|
||||
|
||||
/* Go up one level */
|
||||
{ MODKEY, GDK_h, set_path, { .v = ".." } },
|
||||
{ 0, GDK_BackSpace, set_path, { .v = ".." } },
|
||||
|
||||
/* Terminal launch */
|
||||
{ MODKEY, GDK_x, dir_exec, { .v = TERMINAL } },
|
||||
|
||||
/* Make directory */
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_m, make_dir, { .i = 0755 } },
|
||||
|
||||
{ MODKEY, GDK_m, mv, { 0 } },
|
||||
|
||||
/* Set path */
|
||||
{ MODKEY, GDK_l, set_path, { 0 } },
|
||||
|
||||
/* Preferences */
|
||||
{ MODKEY|GDK_SHIFT_MASK, GDK_h, toggle_pref, { .i = DOTFILES } },
|
||||
|
||||
/* Bookmarks */
|
||||
{ MODKEY, GDK_1, bookmark, { .i = 0 } },
|
||||
{ MODKEY, GDK_2, bookmark, { .i = 1 } },
|
||||
{ MODKEY, GDK_3, bookmark, { .i = 2 } },
|
||||
{ MODKEY, GDK_4, bookmark, { .i = 3 } },
|
||||
{ MODKEY, GDK_5, bookmark, { .i = 4 } },
|
||||
{ MODKEY, GDK_6, bookmark, { .i = 5 } },
|
||||
{ MODKEY, GDK_7, bookmark, { .i = 6 } },
|
||||
{ MODKEY, GDK_8, bookmark, { .i = 7 } },
|
||||
{ MODKEY, GDK_9, bookmark, { .i = 8 } },
|
||||
{ MODKEY, GDK_0, bookmark, { .i = 9 } }
|
||||
};
|
730
system/dfm/dfm.c
Normal file
730
system/dfm/dfm.c
Normal file
@ -0,0 +1,730 @@
|
||||
/* dfm - Simple GTK+ file manager
|
||||
*
|
||||
* Copyright (c) 2011 David Stenberg
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#define ARRSIZE(x) (sizeof(x) / sizeof(*x))
|
||||
#define CLEANMASK(mask) (mask & ~(GDK_MOD2_MASK))
|
||||
|
||||
enum ListColumns {
|
||||
NAME_STR,
|
||||
PERMS_STR,
|
||||
SIZE_STR,
|
||||
MTIME_STR,
|
||||
IS_DIR
|
||||
};
|
||||
|
||||
enum Movement {
|
||||
UP,
|
||||
DOWN,
|
||||
HOME,
|
||||
END,
|
||||
PAGEUP,
|
||||
PAGEDOWN
|
||||
};
|
||||
|
||||
enum Preferences {
|
||||
DOTFILES
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *win;
|
||||
GtkWidget *scroll;
|
||||
GtkWidget *tree;
|
||||
gchar *path;
|
||||
gboolean show_dot;
|
||||
time_t mtime;
|
||||
} FmWindow;
|
||||
|
||||
typedef struct {
|
||||
gboolean b;
|
||||
gint i;
|
||||
void *v;
|
||||
} Arg;
|
||||
|
||||
typedef struct {
|
||||
guint mod;
|
||||
guint key;
|
||||
void (*func)(FmWindow *fw, const Arg *arg);
|
||||
const Arg arg;
|
||||
} Key;
|
||||
|
||||
/* functions */
|
||||
static void action(GtkWidget *w, GtkTreePath *p, GtkTreeViewColumn *c, FmWindow *fw);
|
||||
static void bookmark(FmWindow *fw, const Arg *arg);
|
||||
static gint compare(GtkTreeModel *m, GtkTreeIter *a, GtkTreeIter *b, gpointer p);
|
||||
static gchar *create_perm_str(mode_t mode);
|
||||
static gchar *create_size_str(size_t size);
|
||||
static gchar *create_time_str(const char *fmt, const struct tm *time);
|
||||
static FmWindow *createwin();
|
||||
static void destroywin(GtkWidget *w, FmWindow *fw);
|
||||
static void dir_exec(FmWindow *fw, const Arg *arg);
|
||||
static gint get_mtime(const gchar *path, time_t *time);
|
||||
static GList *get_selected(FmWindow *fw);
|
||||
static gboolean keypress(GtkWidget *w, GdkEventKey *ev, FmWindow *fw);
|
||||
static void make_dir(FmWindow *fw, const Arg *arg);
|
||||
static void move_cursor(FmWindow *fw, const Arg *arg);
|
||||
static void mv(FmWindow *fw, const Arg *arg);
|
||||
static void newwin(FmWindow *fw, const Arg *arg);
|
||||
static void open_directory(FmWindow *fw, const char *str);
|
||||
static void set_path(FmWindow *fw, const Arg *arg);
|
||||
static gchar *prev_dir(gchar *path);
|
||||
static void read_files(FmWindow *fw, DIR *dir);
|
||||
static void reload(FmWindow *fw);
|
||||
static void spawn(const gchar * const *argv, const gchar *path);
|
||||
static gchar *text_dialog(GtkWindow *p, const gchar *title, const gchar *text);
|
||||
static void text_dialog_enter(GtkWidget *w, GtkDialog *dialog);
|
||||
static void toggle_pref(FmWindow *fw, const Arg *arg);
|
||||
static void update(FmWindow *fw);
|
||||
static void *update_thread(void *v);
|
||||
static int valid_filename(const char *s, int show_dot);
|
||||
|
||||
/* variables */
|
||||
static gboolean show_dotfiles = FALSE;
|
||||
static GList *windows = NULL;
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* enters the selected item if directory, otherwise
|
||||
* executes program with the file as argument */
|
||||
void
|
||||
action(GtkWidget *w, GtkTreePath *p, GtkTreeViewColumn *c, FmWindow *fw)
|
||||
{
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(fw->tree));
|
||||
GtkTreeIter iter;
|
||||
gchar *name;
|
||||
gchar fpath[PATH_MAX];
|
||||
gboolean is_dir;
|
||||
|
||||
gtk_tree_model_get_iter(model, &iter, p);
|
||||
gtk_tree_model_get(model, &iter, NAME_STR, &name,
|
||||
IS_DIR, &is_dir, -1);
|
||||
|
||||
chdir(fw->path);
|
||||
realpath(name, fpath);
|
||||
g_free(name);
|
||||
|
||||
if (is_dir) { /* open directory */
|
||||
open_directory(fw, fpath);
|
||||
} else { /* execute program */
|
||||
spawn(filecmd, fpath);
|
||||
}
|
||||
}
|
||||
|
||||
/* open a bookmark */
|
||||
void
|
||||
bookmark(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
if (arg->i >= 0 && arg->i < ARRSIZE(bookmarks))
|
||||
open_directory(fw, (char *)bookmarks[arg->i]);
|
||||
}
|
||||
|
||||
/* compares two rows in the tree model */
|
||||
gint
|
||||
compare(GtkTreeModel *m, GtkTreeIter *a, GtkTreeIter *b, gpointer p)
|
||||
{
|
||||
gchar *name[2];
|
||||
gint isdir[2];
|
||||
gint ret;
|
||||
|
||||
gtk_tree_model_get(m, a, NAME_STR, &name[0], IS_DIR, &isdir[0], -1);
|
||||
gtk_tree_model_get(m, b, NAME_STR, &name[1], IS_DIR, &isdir[1], -1);
|
||||
|
||||
if (isdir[0] == isdir[1])
|
||||
ret = g_ascii_strcasecmp(name[0], name[1]);
|
||||
else
|
||||
ret = isdir[0] ? -1 : 1;
|
||||
|
||||
g_free(name[0]);
|
||||
g_free(name[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* creates a formatted permission string */
|
||||
gchar*
|
||||
create_perm_str(mode_t mode)
|
||||
{
|
||||
char *permstr[] = {
|
||||
"---", "--x", "-w-", "-wx",
|
||||
"r--", "r-x", "rw-", "rwx" };
|
||||
|
||||
return g_strdup_printf("%s%s%s", permstr[(mode >> 6) & 7],
|
||||
permstr[(mode >> 3) & 7],
|
||||
permstr[mode & 7]);
|
||||
}
|
||||
|
||||
/* creates a formatted size string */
|
||||
gchar*
|
||||
create_size_str(size_t size)
|
||||
{
|
||||
if (size < 1024)
|
||||
return g_strdup_printf("%i B", (int)size);
|
||||
else if (size < 1024*1024)
|
||||
return g_strdup_printf("%.1f KB", size/1024.0);
|
||||
else if (size < 1024*1024*1024)
|
||||
return g_strdup_printf("%.1f MB", size/(1024.0*1024));
|
||||
else
|
||||
return g_strdup_printf("%.1f GB", size/(1024.0*1024*1024));
|
||||
}
|
||||
|
||||
/* creates a formatted time string */
|
||||
gchar*
|
||||
create_time_str(const char *fmt, const struct tm *time)
|
||||
{
|
||||
gchar buf[64];
|
||||
strftime(buf, sizeof(buf), fmt, time);
|
||||
return g_strdup(buf);
|
||||
}
|
||||
|
||||
/* creates and initializes a FmWindow */
|
||||
FmWindow*
|
||||
createwin()
|
||||
{
|
||||
FmWindow *fw;
|
||||
|
||||
GtkCellRenderer *rend;
|
||||
GtkListStore *store;
|
||||
GtkTreeSortable *sortable;
|
||||
|
||||
fw = g_malloc(sizeof(FmWindow));
|
||||
fw->path = NULL;
|
||||
fw->show_dot = show_dotfiles;
|
||||
fw->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_default_size(GTK_WINDOW(fw->win), 640, 480);
|
||||
gtk_window_set_icon_name(GTK_WINDOW(fw->win), "folder");
|
||||
|
||||
/* setup scrolled window */
|
||||
fw->scroll = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(fw->scroll),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
|
||||
|
||||
/* setup list store */
|
||||
store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING,
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
|
||||
sortable = GTK_TREE_SORTABLE(store);
|
||||
|
||||
/* setup tree view */
|
||||
fw->tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fw->tree), TRUE);
|
||||
gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(fw->tree), TRUE);
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(fw->tree), TRUE);
|
||||
gtk_tree_selection_set_mode(
|
||||
gtk_tree_view_get_selection(GTK_TREE_VIEW(fw->tree)),
|
||||
GTK_SELECTION_MULTIPLE);
|
||||
|
||||
rend = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(fw->tree),
|
||||
-1, "Name", rend, "text", NAME_STR, NULL);
|
||||
rend = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(fw->tree),
|
||||
-1, "Permissions", rend, "text", PERMS_STR, NULL);
|
||||
rend = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(fw->tree),
|
||||
-1, "Size", rend, "text", SIZE_STR, NULL);
|
||||
rend = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(fw->tree),
|
||||
-1, "Modified", rend, "text", MTIME_STR, NULL);
|
||||
|
||||
/* expand first column */
|
||||
gtk_tree_view_column_set_expand(
|
||||
gtk_tree_view_get_column(GTK_TREE_VIEW(fw->tree), 0),
|
||||
TRUE);
|
||||
|
||||
/* setup list sorting */
|
||||
gtk_tree_sortable_set_sort_func(sortable, NAME_STR, compare, NULL, NULL);
|
||||
gtk_tree_sortable_set_sort_column_id(sortable, NAME_STR, GTK_SORT_ASCENDING);
|
||||
|
||||
/* connect signals */
|
||||
g_signal_connect(G_OBJECT(fw->win), "destroy",
|
||||
G_CALLBACK(destroywin), fw);
|
||||
g_signal_connect(G_OBJECT(fw->win), "key-press-event",
|
||||
G_CALLBACK(keypress), fw);
|
||||
g_signal_connect(G_OBJECT(fw->tree), "row-activated",
|
||||
G_CALLBACK(action), fw);
|
||||
|
||||
/* add widgets */
|
||||
gtk_container_add(GTK_CONTAINER(fw->scroll), fw->tree);
|
||||
gtk_container_add(GTK_CONTAINER(fw->win), fw->scroll);
|
||||
|
||||
gtk_widget_show_all(fw->win);
|
||||
|
||||
return fw;
|
||||
}
|
||||
|
||||
/* removes and deallocates a FmWindow */
|
||||
void
|
||||
destroywin(GtkWidget *w, FmWindow *fw)
|
||||
{
|
||||
if ((windows = g_list_remove(windows, fw)) == NULL)
|
||||
gtk_main_quit();
|
||||
|
||||
gtk_widget_destroy(fw->tree);
|
||||
gtk_widget_destroy(fw->scroll);
|
||||
gtk_widget_destroy(fw->win);
|
||||
|
||||
if (fw->path)
|
||||
g_free(fw->path);
|
||||
|
||||
g_free(fw);
|
||||
}
|
||||
|
||||
/* change directory to current, and spawns program in background */
|
||||
void
|
||||
dir_exec(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
g_return_if_fail(fw->path && arg->v);
|
||||
spawn(arg->v, fw->path);
|
||||
}
|
||||
|
||||
/* get mtime for a file. returns 0 if ok */
|
||||
gint
|
||||
get_mtime(const gchar *path, time_t *time)
|
||||
{
|
||||
struct stat st;
|
||||
gint err;
|
||||
|
||||
g_return_val_if_fail(time, 0);
|
||||
|
||||
if ((err = stat(path, &st)) == 0)
|
||||
*time = st.st_mtime;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* returns a list of name for selected files (relative file names, not absolute) */
|
||||
GList *
|
||||
get_selected(FmWindow *fw)
|
||||
{
|
||||
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(fw->tree));
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
GList *lsel = gtk_tree_selection_get_selected_rows(sel, &model);
|
||||
GList *node = lsel;
|
||||
GList *files = NULL;
|
||||
gchar *name;
|
||||
|
||||
while (node) {
|
||||
gtk_tree_model_get_iter(model, &iter, node->data);
|
||||
gtk_tree_model_get(model, &iter, NAME_STR, &name, -1);
|
||||
files = g_list_append(files, name);
|
||||
|
||||
node = g_list_next(node);
|
||||
}
|
||||
|
||||
g_list_foreach(lsel, (GFunc) gtk_tree_path_free, NULL);
|
||||
g_list_free(lsel);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/* handles key events on the FmWindow */
|
||||
gboolean
|
||||
keypress(GtkWidget *w, GdkEventKey *ev, FmWindow *fw)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < ARRSIZE(keys); i++) {
|
||||
if (gdk_keyval_to_lower(ev->keyval) == keys[i].key &&
|
||||
CLEANMASK(ev->state) == keys[i].mod &&
|
||||
keys[i].func) {
|
||||
keys[i].func(fw, &keys[i].arg);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
make_dir(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
gchar *path;
|
||||
|
||||
g_return_if_fail(fw->path);
|
||||
|
||||
if ((path = text_dialog(GTK_WINDOW(fw->win), "make directory", NULL))) {
|
||||
if (mkdir(path, arg->i) == -1)
|
||||
g_warning("mkdir: %s", strerror(errno));
|
||||
g_free(path);
|
||||
}
|
||||
}
|
||||
|
||||
/* moves cursor in the tree view */
|
||||
void
|
||||
move_cursor(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
/* TODO: fix this */
|
||||
|
||||
GtkMovementStep m;
|
||||
gint v;
|
||||
gboolean ret;
|
||||
|
||||
switch (arg->i) {
|
||||
case UP:
|
||||
m = GTK_MOVEMENT_DISPLAY_LINES;
|
||||
v = -1;
|
||||
break;
|
||||
case DOWN:
|
||||
m = GTK_MOVEMENT_DISPLAY_LINES;
|
||||
v = 1;
|
||||
break;
|
||||
case HOME:
|
||||
m = GTK_MOVEMENT_BUFFER_ENDS;
|
||||
v = -1;
|
||||
break;
|
||||
case END:
|
||||
m = GTK_MOVEMENT_BUFFER_ENDS;
|
||||
v = 1;
|
||||
break;
|
||||
case PAGEUP:
|
||||
m = GTK_MOVEMENT_PAGES;
|
||||
v = -1;
|
||||
break;
|
||||
case PAGEDOWN:
|
||||
m = GTK_MOVEMENT_PAGES;
|
||||
v = 1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
g_signal_emit_by_name(G_OBJECT(fw->tree), "move-cursor", m, v, &ret);
|
||||
}
|
||||
|
||||
void
|
||||
mv(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
/* TODO: dummy atm */
|
||||
|
||||
GList *files = get_selected(fw);
|
||||
GList *iter = files;
|
||||
|
||||
while (iter) {
|
||||
printf("f: '%s'\n", (char *)iter->data);
|
||||
iter = g_list_next(iter);
|
||||
}
|
||||
|
||||
g_list_foreach(files, (GFunc) g_free, NULL);
|
||||
g_list_free(files);
|
||||
}
|
||||
|
||||
/* creates and inserts a new FmWindow to the window list */
|
||||
void
|
||||
newwin(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
FmWindow *new = createwin();
|
||||
windows = g_list_append(windows, new);
|
||||
|
||||
open_directory(new, arg->v ? arg->v : (fw ? fw->path : NULL));
|
||||
}
|
||||
|
||||
/* open and reads directory data to FmWindow */
|
||||
void
|
||||
open_directory(FmWindow *fw, const char *str)
|
||||
{
|
||||
DIR *dir;
|
||||
char rpath[PATH_MAX];
|
||||
|
||||
g_return_if_fail(str);
|
||||
|
||||
/* change to current working directory to get relative paths right */
|
||||
if (fw->path)
|
||||
chdir(fw->path);
|
||||
|
||||
/* get clean absolute path string */
|
||||
realpath(str, rpath);
|
||||
|
||||
if (!(dir = opendir(rpath))) {
|
||||
g_warning("%s: %s\n", rpath, g_strerror(errno));
|
||||
|
||||
if (strcmp(rpath, "/") != 0) {
|
||||
/* try to go up one level and load directory */
|
||||
open_directory(fw, prev_dir(rpath));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fw->path)
|
||||
g_free(fw->path);
|
||||
|
||||
fw->path = g_strdup(rpath);
|
||||
chdir(fw->path);
|
||||
get_mtime(fw->path, &fw->mtime);
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(fw->win), fw->path);
|
||||
|
||||
read_files(fw, dir);
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
gchar*
|
||||
prev_dir(gchar *path)
|
||||
{
|
||||
gchar *p;
|
||||
if ((p = g_strrstr(path, "/"))) {
|
||||
if (p == path)
|
||||
*(p + 1) = '\0';
|
||||
else
|
||||
*p = '\0';
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/* reads files in to fw's list store from an opened DIR struct */
|
||||
void
|
||||
read_files(FmWindow *fw, DIR *dir)
|
||||
{
|
||||
struct dirent *e;
|
||||
struct stat st;
|
||||
struct tm *time;
|
||||
gchar *name_str;
|
||||
gchar *mtime_str;
|
||||
gchar *perms_str;
|
||||
gchar *size_str;
|
||||
|
||||
GtkListStore *store = GTK_LIST_STORE(
|
||||
gtk_tree_view_get_model(GTK_TREE_VIEW(fw->tree)));
|
||||
GtkTreeIter iter;
|
||||
GtkTreeSortable *sortable = GTK_TREE_SORTABLE(store);
|
||||
|
||||
/* remove previous entries */
|
||||
gtk_list_store_clear(store);
|
||||
|
||||
/* disable sort to speed up insertion */
|
||||
gtk_tree_sortable_set_sort_column_id(sortable,
|
||||
GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
|
||||
GTK_SORT_ASCENDING);
|
||||
|
||||
while ((e = readdir(dir))) {
|
||||
|
||||
if (valid_filename(e->d_name, fw->show_dot)
|
||||
&& (stat(e->d_name, &st) == 0)) {
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
name_str = g_strdup_printf("%s/", e->d_name);
|
||||
else
|
||||
name_str = g_strdup(e->d_name);
|
||||
|
||||
time = localtime(&st.st_mtime);
|
||||
mtime_str = create_time_str(timefmt, time);
|
||||
perms_str = create_perm_str(st.st_mode);
|
||||
size_str = create_size_str(st.st_size);
|
||||
|
||||
gtk_list_store_append(store, &iter);
|
||||
gtk_list_store_set(store, &iter,
|
||||
NAME_STR, name_str,
|
||||
PERMS_STR, perms_str,
|
||||
SIZE_STR, size_str,
|
||||
MTIME_STR, mtime_str,
|
||||
IS_DIR, S_ISDIR(st.st_mode),
|
||||
-1);
|
||||
|
||||
g_free(name_str);
|
||||
g_free(mtime_str);
|
||||
g_free(perms_str);
|
||||
g_free(size_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* reenable sort */
|
||||
gtk_tree_sortable_set_sort_column_id(sortable, NAME_STR, GTK_SORT_ASCENDING);
|
||||
}
|
||||
|
||||
/* reload a FmWindow */
|
||||
void
|
||||
reload(FmWindow *fw)
|
||||
{
|
||||
open_directory(fw, fw->path);
|
||||
}
|
||||
|
||||
void
|
||||
set_path(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
char *path;
|
||||
|
||||
if ((path = arg->v)) {
|
||||
open_directory(fw, path);
|
||||
} else if ((path = text_dialog(GTK_WINDOW(fw->win), "path", fw->path))) {
|
||||
open_directory(fw, path);
|
||||
g_free(path);
|
||||
}
|
||||
}
|
||||
|
||||
/* change working directory and spawns a program to the background */
|
||||
void
|
||||
spawn(const gchar * const *argv, const gchar *path)
|
||||
{
|
||||
if (fork() == 0) {
|
||||
g_setenv("DFM_PATH", path, TRUE);
|
||||
chdir(path);
|
||||
execvp(*argv, (gchar **)argv);
|
||||
g_warning("spawn: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
gchar*
|
||||
text_dialog(GtkWindow *p, const gchar *title, const gchar *text)
|
||||
{
|
||||
GtkWidget *dialog = gtk_dialog_new_with_buttons(title, p,
|
||||
GTK_DIALOG_MODAL, NULL);
|
||||
GtkWidget *entry = gtk_entry_new();
|
||||
GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
gchar *str = NULL;
|
||||
|
||||
if (text)
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), text);
|
||||
|
||||
g_signal_connect(G_OBJECT(entry), "activate",
|
||||
G_CALLBACK(text_dialog_enter), dialog);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(area), entry);
|
||||
gtk_widget_show(entry);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == 1)
|
||||
str = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
|
||||
|
||||
/* clean up */
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void
|
||||
text_dialog_enter(GtkWidget *w, GtkDialog *dialog)
|
||||
{
|
||||
gtk_dialog_response(dialog, 1);
|
||||
}
|
||||
|
||||
/* toggle preferences in a FmWindow, and reload if necessary */
|
||||
void
|
||||
toggle_pref(FmWindow *fw, const Arg *arg)
|
||||
{
|
||||
switch (arg->i) {
|
||||
case DOTFILES:
|
||||
fw->show_dot = !fw->show_dot;
|
||||
reload(fw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
update(FmWindow *fw)
|
||||
{
|
||||
time_t mtime = 0;
|
||||
|
||||
if (fw->path) {
|
||||
if (get_mtime(fw->path, &mtime) != 0 || mtime > fw->mtime) {
|
||||
/* directory updated or removed, reload */
|
||||
reload(fw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
update_thread(void *v)
|
||||
{
|
||||
GList *p;
|
||||
|
||||
for (;;) {
|
||||
sleep(polltime);
|
||||
|
||||
gdk_threads_enter();
|
||||
|
||||
for (p = windows; p != NULL; p = g_list_next(p))
|
||||
update((FmWindow *)p->data);
|
||||
|
||||
gdk_threads_leave();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* returns 1 if valid filename, i.e. not '.' or '..' (or .* if show_dot = 0) */
|
||||
int
|
||||
valid_filename(const char *s, int show_dot)
|
||||
{
|
||||
return show_dot ?
|
||||
(g_strcmp0(s, ".") != 0 && g_strcmp0(s, "..") != 0) :
|
||||
*s != '.';
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Arg arg;
|
||||
pthread_t u_tid;
|
||||
pid_t pid;
|
||||
gboolean silent = FALSE;
|
||||
int i;
|
||||
|
||||
/* read arguments */
|
||||
for(i = 1; i < argc && argv[i][0] == '-'; i++) {
|
||||
switch(argv[i][1]) {
|
||||
case 'v':
|
||||
g_print("%s\n", VERSION);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'd':
|
||||
show_dotfiles = TRUE;
|
||||
break;
|
||||
case 's':
|
||||
silent = TRUE;
|
||||
break;
|
||||
default:
|
||||
g_printerr("Usage: %s [-v] [-d] [-s] PATH\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
arg.v = i < argc ? argv[i] : ".";
|
||||
|
||||
if ((pid = fork()) > 0)
|
||||
return EXIT_SUCCESS;
|
||||
else if (pid < 0)
|
||||
printf("fork: %s\n", g_strerror(errno));
|
||||
|
||||
if (silent) {
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
/* initialize threads */
|
||||
g_thread_init(NULL);
|
||||
gdk_threads_init();
|
||||
gdk_threads_enter();
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
newwin(NULL, &arg);
|
||||
|
||||
/* create update thread */
|
||||
pthread_create(&u_tid, NULL, update_thread, NULL);
|
||||
|
||||
gtk_main();
|
||||
gdk_threads_leave();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
28
system/dfm/utils/executor
Executable file
28
system/dfm/utils/executor
Executable file
@ -0,0 +1,28 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Simple program executor
|
||||
# Directs all output to /dev/null
|
||||
|
||||
DEFAULT_PROGRAM="gvim"
|
||||
|
||||
function get_mime() {
|
||||
MIME=`file --mime-type "$1" | cut -d ':' -f 2- | cut -b 2-`
|
||||
|
||||
echo $MIME
|
||||
}
|
||||
|
||||
M=$(get_mime "$1")
|
||||
PROGRAM=$DEFAULT_PROGRAM
|
||||
|
||||
echo $M
|
||||
|
||||
case $M in
|
||||
"application/ogg" )
|
||||
PROGRAM="mplayer" ;;
|
||||
"application/pdf" )
|
||||
PROGRAM="xpdf" ;;
|
||||
"image/jpeg" )
|
||||
PROGRAM="gpicview" ;;
|
||||
esac
|
||||
|
||||
$PROGRAM "$1" &> /dev/null
|
Loading…
x
Reference in New Issue
Block a user