4a3609a4f7
* gtkdtree.c (gtk_dtree_class_init): Sigh. Create a new signal, called "possibly_ungrab", used to request the client to ungrab the mouse at the proper time. This is required because the stupid clist button press handler grabs the mouse, and we don't want that. (gtk_dtree_select_row): Emit the possibly_ungrab signal here. * gscreen.c (panel_tree_drag_motion): Set the panel->drag_tree_dragging_over flag. (panel_tree_drag_leave): Unset said flag. (panel_tree_possibly_ungrab): Ungrab the mouse here.
2631 строка
66 KiB
C
2631 строка
66 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 "x.h"
|
|
#include "util.h"
|
|
#include "global.h"
|
|
#include "dir.h"
|
|
#include "command.h"
|
|
#include "panel.h"
|
|
#define WANT_WIDGETS /* bleah */
|
|
#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 "setup.h"
|
|
#include "file.h"
|
|
#include "fileopctx.h"
|
|
#include "gdesktop.h"
|
|
#include "gdnd.h"
|
|
#include "gtkdtree.h"
|
|
#include "gpageprop.h"
|
|
#include "gpopup.h"
|
|
#include "gcmd.h"
|
|
#include "gcliplabel.h"
|
|
#include "gicon.h"
|
|
#include "gtkflist.h"
|
|
#include "../vfs/vfs.h"
|
|
#include <gdk/gdkprivate.h>
|
|
|
|
#ifndef MAX
|
|
# define MAX(a,b) ((a) > (b) ? a : b)
|
|
#endif
|
|
|
|
/* Whether to display the tree view on the left */
|
|
int tree_panel_visible = -1;
|
|
|
|
/* The pixmaps */
|
|
#include "dir-close.xpm"
|
|
#include "link.xpm"
|
|
#include "dev.xpm"
|
|
|
|
/* Timeout for auto-scroll on drag */
|
|
#define SCROLL_TIMEOUT 100
|
|
|
|
/* Timeout for opening a tree branch on drag */
|
|
#define TREE_OPEN_TIMEOUT 1000
|
|
|
|
/* 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;
|
|
|
|
static GtkTargetEntry drag_types [] = {
|
|
{ TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST },
|
|
{ TARGET_TEXT_PLAIN_TYPE, 0, TARGET_TEXT_PLAIN },
|
|
{ TARGET_URL_TYPE, 0, TARGET_URL }
|
|
};
|
|
|
|
static GtkTargetEntry drop_types [] = {
|
|
{ TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST },
|
|
{ TARGET_URL_TYPE, 0, TARGET_URL }
|
|
};
|
|
|
|
#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;
|
|
|
|
static void file_list_popup (GdkEventButton *event, WPanel *panel);
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void
|
|
panel_cancel_drag_scroll (WPanel *panel)
|
|
{
|
|
g_return_if_fail (panel != NULL);
|
|
|
|
if (panel->timer_id != -1){
|
|
gtk_timeout_remove (panel->timer_id);
|
|
panel->timer_id = -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
static GtkAdjustment *
|
|
scrolled_window_get_vadjustment (GtkScrolledWindow *sw)
|
|
{
|
|
GtkRange *vsb = GTK_RANGE (sw->vscrollbar);
|
|
GtkAdjustment *va = vsb->adjustment;
|
|
|
|
return va;
|
|
}
|
|
|
|
/*
|
|
* 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 = CLIST_FROM_SW (panel->list);
|
|
int i, col, type_col, color;
|
|
char **texts;
|
|
|
|
texts = g_new (char *, items+1);
|
|
|
|
gtk_clist_freeze (GTK_CLIST (cl));
|
|
gtk_clist_clear (GTK_CLIST (cl));
|
|
|
|
/* which column holds the type information */
|
|
type_col = -1;
|
|
|
|
g_assert (items == cl->columns);
|
|
|
|
texts [items] = NULL;
|
|
for (i = 0; i < top; i++){
|
|
file_entry *fe = &panel->dir.list [i];
|
|
format_e *format = panel->format;
|
|
int n;
|
|
|
|
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++;
|
|
}
|
|
|
|
n = gtk_clist_append (cl, texts);
|
|
|
|
/* Do not let the user select .. */
|
|
if (strcmp (fe->fname, "..") == 0)
|
|
gtk_clist_set_selectable (cl, n, FALSE);
|
|
|
|
color = file_compute_color (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);
|
|
|
|
if (fe->f.marked)
|
|
gtk_clist_select_row (cl, i, 0);
|
|
else
|
|
gtk_clist_unselect_row (cl, i, 0);
|
|
|
|
}
|
|
|
|
g_free (texts);
|
|
|
|
/* This is needed as the gtk_clist_append changes selected under us :-( */
|
|
panel->selected = selected;
|
|
|
|
gtk_clist_thaw (GTK_CLIST (cl));
|
|
}
|
|
|
|
/*
|
|
* Icon view: load the panel contents
|
|
*/
|
|
static void
|
|
panel_fill_panel_icons (WPanel *panel)
|
|
{
|
|
const int top = panel->count;
|
|
const int selected = panel->selected;
|
|
GnomeIconList *icons = ILIST_FROM_SW (panel->icons);
|
|
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];
|
|
int p;
|
|
|
|
image = gicon_get_icon_for_file (panel->cwd, fe, TRUE);
|
|
p = gnome_icon_list_append_imlib (icons, image, fe->fname);
|
|
|
|
if (fe->f.marked)
|
|
gnome_icon_list_select_icon (icons, p);
|
|
else
|
|
gnome_icon_list_unselect_icon (icons, p);
|
|
}
|
|
|
|
/* This is needed as the gtk_gnome_icon_list_append_imlib changes selected under us :-( */
|
|
panel->selected = selected;
|
|
|
|
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);
|
|
|
|
gtk_signal_handler_block_by_data (GTK_OBJECT (panel->tree), panel);
|
|
|
|
if (vfs_current_is_local ()){
|
|
char buffer [MC_MAXPATHLEN];
|
|
|
|
get_current_wd (buffer, sizeof (buffer)-1);
|
|
gtk_dtree_select_dir (GTK_DTREE (panel->tree), buffer);
|
|
} else
|
|
gtk_dtree_select_dir (GTK_DTREE (panel->tree), panel->cwd);
|
|
|
|
gtk_signal_handler_unblock_by_data (GTK_OBJECT (panel->tree), 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 (NORMAL, &panel->dir.list[index]);
|
|
panel_file_list_set_row_colors (CLIST_FROM_SW (panel->list), index, color);
|
|
}
|
|
|
|
void
|
|
x_select_item (WPanel *panel)
|
|
{
|
|
if (is_a_desktop_panel (panel))
|
|
return;
|
|
|
|
do_file_mark (panel, panel->selected, 1);
|
|
display_mini_info (panel);
|
|
|
|
if (panel->list_type == list_icons) {
|
|
GnomeIconList *list = ILIST_FROM_SW (panel->icons);
|
|
|
|
gnome_icon_list_select_icon (list, panel->selected);
|
|
if (GTK_WIDGET (list)->allocation.x != -1)
|
|
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 = CLIST_FROM_SW (panel->list);
|
|
|
|
gtk_clist_select_row (clist, panel->selected, 0);
|
|
|
|
/* 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)
|
|
{
|
|
int selected = panel->selected;
|
|
|
|
if (panel->list_type == list_icons)
|
|
gnome_icon_list_unselect_all (ILIST_FROM_SW (panel->icons), NULL, NULL);
|
|
else
|
|
gtk_clist_unselect_all (CLIST_FROM_SW (panel->list));
|
|
|
|
panel->selected = selected;
|
|
}
|
|
|
|
void
|
|
x_filter_changed (WPanel *panel)
|
|
{
|
|
}
|
|
|
|
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 *sw, WPanel *panel, int main_width, int height)
|
|
{
|
|
GtkCList *clist;
|
|
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;
|
|
char_width = gdk_string_width (sw->style->font, "xW") / 2;
|
|
for (format = panel->format; format; format = format->next) {
|
|
format->field_len = format->requested_field_len;
|
|
if (!format->use_in_gui)
|
|
continue;
|
|
|
|
if (format->use_in_gui == 2)
|
|
used_columns += 2;
|
|
else
|
|
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_SCROLLED_WINDOW (sw)->vscrollbar)) {
|
|
int scrollbar_width = GTK_WIDGET (GTK_SCROLLED_WINDOW (sw)->vscrollbar)->requisition.width;
|
|
int scrollbar_space = GTK_SCROLLED_WINDOW_CLASS (GTK_OBJECT (sw)->klass)->scrollbar_spacing;
|
|
|
|
lost_pixels += scrollbar_space + scrollbar_width;
|
|
}
|
|
|
|
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 && expandables > 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;
|
|
|
|
clist = CLIST_FROM_SW (sw);
|
|
|
|
gtk_clist_freeze (clist);
|
|
|
|
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 (clist, i, format->field_len * char_width);
|
|
i++;
|
|
}
|
|
|
|
gtk_clist_thaw (clist);
|
|
}
|
|
|
|
static void
|
|
panel_file_list_select_row (GtkWidget *file_list, gint row, gint column,
|
|
GdkEvent *event, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
|
|
panel->selected = row;
|
|
do_file_mark (panel, row, 1);
|
|
display_mini_info (panel);
|
|
execute_hooks (select_file_hook);
|
|
}
|
|
|
|
static void
|
|
panel_file_list_unselect_row (GtkWidget *widget, int row, int columns, GdkEvent *event, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
do_file_mark (panel, row, 0);
|
|
display_mini_info (panel);
|
|
|
|
if (panel->marked == 0)
|
|
panel->selected = 0;
|
|
}
|
|
|
|
/* Figure out the number of visible lines in the panel */
|
|
static void
|
|
panel_file_list_compute_lines (GtkScrolledWindow *sw, WPanel *panel, int height)
|
|
{
|
|
int lost_pixels = 0;
|
|
if (GTK_WIDGET_VISIBLE (sw->hscrollbar)) {
|
|
int scrollbar_width = GTK_WIDGET (sw->hscrollbar)->requisition.width;
|
|
int scrollbar_space = GTK_SCROLLED_WINDOW_CLASS (GTK_OBJECT (sw)->klass)->scrollbar_spacing;
|
|
|
|
lost_pixels = scrollbar_space + scrollbar_width;
|
|
}
|
|
panel->widget.lines = (height-lost_pixels) / (CLIST_FROM_SW (sw)->row_height + CELL_SPACING);
|
|
}
|
|
|
|
static void
|
|
panel_file_list_size_allocate_hook (GtkWidget *sw, GtkAllocation *allocation, WPanel *panel)
|
|
{
|
|
gtk_signal_handler_block_by_data (GTK_OBJECT (sw), panel);
|
|
panel_file_list_configure_contents (sw, panel, allocation->width, allocation->height);
|
|
gtk_signal_handler_unblock_by_data (GTK_OBJECT (sw), panel);
|
|
|
|
panel_file_list_compute_lines (GTK_SCROLLED_WINDOW (sw), 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++;
|
|
}
|
|
}
|
|
|
|
/* Convenience function to load a pixmap and mask from xpm data */
|
|
static void
|
|
create_pixmap (char **data, GdkPixmap **pixmap, GdkBitmap **mask)
|
|
{
|
|
GdkImlibImage *im;
|
|
|
|
im = gdk_imlib_create_image_from_xpm_data (data);
|
|
gdk_imlib_render (im, im->rgb_width, im->rgb_height);
|
|
*pixmap = gdk_imlib_copy_image (im);
|
|
*mask = gdk_imlib_copy_mask (im);
|
|
gdk_imlib_destroy_image (im);
|
|
}
|
|
|
|
static void
|
|
panel_create_pixmaps (void)
|
|
{
|
|
pixmaps_ready = TRUE;
|
|
|
|
create_pixmap (DIRECTORY_CLOSE_XPM, &icon_directory_pixmap, &icon_directory_mask);
|
|
create_pixmap (link_xpm, &icon_link_pixmap, &icon_link_mask);
|
|
create_pixmap (dev_xpm, &icon_dev_pixmap, &icon_dev_mask);
|
|
}
|
|
|
|
typedef gboolean (*desirable_fn)(WPanel *p, int x, int y);
|
|
typedef gboolean (*scroll_fn)(gpointer data);
|
|
|
|
/* Sets up a timer to scroll a panel component when something is being dragged
|
|
* over it. The `desirable' function should return whether it is desirable to
|
|
* scroll at the specified coordinates; and the `scroll' function should
|
|
* actually scroll the view.
|
|
*/
|
|
static void
|
|
panel_setup_drag_scroll (WPanel *panel, int x, int y, desirable_fn desirable, scroll_fn scroll)
|
|
{
|
|
panel_cancel_drag_scroll (panel);
|
|
|
|
panel->drag_motion_x = x;
|
|
panel->drag_motion_y = y;
|
|
|
|
if ((* desirable) (panel, x, y))
|
|
panel->timer_id = gtk_timeout_add (SCROLL_TIMEOUT, scroll, panel);
|
|
}
|
|
|
|
static void
|
|
panel_file_list_configure (WPanel *panel, GtkWidget *sw, GtkWidget *file_list)
|
|
{
|
|
format_e *format = panel->format;
|
|
int i;
|
|
|
|
/* Set sorting callback */
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "click_column",
|
|
GTK_SIGNAL_FUNC (panel_file_list_column_callback), panel);
|
|
|
|
/* Avoid clist's broken focusing behavior */
|
|
GTK_WIDGET_UNSET_FLAGS (file_list, GTK_CAN_FOCUS);
|
|
|
|
/* Semi-sane selection mode */
|
|
gtk_clist_set_selection_mode (GTK_CLIST (file_list), GTK_SELECTION_EXTENDED);
|
|
|
|
for (i = 0, format = panel->format; format; format = format->next) {
|
|
GtkJustification just = GTK_JUSTIFY_LEFT;
|
|
|
|
if (!format->use_in_gui)
|
|
continue;
|
|
|
|
/* Set desired justification */
|
|
switch (HIDE_FIT (format->just_mode)) {
|
|
case J_LEFT:
|
|
just = GTK_JUSTIFY_LEFT;
|
|
break;
|
|
|
|
case J_RIGHT:
|
|
just = GTK_JUSTIFY_RIGHT;
|
|
break;
|
|
|
|
case J_CENTER:
|
|
just = GTK_JUSTIFY_CENTER;
|
|
break;
|
|
}
|
|
|
|
gtk_clist_set_column_justification (GTK_CLIST (file_list), i, just);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/* Creates an URI list to be transferred during a drop operation */
|
|
static char *
|
|
panel_build_selected_file_list (WPanel *panel, int *file_list_len)
|
|
{
|
|
if (panel->marked){
|
|
char *sep = "\r\n";
|
|
char *data, *copy;
|
|
int i, total_len;
|
|
int cwdlen = strlen (panel->cwd) + 1;
|
|
int filelen = strlen ("file:");
|
|
int seplen = strlen ("\r\n");
|
|
|
|
/* first pass, compute the length */
|
|
total_len = 0;
|
|
for (i = 0; i < panel->count; i++)
|
|
if (panel->dir.list [i].f.marked)
|
|
total_len += (filelen + cwdlen
|
|
+ panel->dir.list [i].fnamelen
|
|
+ seplen);
|
|
|
|
total_len++;
|
|
data = copy = g_malloc (total_len+1);
|
|
for (i = 0; i < panel->count; i++)
|
|
if (panel->dir.list [i].f.marked){
|
|
strcpy (copy, "file:");
|
|
strcpy (© [filelen], panel->cwd);
|
|
copy [filelen+cwdlen-1] = '/';
|
|
strcpy (© [filelen + cwdlen], panel->dir.list [i].fname);
|
|
strcpy (© [filelen + cwdlen + panel->dir.list [i].fnamelen], sep);
|
|
copy += filelen + cwdlen + panel->dir.list [i].fnamelen + seplen;
|
|
}
|
|
data [total_len] = 0;
|
|
*file_list_len = total_len;
|
|
return data;
|
|
} else {
|
|
char *fullname, *uri;
|
|
|
|
fullname = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
|
|
|
|
uri = g_strconcat ("file:", fullname, NULL);
|
|
g_free (fullname);
|
|
|
|
*file_list_len = strlen (uri) + 1;
|
|
return uri;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* panel_drag_data_get:
|
|
*
|
|
* Invoked when a drag operation has been performed, this routine
|
|
* provides the data to be transfered
|
|
*/
|
|
static void
|
|
panel_drag_data_get (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
GtkSelectionData *selection_data,
|
|
guint info,
|
|
guint32 time,
|
|
WPanel *panel)
|
|
{
|
|
int len;
|
|
char *data;
|
|
GList *files;
|
|
|
|
panel_cancel_drag_scroll (panel);
|
|
data = panel_build_selected_file_list (panel, &len);
|
|
|
|
switch (info){
|
|
case TARGET_URI_LIST:
|
|
case TARGET_TEXT_PLAIN:
|
|
gtk_selection_data_set (selection_data, selection_data->target, 8, data, len);
|
|
break;
|
|
|
|
case TARGET_URL:
|
|
files = gnome_uri_list_extract_uris (data);
|
|
if (files) {
|
|
gtk_selection_data_set (selection_data,
|
|
selection_data->target,
|
|
8,
|
|
files->data,
|
|
strlen (files->data));
|
|
}
|
|
gnome_uri_list_free_strings (files);
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
g_free (data);
|
|
}
|
|
|
|
/**
|
|
* panel_drag_data_delete:
|
|
*
|
|
* Invoked when the destination requests the information to be deleted
|
|
* possibly because the operation was MOVE.
|
|
*/
|
|
static void
|
|
panel_drag_data_delete (GtkWidget *widget, GdkDragContext *context, WPanel *panel)
|
|
{
|
|
/* Things is: The File manager already handles file moving */
|
|
}
|
|
|
|
/* Performs a drop on a panel. If idx is -1, then drops on the panel's cwd
|
|
* itself.
|
|
*/
|
|
static void
|
|
drop_on_panel (WPanel *panel, int idx, GdkDragContext *context, GtkSelectionData *selection_data)
|
|
{
|
|
char *file;
|
|
file_entry *fe;
|
|
int drop_on_dir;
|
|
int reload;
|
|
|
|
g_assert (panel != NULL);
|
|
g_assert (idx == -1 || idx < panel->count);
|
|
g_assert (context != NULL);
|
|
g_assert (selection_data != NULL);
|
|
|
|
drop_on_dir = FALSE;
|
|
|
|
if (idx == -1)
|
|
drop_on_dir = TRUE;
|
|
else {
|
|
fe = &panel->dir.list[idx];
|
|
file = g_concat_dir_and_file (panel->cwd, fe->fname);
|
|
|
|
if (!((S_ISDIR (fe->buf.st_mode) || fe->f.link_to_dir)
|
|
|| gdnd_can_drop_on_file (file, fe))) {
|
|
g_free (file);
|
|
drop_on_dir = TRUE;
|
|
}
|
|
}
|
|
|
|
if (drop_on_dir) {
|
|
file = panel->cwd;
|
|
fe = file_entry_from_file (file);
|
|
if (!fe)
|
|
return; /* eeeek */
|
|
}
|
|
|
|
reload = gdnd_perform_drop (context, selection_data, file, fe);
|
|
|
|
if (file != panel->cwd)
|
|
g_free (file);
|
|
|
|
if (drop_on_dir)
|
|
file_entry_free (fe);
|
|
|
|
if (reload) {
|
|
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
|
|
repaint_screen ();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* panel_icon_list_drag_data_received:
|
|
*
|
|
* Invoked on the target side of a Drag and Drop operation when data has been
|
|
* dropped.
|
|
*/
|
|
static void
|
|
panel_icon_list_drag_data_received (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *selection_data,
|
|
guint info,
|
|
guint32 time,
|
|
WPanel *panel)
|
|
{
|
|
int idx;
|
|
|
|
idx = gnome_icon_list_get_icon_at (GNOME_ICON_LIST (widget), x, y);
|
|
drop_on_panel (panel, idx, context, selection_data);
|
|
}
|
|
|
|
/**
|
|
* panel_clist_drag_data_received:
|
|
*
|
|
* Invoked on the target side of a Drag and Drop operation when data has been
|
|
* dropped.
|
|
*/
|
|
static void
|
|
panel_clist_drag_data_received (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *selection_data,
|
|
guint info,
|
|
guint32 time,
|
|
WPanel *panel)
|
|
{
|
|
GtkCList *clist;
|
|
int row;
|
|
|
|
clist = GTK_CLIST (widget);
|
|
|
|
/* Normalize the y coordinate to the clist_window */
|
|
|
|
y -= (GTK_CONTAINER (clist)->border_width
|
|
+ clist->column_title_area.y
|
|
+ clist->column_title_area.height);
|
|
|
|
if (gtk_clist_get_selection_info (GTK_CLIST (widget), x, y, &row, NULL) == 0)
|
|
row = -1;
|
|
|
|
drop_on_panel (panel, row, context, selection_data);
|
|
}
|
|
|
|
/**
|
|
* panel_tree_drag_data_received:
|
|
*
|
|
* Invoked on the target side when a drop has been received in the Tree
|
|
*/
|
|
static void
|
|
panel_tree_drag_data_received (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *selection_data,
|
|
guint info,
|
|
guint32 time,
|
|
WPanel *panel)
|
|
{
|
|
GtkDTree *dtree = GTK_DTREE (widget);
|
|
GtkCTreeNode *node;
|
|
int row, col;
|
|
file_entry *fe;
|
|
char *path;
|
|
int reload;
|
|
|
|
if (!gtk_clist_get_selection_info (GTK_CLIST (dtree), x, y, &row, &col))
|
|
return;
|
|
|
|
node = gtk_ctree_node_nth (GTK_CTREE (dtree), row);
|
|
if (!node)
|
|
return;
|
|
|
|
path = gtk_dtree_get_row_path (dtree, node, 0);
|
|
fe = file_entry_from_file (path);
|
|
if (!fe) {
|
|
g_free (path);
|
|
return; /* eeeek */
|
|
}
|
|
|
|
reload = gdnd_perform_drop (context, selection_data, path, fe);
|
|
|
|
file_entry_free (fe);
|
|
g_free (path);
|
|
|
|
if (reload) {
|
|
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
|
|
repaint_screen ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
load_dnd_icons (void)
|
|
{
|
|
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);
|
|
}
|
|
|
|
/* Convenience function to start a drag operation for the icon and file lists */
|
|
static void
|
|
start_drag (GtkWidget *widget, int button, GdkEvent *event)
|
|
{
|
|
GtkTargetList *list;
|
|
GdkDragContext *context;
|
|
|
|
list = gtk_target_list_new (drag_types, ELEMENTS (drag_types));
|
|
|
|
context = gtk_drag_begin (widget, list,
|
|
(GDK_ACTION_COPY | GDK_ACTION_MOVE
|
|
| GDK_ACTION_LINK | GDK_ACTION_ASK),
|
|
button, event);
|
|
gtk_drag_set_icon_default (context);
|
|
}
|
|
|
|
static int
|
|
panel_widget_motion (GtkWidget *widget, GdkEventMotion *event, WPanel *panel)
|
|
{
|
|
if (!panel->maybe_start_drag)
|
|
return FALSE;
|
|
|
|
if (!((panel->maybe_start_drag == 1 && (event->state & GDK_BUTTON1_MASK))
|
|
|| (panel->maybe_start_drag == 2 && (event->state & GDK_BUTTON2_MASK))))
|
|
return FALSE;
|
|
|
|
/* This is the same threshold value that is used in gtkdnd.c */
|
|
|
|
if (MAX (abs (panel->click_x - event->x),
|
|
abs (panel->click_y - event->y)) <= 3)
|
|
return FALSE;
|
|
|
|
start_drag (widget, panel->maybe_start_drag, (GdkEvent *) event);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* panel_drag_begin:
|
|
*
|
|
* Invoked when a drag is starting in the List view or the Icon view
|
|
*/
|
|
static void
|
|
panel_drag_begin (GtkWidget *widget, GdkDragContext *context, WPanel *panel)
|
|
{
|
|
panel->dragging = 1;
|
|
}
|
|
|
|
/**
|
|
* panel_drag_end:
|
|
*
|
|
* Invoked when a drag has finished in the List view or the Icon view
|
|
*/
|
|
static void
|
|
panel_drag_end (GtkWidget *widget, GdkDragContext *context, WPanel *panel)
|
|
{
|
|
panel_cancel_drag_scroll (panel);
|
|
panel->dragging = 0;
|
|
}
|
|
|
|
/**
|
|
* panel_clist_scrolling_is_desirable:
|
|
*
|
|
* If the cursor is in a position close to either edge (top or bottom)
|
|
* and there is possible to scroll the window, this routine returns
|
|
* true.
|
|
*/
|
|
static gboolean
|
|
panel_clist_scrolling_is_desirable (WPanel *panel, int x, int y)
|
|
{
|
|
GtkAdjustment *va;
|
|
|
|
va = scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (panel->list));
|
|
|
|
if (y < 10) {
|
|
if (va->value > va->lower)
|
|
return TRUE;
|
|
} else {
|
|
if (y > (CLIST_FROM_SW (panel->list)->clist_window_height - 10)) {
|
|
if (va->value < va->upper - va->page_size)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
* panel_clist_scroll:
|
|
*
|
|
* Timer callback invoked to scroll the clist window
|
|
*/
|
|
static gboolean
|
|
panel_clist_scroll (gpointer data)
|
|
{
|
|
WPanel *panel = data;
|
|
GtkAdjustment *va;
|
|
double v;
|
|
|
|
va = scrolled_window_get_vadjustment (panel->list);
|
|
|
|
if (panel->drag_motion_y < 10) {
|
|
v = va->value - va->step_increment;
|
|
if (v < va->lower)
|
|
v = va->lower;
|
|
|
|
gtk_adjustment_set_value (va, v);
|
|
} else {
|
|
v = va->value + va->step_increment;
|
|
if (v > va->upper - va->page_size)
|
|
v = va->upper - va->page_size;
|
|
|
|
gtk_adjustment_set_value (va, v);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Callback used for drag motion events over the clist. We set up
|
|
* auto-scrolling and validate the drop to present the user with the correct
|
|
* feedback.
|
|
*/
|
|
static gboolean
|
|
panel_clist_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time,
|
|
gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
GtkCList *clist;
|
|
GdkDragAction action;
|
|
GtkWidget *source_widget;
|
|
gint idx;
|
|
file_entry *fe;
|
|
char *full_name;
|
|
|
|
panel = data;
|
|
|
|
/* Normalize the y coordinate to the clist_window */
|
|
|
|
clist = CLIST_FROM_SW (panel->list);
|
|
y -= (GTK_CONTAINER (clist)->border_width
|
|
+ clist->column_title_area.y
|
|
+ clist->column_title_area.height);
|
|
|
|
if (y < 0) {
|
|
gdk_drag_status (context, 0, time);
|
|
goto out;
|
|
}
|
|
|
|
/* Set up auto-scrolling */
|
|
|
|
panel_setup_drag_scroll (panel, x, y,
|
|
panel_clist_scrolling_is_desirable,
|
|
panel_clist_scroll);
|
|
|
|
/* Validate the drop */
|
|
|
|
gdnd_find_panel_by_drag_context (context, &source_widget);
|
|
|
|
if (!gtk_clist_get_selection_info (GTK_CLIST (widget), x, y, &idx, NULL))
|
|
fe = NULL;
|
|
else
|
|
fe = &panel->dir.list[idx];
|
|
|
|
full_name = fe ? g_concat_dir_and_file (panel->cwd, fe->fname) : panel->cwd;
|
|
|
|
action = gdnd_validate_action (context,
|
|
FALSE,
|
|
source_widget != NULL,
|
|
source_widget == widget,
|
|
full_name,
|
|
fe,
|
|
fe ? fe->f.marked : FALSE);
|
|
|
|
if (full_name != panel->cwd)
|
|
g_free (full_name);
|
|
|
|
gdk_drag_status (context, action, time);
|
|
|
|
out:
|
|
gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "drag_motion");
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* panel_clist_drag_leave
|
|
*
|
|
* Invoked when the dragged object has left our region
|
|
*/
|
|
static void
|
|
panel_clist_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
panel_cancel_drag_scroll (panel);
|
|
}
|
|
|
|
/**
|
|
* panel_icon_list_scrolling_is_desirable:
|
|
*
|
|
* If the cursor is in a position close to either edge (top or bottom)
|
|
* and there is possible to scroll the window, this routine returns
|
|
* true.
|
|
*/
|
|
static gboolean
|
|
panel_icon_list_scrolling_is_desirable (WPanel *panel, int x, int y)
|
|
{
|
|
GtkAdjustment *va;
|
|
|
|
va = scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (panel->icons));
|
|
|
|
if (y < 10) {
|
|
if (va->value > va->lower)
|
|
return TRUE;
|
|
} else {
|
|
if (y > (GTK_WIDGET (ILIST_FROM_SW (panel->icons))->allocation.height - 10)) {
|
|
if (va->value < va->upper - va->page_size)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
* panel_icon_list_scroll:
|
|
*
|
|
* Timer callback invoked to scroll the clist window
|
|
*/
|
|
static gboolean
|
|
panel_icon_list_scroll (gpointer data)
|
|
{
|
|
WPanel *panel = data;
|
|
GtkAdjustment *va;
|
|
double v;
|
|
|
|
va = scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (panel->icons));
|
|
|
|
if (panel->drag_motion_y < 10) {
|
|
v = va->value - va->step_increment;
|
|
if (v < va->lower)
|
|
v = va->lower;
|
|
|
|
gtk_adjustment_set_value (va, v);
|
|
} else {
|
|
v = va->value + va->step_increment;
|
|
if (v > va->upper - va->page_size)
|
|
v = va->upper - va->page_size;
|
|
|
|
gtk_adjustment_set_value (va, v);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Callback used for drag motion events in the icon list. We need to set up
|
|
* auto-scrolling and validate the drop to present the user with the correct
|
|
* feedback.
|
|
*/
|
|
static gboolean
|
|
panel_icon_list_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time,
|
|
gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
GdkDragAction action;
|
|
GtkWidget *source_widget;
|
|
int idx;
|
|
file_entry *fe;
|
|
char *full_name;
|
|
|
|
panel = data;
|
|
|
|
/* Set up auto-scrolling */
|
|
|
|
panel_setup_drag_scroll (panel, x, y,
|
|
panel_icon_list_scrolling_is_desirable,
|
|
panel_icon_list_scroll);
|
|
|
|
/* Validate the drop */
|
|
|
|
gdnd_find_panel_by_drag_context (context, &source_widget);
|
|
|
|
idx = gnome_icon_list_get_icon_at (GNOME_ICON_LIST (widget), x, y);
|
|
fe = (idx == -1) ? NULL : &panel->dir.list[idx];
|
|
|
|
full_name = fe ? g_concat_dir_and_file (panel->cwd, fe->fname) : panel->cwd;
|
|
|
|
action = gdnd_validate_action (context,
|
|
FALSE,
|
|
source_widget != NULL,
|
|
source_widget == widget,
|
|
full_name,
|
|
fe,
|
|
fe ? fe->f.marked : FALSE);
|
|
|
|
if (full_name != panel->cwd)
|
|
g_free (full_name);
|
|
|
|
gdk_drag_status (context, action, time);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* panel_icon_list_drag_leave:
|
|
*
|
|
* Invoked when the dragged object has left our region
|
|
*/
|
|
static void
|
|
panel_icon_list_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, gpointer data)
|
|
{
|
|
WPanel *panel = data;
|
|
|
|
panel_cancel_drag_scroll (panel);
|
|
}
|
|
|
|
/* Handler for the row_popup_menu signal of the file list. */
|
|
static void
|
|
panel_file_list_row_popup_menu (GtkFList *flist, GdkEventButton *event, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
gpopup_do_popup2 (event, panel, NULL);
|
|
}
|
|
|
|
/* Handler for the empty_popup_menu signal of the file list. */
|
|
static void
|
|
panel_file_list_empty_popup_menu (GtkFList *flist, GdkEventButton *event, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
file_list_popup (event, panel);
|
|
}
|
|
|
|
/* Handler for the open_row signal of the file list */
|
|
static void
|
|
panel_file_list_open_row (GtkFList *flist, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
do_enter (panel);
|
|
}
|
|
|
|
/* Handler for the start_drag signal of the file list */
|
|
static void
|
|
panel_file_list_start_drag (GtkFList *flist, gint button, GdkEvent *event, gpointer data)
|
|
{
|
|
start_drag (GTK_WIDGET (flist), button, event);
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
GtkWidget *sw;
|
|
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;
|
|
|
|
sw = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
|
|
file_list = gtk_flist_new_with_titles (panel, items, titles);
|
|
gtk_container_add (GTK_CONTAINER (sw), file_list);
|
|
gtk_widget_show (file_list);
|
|
|
|
panel_file_list_configure (panel, sw, file_list);
|
|
g_free (titles);
|
|
|
|
gtk_signal_connect_after (GTK_OBJECT (sw), "size_allocate",
|
|
GTK_SIGNAL_FUNC (panel_file_list_size_allocate_hook),
|
|
panel);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "select_row",
|
|
GTK_SIGNAL_FUNC (panel_file_list_select_row),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "unselect_row",
|
|
GTK_SIGNAL_FUNC (panel_file_list_unselect_row),
|
|
panel);
|
|
|
|
/* Connect to the flist signals */
|
|
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "row_popup_menu",
|
|
GTK_SIGNAL_FUNC (panel_file_list_row_popup_menu),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "empty_popup_menu",
|
|
GTK_SIGNAL_FUNC (panel_file_list_empty_popup_menu),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "open_row",
|
|
GTK_SIGNAL_FUNC (panel_file_list_open_row),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "start_drag",
|
|
GTK_SIGNAL_FUNC (panel_file_list_start_drag),
|
|
panel);
|
|
|
|
/* Set up drag and drop */
|
|
|
|
load_dnd_icons ();
|
|
|
|
gtk_drag_dest_set (GTK_WIDGET (file_list),
|
|
GTK_DEST_DEFAULT_DROP,
|
|
drop_types, ELEMENTS (drop_types),
|
|
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "drag_data_get",
|
|
GTK_SIGNAL_FUNC (panel_drag_data_get), panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "drag_data_delete",
|
|
GTK_SIGNAL_FUNC (panel_drag_data_delete), panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "drag_data_received",
|
|
GTK_SIGNAL_FUNC (panel_clist_drag_data_received), panel);
|
|
|
|
/*
|
|
* This signal is provided for scrolling the main window
|
|
* if data is being dragged
|
|
*/
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "drag_motion",
|
|
GTK_SIGNAL_FUNC (panel_clist_drag_motion), panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "drag_leave",
|
|
GTK_SIGNAL_FUNC (panel_clist_drag_leave), panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "drag_begin",
|
|
GTK_SIGNAL_FUNC (panel_drag_begin), panel);
|
|
gtk_signal_connect (GTK_OBJECT (file_list), "drag_end",
|
|
GTK_SIGNAL_FUNC (panel_drag_end), panel);
|
|
|
|
return sw;
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
|
|
/* Do not let the user select .. */
|
|
if (strcmp (panel->dir.list[index].fname, "..") == 0)
|
|
gnome_icon_list_unselect_icon (GNOME_ICON_LIST (widget), index);
|
|
|
|
if (!event)
|
|
return;
|
|
|
|
switch (event->type){
|
|
case GDK_BUTTON_PRESS:
|
|
if (event->button.button == 3)
|
|
gpopup_do_popup2 ((GdkEventButton *) event, panel, NULL);
|
|
|
|
break;
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
if (event->button.button == 2){
|
|
char *fullname;
|
|
|
|
if (S_ISDIR (panel->dir.list [index].buf.st_mode) ||
|
|
panel->dir.list [index].f.link_to_dir){
|
|
fullname = concat_dir_and_file (panel->cwd, panel->dir.list [index].fname);
|
|
new_panel_at (fullname);
|
|
g_free (fullname);
|
|
}
|
|
}
|
|
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 int
|
|
queue_reread_cmd (gpointer data)
|
|
{
|
|
reread_cmd ();
|
|
return FALSE;
|
|
}
|
|
|
|
/* Renames a file using a file operation context. Returns FILE_CONT on success. */
|
|
int
|
|
rename_file_with_context (char *source, char *dest)
|
|
{
|
|
FileOpContext *ctx;
|
|
struct stat s;
|
|
long count;
|
|
double bytes;
|
|
int retval;
|
|
|
|
if (mc_lstat (source, &s) != 0)
|
|
return FILE_ABORT;
|
|
|
|
ctx = file_op_context_new ();
|
|
file_op_context_create_ui (ctx, OP_MOVE, FALSE);
|
|
|
|
count = 1;
|
|
bytes = s.st_size;
|
|
|
|
retval = move_file_file (ctx, source, dest, &count, &bytes);
|
|
file_op_context_destroy (ctx);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int
|
|
panel_icon_renamed (GtkWidget *widget, int index, char *dest, WPanel *panel)
|
|
{
|
|
char *source;
|
|
char *fullname;
|
|
int retval;
|
|
|
|
if (strcmp (dest, panel->dir.list[index].fname) == 0)
|
|
return TRUE; /* do nothing if the name did not change */
|
|
|
|
source = g_concat_dir_and_file (cpanel->cwd, panel->dir.list[index].fname);
|
|
fullname = g_concat_dir_and_file (cpanel->cwd, dest);
|
|
|
|
if (rename_file_with_context (source, dest) == FILE_CONT) {
|
|
g_free (panel->dir.list [index].fname);
|
|
panel->dir.list [index].fname = g_strdup (dest);
|
|
|
|
gtk_idle_add (queue_reread_cmd, NULL);
|
|
retval = TRUE;
|
|
} else
|
|
retval = FALSE;
|
|
|
|
g_free (source);
|
|
g_free (fullname);
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* Callback for rescanning the cwd */
|
|
static void
|
|
handle_rescan_directory (GtkWidget *widget, gpointer data)
|
|
{
|
|
reread_cmd ();
|
|
}
|
|
|
|
/* The popup menu for file panels */
|
|
static GnomeUIInfo file_list_popup_items[] = {
|
|
GNOMEUIINFO_ITEM_NONE (N_("_Rescan Directory"), N_("Reloads the current directory"),
|
|
handle_rescan_directory),
|
|
GNOMEUIINFO_ITEM_NONE (N_("New _Directory..."), N_("Creates a new directory here"),
|
|
gnome_mkdir_cmd),
|
|
GNOMEUIINFO_ITEM_NONE (N_("New _File..."), N_("Creates a new file here"),
|
|
gnome_newfile_cmd),
|
|
GNOMEUIINFO_END
|
|
};
|
|
|
|
/* Creates the popup menu when the user clicks button 3 on the blank area of the
|
|
* file panels.
|
|
*/
|
|
static void
|
|
file_list_popup (GdkEventButton *event, WPanel *panel)
|
|
{
|
|
GtkWidget *popup;
|
|
|
|
popup = gnome_popup_menu_new (file_list_popup_items);
|
|
gnome_popup_menu_do_popup_modal (popup, NULL, NULL, event, panel);
|
|
gtk_widget_destroy (popup);
|
|
}
|
|
|
|
|
|
/* Returns whether an icon in the icon list is being edited. FIXME: This
|
|
* function uses a fantastically ugly hack to figure this out. It would be
|
|
* saner to have a function provided by the icon list widget to do it, but we
|
|
* can't break forwards compatibility at this point. It would be even saner to
|
|
* have a good DnD API for the icon list.
|
|
*/
|
|
static int
|
|
editing_icon_list (GnomeIconList *gil)
|
|
{
|
|
GnomeCanvasItem *item;
|
|
|
|
item = GNOME_CANVAS (gil)->focused_item;
|
|
return (item && GNOME_IS_ICON_TEXT_ITEM (item) && GNOME_ICON_TEXT_ITEM (item)->editing);
|
|
}
|
|
|
|
/*
|
|
* Strategy for activaing the drags from the icon-list:
|
|
*
|
|
* The icon-list uses the button-press/motion-notify events for
|
|
* the banding selection. We catch the events and only if the
|
|
* click happens in an icon and the user moves the mouse enough (a
|
|
* threshold to give it a better feel) activa the drag and drop.
|
|
*
|
|
*/
|
|
static int
|
|
panel_icon_list_button_press (GtkWidget *widget, GdkEventButton *event, WPanel *panel)
|
|
{
|
|
GnomeIconList *gil = GNOME_ICON_LIST (widget);
|
|
int icon;
|
|
|
|
if (editing_icon_list (gil))
|
|
return FALSE;
|
|
|
|
if (event->type != GDK_BUTTON_PRESS)
|
|
return FALSE;
|
|
|
|
icon = gnome_icon_list_get_icon_at (gil, event->x, event->y);
|
|
|
|
if (icon == -1) {
|
|
if (event->button == 3) {
|
|
file_list_popup (event, panel);
|
|
return TRUE;
|
|
}
|
|
} else if (event->button != 3)
|
|
panel->maybe_start_drag = event->button;
|
|
|
|
panel->click_x = event->x;
|
|
panel->click_y = event->y;
|
|
return FALSE;
|
|
}
|
|
|
|
static int
|
|
panel_icon_list_button_release (GtkWidget *widget, GdkEventButton *event, WPanel *panel)
|
|
{
|
|
panel->maybe_start_drag = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Create and setup the icon field display */
|
|
static GtkWidget *
|
|
panel_create_icon_display (WPanel *panel)
|
|
{
|
|
GtkWidget *sw;
|
|
GnomeIconList *ilist;
|
|
|
|
sw = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
|
|
ilist = GNOME_ICON_LIST (
|
|
gnome_icon_list_new_flags (90, NULL,
|
|
(GNOME_ICON_LIST_IS_EDITABLE
|
|
| GNOME_ICON_LIST_STATIC_TEXT)));
|
|
gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (ilist));
|
|
gtk_widget_show (GTK_WIDGET (ilist));
|
|
|
|
gnome_icon_list_set_separators (ilist, " /-_.");
|
|
gnome_icon_list_set_row_spacing (ilist, 2);
|
|
gnome_icon_list_set_col_spacing (ilist, 2);
|
|
gnome_icon_list_set_icon_border (ilist, 2);
|
|
gnome_icon_list_set_text_spacing (ilist, 2);
|
|
|
|
gnome_icon_list_set_selection_mode (ilist, GTK_SELECTION_MULTIPLE);
|
|
GTK_WIDGET_SET_FLAGS (ilist, GTK_CAN_FOCUS);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "select_icon",
|
|
GTK_SIGNAL_FUNC (panel_icon_list_select_icon),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "unselect_icon",
|
|
GTK_SIGNAL_FUNC (panel_icon_list_unselect_icon),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "text_changed",
|
|
GTK_SIGNAL_FUNC (panel_icon_renamed),
|
|
panel);
|
|
|
|
/* Setup the icons and DnD */
|
|
|
|
load_dnd_icons ();
|
|
|
|
gtk_drag_dest_set (GTK_WIDGET (ilist),
|
|
GTK_DEST_DEFAULT_DROP,
|
|
drop_types, ELEMENTS (drop_types),
|
|
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "drag_data_get",
|
|
GTK_SIGNAL_FUNC (panel_drag_data_get),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "drag_data_delete",
|
|
GTK_SIGNAL_FUNC (panel_drag_data_delete),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "drag_data_received",
|
|
GTK_SIGNAL_FUNC (panel_icon_list_drag_data_received),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "drag_begin",
|
|
GTK_SIGNAL_FUNC (panel_drag_begin), panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "drag_end",
|
|
GTK_SIGNAL_FUNC (panel_drag_end), panel);
|
|
|
|
/* These implement our drag-start activation code, as we have a pretty oveloaded widget */
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "button_press_event",
|
|
GTK_SIGNAL_FUNC (panel_icon_list_button_press),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "button_release_event",
|
|
GTK_SIGNAL_FUNC (panel_icon_list_button_release),
|
|
panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "motion_notify_event",
|
|
GTK_SIGNAL_FUNC (panel_widget_motion),
|
|
panel);
|
|
|
|
/* This signal is provide for scrolling the main window if data is being
|
|
* dragged.
|
|
*/
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "drag_motion",
|
|
GTK_SIGNAL_FUNC (panel_icon_list_drag_motion), panel);
|
|
gtk_signal_connect (GTK_OBJECT (ilist), "drag_leave",
|
|
GTK_SIGNAL_FUNC (panel_icon_list_drag_leave), panel);
|
|
|
|
return sw;
|
|
}
|
|
|
|
static 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_container_add (GTK_CONTAINER (panel->panel_listbox), panel->list);
|
|
gtk_widget_show_all (panel->list);
|
|
}
|
|
|
|
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;
|
|
/* FIXME: for now, we set the usize. Ultimately, toolbar
|
|
* will let you expand it, we hope.
|
|
*/
|
|
gtk_widget_set_usize (GTK_WIDGET (in->widget.wdata), 296, -1);
|
|
return GTK_WIDGET (in->widget.wdata);
|
|
}
|
|
|
|
void
|
|
display_mini_info (WPanel *panel)
|
|
{
|
|
GnomeAppBar *bar = GNOME_APPBAR (panel->ministatus);
|
|
|
|
if (panel->searching) {
|
|
char *buf;
|
|
|
|
buf = g_strdup_printf (_("Search: %s"), panel->search_buffer);
|
|
gnome_appbar_pop (bar);
|
|
gnome_appbar_push (bar, buf);
|
|
g_free (buf);
|
|
return;
|
|
}
|
|
|
|
if (panel->marked){
|
|
char *buf;
|
|
|
|
buf = g_strdup_printf ((panel->marked == 1) ? _("%s bytes in %d file") : _("%s bytes in %d files"),
|
|
size_trunc_sep (panel->total),
|
|
panel->marked);
|
|
gnome_appbar_pop (bar);
|
|
gnome_appbar_push (bar, buf);
|
|
g_free (buf);
|
|
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);
|
|
g_free (link);
|
|
|
|
if (len > 0){
|
|
link_target [len] = 0;
|
|
/* FIXME: Links should be handled differently */
|
|
/* str = g_strconcat ("-> ", link_target, NULL); */
|
|
gnome_appbar_pop (bar);
|
|
gnome_appbar_push (bar, " ");
|
|
/* g_free (str); */
|
|
} else {
|
|
gnome_appbar_pop (bar);
|
|
gnome_appbar_push (bar, _("<readlink failed>"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (panel->estimated_total > 8){
|
|
int len = panel->estimated_total;
|
|
char *buffer;
|
|
|
|
buffer = g_malloc (len + 2);
|
|
format_file (buffer, panel, panel->selected, panel->estimated_total-2, 0, 1);
|
|
buffer [len] = 0;
|
|
gnome_appbar_pop (bar);
|
|
gnome_appbar_push (bar, buffer);
|
|
g_free (buffer);
|
|
}
|
|
if (panel->list_type == list_icons){
|
|
if (panel->marked == 0){
|
|
gnome_appbar_pop (bar);
|
|
gnome_appbar_push (bar, " ");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Signal handler for DTree's "directory_changed" signal */
|
|
static void
|
|
panel_chdir (GtkDTree *dtree, char *path, WPanel *panel)
|
|
{
|
|
if (!panel->dragging)
|
|
do_panel_cd (panel, path, cd_exact);
|
|
}
|
|
|
|
static void
|
|
set_cursor (WPanel *panel, GdkCursorType type)
|
|
{
|
|
GdkCursor *cursor;
|
|
|
|
cursor = gdk_cursor_new (type);
|
|
gdk_window_set_cursor (GTK_WIDGET (panel->xwindow)->window, cursor);
|
|
gdk_cursor_destroy (cursor);
|
|
gdk_flush ();
|
|
}
|
|
|
|
static void
|
|
panel_tree_scan_begin (GtkWidget *widget, gpointer data)
|
|
{
|
|
set_cursor (data, GDK_WATCH);
|
|
}
|
|
|
|
static void
|
|
panel_tree_scan_end (GtkWidget *widget, gpointer data)
|
|
{
|
|
set_cursor (data, GDK_TOP_LEFT_ARROW);
|
|
}
|
|
|
|
/* Handler for the possibly_ungrab signal of the dtree widget */
|
|
static void
|
|
panel_tree_possibly_ungrab (GtkWidget *widget, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
|
|
/* The stupid clist button press handler grabs the mouse. We will get
|
|
* called when the user presses the mouse on the tree, so we ungrab it.
|
|
* Also, we have to make sure we don't knock away a DnD grab.
|
|
*/
|
|
if (!panel->drag_tree_dragging_over)
|
|
gdk_pointer_ungrab (GDK_CURRENT_TIME);
|
|
}
|
|
|
|
/* Callback for the drag_begin signal of the tree */
|
|
static void
|
|
panel_tree_drag_begin (GtkWidget *widget, GdkDragContext *context, gpointer data)
|
|
{
|
|
GtkDTree *dtree;
|
|
WPanel *panel;
|
|
|
|
dtree = GTK_DTREE (widget);
|
|
panel = data;
|
|
|
|
panel->dragging = TRUE;
|
|
dtree->drag_dir = g_strdup (dtree->current_path);
|
|
}
|
|
|
|
/* Callback for the drag_end signal of the tree */
|
|
static void
|
|
panel_tree_drag_end (GtkWidget *widget, GdkDragContext *context, gpointer data)
|
|
{
|
|
GtkDTree *dtree;
|
|
WPanel *panel;
|
|
|
|
dtree = GTK_DTREE (widget);
|
|
panel = data;
|
|
|
|
panel->dragging = FALSE;
|
|
g_free (dtree->drag_dir);
|
|
dtree->drag_dir = NULL;
|
|
}
|
|
|
|
/* Callback for the drag_data_get signal of the tree */
|
|
static void
|
|
panel_tree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
|
|
GtkSelectionData *selection_data, guint info, guint time, gpointer data)
|
|
{
|
|
GtkDTree *dtree;
|
|
char *str;
|
|
|
|
dtree = GTK_DTREE (widget);
|
|
|
|
switch (info){
|
|
case TARGET_URI_LIST:
|
|
case TARGET_TEXT_PLAIN:
|
|
str = g_strconcat ("file:", dtree->drag_dir, NULL);
|
|
gtk_selection_data_set (selection_data, selection_data->target, 8,
|
|
str, strlen (str) + 1);
|
|
break;
|
|
|
|
default:
|
|
/* FIXME: handle TARGET_URL */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* tree_drag_open_directory:
|
|
*
|
|
* This routine is invoked in a delayed fashion if the user
|
|
* keeps the drag cursor still over the widget.
|
|
*/
|
|
static gint
|
|
tree_drag_open_directory (gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
GtkDTree *dtree;
|
|
GtkCTreeNode *node;
|
|
|
|
panel = data;
|
|
dtree = GTK_DTREE (panel->tree);
|
|
|
|
node = gtk_ctree_node_nth (GTK_CTREE (panel->tree), panel->drag_tree_row);
|
|
g_assert (node != NULL);
|
|
|
|
if (!GTK_CTREE_ROW (node)->expanded) {
|
|
#if 0
|
|
/* FIXME: Disabled until fully debugged. Should also be configurable. */
|
|
dtree->auto_expanded_nodes = g_list_append (dtree->auto_expanded_nodes, node);
|
|
#endif
|
|
gtk_ctree_expand (GTK_CTREE (panel->tree), node);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Handles automatic collapsing of the tree nodes when doing drag and drop */
|
|
static void
|
|
panel_tree_check_auto_expand (WPanel *panel, GtkCTreeNode *current)
|
|
{
|
|
GtkDTree *dtree;
|
|
GtkCTree *ctree;
|
|
GtkCList *clist;
|
|
GList *free_list;
|
|
GList *tmp_list;
|
|
gint row, old_y, new_y;
|
|
|
|
dtree = GTK_DTREE (panel->tree);
|
|
ctree = GTK_CTREE (panel->tree);
|
|
clist = GTK_CLIST (panel->tree);
|
|
tmp_list = dtree->auto_expanded_nodes;
|
|
|
|
if (current)
|
|
for (; tmp_list; tmp_list = tmp_list->next)
|
|
if (!gtk_dtree_is_ancestor (dtree, tmp_list->data, current))
|
|
break;
|
|
|
|
/* Collapse the rows as necessary. If possible, try to do so that the
|
|
* "current" stays the same place on the screen.
|
|
*/
|
|
if (tmp_list) {
|
|
if (current) {
|
|
row = g_list_position (clist->row_list, (GList *) current);
|
|
old_y = row * clist->row_height - clist->vadjustment->value;
|
|
}
|
|
|
|
free_list = tmp_list;
|
|
|
|
for (; tmp_list; tmp_list = tmp_list->next)
|
|
gtk_ctree_collapse (GTK_CTREE (panel->tree), tmp_list->data);
|
|
|
|
/* We have to calculate the row position again because rows may
|
|
* have shifted during the collapse.
|
|
*/
|
|
if (current) {
|
|
row = g_list_position (clist->row_list, (GList *) current);
|
|
new_y = row * clist->row_height - clist->vadjustment->value;
|
|
|
|
if (new_y != old_y)
|
|
gtk_adjustment_set_value (clist->vadjustment,
|
|
clist->vadjustment->value + new_y - old_y);
|
|
}
|
|
|
|
if (free_list->prev)
|
|
free_list->prev->next = NULL;
|
|
else
|
|
dtree->auto_expanded_nodes = NULL;
|
|
|
|
free_list->prev = NULL;
|
|
g_list_free (free_list);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* panel_tree_scrolling_is_desirable:
|
|
*
|
|
* If the cursor is in a position close to either edge (top or bottom)
|
|
* and there is possible to scroll the window, this routine returns
|
|
* true.
|
|
*/
|
|
static gboolean
|
|
panel_tree_scrolling_is_desirable (WPanel *panel, int x, int y)
|
|
{
|
|
GtkDTree *dtree = GTK_DTREE (panel->tree);
|
|
GtkAdjustment *va;
|
|
|
|
va = scrolled_window_get_vadjustment (panel->tree_scrolled_window);
|
|
|
|
if (y < 10) {
|
|
if (va->value > va->lower)
|
|
return TRUE;
|
|
} else {
|
|
if (y > (GTK_WIDGET (dtree)->allocation.height - 10)){
|
|
if (va->value < va->upper - va->page_size)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Timer callback to scroll the tree */
|
|
static gboolean
|
|
panel_tree_scroll (gpointer data)
|
|
{
|
|
WPanel *panel = data;
|
|
GtkAdjustment *va;
|
|
double v;
|
|
|
|
va = scrolled_window_get_vadjustment (panel->tree_scrolled_window);
|
|
|
|
if (panel->drag_motion_y < 10) {
|
|
v = va->value - va->step_increment;
|
|
if (v < va->lower)
|
|
v = va->lower;
|
|
|
|
gtk_adjustment_set_value (va, v);
|
|
} else {
|
|
v = va->value + va->step_increment;
|
|
if (v > va->upper - va->page_size)
|
|
v = va->upper - va->page_size;
|
|
|
|
gtk_adjustment_set_value (va, v);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Callback for the drag_motion signal of the tree. We set up a timer to
|
|
* automatically open nodes if the user hovers over them.
|
|
*/
|
|
static gboolean
|
|
panel_tree_drag_motion (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time,
|
|
gpointer data)
|
|
{
|
|
GtkDTree *dtree;
|
|
WPanel *panel;
|
|
int on_row, row, col;
|
|
GtkCTreeNode *node;
|
|
GdkDragAction action;
|
|
GtkWidget *source_widget;
|
|
char *row_path;
|
|
int on_drag_row;
|
|
|
|
dtree = GTK_DTREE (widget);
|
|
panel = data;
|
|
|
|
panel->drag_tree_dragging_over = TRUE;
|
|
panel_setup_drag_scroll (panel, x, y,
|
|
panel_tree_scrolling_is_desirable,
|
|
panel_tree_scroll);
|
|
|
|
on_row = gtk_clist_get_selection_info (GTK_CLIST (widget), x, y, &row, &col);
|
|
|
|
/* Remove the auto-expansion timeout if we are on the blank area of the
|
|
* tree or on a row different from the previous one.
|
|
*/
|
|
if ((!on_row || row != panel->drag_tree_row) && panel->drag_tree_timeout_id != 0) {
|
|
gtk_timeout_remove (panel->drag_tree_timeout_id);
|
|
panel->drag_tree_timeout_id = 0;
|
|
|
|
if (panel->drag_tree_fe) {
|
|
file_entry_free (panel->drag_tree_fe);
|
|
panel->drag_tree_fe = NULL;
|
|
}
|
|
}
|
|
|
|
action = 0;
|
|
|
|
if (on_row) {
|
|
node = gtk_ctree_node_nth (GTK_CTREE (dtree), row);
|
|
row_path = gtk_dtree_get_row_path (dtree, node, 0);
|
|
|
|
if (row != panel->drag_tree_row) {
|
|
/* Highlight the row by selecting it */
|
|
|
|
panel_tree_check_auto_expand (panel, node);
|
|
|
|
dtree->internal = TRUE;
|
|
gtk_clist_select_row (GTK_CLIST (widget), row, 0);
|
|
dtree->internal = FALSE;
|
|
|
|
/* Create the file entry to validate drops */
|
|
|
|
panel->drag_tree_fe = file_entry_from_file (row_path);
|
|
|
|
/* Install the timeout handler for auto-expansion */
|
|
|
|
panel->drag_tree_timeout_id = gtk_timeout_add (TREE_OPEN_TIMEOUT,
|
|
tree_drag_open_directory,
|
|
panel);
|
|
panel->drag_tree_row = row;
|
|
}
|
|
|
|
/* Validate the action */
|
|
|
|
gdnd_find_panel_by_drag_context (context, &source_widget);
|
|
|
|
/* If this tree is the drag source, see if the user is trying to
|
|
* drop on the row being dragged. Otherwise, consider all rows
|
|
* as not selected.
|
|
*/
|
|
if (source_widget == widget) {
|
|
g_assert (dtree->drag_dir != NULL);
|
|
on_drag_row = strcmp (row_path, dtree->drag_dir) == 0;
|
|
} else
|
|
on_drag_row = FALSE;
|
|
|
|
action = gdnd_validate_action (context,
|
|
FALSE,
|
|
source_widget != NULL,
|
|
source_widget == widget,
|
|
row_path,
|
|
panel->drag_tree_fe,
|
|
on_drag_row);
|
|
|
|
g_free (row_path);
|
|
} else {
|
|
panel->drag_tree_row = -1;
|
|
panel_tree_check_auto_expand (panel, NULL);
|
|
}
|
|
|
|
gdk_drag_status (context, action, time);
|
|
return TRUE;
|
|
}
|
|
|
|
/* Callback for the drag_leave signal of the tree. We deactivate the timeout for
|
|
* automatic branch expansion.
|
|
*/
|
|
static void
|
|
panel_tree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
|
|
panel->drag_tree_dragging_over = FALSE;
|
|
panel_cancel_drag_scroll (panel);
|
|
|
|
if (panel->drag_tree_timeout_id != 0) {
|
|
gtk_timeout_remove (panel->drag_tree_timeout_id);
|
|
panel->drag_tree_timeout_id = 0;
|
|
}
|
|
|
|
if (panel->drag_tree_fe) {
|
|
file_entry_free (panel->drag_tree_fe);
|
|
panel->drag_tree_fe = NULL;
|
|
}
|
|
|
|
if (panel->drag_tree_row != -1)
|
|
panel_tree_check_auto_expand (panel, NULL);
|
|
|
|
panel->drag_tree_row = -1;
|
|
}
|
|
|
|
#if CONTEXT_MENU_ON_TREE
|
|
static void
|
|
tree_do_op (GtkWidget *tree, WPanel *panel, int operation)
|
|
{
|
|
}
|
|
|
|
static void
|
|
tree_copy_cmd (GtkWidget *tree, WPanel *panel)
|
|
{
|
|
tree_do_op (tree, panel, OP_COPY);
|
|
}
|
|
|
|
static void
|
|
tree_del_cmd (GtkWidget *tree, WPanel *panel)
|
|
{
|
|
tree_do_op (tree, panel, OP_DELETE);
|
|
}
|
|
|
|
static void
|
|
tree_ren_cmd (GtkWidget *tree, WPanel *panel)
|
|
{
|
|
tree_do_op (tree, panel, OP_MOVE);
|
|
}
|
|
|
|
static GnomeUIInfo tree_popup_items[] = {
|
|
GNOMEUIINFO_ITEM_STOCK(N_("_Copy..."), N_("Copy directory"), tree_copy_cmd, GNOME_STOCK_PIXMAP_COPY),
|
|
GNOMEUIINFO_ITEM_STOCK(N_("_Delete..."), N_("Delete directory"), tree_del_cmd, GNOME_STOCK_PIXMAP_TRASH),
|
|
GNOMEUIINFO_ITEM_NONE(N_("_Move..."), N_("Rename or move directory"), tree_ren_cmd),
|
|
|
|
GNOMEUIINFO_END
|
|
};
|
|
|
|
static void
|
|
panel_tree_button_press (GtkWidget *widget, GdkEventButton *event, WPanel *panel)
|
|
{
|
|
GtkWidget *popup;
|
|
|
|
if (event->type != GDK_BUTTON_PRESS)
|
|
return;
|
|
|
|
if (event->button != 3)
|
|
return;
|
|
|
|
popup = gnome_popup_menu_new (tree_popup_items);
|
|
gnome_popup_menu_do_popup_modal (popup, NULL, NULL, event, panel);
|
|
gtk_widget_destroy (popup);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* panel_create_tree_view:
|
|
*
|
|
* Create and initializes the GtkDTree widget for being used in the
|
|
* Panel
|
|
*/
|
|
static GtkWidget *
|
|
panel_create_tree_view (WPanel *panel)
|
|
{
|
|
GtkWidget *tree;
|
|
|
|
tree = gtk_dtree_new ();
|
|
gtk_ctree_set_line_style (GTK_CTREE (tree), GTK_CTREE_LINES_DOTTED);
|
|
gtk_ctree_set_expander_style (GTK_CTREE (tree), GTK_CTREE_EXPANDER_SQUARE);
|
|
gtk_ctree_set_indent (GTK_CTREE (tree), 10);
|
|
|
|
/* DTree signals */
|
|
|
|
gtk_signal_connect (GTK_OBJECT (tree), "directory_changed",
|
|
GTK_SIGNAL_FUNC (panel_chdir), panel);
|
|
gtk_signal_connect (GTK_OBJECT (tree), "scan_begin",
|
|
GTK_SIGNAL_FUNC (panel_tree_scan_begin), panel);
|
|
gtk_signal_connect (GTK_OBJECT (tree), "scan_end",
|
|
GTK_SIGNAL_FUNC (panel_tree_scan_end), panel);
|
|
gtk_signal_connect (GTK_OBJECT (tree), "possibly_ungrab",
|
|
GTK_SIGNAL_FUNC (panel_tree_possibly_ungrab), panel);
|
|
|
|
/* Set up drag source */
|
|
|
|
gtk_drag_source_set (GTK_WIDGET (tree), GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
|
|
drag_types, ELEMENTS (drag_types),
|
|
(GDK_ACTION_LINK | GDK_ACTION_MOVE | GDK_ACTION_COPY
|
|
| GDK_ACTION_ASK | GDK_ACTION_DEFAULT));
|
|
|
|
gtk_signal_connect (GTK_OBJECT (tree), "drag_begin",
|
|
GTK_SIGNAL_FUNC (panel_tree_drag_begin), panel);
|
|
gtk_signal_connect (GTK_OBJECT (tree), "drag_end",
|
|
GTK_SIGNAL_FUNC (panel_tree_drag_end), panel);
|
|
gtk_signal_connect (GTK_OBJECT (tree), "drag_data_get",
|
|
GTK_SIGNAL_FUNC (panel_tree_drag_data_get), panel);
|
|
|
|
/* Set up drag destination */
|
|
|
|
gtk_drag_dest_set (GTK_WIDGET (tree),
|
|
GTK_DEST_DEFAULT_DROP,
|
|
drop_types, ELEMENTS (drop_types),
|
|
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (tree), "drag_motion",
|
|
GTK_SIGNAL_FUNC (panel_tree_drag_motion), panel);
|
|
gtk_signal_connect (GTK_OBJECT (tree), "drag_leave",
|
|
GTK_SIGNAL_FUNC (panel_tree_drag_leave), panel);
|
|
gtk_signal_connect (GTK_OBJECT (tree), "drag_data_received",
|
|
GTK_SIGNAL_FUNC (panel_tree_drag_data_received), panel);
|
|
|
|
#ifdef CONTEXT_MENU_ON_TREE
|
|
/* Context sensitive menu */
|
|
gtk_signal_connect_after (GTK_OBJECT (tree), "button_press_event",
|
|
GTK_SIGNAL_FUNC (panel_tree_button_press), panel);
|
|
gtk_clist_set_button_actions (GTK_CLIST (tree), 2, GTK_BUTTON_SELECTS);
|
|
#endif
|
|
return tree;
|
|
}
|
|
|
|
/*
|
|
* create_and_setup_pane:
|
|
*
|
|
* Creates the horizontal GtkPaned widget that holds the tree
|
|
* and the listing/iconing displays
|
|
*/
|
|
static GtkWidget *
|
|
create_and_setup_pane (WPanel *panel)
|
|
{
|
|
GtkWidget *pane;
|
|
GtkWidget *tree = panel->tree;
|
|
GdkFont *tree_font = tree->style->font;
|
|
int size;
|
|
|
|
pane = gtk_hpaned_new ();
|
|
|
|
if (tree_panel_visible == -1)
|
|
size = 20 * gdk_string_width (tree_font, "W");
|
|
else {
|
|
if (tree_panel_visible)
|
|
size = tree_panel_visible;
|
|
else
|
|
size = 0;
|
|
}
|
|
#if 0
|
|
gtk_paned_set_position (GTK_PANED (pane), size);
|
|
#else
|
|
/*
|
|
* Hack: set the default startup size for the pane without
|
|
* using _set_usize which would set the minimal size
|
|
*/
|
|
GTK_PANED (pane)->child1_size = size;
|
|
GTK_PANED (pane)->position_set = TRUE;
|
|
#endif
|
|
gtk_widget_show (pane);
|
|
|
|
return pane;
|
|
}
|
|
|
|
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 void
|
|
rescan_panel (GtkWidget *widget, gpointer data)
|
|
{
|
|
reread_cmd ();
|
|
}
|
|
|
|
static void
|
|
go_home (GtkWidget *widget, WPanel *panel)
|
|
{
|
|
do_panel_cd (panel, "~", cd_exact);
|
|
}
|
|
|
|
/* The toolbar */
|
|
|
|
static GnomeUIInfo toolbar[] = {
|
|
GNOMEUIINFO_ITEM_STOCK (N_("Back"), N_("Go to the previously visited directory"),
|
|
panel_back, GNOME_STOCK_PIXMAP_BACK),
|
|
GNOMEUIINFO_ITEM_STOCK (N_("Up"), N_("Go up a level in the directory heirarchy"),
|
|
panel_up, GNOME_STOCK_PIXMAP_UP),
|
|
GNOMEUIINFO_ITEM_STOCK (N_("Forward"), N_("Go to the next directory"),
|
|
panel_fwd, GNOME_STOCK_PIXMAP_FORWARD),
|
|
GNOMEUIINFO_SEPARATOR,
|
|
GNOMEUIINFO_ITEM_STOCK (N_("Rescan"), N_("Rescan the current directory"),
|
|
rescan_panel, GNOME_STOCK_PIXMAP_REFRESH),
|
|
GNOMEUIINFO_SEPARATOR,
|
|
GNOMEUIINFO_ITEM_STOCK (N_("Home"), N_("Go to your home directory"),
|
|
go_home, GNOME_STOCK_PIXMAP_HOME),
|
|
GNOMEUIINFO_SEPARATOR,
|
|
GNOMEUIINFO_RADIOLIST(panel_view_toolbar_uiinfo),
|
|
GNOMEUIINFO_END
|
|
};
|
|
|
|
static void
|
|
do_ui_signal_connect (GnomeUIInfo *uiinfo, gchar *signal_name,
|
|
GnomeUIBuilderData *uibdata)
|
|
{
|
|
if (uiinfo->moreinfo)
|
|
gtk_signal_connect (GTK_OBJECT (uiinfo->widget),
|
|
signal_name, uiinfo->moreinfo, uibdata->data ?
|
|
uibdata->data : uiinfo->user_data);
|
|
}
|
|
|
|
static void
|
|
tree_size_allocate (GtkWidget *widget, GtkAllocation *allocation, WPanel *panel)
|
|
{
|
|
if (allocation->width <= 0){
|
|
tree_panel_visible = 0;
|
|
} else {
|
|
tree_panel_visible = allocation->width;
|
|
}
|
|
save_setup ();
|
|
}
|
|
|
|
void
|
|
x_create_panel (Dlg_head *h, widget_data parent, WPanel *panel)
|
|
{
|
|
GtkWidget *status_line, *vbox, *ministatus_box;
|
|
GtkWidget *cwd;
|
|
GtkWidget *dock;
|
|
GnomeUIBuilderData uibdata;
|
|
|
|
panel->xwindow = gtk_widget_get_toplevel (GTK_WIDGET (panel->widget.wdata));
|
|
|
|
panel->table = gtk_table_new (2, 1, 0);
|
|
|
|
/*
|
|
* Tree View
|
|
*/
|
|
panel->tree_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_policy (
|
|
GTK_SCROLLED_WINDOW (panel->tree_scrolled_window),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
panel->tree = panel_create_tree_view (panel);
|
|
gtk_container_add (GTK_CONTAINER (panel->tree_scrolled_window), panel->tree);
|
|
gtk_widget_show_all (panel->tree_scrolled_window);
|
|
|
|
/*
|
|
* Icon and Listing display
|
|
*/
|
|
panel->notebook = gtk_notebook_new ();
|
|
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (panel->notebook), FALSE);
|
|
gtk_widget_show (panel->notebook);
|
|
|
|
panel->icons = panel_create_icon_display (panel);
|
|
gtk_widget_show (panel->icons);
|
|
|
|
panel->list = panel_create_file_list (panel);
|
|
gtk_widget_ref (panel->icons);
|
|
gtk_widget_ref (panel->list);
|
|
|
|
panel->panel_listbox = gtk_event_box_new ();
|
|
gtk_widget_show (panel->panel_listbox);
|
|
gtk_container_add (GTK_CONTAINER (panel->panel_listbox), panel->list);
|
|
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (panel->notebook), panel->icons, NULL);
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (panel->notebook), panel->panel_listbox, NULL);
|
|
gtk_notebook_set_page (GTK_NOTEBOOK (panel->notebook),
|
|
panel->list_type == list_icons ? 0 : 1);
|
|
|
|
gtk_widget_show (panel->icons);
|
|
gtk_widget_show (panel->list);
|
|
gtk_widget_show (panel->notebook);
|
|
|
|
/*
|
|
* Pane
|
|
*/
|
|
panel->pane = create_and_setup_pane (panel);
|
|
gtk_paned_add1 (GTK_PANED (panel->pane), panel->tree_scrolled_window);
|
|
gtk_signal_connect (GTK_OBJECT (panel->tree_scrolled_window), "size_allocate",
|
|
GTK_SIGNAL_FUNC (tree_size_allocate), panel);
|
|
|
|
/*
|
|
* Current Working directory
|
|
*/
|
|
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;
|
|
|
|
/*
|
|
* We go through a lot of pain, wrestling with gnome_app* and gmc's @#$&*#$ internal structure and
|
|
* make the #@$*&@#$ toolbars here...
|
|
*/
|
|
|
|
status_line = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH);
|
|
uibdata.connect_func = do_ui_signal_connect;
|
|
uibdata.data = panel;
|
|
uibdata.is_interp = FALSE;
|
|
uibdata.relay_func = NULL;
|
|
uibdata.destroy_func = NULL;
|
|
|
|
gnome_app_fill_toolbar_custom (GTK_TOOLBAR (status_line), toolbar, &uibdata, NULL);
|
|
gnome_app_add_toolbar (GNOME_APP (panel->xwindow),
|
|
GTK_TOOLBAR (status_line),
|
|
"gmc-toolbar0",
|
|
GNOME_DOCK_ITEM_BEH_EXCLUSIVE,
|
|
GNOME_DOCK_TOP,
|
|
2, 0, 0);
|
|
panel->view_toolbar_items = copy_uiinfo_widgets (panel_view_toolbar_uiinfo);
|
|
|
|
panel->back_b = toolbar[0].widget;
|
|
panel->up_b = toolbar[1].widget;
|
|
panel->fwd_b = toolbar[2].widget;
|
|
panel_update_marks (panel);
|
|
|
|
/* Set the list type by poking a toolbar item. Yes, this is hackish.
|
|
* We fall back to icon view if a certain listing type is not supported.
|
|
* Be sure to keep this in sync with the uiinfo arrays in glayout.c.
|
|
*/
|
|
|
|
if (panel->list_type == list_brief)
|
|
gtk_toggle_button_set_active (
|
|
GTK_TOGGLE_BUTTON (panel_view_toolbar_uiinfo[1].widget), TRUE);
|
|
else if (panel->list_type == list_full)
|
|
gtk_toggle_button_set_active (
|
|
GTK_TOGGLE_BUTTON (panel_view_toolbar_uiinfo[2].widget), TRUE);
|
|
else if (panel->list_type == list_user)
|
|
gtk_toggle_button_set_active (
|
|
GTK_TOGGLE_BUTTON (panel_view_toolbar_uiinfo[3].widget), TRUE);
|
|
else
|
|
gtk_toggle_button_set_active (
|
|
GTK_TOGGLE_BUTTON (panel_view_toolbar_uiinfo[0].widget), TRUE);
|
|
|
|
status_line = gtk_hbox_new (FALSE, 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (status_line), 3);
|
|
gtk_box_pack_start (GTK_BOX (status_line),
|
|
gtk_label_new (_("Location:")), FALSE, FALSE, 0);
|
|
gtk_box_pack_start (GTK_BOX (status_line),
|
|
cwd, TRUE, TRUE, 0);
|
|
|
|
dock = gnome_dock_item_new ("gmc-toolbar1",
|
|
(GNOME_DOCK_ITEM_BEH_EXCLUSIVE
|
|
| GNOME_DOCK_ITEM_BEH_NEVER_VERTICAL));
|
|
gtk_container_add (GTK_CONTAINER(dock), status_line);
|
|
gnome_dock_add_item (GNOME_DOCK(GNOME_APP (panel->xwindow)->dock),
|
|
GNOME_DOCK_ITEM (dock), GNOME_DOCK_TOP, 1, 0, 0, FALSE);
|
|
|
|
gtk_widget_show_all (dock);
|
|
|
|
panel->view_table = gtk_table_new (1, 1, 0);
|
|
gtk_widget_show (panel->view_table);
|
|
|
|
/*
|
|
* The status bar.
|
|
*/
|
|
ministatus_box = gtk_frame_new (NULL);
|
|
gtk_frame_set_shadow_type (GTK_FRAME(ministatus_box), GTK_SHADOW_IN);
|
|
|
|
panel->status = gtk_label_new (_("Show all files"));
|
|
gtk_misc_set_alignment (GTK_MISC (panel->status), 0.0, 0.0);
|
|
gtk_misc_set_padding (GTK_MISC (panel->status), 2, 0);
|
|
|
|
gtk_box_pack_start (GTK_BOX (panel->ministatus), ministatus_box, FALSE, FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER(ministatus_box), panel->status);
|
|
|
|
gtk_widget_show (ministatus_box);
|
|
gtk_widget_show (panel->status);
|
|
|
|
/*
|
|
* Put the icon list and the file listing in a nice frame
|
|
*/
|
|
|
|
/* Add both the icon view and the listing view */
|
|
gtk_table_attach (GTK_TABLE (panel->view_table), panel->notebook, 0, 1, 0, 1,
|
|
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
|
|
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
|
|
0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (panel->table), panel->pane, 0, 1, 1, 2,
|
|
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
|
|
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
|
|
0, 0);
|
|
|
|
gtk_paned_add2 (GTK_PANED (panel->pane), panel->view_table);
|
|
|
|
/*
|
|
* ministatus_box is a container created just to put the
|
|
* panel->ministatus inside.
|
|
*
|
|
* Then the resize mode for ministatus_box is changed to stop
|
|
* any size-changed messages to be propagated above.
|
|
*
|
|
* This is required as the panel->ministatus Label is changed
|
|
* very often (to display status information). If this hack
|
|
* is not made, then the resize is queued and the whole window
|
|
* flickers each time this changes
|
|
*/
|
|
#if 0
|
|
ministatus_box = gtk_hbox_new (FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER (ministatus_box), panel->ministatus);
|
|
gtk_widget_show (ministatus_box);
|
|
gtk_container_set_resize_mode (GTK_CONTAINER (ministatus_box), GTK_RESIZE_QUEUE);
|
|
gtk_table_attach (GTK_TABLE (panel->table), ministatus_box, 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);
|
|
|
|
#endif
|
|
/* 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));
|
|
|
|
if (!pixmaps_ready)
|
|
panel_create_pixmaps ();
|
|
|
|
/* 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;
|
|
|
|
panel->timer_id = -1;
|
|
}
|
|
|
|
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 [BUF_TINY];
|
|
|
|
if (!num)
|
|
return "New Left Panel";
|
|
else if (num == 1)
|
|
return "New Right Panel";
|
|
else {
|
|
g_snprintf (buffer, sizeof (buffer), "%ith Panel", num);
|
|
return buffer;
|
|
}
|
|
}
|
|
|
|
void
|
|
load_hint (void)
|
|
{
|
|
char *hint;
|
|
|
|
if ((hint = get_random_hint ())){
|
|
if (*hint)
|
|
set_hintbar (hint);
|
|
g_free (hint);
|
|
} else
|
|
set_hintbar ("The GNOME File Manager " VERSION);
|
|
|
|
}
|
|
|
|
void
|
|
paint_frame (WPanel *panel)
|
|
{
|
|
}
|
|
|
|
void
|
|
x_reset_sort_labels (WPanel *panel)
|
|
{
|
|
int page;
|
|
|
|
if (!panel->notebook)
|
|
return;
|
|
|
|
if (panel->list_type == list_icons){
|
|
page = 0;
|
|
} else {
|
|
page = 1;
|
|
panel_switch_new_display_mode (panel);
|
|
}
|
|
gtk_notebook_set_page (GTK_NOTEBOOK (panel->notebook), page);
|
|
}
|
|
|
|
/* Releases all of the X resources allocated */
|
|
void
|
|
x_panel_destroy (WPanel *panel)
|
|
{
|
|
gtk_widget_destroy (GTK_WIDGET (panel->xwindow));
|
|
}
|