mc/gnome/gscreen.c
Miguel de Icaza a416ee4f7b Cool changes:
1998-05-22  Miguel de Icaza  <miguel@nuclecu.unam.mx>

	* gwidget.c (x_create_input): Disable the use of the GNOME entries
	for now, as they are very slow.  We need to figure out what is
	wrong with this.

	With this change, dialog boxes close quickly instead of taking
	ages to close.

	* gscreen.c, gdesktop.c (file_popup_add_context, file_popup):
	Share the context menu code in gdesktop.c and gscreen.c.  The
	desktop pop up menus now include all of the stuff that would have
	appeared in the Panel.

	* gdesktop.c (desktop_icon_remove): Remove the file associated
	with this desktop entry if it is on the ~/desktop directory.
1998-05-23 00:55:03 +00:00

1963 lines
51 KiB
C

/* GNU Midnight Commander -- GNOME edition
*
* Directory display routines
*
* Copyright (C) 1997 The Free Software Foundation
*
* Authors: Miguel de Icaza
* Federico Mena
*/
#include <config.h>
#include <string.h>
#include <stdlib.h> /* atoi */
#include "fs.h"
#include "x.h"
#include "dir.h"
#include "panel.h"
#include "command.h"
#include "panel.h" /* current_panel */
#include "command.h" /* cmdline */
#include "main.h"
#include "color.h"
#include "mouse.h"
#include "layout.h" /* get_panel_widget */
#include "ext.h" /* regex_command */
#include "cmd.h" /* copy_cmd, ren_cmd, delete_cmd, ... */
#include "gscreen.h"
#include "dir.h"
#include "dialog.h"
#include "gdesktop.h"
#include "gpageprop.h"
#include "gcliplabel.h"
#include "gblist.h"
#include "../vfs/vfs.h"
#include <gdk/gdkprivate.h>
/* The pixmaps */
#include "directory.xpm"
#include "link.xpm"
#include "dev.xpm"
#include "listing-list.xpm"
#include "listing-iconic.xpm"
/* This is used to initialize our pixmaps */
static int pixmaps_ready;
GdkPixmap *icon_directory_pixmap;
GdkBitmap *icon_directory_mask;
GdkPixmap *icon_link_pixmap;
GdkBitmap *icon_link_mask;
GdkPixmap *icon_dev_pixmap;
GdkBitmap *icon_dev_mask;
/* These are big images used in the Icon View, for the gnome_icon_list */
static GdkImlibImage *icon_view_directory;
static GdkImlibImage *icon_view_executable;
static GdkImlibImage *icon_view_symlink;
static GdkImlibImage *icon_view_device;
static GdkImlibImage *icon_view_regular;
static GdkImlibImage *icon_view_core;
static GdkImlibImage *icon_view_sock;
static char *drag_types [] = { "text/plain", "file:ALL", "url:ALL" };
static char *drop_types [] = { "url:ALL" };
#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
/* GtkWidgets with the shaped windows for dragging */
GtkWidget *drag_directory = NULL;
GtkWidget *drag_directory_ok = NULL;
GtkWidget *drag_multiple = NULL;
GtkWidget *drag_multiple_ok = NULL;
typedef void (*context_menu_callback)(GtkWidget *, void *);
/*
* Flags for the context-sensitive popup menus
*/
#define F_ALL 1
#define F_REGULAR 2
#define F_SYMLINK 4
#define F_SINGLE 8
#define F_NOTDIR 16
#define F_DICON 32 /* Only applies to desktop_icon_t */
#define F_PANEL 64 /* Only applies to WPanel */
static void panel_file_list_configure_contents (GtkWidget *file_list, WPanel *panel, int main_width, int height);
void
repaint_file (WPanel *panel, int file_index, int move, int attr, int isstatus)
{
}
/*
* Invoked by the generic code: show current working directory
*/
void
show_dir (WPanel *panel)
{
assign_text (panel->current_dir, panel->cwd);
update_input (panel->current_dir, 1);
gtk_window_set_title (GTK_WINDOW (panel->xwindow), panel->cwd);
}
/*
* Utility routine: Try to load a bitmap for a file_entry
*/
static void
panel_file_list_set_type_bitmap (GtkCList *cl, int row, int column, int color, file_entry *fe)
{
/* Here, add more icons */
switch (color){
case DIRECTORY_COLOR:
gtk_clist_set_pixmap (cl, row, column, icon_directory_pixmap, icon_directory_mask);
break;
case LINK_COLOR:
gtk_clist_set_pixmap (cl, row, column, icon_link_pixmap, icon_link_mask);
break;
case DEVICE_COLOR:
gtk_clist_set_pixmap (cl, row, column, icon_dev_pixmap, icon_dev_mask);
break;
}
}
/*
* Sets the color attributes for a given row.
*/
static void
panel_file_list_set_row_colors (GtkCList *cl, int row, int color_pair)
{
gtk_clist_set_foreground (cl, row, gmc_color_pairs [color_pair].fore);
gtk_clist_set_background (cl, row, gmc_color_pairs [color_pair].back);
}
/*
* Update the status of the back and forward history buttons.
* Called from the generic code
*/
void
x_panel_update_marks (WPanel *panel)
{
int ff = panel->dir_history->next ? 1 : 0;
int bf = panel->dir_history->prev ? 1 : 0;
if (!panel->fwd_b)
return;
gtk_widget_set_sensitive (panel->fwd_b, ff);
gtk_widget_set_sensitive (panel->back_b, bf);
}
/*
* Listing view: Load the contents
*/
static void
panel_fill_panel_list (WPanel *panel)
{
const int top = panel->count;
const int items = panel->format->items;
const int selected = panel->selected;
GtkCList *cl = GTK_CLIST (panel->list);
int i, col, type_col, color;
char **texts;
texts = malloc (sizeof (char *) * items);
gtk_clist_freeze (GTK_CLIST (cl));
gtk_clist_clear (GTK_CLIST (cl));
/* which column holds the type information */
type_col = -1;
for (i = 0; i < top; i++){
file_entry *fe = &panel->dir.list [i];
format_e *format = panel->format;
for (col = 0; format; format = format->next){
if (!format->use_in_gui)
continue;
if (type_col == -1)
if (strcmp (format->id, "type") == 0)
type_col = col;
if (!format->string_fn)
texts [col] = "";
else
texts [col] = (*format->string_fn)(fe, 10);
col++;
}
gtk_clist_append (cl, texts);
color = file_compute_color (fe->f.marked ? MARKED : NORMAL, fe);
panel_file_list_set_row_colors (cl, i, color);
if (type_col != -1)
panel_file_list_set_type_bitmap (cl, i, type_col, color, fe);
}
/* This is needed as the gtk_clist_append changes selected under us :-( */
panel->selected = selected;
select_item (panel);
gtk_clist_thaw (GTK_CLIST (cl));
free (texts);
}
/*
* Icon view: load the panel contents
*/
static void
panel_fill_panel_icons (WPanel *panel)
{
GnomeIconList *icons = GNOME_ICON_LIST (panel->icons);
const int top = panel->count;
const int selected = panel->selected;
int i;
GdkImlibImage *image;
gnome_icon_list_freeze (icons);
gnome_icon_list_clear (icons);
for (i = 0; i < top; i++){
file_entry *fe = &panel->dir.list [i];
switch (file_entry_color (fe)){
case DIRECTORY_COLOR:
image = icon_view_directory;
break;
case LINK_COLOR:
image = icon_view_symlink;
break;
case DEVICE_COLOR:
image = icon_view_device;
break;
case SPECIAL_COLOR:
image = icon_view_sock;
break;
case EXECUTABLE_COLOR:
image = icon_view_executable;
break;
case CORE_COLOR:
image = icon_view_core;
break;
case STALLED_COLOR:
case NORMAL_COLOR:
default:
image = icon_view_regular;
}
gnome_icon_list_append_imlib (icons, image, fe->fname);
}
/* This is needed as the gtk_clist_append changes selected under us :-( */
panel->selected = selected;
select_item (panel);
gnome_icon_list_thaw (icons);
}
/*
* Invoked from the generic code to fill the display
*/
void
x_fill_panel (WPanel *panel)
{
if (panel->list_type == list_icons)
panel_fill_panel_icons (panel);
else
panel_fill_panel_list (panel);
}
static void
gmc_panel_set_size (int index, int boot)
{
Widget *w;
WPanel *p;
w = (Widget *) get_panel_widget (index);
p = (WPanel *) w;
w->cols = 40;
w->lines = 25;
set_panel_formats (p);
paint_panel (p);
if (!boot)
paint_frame (p);
x_fill_panel (p);
}
void
x_panel_set_size (int index)
{
printf ("WARNING: set size called\n");
gmc_panel_set_size (index, 1);
}
/*
* Invoked when the f.mark field of a file item changes
*/
void
x_panel_select_item (WPanel *panel, int index, int value)
{
int color;
color = file_compute_color (value ? MARKED : NORMAL, &panel->dir.list[index]);
panel_file_list_set_row_colors (GTK_CLIST (panel->list), index, color);
}
void
x_select_item (WPanel *panel)
{
if (panel->list_type == list_icons){
GnomeIconList *list = GNOME_ICON_LIST (panel->icons);
do_file_mark (panel, panel->selected, 1);
display_mini_info (panel);
gnome_icon_list_select_icon (list, panel->selected);
if (list->icon_rows){
if (gnome_icon_list_icon_is_visible (list, panel->selected) != GTK_VISIBILITY_FULL)
gnome_icon_list_moveto (list, panel->selected, 0.5);
}
} else {
GtkCList *clist = GTK_CLIST (panel->list);
int color, marked;
if (panel->dir.list [panel->selected].f.marked)
marked = 1;
else
marked = 0;
color = file_compute_color (marked ? MARKED_SELECTED : SELECTED, &panel->dir.list [panel->selected]);
panel_file_list_set_row_colors (GTK_CLIST (panel->list), panel->selected, color);
/* Make it visible */
if (gtk_clist_row_is_visible (clist, panel->selected) != GTK_VISIBILITY_FULL)
gtk_clist_moveto (clist, panel->selected, 0, 0.5, 0.0);
}
}
void
x_unselect_item (WPanel *panel)
{
if (panel->list_type == list_icons){
int selected = panel->selected;
/* This changes the panel->selected */
gnome_icon_list_unselect_all (GNOME_ICON_LIST (panel->icons), NULL, NULL);
panel->selected = selected;
} else {
int color;
int val;
val = panel->dir.list [panel->selected].f.marked ? MARKED : NORMAL;
color = file_compute_color (val, &panel->dir.list [panel->selected]);
panel_file_list_set_row_colors (GTK_CLIST (panel->list), panel->selected, color);
}
}
void
x_filter_changed (WPanel *panel)
{
assign_text (panel->filter_w, panel->filter ? panel->filter : "");
update_input (panel->filter_w, 1);
}
void
x_adjust_top_file (WPanel *panel)
{
/* gtk_clist_moveto (GTK_CLIST (panel->list), panel->top_file, 0, 0.0, 0.0); */
}
/*
* These two constants taken from Gtk sources, hack to figure out how much
* of the clist is visible
*/
#define COLUMN_INSET 3
#define CELL_SPACING 1
/*
* Configures the columns title sizes for the panel->list CList widget
*/
static void
panel_file_list_configure_contents (GtkWidget *file_list, WPanel *panel, int main_width, int height)
{
format_e *format = panel->format;
int i, used_columns, expandables, items;
int char_width, usable_pixels, extra_pixels, width;
int total_columns, extra_columns;
int expand_space, extra_space, shrink_space;
int lost_pixels, display_the_mini_info;
/* Pass 1: Count minimum columns,
* set field_len to default to the requested_field_len
* and compute how much space we lost to the column decorations
*/
lost_pixels = used_columns = expandables = items = 0;
for (format = panel->format; format; format = format->next){
format->field_len = format->requested_field_len;
if (!format->use_in_gui)
continue;
used_columns += format->field_len;
items++;
if (format->expand)
expandables++;
lost_pixels += CELL_SPACING + (2 * COLUMN_INSET);
}
/* The left scrollbar might take some space from us, use this information */
if (GTK_WIDGET_VISIBLE (GTK_CLIST (file_list)->vscrollbar)){
int scrollbar_width = GTK_WIDGET (GTK_CLIST (file_list)->vscrollbar)->requisition.width;
int scrollbar_space = GTK_CLIST_CLASS (GTK_OBJECT (file_list)->klass)->scrollbar_spacing;
lost_pixels += scrollbar_space + scrollbar_width;
}
char_width = gdk_string_width (file_list->style->font, "xW") / 2;
width = main_width - lost_pixels;
extra_pixels = width % char_width;
usable_pixels = width - extra_pixels;
total_columns = usable_pixels / char_width;
extra_columns = total_columns - used_columns;
if (extra_columns > 0){
expand_space = extra_columns / expandables;
extra_space = extra_columns % expandables;
} else
extra_space = expand_space = 0;
/* Hack: the default mini-info display only gets displayed
* if panel->estimated_total is not zero, ie, if this has been
* initialized for the first time.
*/
display_the_mini_info = (panel->estimated_total == 0);
panel->estimated_total = total_columns;
if (display_the_mini_info)
display_mini_info (panel);
/* If we dont have enough space, shorten the fields */
if (used_columns > total_columns){
expand_space = 0;
shrink_space = (used_columns - total_columns) / items;
} else
shrink_space = 0;
gtk_clist_freeze (GTK_CLIST (file_list));
for (i = 0, format = panel->format; format; format = format->next){
if (!format->use_in_gui)
continue;
format->field_len += (format->expand ? expand_space : 0) - shrink_space;
gtk_clist_set_column_width (GTK_CLIST (file_list), i, format->field_len * char_width);
i++;
}
gtk_clist_thaw (GTK_CLIST (file_list));
}
static void
panel_action_open_with (GtkWidget *widget, WPanel *panel)
{
char *command;
command = input_expand_dialog (_(" Open with..."),
_("Enter extra arguments:"), panel->dir.list [panel->selected].fname);
if (!command)
return;
execute (command);
free (command);
}
static void
panel_action_open (GtkWidget *widget, WPanel *panel)
{
if (do_enter (panel))
return;
panel_action_open_with (widget, panel);
}
void
panel_action_view (GtkWidget *widget, WPanel *panel)
{
view_cmd (panel);
}
void
panel_action_view_unfiltered (GtkWidget *widget, WPanel *panel)
{
view_simple_cmd (panel);
}
void
panel_action_properties (GtkWidget *widget, WPanel *panel)
{
file_entry *fe = &panel->dir.list [panel->selected];
char *full_name = concat_dir_and_file (panel->cwd, fe->fname);
if (item_properties (GTK_WIDGET (panel->list), full_name, NULL) != 0){
reread_cmd ();
}
free (full_name);
}
/*
* The context menu: text displayed, condition that must be met and
* the routine that gets invoked upon activation.
*/
static struct {
char *text;
int flags;
context_menu_callback callback;
} file_actions [] = {
{ N_("Properties"), F_SINGLE | F_PANEL, (context_menu_callback) panel_action_properties },
{ N_("Properties"), F_SINGLE | F_DICON, (context_menu_callback) desktop_icon_properties },
{ "", F_SINGLE, NULL },
{ N_("Open"), F_PANEL | F_ALL, (context_menu_callback) panel_action_open },
{ N_("Open"), F_DICON | F_ALL, (context_menu_callback) desktop_icon_execute },
{ N_("Open with"), F_PANEL | F_ALL, (context_menu_callback) panel_action_open_with },
{ N_("View"), F_PANEL | F_NOTDIR, (context_menu_callback) panel_action_view },
{ N_("View unfiltered"), F_PANEL | F_NOTDIR, (context_menu_callback) panel_action_view_unfiltered },
{ "", 0, NULL },
{ N_("Link..."), F_PANEL | F_REGULAR | F_SINGLE, (context_menu_callback) link_cmd },
{ N_("Symlink..."), F_PANEL | F_SINGLE, (context_menu_callback) symlink_cmd },
{ N_("Edit symlink..."), F_PANEL | F_SYMLINK, (context_menu_callback) edit_symlink_cmd },
{ NULL, 0, NULL },
};
typedef struct {
char *text;
context_menu_callback callback;
} common_menu_t;
/*
* context menu, constant entries
*/
common_menu_t common_panel_actions [] = {
{ N_("Copy..."), (context_menu_callback) copy_cmd },
{ N_("Rename/move.."), (context_menu_callback) ren_cmd },
{ N_("Delete..."), (context_menu_callback) delete_cmd },
{ NULL, NULL }
};
common_menu_t common_dicon_actions [] = {
{ N_("Delete"), (context_menu_callback) desktop_icon_delete },
{ NULL, NULL }
};
static GtkWidget *
create_popup_submenu (WPanel *panel, desktop_icon_t *di, int row, char *filename)
{
static int submenu_translated;
GtkWidget *menu;
int i;
void *closure;
closure = (panel != 0 ? (void *) panel : (void *)di);
if (!submenu_translated){
/* FIXME translate it */
submenu_translated = 1;
}
menu = gtk_menu_new ();
for (i = 0; file_actions [i].text; i++){
GtkWidget *item;
/* First, try F_PANEL and F_DICON flags */
if (di && (file_actions [i].flags & F_PANEL))
continue;
if (panel && (file_actions [i].flags & F_DICON))
continue;
/* Items with F_ALL bypass any other condition */
if (!(file_actions [i].flags & F_ALL)){
/* Items with F_SINGLE require that ONLY ONE marked files exist */
if (panel && file_actions [i].flags & F_SINGLE){
if (panel->marked > 1)
continue;
}
/* Items with F_NOTDIR requiere that the selection is not a directory */
if (panel && file_actions [i].flags & F_NOTDIR){
struct stat *s = &panel->dir.list [row].buf;
if (panel->dir.list [row].f.link_to_dir)
continue;
if (S_ISDIR (s->st_mode))
continue;
}
/* Items with F_REGULAR do not accept any strange file types */
if (panel && file_actions [i].flags & F_REGULAR){
struct stat *s = &panel->dir.list [row].buf;
if (S_ISLNK (panel->dir.list [row].f.link_to_dir))
continue;
if (S_ISSOCK (s->st_mode) || S_ISCHR (s->st_mode) ||
S_ISFIFO (s->st_mode) || S_ISBLK (s->st_mode))
continue;
}
/* Items with F_SYMLINK only operate on symbolic links */
if (panel && file_actions [i].flags & F_SYMLINK){
if (!S_ISLNK (panel->dir.list [row].buf.st_mode))
continue;
}
}
if (*file_actions [i].text)
item = gtk_menu_item_new_with_label (_(file_actions [i].text));
else
item = gtk_menu_item_new ();
gtk_widget_show (item);
if (file_actions [i].callback){
gtk_signal_connect (GTK_OBJECT (item), "activate",
GTK_SIGNAL_FUNC(file_actions [i].callback), closure);
}
gtk_menu_append (GTK_MENU (menu), item);
}
return menu;
}
/*
* Ok, this activates a menu popup action for a filename
* it is kind of hackish, it gets the desired action from the
* item, so it has to peek inside the item to retrieve the label
*/
static void
popup_activate_by_string (GtkMenuItem *item, WPanel *panel)
{
char *filename = panel->dir.list [panel->selected].fname;
char *action;
int movedir;
g_return_if_fail (GTK_IS_MENU_ITEM (item));
g_return_if_fail (GTK_IS_LABEL (GTK_BIN (item)->child));
action = GTK_LABEL (GTK_BIN (item)->child)->label;
regex_command (filename, action, NULL, &movedir);
}
static void
popup_activate_desktop_icon (GtkMenuItem *item, char *filename)
{
char *action;
int movedir;
action = GTK_LABEL (GTK_BIN (item)->child)->label;
regex_command (filename, action, NULL, &movedir);
}
static void
file_popup_add_context (GtkMenu *menu, WPanel *panel, desktop_icon_t *di, char *filename)
{
GtkWidget *item;
char *p, *q;
int c, i;
void *closure, *regex_closure;
common_menu_t *menu_p;
GtkSignalFunc regex_func;
if (panel){
menu_p = common_panel_actions;
closure = panel;
regex_func = GTK_SIGNAL_FUNC (popup_activate_by_string);
regex_closure = panel;
} else {
menu_p = common_dicon_actions;
closure = di;
regex_func = GTK_SIGNAL_FUNC (popup_activate_desktop_icon);
regex_closure = di->dentry->exec [0];
}
for (i = 0; menu_p [i].text; i++){
GtkWidget *item;
item = gtk_menu_item_new_with_label (_(menu_p [i].text));
gtk_widget_show (item);
gtk_signal_connect (GTK_OBJECT (item), "activate",
GTK_SIGNAL_FUNC (menu_p [i].callback), closure);
gtk_menu_append (GTK_MENU (menu), item);
}
p = regex_command (filename, NULL, NULL, NULL);
if (!p)
return;
item = gtk_menu_item_new ();
gtk_widget_show (item);
gtk_menu_append (menu, item);
for (;;){
while (*p == ' ' || *p == '\t')
p++;
if (!*p)
break;
q = p;
while (*q && *q != '=' && *q != '\t')
q++;
c = *q;
*q = 0;
item = gtk_menu_item_new_with_label (p);
gtk_widget_show (item);
gtk_signal_connect (GTK_OBJECT(item), "activate", regex_func, regex_closure);
gtk_menu_append (menu, item);
if (!c)
break;
p = q + 1;
}
}
/*
* Create a context menu
* It can take either a WPanel or a GnomeDesktopEntry. One of them should
* be set to NULL.
*/
void
file_popup (GdkEventButton *event, void *WPanel_pointer, void *desktop_icon_t_pointer, int row, char *filename)
{
GtkWidget *menu = gtk_menu_new ();
GtkWidget *submenu;
GtkWidget *item;
WPanel *panel = WPanel_pointer;
desktop_icon_t *di = desktop_icon_t_pointer;
char *str;
g_return_if_fail (((panel != NULL) ^ (di != NULL)));
if (panel)
str = (panel->marked > 1) ? "..." : filename;
else
str = filename;
if (panel){
item = gtk_menu_item_new_with_label (str);
gtk_widget_show (item);
gtk_menu_append (GTK_MENU (menu), item);
submenu = create_popup_submenu (panel, di, row, filename);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
} else
menu = create_popup_submenu (panel, di, row, filename);
file_popup_add_context (GTK_MENU (menu), panel, di, filename);
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->time);
}
static void
internal_select_item (GtkWidget *file_list, WPanel *panel, int row)
{
unselect_item (panel);
panel->selected = row;
gtk_signal_handler_block_by_data (GTK_OBJECT (file_list), panel);
select_item (panel);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (file_list), panel);
}
static void
panel_file_list_select_row (GtkWidget *file_list, int row, int column, GdkEvent *event, WPanel *panel)
{
int current_selection = panel->selected;
if (!event) {
internal_select_item (file_list, panel, row);
return;
}
switch (event->type) {
case GDK_BUTTON_PRESS:
gtk_clist_unselect_row (GTK_CLIST (panel->list), row, 0);
internal_select_item (file_list, panel, row);
switch (event->button.button) {
case 1:
if (!(event->button.state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
break;
/* fallback if shift-click is pressed */
do_file_mark_range (panel, row, current_selection);
break;
case 2:
do_file_mark (panel, row, !panel->dir.list[row].f.marked);
break;
case 3:
file_popup (&event->button, panel, NULL, row, panel->dir.list[row].fname);
break;
}
break;
case GDK_2BUTTON_PRESS:
gtk_clist_unselect_row (GTK_CLIST (panel->list), row, 0);
if (event->button.button == 1)
do_enter (panel);
break;
default:
break;
}
}
/* Figure out the number of visible lines in the panel */
static void
panel_file_list_compute_lines (GtkCList *file_list, WPanel *panel, int height)
{
int lost_pixels = 0;
if (GTK_WIDGET_VISIBLE (file_list->hscrollbar)){
int scrollbar_width = GTK_WIDGET (file_list->hscrollbar)->requisition.width;
int scrollbar_space = GTK_CLIST_CLASS (GTK_OBJECT (file_list)->klass)->scrollbar_spacing;
lost_pixels = scrollbar_space + scrollbar_width;
}
panel->widget.lines = (height-lost_pixels) /
(GTK_CLIST (file_list)->row_height + CELL_SPACING);
}
static void
panel_file_list_size_allocate_hook (GtkWidget *file_list, GtkAllocation *allocation, WPanel *panel)
{
gtk_signal_handler_block_by_data (GTK_OBJECT (file_list), panel);
panel_file_list_configure_contents (file_list, panel, allocation->width, allocation->height);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (file_list), panel);
panel_file_list_compute_lines (GTK_CLIST (file_list), panel, allocation->height);
}
static void
panel_file_list_column_callback (GtkWidget *widget, int col, WPanel *panel)
{
format_e *format;
int i;
for (i = 0, format = panel->format; format; format = format->next){
if (!format->use_in_gui)
continue;
if (i == col){
sortfn *sorting_routine;
sorting_routine = get_sort_fn (format->id);
if (!sorting_routine)
return;
if (sorting_routine == panel->sort_type)
panel->reverse = !panel->reverse;
panel->sort_type = sorting_routine;
do_re_sort (panel);
return;
}
i++;
}
}
static void
panel_create_pixmaps (GtkWidget *parent)
{
GdkColor color = gtk_widget_get_style (parent)->bg [GTK_STATE_NORMAL];
pixmaps_ready = 1;
icon_directory_pixmap = gdk_pixmap_create_from_xpm_d (parent->window, &icon_directory_mask, &color, directory_xpm);
icon_link_pixmap = gdk_pixmap_create_from_xpm_d (parent->window, &icon_link_mask, &color, link_xpm);
icon_dev_pixmap = gdk_pixmap_create_from_xpm_d (parent->window, &icon_dev_mask, &color, dev_xpm);
}
static void
panel_file_list_scrolled (GtkAdjustment *adj, WPanel *panel)
{
if (!GTK_IS_ADJUSTMENT (adj)) {
fprintf (stderr, "file_list_is_scrolled is called and there are not enough boats!\n");
exit (1);
}
}
static void
panel_configure_file_list (WPanel *panel, GtkWidget *file_list)
{
format_e *format = panel->format;
GtkCList *cl = GTK_CLIST (file_list);
GtkObject *adjustment;
int i;
/* Set sorting callback */
gtk_signal_connect (GTK_OBJECT (file_list), "click_column",
GTK_SIGNAL_FUNC (panel_file_list_column_callback), panel);
/* Configure the CList */
gtk_clist_set_selection_mode (cl, GTK_SELECTION_SINGLE);
gtk_clist_set_policy (cl, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
for (i = 0, format = panel->format; format; format = format->next){
GtkJustification just;
if (!format->use_in_gui)
continue;
/* Set desired justification */
if (format->just_mode == J_LEFT)
just = GTK_JUSTIFY_LEFT;
else
just = GTK_JUSTIFY_RIGHT;
gtk_clist_set_column_justification (cl, i, just);
i++;
}
/* Configure the scrolbars */
adjustment = GTK_OBJECT (gtk_range_get_adjustment (GTK_RANGE (cl->vscrollbar)));
gtk_signal_connect_after (GTK_OBJECT(adjustment), "value_changed",
GTK_SIGNAL_FUNC (panel_file_list_scrolled), panel);
}
static void *
panel_build_selected_file_list (WPanel *panel, int *file_list_len)
{
if (panel->marked){
char *data, *copy;
int i, total_len = 0;
int cwdlen = strlen (panel->cwd) + 1;
/* first pass, compute the length */
for (i = 0; i < panel->count; i++)
if (panel->dir.list [i].f.marked)
total_len += (cwdlen + panel->dir.list [i].fnamelen + 1);
data = copy = xmalloc (total_len, "build_selected_file_list");
for (i = 0; i < panel->count; i++)
if (panel->dir.list [i].f.marked){
strcpy (copy, panel->cwd);
copy [cwdlen-1] = '/';
strcpy (&copy [cwdlen], panel->dir.list [i].fname);
copy += panel->dir.list [i].fnamelen + 1 + cwdlen;
}
*file_list_len = total_len;
return data;
} else {
char *fullname = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
*file_list_len = strlen (fullname) + 1;
return fullname;
}
}
/*
* Handler for text/plain and url:ALL drag types
*
* Sets the drag information to the filenames selected on the panel
*/
static void
panel_transfer_file_names (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel, int *len, char **data)
{
*data = panel_build_selected_file_list (panel, len);
}
/*
* Handler for file:ALL type (target application only understands local pathnames)
*
* Makes local copies of the files and transfers the filenames.
*/
static void
panel_make_local_copies_and_transfer (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel,
int *len, char **data)
{
char *filename, *localname;
int i;
if (panel->marked){
char **local_names_array, *p;
int j, total_len;
/* First assemble all of the filenames */
local_names_array = malloc (sizeof (char *) * panel->marked);
total_len = j = 0;
for (i = 0; i < panel->count; i++){
char *filename;
if (!panel->dir.list [i].f.marked)
continue;
filename = concat_dir_and_file (panel->cwd, panel->dir.list [i].fname);
localname = mc_getlocalcopy (filename);
total_len += strlen (localname) + 1;
local_names_array [j++] = localname;
free (filename);
}
*len = total_len;
*data = p = malloc (total_len);
for (i = 0; i < j; i++){
strcpy (p, local_names_array [i]);
g_free (local_names_array [i]);
p += strlen (p) + 1;
}
} else {
filename = concat_dir_and_file (panel->cwd, panel->dir.list [i].fname);
localname = mc_getlocalcopy (filename);
free (filename);
*data = localname;
*len = strlen (localname + 1);
}
}
static void
panel_drag_request (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel, int *len, char **data)
{
*len = 0;
*data = 0;
if ((strcmp (event->data_type, "text/plain") == 0) ||
(strcmp (event->data_type, "url:ALL") == 0)){
panel_transfer_file_names (widget, event, panel, len, data);
} else if (strcmp (event->data_type, "file:ALL") == 0){
if (vfs_file_is_local (panel->cwd))
panel_transfer_file_names (widget, event, panel, len, data);
else
panel_make_local_copies_and_transfer (widget, event, panel, len, data);
}
}
/*
* Listing mode: drag request handler
*/
static void
panel_clist_drag_request (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel)
{
GdkWindowPrivate *clist_window = (GdkWindowPrivate *) (GTK_WIDGET (widget)->window);
GdkWindowPrivate *clist_areaw = (GdkWindowPrivate *) (GTK_CLIST (widget)->clist_window);
char *data;
int len;
panel_drag_request (widget, event, panel, &len, &data);
/* Now transfer the DnD information */
if (len && data){
if (clist_window->dnd_drag_accepted)
gdk_window_dnd_data_set ((GdkWindow *)clist_window, (GdkEvent *) event, data, len);
else
gdk_window_dnd_data_set ((GdkWindow *)clist_areaw, (GdkEvent *) event, data, len);
free (data);
}
}
/*
* Invoked when a drop has happened on the panel
*/
static void
panel_clist_drop_data_available (GtkWidget *widget, GdkEventDropDataAvailable *data, WPanel *panel)
{
gint winx, winy;
gint dropx, dropy;
gint row;
char *drop_dir;
gdk_window_get_origin (GTK_CLIST (widget)->clist_window, &winx, &winy);
dropx = data->coords.x - winx;
dropy = data->coords.y - winy;
if (dropx < 0 || dropy < 0)
return;
if (gtk_clist_get_selection_info (GTK_CLIST (widget), dropx, dropy, &row, NULL) == 0)
drop_dir = panel->cwd;
else {
g_assert (row < panel->count);
if (S_ISDIR (panel->dir.list [row].buf.st_mode))
drop_dir = concat_dir_and_file (panel->cwd, panel->dir.list [row].fname);
else
drop_dir = panel->cwd;
}
drop_on_directory (data, drop_dir, 0);
if (drop_dir != panel->cwd)
free (drop_dir);
update_one_panel_widget (panel, 0, UP_KEEPSEL);
panel_update_contents (panel);
}
static void
panel_drag_begin (GtkWidget *widget, GdkEvent *event, WPanel *panel)
{
GdkPoint hotspot = { 15, 15 };
if (panel->marked > 1){
if (drag_multiple && drag_multiple_ok){
gdk_dnd_set_drag_shape (drag_multiple->window, &hotspot,
drag_multiple_ok->window, &hotspot);
gtk_widget_show (drag_multiple);
gtk_widget_show (drag_multiple_ok);
}
} else {
if (drag_directory && drag_directory_ok)
gdk_dnd_set_drag_shape (drag_directory->window, &hotspot,
drag_directory_ok->window, &hotspot);
gtk_widget_show (drag_directory_ok);
gtk_widget_show (drag_directory);
}
}
static void
panel_icon_list_drag_begin (GtkWidget *widget, GdkEvent *event, WPanel *panel)
{
GnomeIconList *icons = GNOME_ICON_LIST (panel->icons);
icons->last_clicked = -1;
panel_drag_begin (widget, event, panel);
}
static void
panel_artificial_drag_start (GtkCList *window, GdkEventMotion *event)
{
artificial_drag_start (window->clist_window, event->x, event->y);
}
static GtkWidget *
load_transparent_image (char *base)
{
char *f = concat_dir_and_file (ICONDIR, base);
GtkWidget *w;
w = make_transparent_window (f);
g_free (f);
return w;
}
static void
load_dnd_icons (void)
{
GdkPoint hotspot = { 5, 5 };
if (!drag_directory)
drag_directory = gnome_stock_transparent_window (GNOME_STOCK_PIXMAP_NOT, NULL);
if (!drag_directory_ok)
drag_directory_ok = gnome_stock_transparent_window (GNOME_STOCK_PIXMAP_NEW, NULL);
if (!drag_multiple)
drag_multiple = gnome_stock_transparent_window (GNOME_STOCK_PIXMAP_NOT, NULL);
if (!drag_multiple_ok)
drag_multiple_ok = gnome_stock_transparent_window (GNOME_STOCK_PIXMAP_MULTIPLE, NULL);
if (drag_directory && drag_directory_ok)
gdk_dnd_set_drag_shape (drag_directory->window, &hotspot,
drag_directory_ok->window, &hotspot);
}
/*
* Pixmaps can only be loaded once the window has been realized, so
* this is why this hook is here
*/
static void
panel_realized (GtkWidget *file_list, WPanel *panel)
{
GtkObject *obj = GTK_OBJECT (file_list);
load_dnd_icons ();
/* DND: Drag setup */
gtk_signal_connect (obj, "drag_request_event", GTK_SIGNAL_FUNC (panel_clist_drag_request), panel);
gtk_signal_connect (obj, "drag_begin_event", GTK_SIGNAL_FUNC (panel_drag_begin), panel);
gdk_window_dnd_drag_set (GTK_CLIST (file_list)->clist_window, TRUE, drag_types, ELEMENTS (drag_types));
/* DND: Drop setup */
gtk_signal_connect (obj, "drop_data_available_event", GTK_SIGNAL_FUNC (panel_clist_drop_data_available), panel);
/* Artificial way of getting drag to start without leaving the widget boundary */
gtk_signal_connect (obj, "motion_notify_event",
GTK_SIGNAL_FUNC (panel_artificial_drag_start), panel);
gdk_window_dnd_drop_set (GTK_CLIST (file_list)->clist_window, TRUE, drop_types, ELEMENTS (drop_types), FALSE);
}
/*
* Create, setup the file listing display.
*/
static GtkWidget *
panel_create_file_list (WPanel *panel)
{
const int items = panel->format->items;
format_e *format = panel->format;
GtkWidget *file_list;
GtkCList *clist;
gchar **titles;
int i;
titles = g_new (char *, items);
for (i = 0; i < items; format = format->next)
if (format->use_in_gui)
titles [i++] = format->title;
file_list = gtk_blist_new_with_titles (items, titles);
clist = GTK_CLIST (file_list);
panel_configure_file_list (panel, file_list);
free (titles);
gtk_signal_connect_after (GTK_OBJECT (file_list), "size_allocate",
GTK_SIGNAL_FUNC (panel_file_list_size_allocate_hook),
panel);
gtk_signal_connect (GTK_OBJECT (file_list), "realize",
GTK_SIGNAL_FUNC (panel_realized),
panel);
gtk_signal_connect (GTK_OBJECT (file_list), "select_row",
GTK_SIGNAL_FUNC (panel_file_list_select_row),
panel);
return file_list;
}
/*
* Callback: icon selected
*/
static void
panel_icon_list_select_icon (GtkWidget *widget, int index, GdkEvent *event, WPanel *panel)
{
panel->selected = index;
do_file_mark (panel, index, 1);
display_mini_info (panel);
execute_hooks (select_file_hook);
if (!event)
return;
switch (event->type){
case GDK_BUTTON_PRESS:
if (event->button.button == 3){
file_popup (&event->button, panel, NULL, index, panel->dir.list [index].fname);
return;
}
break;
case GDK_2BUTTON_PRESS:
if (event->button.button == 1)
do_enter (panel);
break;
default:
break;
}
}
static void
panel_icon_list_unselect_icon (GtkWidget *widget, int index, GdkEvent *event, WPanel *panel)
{
do_file_mark (panel, index, 0);
display_mini_info (panel);
if (panel->marked == 0)
panel->selected = 0;
}
static GdkImlibImage *
load_image_icon_view (char *base)
{
GdkImlibImage *im;
char *f = concat_dir_and_file (ICONDIR, base);
im = gdk_imlib_load_image (f);
g_free (f);
return im;
}
void
load_imlib_icons (void)
{
static int loaded;
if (loaded)
return;
icon_view_directory = load_image_icon_view ("i-directory.png");
icon_view_executable = load_image_icon_view ("i-executable.png");
icon_view_symlink = load_image_icon_view ("i-symlink.png");
icon_view_device = load_image_icon_view ("i-device.png");
icon_view_regular = load_image_icon_view ("i-regular.png");
icon_view_core = load_image_icon_view ("i-core.png");
icon_view_sock = load_image_icon_view ("i-sock.png");
loaded = 1;
}
static void
panel_icon_list_artificial_drag_start (GtkObject *obj, GdkEventMotion *event)
{
GnomeIconList *ilist = GNOME_ICON_LIST (obj);
artificial_drag_start (ilist->ilist_window, event->x, event->y);
}
/*
* Icon view drag request handler
*/
static void
panel_icon_list_drag_request (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel)
{
GnomeIconList *ilist = GNOME_ICON_LIST (widget);
char *data;
int len;
panel_drag_request (widget, event, panel, &len, &data);
if (len && data){
gdk_window_dnd_data_set (ilist->ilist_window, (GdkEvent *) event, data, len);
free (data);
}
}
static void
panel_icon_list_drop_data_available (GtkWidget *widget, GdkEventDropDataAvailable *data, WPanel *panel)
{
GnomeIconList *ilist = GNOME_ICON_LIST (widget);
gint winx, winy;
gint dropx, dropy;
gint item;
char *drop_dir;
gdk_window_get_origin (ilist->ilist_window, &winx, &winy);
dropx = data->coords.x - winx;
dropy = data->coords.y - winy;
if (dropx < 0 || dropy < 0)
return;
item = gnome_icon_list_get_icon_at (ilist, dropx, dropy);
if (item == -1)
drop_dir = panel->cwd;
else {
g_assert (item < panel->count);
if (S_ISDIR (panel->dir.list [item].buf.st_mode))
drop_dir = concat_dir_and_file (panel->cwd, panel->dir.list [item].fname);
else
drop_dir = panel->cwd;
}
drop_on_directory (data, drop_dir, 0);
if (drop_dir != panel->cwd)
free (drop_dir);
update_one_panel_widget (panel, 0, UP_KEEPSEL);
panel_update_contents (panel);
}
/*
* Setup for the icon view
*/
static void
panel_icon_list_realized (GtkObject *obj, WPanel *panel)
{
GnomeIconList *icon = GNOME_ICON_LIST (obj);
load_imlib_icons ();
load_dnd_icons ();
/* DND: Drag setup */
gtk_signal_connect (obj, "drag_request_event", GTK_SIGNAL_FUNC (panel_icon_list_drag_request), panel);
gtk_signal_connect (obj, "drag_begin_event", GTK_SIGNAL_FUNC (panel_icon_list_drag_begin), panel);
gdk_window_dnd_drag_set (icon->ilist_window, TRUE, drag_types, ELEMENTS (drag_types));
/* DND: Drop setup */
gtk_signal_connect (obj, "drop_data_available_event",
GTK_SIGNAL_FUNC (panel_icon_list_drop_data_available), panel);
gtk_signal_connect (obj, "motion_notify_event",
GTK_SIGNAL_FUNC (panel_icon_list_artificial_drag_start), panel);
gdk_window_dnd_drop_set (icon->ilist_window, TRUE, drop_types, ELEMENTS (drop_types), FALSE);
}
/*
* Create and setup the icon field display
*/
static GtkWidget *
panel_create_icon_display (WPanel *panel)
{
GnomeIconList *icon_field;
icon_field = GNOME_ICON_LIST (gnome_icon_list_new ());
gnome_icon_list_set_separators (icon_field, " /-_.");
gnome_icon_list_set_selection_mode (icon_field, GTK_SELECTION_MULTIPLE);
gtk_signal_connect (GTK_OBJECT (icon_field), "select_icon",
GTK_SIGNAL_FUNC (panel_icon_list_select_icon), panel);
gtk_signal_connect (GTK_OBJECT (icon_field), "unselect_icon",
GTK_SIGNAL_FUNC (panel_icon_list_unselect_icon), panel);
gtk_signal_connect (GTK_OBJECT (icon_field), "realize",
GTK_SIGNAL_FUNC (panel_icon_list_realized), panel);
return GTK_WIDGET (icon_field);
}
void
panel_switch_new_display_mode (WPanel *panel)
{
GtkWidget *old_list = panel->list;
if (!old_list)
return;
panel->list = panel_create_file_list (panel);
gtk_widget_destroy (old_list);
gtk_table_attach (GTK_TABLE (panel->table), panel->list, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
0, 0);
gtk_widget_show (panel->list);
panel_update_contents (panel);
}
static GtkWidget *
panel_create_cwd (Dlg_head *h, WPanel *panel, void **entry)
{
WInput *in;
in = input_new (0, 0, 0, 10, "", "cwd");
add_widget (h, in);
/* Force the creation of the gtk widget */
send_message_to (h, (Widget *) in, WIDGET_INIT, 0);
*entry = in;
return GTK_WIDGET (in->widget.wdata);
}
/* FIXME: for now, this list is hardcoded. We want a way to let the user configure it. */
static struct filter_item {
char *text;
char *glob;
} filter_items [] = {
{ N_("All files"),
"*" },
{ N_("Archives and compressed files"),
"*.(tar|gz|tgz|taz|zip|lha|zoo|pak|sit|arc|arj|rar|huf|lzh)" },
{ N_("RPM/DEB files"),
"*.(rpm|deb)" },
{ N_("Text/Document files"),
"*.(txt|tex|doc|rtf)" },
{ N_("HTML and SGML files"),
"*.(html|htm|sgml|sgm)" },
{ N_("Postscript and PDF files"),
"*.(ps|pdf)" },
{ N_("Spreadsheet files"),
"*.(xls|wks|wk1)" },
{ N_("Image files"),
"*.(png|jpg|jpeg|xcf|gif|tif|tiff|xbm|xpm|pbm|pgm|ppm|tga|rgb|iff|lbm|ilbm|"
"bmp|pcx|pic|pict|psd|gbr|pat|ico|fig|cgm|rle|fits)" },
{ N_("Video/animation files"),
"*.(mpg|mpeg|mov|avi|fli|flc|flh|flx|dl)" },
{ N_("Audio files"),
"*.(au|wav|mp3|snd|mod|s3m|ra)" },
{ N_("C program files"),
"*.[ch]" },
{ N_("C++ program files"),
"*.(cc|C|cpp|cxx|h|H)" },
{ N_("Objective-C program files"),
"*.[mh]" },
{ N_("Scheme program files"),
"*.scm" },
{ N_("Assembler program files"),
"*.(s|S|asm)" },
{ N_("Misc. program files"),
"*.(awk|sed|lex|l|y|sh|idl|pl|py|am|in|f|el|bas|pas|java|sl|p|m4|tcl|pov)" },
{ N_("Font files"),
"*.(pfa|pfb|afm|ttf|fon|pcf|pcf.gz|spd)" }
};
static GtkWidget *filter_menu;
static void
filter_item_select (GtkWidget *widget, gpointer data)
{
/* FIXME: the hintbar resizes horribly and screws the panel */
#if 0
struct filter_item *fi = gtk_object_get_user_data (GTK_OBJECT (widget));
set_hintbar (easy_patterns ? fi->glob : fi->regexp);
#endif
}
static void
filter_item_deselect (GtkWidget *widget, gpointer data)
{
/* set_hintbar (""); */
}
static void
filter_item_activate (GtkWidget *widget, gpointer data)
{
struct filter_item *fi = gtk_object_get_user_data (GTK_OBJECT (widget));
WPanel *panel = data;
char *pattern;
if (easy_patterns)
pattern = g_strdup (fi->glob);
else {
/* This is sort of a hack to force convert_pattern() to actually convert the thing */
easy_patterns = 1;
pattern = convert_pattern (fi->glob, match_file, 0);
easy_patterns = 0;
}
set_panel_filter_to (panel, pattern);
}
static void
build_filter_menu (WPanel *panel, GtkWidget *button)
{
GtkWidget *item;
int i;
if (filter_menu)
return;
/* FIXME: the filter menu is global, and it is never destroyed */
filter_menu = gtk_menu_new ();
gtk_object_set_user_data (GTK_OBJECT (filter_menu), button);
for (i = 0; i < ELEMENTS (filter_items); i++) {
item = gtk_menu_item_new_with_label (_(filter_items[i].text));
gtk_object_set_user_data (GTK_OBJECT (item), &filter_items[i]);
gtk_signal_connect (GTK_OBJECT (item), "select",
(GtkSignalFunc) filter_item_select,
panel);
gtk_signal_connect (GTK_OBJECT (item), "deselect",
(GtkSignalFunc) filter_item_deselect,
panel);
gtk_signal_connect (GTK_OBJECT (item), "activate",
(GtkSignalFunc) filter_item_activate,
panel);
gtk_widget_show (item);
gtk_menu_append (GTK_MENU (filter_menu), item);
}
}
static void
position_filter_popup (GtkMenu *menu, gint *x, gint *y, gpointer data)
{
int screen_width, screen_height;
GtkWidget *wmenu = GTK_WIDGET (menu);
GtkWidget *button = GTK_WIDGET (data);
/* This code is mostly ripped off from gtkmenu.c - Federico */
screen_width = gdk_screen_width ();
screen_height = gdk_screen_height ();
gdk_window_get_origin (button->window, x, y);
*y += button->allocation.height;
if ((*x + wmenu->requisition.width) > screen_width)
*x -= (*x + wmenu->requisition.width) - screen_width;
if ((*y + wmenu->requisition.height) > screen_height)
*y -= (*y + wmenu->requisition.height) - screen_height;
if (*y < 0)
*y = 0;
}
static void
show_filter_popup (GtkWidget *button, gpointer data)
{
WPanel *panel;
panel = data;
build_filter_menu (panel, button);
gtk_menu_popup (GTK_MENU (filter_menu), NULL, NULL,
position_filter_popup,
button,
1,
GDK_CURRENT_TIME);
}
void
display_mini_info (WPanel *panel)
{
GtkLabel *label = GTK_LABEL (panel->ministatus);
if (panel->searching){
char *str = copy_strings (N_("Search: "), panel->search_buffer, NULL);
gtk_clip_label_set (label, str);
free (str);
return;
}
if (panel->marked){
char buffer [120];
sprintf (buffer, N_(" %s bytes in %d file%s"),
size_trunc_sep (panel->total), panel->marked,
panel->marked == 1 ? "" : "s");
gtk_clip_label_set (label, buffer);
return;
}
if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)){
char *link, link_target [MC_MAXPATHLEN];
int len;
link = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
len = mc_readlink (link, link_target, MC_MAXPATHLEN);
free (link);
if (len > 0){
char *str;
link_target [len] = 0;
str = copy_strings ("-> ", link_target, NULL);
gtk_clip_label_set (label, str);
free (str);
} else
gtk_clip_label_set (label, N_("<readlink failed>"));
return;
}
if (panel->estimated_total){
int len = panel->estimated_total;
char *buffer;
buffer = xmalloc (len + 2, "display_mini_info");
format_file (buffer, panel, panel->selected, panel->estimated_total-2, 0, 1);
buffer [len] = 0;
gtk_clip_label_set (label, buffer);
free (buffer);
}
if (panel->list_type == list_icons){
if (panel->marked == 0){
gtk_clip_label_set (label, "");
}
}
}
static GtkWidget *
panel_create_filter (Dlg_head *h, WPanel *panel, void **filter_w)
{
GtkWidget *fhbox;
GtkWidget *button;
GtkWidget *arrow;
GtkWidget *label;
GtkWidget *ihbox;
WInput *in;
fhbox = gtk_hbox_new (FALSE, 0);
/* Filter popup button */
button = gtk_button_new ();
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) show_filter_popup,
panel);
GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
gtk_box_pack_start (GTK_BOX (fhbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
ihbox = gtk_hbox_new (FALSE, 3);
gtk_container_add (GTK_CONTAINER (button), ihbox);
gtk_widget_show (ihbox);
arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
gtk_box_pack_start (GTK_BOX (ihbox), arrow, TRUE, TRUE, 0);
gtk_widget_show (arrow);
label = gtk_label_new (N_("Filter"));
gtk_box_pack_start (GTK_BOX (ihbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
/* Filter input line */
in = input_new (0, 0, 0, 10, "", "filter");
add_widget (h, in);
/* Force the creation of the gtk widget */
send_message_to (h, (Widget *) in, WIDGET_INIT, 0);
*filter_w = in;
gtk_box_pack_start (GTK_BOX (fhbox), GTK_WIDGET (in->widget.wdata), TRUE, TRUE, 0);
return fhbox;
}
static void
panel_back (GtkWidget *button, WPanel *panel)
{
directory_history_prev (panel);
}
static void
panel_fwd (GtkWidget *button, WPanel *panel)
{
directory_history_next (panel);
}
static void
panel_up (GtkWidget *button, WPanel *panel)
{
do_panel_cd (panel, "..", cd_exact);
}
static GtkWidget *
button_switch_to (char **icon, GtkSignalFunc fn, void *closure)
{
GtkWidget *button, *pix;
button = gtk_button_new ();
pix = gnome_pixmap_new_from_xpm_d (icon);
gtk_container_add (GTK_CONTAINER (button), pix);
gtk_signal_connect (GTK_OBJECT (button), "clicked", fn, closure);
return button;
}
static void
do_switch_to_iconic (GtkWidget *widget, WPanel *panel)
{
if (panel->list_type == list_icons)
return;
panel->list_type = list_icons;
set_panel_formats (panel);
paint_panel (panel);
do_refresh ();
}
static void
do_switch_to_listing (GtkWidget *widget, WPanel *panel)
{
if (panel->list_type != list_icons)
return;
panel->list_type = list_full;
set_panel_formats (panel);
paint_panel (panel);
do_refresh ();
}
static GtkWidget *
button_switch_to_icon (WPanel *panel)
{
return button_switch_to (listing_iconic_xpm, GTK_SIGNAL_FUNC (do_switch_to_iconic), panel);
}
static GtkWidget *
button_switch_to_listing (WPanel *panel)
{
return button_switch_to (listing_list_xpm, GTK_SIGNAL_FUNC (do_switch_to_listing), panel);
}
void
x_create_panel (Dlg_head *h, widget_data parent, WPanel *panel)
{
GtkWidget *status_line, *filter, *vbox;
GtkWidget *frame, *cwd, *back_p, *fwd_p;
GtkWidget *display;
panel->xwindow = gtk_widget_get_toplevel (GTK_WIDGET (panel->widget.wdata));
panel->table = gtk_table_new (2, 1, 0);
panel->icons = panel_create_icon_display (panel);
panel->list = panel_create_file_list (panel);
gtk_widget_ref (panel->icons);
gtk_widget_ref (panel->list);
if (panel->list_type == list_icons)
display = panel->icons;
else
display = panel->list;
filter = panel_create_filter (h, panel, &panel->filter_w);
cwd = panel_create_cwd (h, panel, &panel->current_dir);
/* We do not want the focus by default (and the previos add_widget just gave it to us) */
h->current = h->current->prev;
/* buttons */
back_p = gnome_stock_pixmap_widget_new (panel->xwindow, GNOME_STOCK_MENU_BACK);
fwd_p = gnome_stock_pixmap_widget_new (panel->xwindow, GNOME_STOCK_MENU_FORWARD);
panel->up_b = gtk_button_new_with_label ("up");
panel->back_b = gtk_button_new ();
panel->fwd_b = gtk_button_new ();
gtk_container_add (GTK_CONTAINER (panel->back_b), back_p);
gtk_container_add (GTK_CONTAINER (panel->fwd_b), fwd_p);
gtk_signal_connect (GTK_OBJECT (panel->back_b), "clicked", GTK_SIGNAL_FUNC(panel_back), panel);
gtk_signal_connect (GTK_OBJECT (panel->fwd_b), "clicked", GTK_SIGNAL_FUNC(panel_fwd), panel);
gtk_signal_connect (GTK_OBJECT (panel->up_b), "clicked", GTK_SIGNAL_FUNC(panel_up), panel);
panel_update_marks (panel);
/* ministatus */
panel->ministatus = gtk_clip_label_new ("");
gtk_misc_set_alignment (GTK_MISC (panel->ministatus), 0.0, 0.0);
gtk_misc_set_padding (GTK_MISC (panel->ministatus), 3, 0);
gtk_widget_show (panel->ministatus);
status_line = gtk_hbox_new (0, 0);
gtk_container_border_width (GTK_CONTAINER (status_line), 3);
gtk_label_set_justify (GTK_LABEL (panel->ministatus), GTK_JUSTIFY_LEFT);
gtk_box_pack_start (GTK_BOX (status_line), panel->back_b, 0, 0, 2);
gtk_box_pack_start (GTK_BOX (status_line), panel->up_b, 0, 0, 2);
gtk_box_pack_start (GTK_BOX (status_line), panel->fwd_b, 0, 0, 2);
gtk_box_pack_start (GTK_BOX (status_line), cwd, 1, 1, 5);
gtk_box_pack_start (GTK_BOX (status_line), button_switch_to_icon (panel), 0, 0, 2);
gtk_box_pack_start (GTK_BOX (status_line), button_switch_to_listing (panel), 0, 0, 2);
#if 0
/* Remove the filter for now, until I add another toolbar */
gtk_box_pack_end (GTK_BOX (status_line), filter, 0, 0, 0);
#endif
gtk_widget_show_all (status_line);
/* The statusbar */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_container_border_width (GTK_CONTAINER (frame), 3);
panel->status = gtk_clip_label_new ("");
gtk_misc_set_alignment (GTK_MISC (panel->status), 0.0, 0.5);
gtk_misc_set_padding (GTK_MISC (panel->status), 3, 0);
gtk_container_add (GTK_CONTAINER (frame), panel->status);
gtk_label_set_justify (GTK_LABEL (panel->status), GTK_JUSTIFY_LEFT);
gtk_widget_show_all (frame);
/* Add both the icon view and the listing view */
gtk_table_attach (GTK_TABLE (panel->table), panel->icons, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
0, 0);
gtk_table_attach (GTK_TABLE (panel->table), panel->list, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
0, 0);
gtk_widget_show (display);
gtk_table_attach (GTK_TABLE (panel->table), status_line, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
gtk_table_attach (GTK_TABLE (panel->table), panel->ministatus, 0, 1, 2, 3,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
0, 0, 0);
gtk_table_attach (GTK_TABLE (panel->table), frame, 0, 1, 3, 4,
GTK_EXPAND | GTK_FILL,
0, 0, 0);
/* Ultra nasty hack: pull the vbox from wdata */
vbox = GTK_WIDGET (panel->widget.wdata);
panel->widget.wdata = (widget_data) panel->table;
/* Now, insert our table in our parent */
gtk_container_add (GTK_CONTAINER (vbox), panel->table);
gtk_widget_show (vbox);
gtk_widget_show (panel->table);
if (!(panel->widget.options & W_PANEL_HIDDEN))
gtk_widget_show (gtk_widget_get_toplevel (panel->table));
/* This is a bug workaround for the icon list, as the icon */
gtk_widget_queue_resize (panel->icons);
if (!pixmaps_ready){
if (!GTK_WIDGET_REALIZED (panel->list))
gtk_widget_realize (panel->list);
panel_create_pixmaps (panel->list);
}
/* In GNOME the panel wants to have the cursor, to avoid "auto" focusing the
* filter input line
*/
panel->widget.options |= W_WANT_CURSOR;
panel->estimated_total = 0;
}
void
panel_update_cols (Widget *panel, int frame_size)
{
panel->cols = 60;
panel->lines = 20;
}
char *
get_nth_panel_name (int num)
{
static char buffer [20];
if (!num)
return "New Left Panel";
else if (num == 1)
return "New Right Panel";
else {
sprintf (buffer, "%ith Panel", num);
return buffer;
}
}
void
load_hint (void)
{
char *hint;
if ((hint = get_random_hint ())){
if (*hint)
set_hintbar (hint);
free (hint);
} else
set_hintbar ("The GNOME File Manager " VERSION);
}
void
paint_frame (WPanel *panel)
{
}
void
x_reset_sort_labels (WPanel *panel)
{
if (panel->list_type == list_icons){
if (panel->icons)
gtk_widget_show (panel->icons);
if (panel->list)
gtk_widget_hide (panel->list);
} else {
panel_switch_new_display_mode (panel);
if (panel->list)
gtk_widget_show (panel->list);
if (panel->icons)
gtk_widget_hide (panel->icons);
}
}
/* Releases all of the X resources allocated */
void
x_panel_destroy (WPanel *panel)
{
gtk_widget_destroy (GTK_WIDGET (panel->xwindow));
}