From 44a1b32eebb17f634e690e18cc83f4d9a9b7d114 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Wed, 9 Dec 1998 17:23:38 +0000 Subject: [PATCH] 1998-12-08 Federico Mena Quintero * gdesktop.c: Moved the old DnD cruft to olddnd.c to keep it there for reference purposes. * gmetadata.c: Removed the gmeta_get_icon_for_file() function, as it is obsoleted by gicon_get_icon_for_file(). * gdesktop.c (desktop_icon_info_new): Made it use gicon_get_icon_for_file(). * gdesktop-icon.c (set_icon): Now we handle things internally using an imlib image, not a filename. (desktop_icon_new): Now takes an imlib image for the icon instead of a filename. (desktop_icon_set_icon): Likewise. --- gnome/ChangeLog | 17 + gnome/gdesktop-icon.c | 33 +- gnome/gdesktop-icon.h | 8 +- gnome/gdesktop.c | 1503 +---------------------------------------- gnome/gmetadata.c | 35 - gnome/gmetadata.h | 3 - gnome/olddnd.c | 1486 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1527 insertions(+), 1558 deletions(-) diff --git a/gnome/ChangeLog b/gnome/ChangeLog index f5cddd575..5b17cbeab 100644 --- a/gnome/ChangeLog +++ b/gnome/ChangeLog @@ -1,3 +1,20 @@ +1998-12-08 Federico Mena Quintero + + * gdesktop.c: Moved the old DnD cruft to olddnd.c to keep it there + for reference purposes. + + * gmetadata.c: Removed the gmeta_get_icon_for_file() function, as + it is obsoleted by gicon_get_icon_for_file(). + + * gdesktop.c (desktop_icon_info_new): Made it use + gicon_get_icon_for_file(). + + * gdesktop-icon.c (set_icon): Now we handle things internally + using an imlib image, not a filename. + (desktop_icon_new): Now takes an imlib image for the icon instead + of a filename. + (desktop_icon_set_icon): Likewise. + 1998-12-08 Miguel de Icaza * gtkdtree.c (gtk_dtree_new): Use imlib's visual and colormap. diff --git a/gnome/gdesktop-icon.c b/gnome/gdesktop-icon.c index 20d040c92..43a29f838 100644 --- a/gnome/gdesktop-icon.c +++ b/gnome/gdesktop-icon.c @@ -180,24 +180,15 @@ desktop_icon_realize (GtkWidget *widget) NULL); } -/* Sets the icon from the specified image file. Does not re-create the window shape for the desktop +/* Sets the icon from the specified image. Does not re-create the window shape for the desktop * icon. */ static void -set_icon (DesktopIcon *dicon, char *image_file) +set_icon (DesktopIcon *dicon, GdkImlibImage *im) { - GdkImlibImage *im, *old_im; + GdkImlibImage *old_im; GtkArg arg; - /* Load the new image */ - - if (!g_file_exists (image_file)) - return; - - im = gdk_imlib_load_image (image_file); - if (!im) - return; - /* Destroy the old image if it exists */ arg.name = "image"; @@ -242,7 +233,7 @@ set_text (DesktopIcon *dicon, char *text) /** * desktop_icon_new - * @image_file: Name of the image file that contains the icon. + * @image: Imlib image with the icon. * @text: Text to use for the icon. * * Creates a new desktop icon widget with the specified icon image and text. The icon has to be @@ -251,16 +242,16 @@ set_text (DesktopIcon *dicon, char *text) * Returns the newly-created desktop icon widget. */ GtkWidget * -desktop_icon_new (char *image_file, char *text) +desktop_icon_new (GdkImlibImage *image, char *text) { DesktopIcon *dicon; - g_return_val_if_fail (image_file != NULL, NULL); + g_return_val_if_fail (image != NULL, NULL); g_return_val_if_fail (text != NULL, NULL); dicon = gtk_type_new (desktop_icon_get_type ()); - set_icon (dicon, image_file); + set_icon (dicon, image); set_text (dicon, text); desktop_icon_reshape (dicon); @@ -270,18 +261,18 @@ desktop_icon_new (char *image_file, char *text) /** * desktop_icon_set_icon * @dicon: The desktop icon to set the icon for - * @image_file: Name of the image file that contains the icon + * @image: Imlib image with the icon. * - * Sets a new icon for an existing desktop icon. If the file does not exist, it does nothing. + * Sets a new icon for an existing desktop icon. */ void -desktop_icon_set_icon (DesktopIcon *dicon, char *image_file) +desktop_icon_set_icon (DesktopIcon *dicon, GdkImlibImage *image) { g_return_if_fail (dicon != NULL); g_return_if_fail (IS_DESKTOP_ICON (dicon)); - g_return_if_fail (image_file != NULL); + g_return_if_fail (image != NULL); - set_icon (dicon, image_file); + set_icon (dicon, image); desktop_icon_reshape (dicon); } diff --git a/gnome/gdesktop-icon.h b/gnome/gdesktop-icon.h index a1008c067..1cbc56685 100644 --- a/gnome/gdesktop-icon.h +++ b/gnome/gdesktop-icon.h @@ -52,11 +52,11 @@ struct _DesktopIconClass { /* Standard Gtk function */ GtkType desktop_icon_get_type (void); -/* Creates a new desktop icon from the specified image file, and with the specified title */ -GtkWidget *desktop_icon_new (char *image_file, char *text); +/* Creates a new desktop icon from the specified image, and with the specified title */ +GtkWidget *desktop_icon_new (GdkImlibImage *image, char *text); -/* Sets the icon from the specified file name */ -void desktop_icon_set_icon (DesktopIcon *dicon, char *image_file); +/* Sets the icon from the specified image */ +void desktop_icon_set_icon (DesktopIcon *dicon, GdkImlibImage *image); /* Sets the icon's text */ void desktop_icon_set_text (DesktopIcon *dicon, char *text); diff --git a/gnome/gdesktop.c b/gnome/gdesktop.c index 10a1c25ca..aa6a8b10d 100644 --- a/gnome/gdesktop.c +++ b/gnome/gdesktop.c @@ -25,7 +25,7 @@ * - Select icons with rubberband on the root window. * */ -#if 1 + #include #include "fs.h" #include @@ -36,6 +36,7 @@ #include "dir.h" #include "gdesktop.h" #include "gdesktop-icon.h" +#include "gicon.h" #include "gmain.h" #include "gmetadata.h" #include "gdnd.h" @@ -924,24 +925,26 @@ static struct desktop_icon_info * desktop_icon_info_new (char *filename, int auto_pos, int xpos, int ypos) { struct desktop_icon_info *dii; + file_entry *fe; char *full_name; - char *icon_name; + GdkImlibImage *icon_im; /* Create the icon structure */ full_name = g_concat_dir_and_file (desktop_directory, filename); - icon_name = gmeta_get_icon_for_file (full_name); + fe = file_entry_from_file (full_name); + icon_im = gicon_get_icon_for_file (fe); dii = g_new (struct desktop_icon_info, 1); - dii->dicon = desktop_icon_new (icon_name, filename); + dii->dicon = desktop_icon_new (icon_im, filename); dii->x = 0; dii->y = 0; dii->slot = -1; dii->filename = g_strdup (filename); dii->selected = FALSE; + file_entry_free (fe); g_free (full_name); - g_free (icon_name); /* Connect to the icon's signals */ @@ -1297,1493 +1300,3 @@ desktop_destroy (void) gtk_widget_destroy (dnd_proxy_window); XDeleteProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (), gdk_atom_intern ("XdndProxy", FALSE)); } - - - - - - - - -#else - -#include -#include "fs.h" -#include -#include "gdesktop-icon.h" -#include "gdesktop.h" -#include "../vfs/vfs.h" -#include -#include "mad.h" -#include "main.h" -#include "file.h" -#include "global.h" -#include "panel.h" -#include "gscreen.h" -#include "ext.h" -#include "dialog.h" -#include "gpageprop.h" -#include -#include -#include "gcache.h" -#include "gmain.h" - -/* places used in the grid */ -static char *spot_array; - -/* number of icons that fit along the x and y axis */ -static int x_spots, y_spots; - -/* operations on drops */ -enum { - OPER_COPY, - OPER_MOVE, - OPER_LINK -}; - -/* The X11 root window */ -static GnomeRootWin *root_window; - - -/* The full name of the desktop directory ~/desktop */ -char *desktop_directory; - -static void desktop_reload (char *desktop_dir, GdkPoint *drop_position); -static void desktop_icon_context_popup (GdkEventButton *event, desktop_icon_t *di); - -/* The list with the filenames we have actually loaded */ -static GList *desktop_icons; - -#define ELEMENTS(x) (sizeof (x) / sizeof (x[0])) - -static void -init_spot_list (void) -{ - int size; - - x_spots = gdk_screen_width () / SNAP_X; - y_spots = gdk_screen_height () / SNAP_Y; - size = (x_spots * y_spots) / 8; - spot_array = xmalloc (size+1, "spot_array"); - memset (spot_array, 0, size); -} - -static int -is_spot_set (int x, int y) -{ - int o = (x * x_spots + y); - int idx = o / 8; - int bit = o % 8; - - return spot_array [idx] & (1 << bit); -} - -static void -set_spot_val (int x, int y, int set) -{ - int o = (x * x_spots + y); - int idx = o / 8; - int bit = o % 8; - - if (set) - spot_array [idx] |= (1 << bit); - else - spot_array [idx] &= ~(1 << bit); -} - -static void -allocate_free_spot (int *rx, int *ry) -{ - int x, y; - - for (x = 0; x < x_spots; x++) - for (y = 0; y < y_spots; y++) - if (!is_spot_set (x, y)){ - *rx = x; - *ry = y; - set_spot_val (x, y, 1); - return; - } -} - -static void -snap_to (desktop_icon_t *di, int absolute, int x, int y) -{ - int nx = x/SNAP_X; - int ny = y/SNAP_Y; - - if (!absolute && is_spot_set (nx, ny)) - allocate_free_spot (&di->grid_x, &di->grid_y); - else { - set_spot_val (nx, ny, 1); - di->grid_x = nx; - di->grid_y = ny; - } - -} - -/* Get snapped position for an icon */ -static void -get_icon_screen_x_y (desktop_icon_t *di, int *x, int *y) -{ - int w, h; - - w = DESKTOP_ICON (di->widget)->width; - h = DESKTOP_ICON (di->widget)->height; - - if (di->grid_x != -1){ - *x = di->grid_x * SNAP_X; - *y = di->grid_y * SNAP_Y; - - *x = *x + (SNAP_X - w) / 2; - if (*x < 0) - *x = 0; - - if (h > SNAP_Y) - *y = *y + (SNAP_Y - h) / 2; - else - *y = *y + (SNAP_Y - h); - } else { - *x = di->x; - *y = di->y; - } -} - -/* - * If the dentry is zero, then no information from the on-disk .desktop file is used - * In this case, we probably will have to store the geometry for a file somewhere - * else. - */ -static int current_x, current_y; - -static void -desktop_icon_set_position (desktop_icon_t *di) -{ - static int x, y = 10; - - x = -1; - if (di->dentry && di->dentry->geometry){ - char *comma = strchr (di->dentry->geometry, ','); - - if (comma){ - x = atoi (di->dentry->geometry); - comma++; - y = atoi (comma); - } - } - - if (icons_snap_to_grid){ - if (x == -1){ - x = current_x; - y = current_y; - - current_y += SNAP_Y; - if (current_y > gdk_screen_height ()) - current_x += SNAP_X; - - snap_to (di, 1, x, y); - } else - snap_to (di, 0, x, y); - - get_icon_screen_x_y (di, &x, &y); - } else { - /* This find-spot routine can obviously be improved, left as an excercise - * to the hacker - */ - if (x == -1){ - x = current_x; - y = current_y; - - current_y += DESKTOP_ICON (di)->height + 8; - if (current_y > gdk_screen_height ()){ - current_x += SNAP_X; - current_y = 0; - } - } - x += 6; - di->grid_x = di->grid_y = -1; - } - - di->x = x; - di->y = y; - - gtk_widget_set_uposition (di->widget, x, y); -} - -/* - * Returns the icon associated with the given file name, or app.xpm - * if no icon is defined for this application - */ -static char * -get_desktop_icon (char *pathname) -{ - char *fname, *full_fname; - - fname = regex_command (x_basename (pathname), "Icon", 0, 0); - - /* Try the GNOME icon */ - if (fname){ - full_fname = gnome_unconditional_pixmap_file (fname); - free (fname); - if (exist_file (full_fname)) - return full_fname; - g_free (full_fname); - } - - /* Try a mc icon */ - if (fname){ - full_fname = concat_dir_and_file (ICONDIR, fname); - if (exist_file (full_fname)) - return full_fname; - - free (full_fname); - } - - return gnome_unconditional_pixmap_file ("launcher-program.png"); -} - -/* - * Hackisigh routine taken from GDK - */ -#ifdef OLD_DND -static void -gdk_dnd_drag_begin (GdkWindow *initial_window) -{ - GdkEventDragBegin tev; - tev.type = GDK_DRAG_BEGIN; - tev.window = initial_window; - tev.u.allflags = 0; - tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; - - gdk_event_put ((GdkEvent *) &tev); -} - -void -artificial_drag_start (GdkWindow *window, int x, int y) -{ - GdkWindowPrivate *wp = (GdkWindowPrivate *) window; - - if (!wp->dnd_drag_enabled) - return; -#if 1 - if (!gdk_dnd.drag_perhaps) - return; - if (gdk_dnd.dnd_grabbed) - return; - if (gdk_dnd.drag_really) - return; - gdk_dnd_drag_addwindow (window); - gdk_dnd_drag_begin (window); - XGrabPointer (gdk_display, wp->xwindow, False, - ButtonMotionMask | ButtonPressMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, gdk_root_window, - None, CurrentTime); - gdk_dnd.dnd_grabbed = TRUE; - gdk_dnd.drag_really = 1; - gdk_dnd_display_drag_cursor (x, y, FALSE, TRUE); -#else - gdk_dnd.real_sw = wp; - gdk_dnd.dnd_drag_start.x = x; - gdk_dnd.dnd_drag_start.y = y; - gdk_dnd.drag_perhaps = 1; - if(gdk_dnd.drag_startwindows) - { - g_free(gdk_dnd.drag_startwindows); - gdk_dnd.drag_startwindows = NULL; - } - gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; - gdk_dnd.dnd_grabbed = FALSE; - { - /* Set motion mask for first DnD'd window, since it - will be the one that is actually dragged */ - XWindowAttributes dnd_winattr; - XSetWindowAttributes dnd_setwinattr; - - /* We need to get motion events while the button is down, so - we can know whether to really start dragging or not... */ - XGetWindowAttributes(gdk_display, (Window)wp->xwindow, - &dnd_winattr); - - wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; - dnd_setwinattr.event_mask = - wp->dnd_drag_eventmask = ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | - EnterWindowMask | LeaveWindowMask; - XChangeWindowAttributes(gdk_display, wp->xwindow, - CWEventMask, &dnd_setwinattr); - } -#endif -} -#endif /* OLD_DND */ - -static GdkDragAction operation_value; - -static void -set_option (GtkWidget *widget, GdkDragAction value) -{ - operation_value = value; - gtk_main_quit (); -} - -static void -option_menu_gone () -{ - operation_value = GDK_ACTION_ASK; - gtk_main_quit (); -} - -static GdkDragAction -get_operation (guint32 timestamp, int x, int y) -{ - static GtkWidget *menu; - - if (!menu){ - GtkWidget *item; - - menu = gtk_menu_new (); - - item = gtk_menu_item_new_with_label (_("Copy")); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_COPY); - gtk_menu_append (GTK_MENU (menu), item); - gtk_widget_show (item); - - item = gtk_menu_item_new_with_label (_("Move")); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_MOVE); - gtk_menu_append (GTK_MENU (menu), item); - gtk_widget_show (item); - - /* Not yet implemented the Link bits, so better to not show what we dont have */ - item = gtk_menu_item_new_with_label (_("Link")); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_LINK); - gtk_menu_append (GTK_MENU (menu), item); - gtk_widget_show (item); - - gtk_signal_connect (GTK_OBJECT (menu), "hide", GTK_SIGNAL_FUNC(option_menu_gone), 0); - } - - gtk_widget_set_uposition (menu, x, y); - - /* FIXME: We should catch any events that escape this menu and cancel it */ - operation_value = GDK_ACTION_ASK; - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, 0, NULL, 1, timestamp); - gtk_grab_add (menu); - gtk_main (); - gtk_grab_remove (menu); - gtk_widget_hide (menu); - - return operation_value; -} - -/* - * Used by check_window_id_in_one_panel and find_panel_owning_window_id for finding - * the panel that contains the specified window id (used to figure where the drag - * started) - */ -static WPanel *temp_panel; - -static void -check_window_in_one_panel (gpointer data, gpointer user_data) -{ - PanelContainer *pc = (PanelContainer *) data; - GdkWindowPrivate *w = (GdkWindowPrivate *) user_data; - WPanel *panel = pc->panel; - - if (panel->list_type == list_icons){ - GnomeIconList *icon_list = GNOME_ICON_LIST (panel->icons); - GdkWindowPrivate *wp = (GdkWindowPrivate *) GTK_WIDGET (icon_list)->window; - - if (w->xwindow == wp->xwindow){ - temp_panel = panel; - return; - } - } else { - GtkCList *clist = GTK_CLIST (panel->list); - GdkWindowPrivate *wp = (GdkWindowPrivate *) clist->clist_window; - - if (w->xwindow == wp->xwindow){ - temp_panel = panel; - return; - } - } -} - -static WPanel * -find_panel_owning_window (GdkWindow *window) -{ - temp_panel = NULL; - - printf ("Looking for window %x\n", window); - - g_list_foreach (containers, check_window_in_one_panel, window); - - return temp_panel; -} - -static void -perform_drop_on_directory (WPanel *source_panel, GdkDragAction action, char *dest) -{ - switch (action){ - case GDK_ACTION_COPY: - panel_operate (source_panel, OP_COPY, dest); - break; - - case GDK_ACTION_MOVE: - panel_operate (source_panel, OP_MOVE, dest); - break; - } -} - -static void -perform_drop_manually (GList *names, GdkDragAction action, char *dest) -{ - struct stat buf; - - switch (action){ - case GDK_ACTION_COPY: - create_op_win (OP_COPY, 0); - break; - - case GDK_ACTION_MOVE: - create_op_win (OP_MOVE, 0); - break; - - default: - g_assert_not_reached (); - } - - file_mask_defaults (); - - for (; names; names = names->next){ - char *p = names->data; - char *tmpf; - int res, v; - - if (strncmp (p, "file:", 5) == 0) - p += 5; - - switch (action){ - case GDK_ACTION_COPY: - tmpf = concat_dir_and_file (dest, x_basename (p)); - do { - res = mc_stat (p, &buf); - if (res != 0){ - v = file_error (" Could not stat %s \n %s ", tmpf); - if (v != FILE_RETRY) - res = 0; - } else { - if (S_ISDIR (buf.st_mode)) - copy_dir_dir (p, tmpf, 1, 0, 0, 0); - else - copy_file_file (p, tmpf, 1); - } - } while (res != 0); - free (tmpf); - break; - - case GDK_ACTION_MOVE: - tmpf = concat_dir_and_file (dest, x_basename (p)); - do { - res = mc_stat (p, &buf); - if (res != 0){ - v = file_error (" Could not stat %s \n %s ", tmpf); - if (v != FILE_RETRY) - res = 0; - } else { - if (S_ISDIR (buf.st_mode)) - move_dir_dir (p, tmpf); - else - move_file_file (p, tmpf); - } - } while (res != 0); - free (tmpf); - break; - - default: - g_assert_not_reached (); - } - } - - destroy_op_win (); -} - -static void -do_symlinks (GList *names, char *dest) -{ - for (; names; names = names->next){ - char *full_dest_name; - char *name = names->data; - - full_dest_name = concat_dir_and_file (dest, x_basename (name)); - if (strncmp (name, "file:", 5) == 0) - mc_symlink (name+5, full_dest_name); - else - mc_symlink (name, full_dest_name); - - free (full_dest_name); - } -} - -#if OLD_DND -static char ** -drops_from_event (GdkEventDropDataAvailable *event, int *argc) -{ - int count, i, len; - int arguments; - char *p, **argv; - - /* Count the number of file names received */ - count = event->data_numbytes; - p = event->data; - arguments = 0; - while (count){ - arguments++; - len = strlen (p) + 1; - count -= len; - p += len; - } - - /* Create the exec vector with all of the filenames */ - argv = (char **) xmalloc (sizeof (char *) * arguments + 1, "arguments"); - count = event->data_numbytes; - p = event->data; - i = 0; - do { - len = 1 + strlen (p); - count -= len; - argv [i++] = p; - p += len; - } while (count); - argv [i] = 0; - *argc = i; - - return argv; -} -#endif /* OLD_DND */ - -void -drop_on_directory (GtkSelectionData *sel_data, GdkDragContext *context, - GdkDragAction action, char *dest, int force_manually) -{ - WPanel *source_panel; - GList *names; - - gdk_flush (); - g_warning ("Figure out the data type\n"); - if (sel_data->data == NULL) - return; - - printf ("action=%d\n", action); - if (action == GDK_ACTION_ASK){ - g_warning ("I need the event here\n"); -#if 0 - action = get_operation (event->timestamp, event->coords.x, event->coords.y); -#endif - } - - printf ("action=%d\n", action); - if (action == GDK_ACTION_ASK) - return; - - /* - * Optimization: if we are dragging from the same process, we can - * display a nicer status bar. - */ - source_panel = find_panel_owning_window (context->source_window); - - printf ("SOurce_Panel=%p\n", source_panel); - - names = gnome_uri_list_extract_uris ((char *)sel_data->data); - - /* Symlinks do not use any panel/file.c optimization */ - if (action == GDK_ACTION_LINK){ - do_symlinks (names, dest); - gnome_uri_list_free_strings (names); - return; - } - - if (source_panel && !force_manually){ - perform_drop_on_directory (source_panel, action, dest); - update_one_panel_widget (source_panel, 0, UP_KEEPSEL); - panel_update_contents (source_panel); - } else - perform_drop_manually (names, action, dest); - - gnome_uri_list_free_strings (names); - return; -} - -/* - * destroys a desktop_icon_t structure and anything that was held there, - * including the desktop widget. - */ -static void -desktop_release_desktop_icon_t (desktop_icon_t *di, int destroy_dentry) -{ - if (di->dentry){ - if (destroy_dentry) - gnome_desktop_entry_destroy (di->dentry); - else - gnome_desktop_entry_free (di->dentry); - } else { - free (di->pathname); - di->pathname = 0; - } - - if (di->widget){ - gtk_widget_destroy (di->widget); - di->widget = 0; - } - free (di); -} - -static int -remove_directory (char *path) -{ - int i; - - if (confirm_delete){ - char *buffer; - - if (know_not_what_am_i_doing) - query_set_sel (1); - buffer = copy_strings (_("Do you want to delete "), path, "?", NULL); - i = query_dialog (_("Delete"), buffer, - D_ERROR, 2, _("&Yes"), _("&No")); - free (buffer); - if (i != 0) - return 0; - } - create_op_win (OP_DELETE, 0); - erase_dir (path); - destroy_op_win (); - update_panels (UP_OPTIMIZE, UP_KEEPSEL); - return 1; -} - -/* - * Removes an icon from the desktop and kills the ~/desktop file associated with it - */ -static void -desktop_icon_remove (desktop_icon_t *di) -{ - desktop_icons = g_list_remove (desktop_icons, di); - - if (di->dentry == NULL){ - /* launch entry */ - mc_unlink (di->pathname); - } else { - /* a .destop file or a directory */ - /* Remove the .desktop */ - mc_unlink (di->dentry->location); - - if (strcmp (di->dentry->type, "Directory") == 0){ - struct stat s; - - if (mc_lstat (di->dentry->exec[0], &s) == 0){ - if (S_ISLNK (s.st_mode)) - mc_unlink (di->dentry->exec[0]); - else - if (!remove_directory (di->dentry->exec[0])) - return; - } - } else { - if (strncmp (di->dentry->exec [0], desktop_directory, strlen (desktop_directory)) == 0) - mc_unlink (di->dentry->exec [0]); - } - } - desktop_release_desktop_icon_t (di, 1); -} - -#ifdef OLD_DN -static void -drop_on_launch_entry (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) -{ - struct stat s; - char *r; - char **drops; - int drop_count; - - /* try to stat it, if it fails, remove it from desktop */ - if (!mc_stat (di->dentry->exec [0], &s) == 0){ - desktop_icon_remove (di); - return; - } - - drops = drops_from_event (event, &drop_count); - - r = regex_command (di->pathname, "Drop", drops, 0); - if (r && strcmp (r, "Success") == 0){ - free (drops); - return; - } - - if (is_exe (s.st_mode)) - gnome_desktop_entry_launch_with_args (di->dentry, drop_count, drops); - - free (drops); -} - -static void -url_dropped (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) -{ - char *p; - int count; - int len; - int is_directory = 0; - - /* if DI is set to zero, then it is a drop on the root window */ - if (di) - is_directory = strcasecmp (di->dentry->type, "directory") == 0; - else { - char *drop_location; - - drop_on_directory (event, desktop_directory, 1); - desktop_reload (desktop_directory, &event->coords); - return; - } - - if (is_directory){ - drop_on_directory (event, di->dentry->exec[0], 0); - return; - } - - /* Last case: regular desktop stuff */ - drop_on_launch_entry (widget, event, di); -} - -static int -drop_cb (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) -{ - if (strcmp (event->data_type, "icon/root") == 0){ - printf ("ICON DROPPED ON ROOT!\n"); - } if (strcmp (event->data_type, "url:ALL") == 0 || - (strcmp (event->data_type, "file:ALL") == 0) || - (strcmp (event->data_type, "text/plain") == 0)){ - url_dropped (widget, event, di); - } else - return FALSE; - return TRUE; -} - -static void -drop_enter_leave () -{ -/* printf ("Enter/Leave\n"); */ -} - -static void -connect_drop_signals (GtkWidget *widget, desktop_icon_t *di) -{ - GtkObject *o = GTK_OBJECT (widget); - - gtk_signal_connect (o, "drop_enter_event", GTK_SIGNAL_FUNC (drop_enter_leave), di); - gtk_signal_connect (o, "drop_leave_event", GTK_SIGNAL_FUNC (drop_enter_leave), di); - gtk_signal_connect (o, "drop_data_available_event", GTK_SIGNAL_FUNC (drop_cb), di); -} -#endif /* OLD DND */ - -void -desktop_icon_execute (GtkWidget *ignored, desktop_icon_t *di) -{ - /* Ultra lame-o execute. This should be replaced by the fixed regexp_command - * invocation - */ - - if (strcmp (di->dentry->type, "Directory") == 0) - new_panel_at (di->dentry->exec[0]); - else - gnome_desktop_entry_launch (di->dentry); -} - -static void -start_icon_drag (GtkWidget *wi, GdkEventMotion *event) -{ - printf ("MOTION NOTIF!\n"); -#ifdef OLD_DND - artificial_drag_start (wi->window, event->x, event->y); -#endif -} - -GdkPoint root_icon_drag_hotspot = { 15, 15 }; - -static void -desktop_icon_configure_position (desktop_icon_t *di, int x, int y) -{ - gtk_widget_set_uposition (di->widget, x, y); - - if (di->dentry){ - char buffer [40]; - - sprintf (buffer, "%d,%d", x, y); - if (di->dentry->geometry) - g_free (di->dentry->geometry); - di->dentry->geometry = g_strdup (buffer); - gnome_desktop_entry_save (di->dentry); - } -} - -#ifdef OLD_DND -static void -desktop_icon_drag_request (GtkWidget *widget, GdkEventDragRequest *event, desktop_icon_t *di) -{ - printf ("Drag type: %s\n", event->data_type); - - if (strcmp (event->data_type, "url:ALL") == 0){ - gdk_window_dnd_data_set (widget->window, (GdkEvent *)event, di->pathname, strlen (di->pathname) + 1); - } else { - int drop_x, drop_y; - - drop_x = event->drop_coords.x - root_icon_drag_hotspot.x; - drop_y = event->drop_coords.y - root_icon_drag_hotspot.y; - - /* Icon dropped on root. We take care of it */ - printf ("Dropped at %d %d\n", drop_x, drop_y); - - if (di->grid_x != -1) - set_spot_val (di->grid_x, di->grid_y, 0); - - if (icons_snap_to_grid){ - snap_to (di, 0, drop_x, drop_y); - get_icon_screen_x_y (di, &drop_x, &drop_y); - } - - desktop_icon_configure_position (di, drop_x, drop_y); - } -} -#endif - -static GtkWidget *root_drag_ok_window; -static GtkWidget *root_drag_not_ok_window; - -static void -destroy_shaped_dnd_windows (void) -{ - if (root_drag_not_ok_window){ - gtk_widget_destroy (root_drag_not_ok_window); - root_drag_not_ok_window = 0; - } - - if (root_drag_ok_window){ - gtk_widget_destroy (root_drag_ok_window); - root_drag_ok_window = 0; - } -} - -void -gnome_arrange_icons (void) -{ - GList *l; - - current_x = current_y = 0; - memset (spot_array, 0, (x_spots * y_spots)/8); - - for (l = desktop_icons; l; l = l->next){ - desktop_icon_t *di = l->data; - int x, y; - - snap_to (di, 1, current_x, current_y); - get_icon_screen_x_y (di, &x, &y); - desktop_icon_configure_position (di, x, y); - - current_y += SNAP_Y; - if (current_y == gdk_screen_height ()){ - current_y = 0; - current_x += SNAP_X; - } - } -} - -/* As Elliot can not be bothered to fix his DnD code in Gdk and it is an absolute mess */ -static int in_desktop_dnd; - -static void -desktop_icon_drag_start (GtkWidget *widget, GdkEvent *event, desktop_icon_t *di) -{ - char *fname; - - if (in_desktop_dnd) - return; - - in_desktop_dnd = 1; - - /* This should not happen, as the drag end routine should destroy those widgets */ - destroy_shaped_dnd_windows (); - - if (di->dentry) - fname = strdup (di->dentry->icon); - else - fname = get_desktop_icon (di->pathname); - - if (fname){ - /* FIXME: we are using the same icon for ok and not ok drags */ - root_drag_ok_window = make_transparent_window (fname); - root_drag_not_ok_window = make_transparent_window (fname); - if (root_drag_not_ok_window && root_drag_ok_window){ -#ifdef OLD_DND - gdk_dnd_set_drag_shape (root_drag_ok_window->window, &root_icon_drag_hotspot, - root_drag_not_ok_window->window, &root_icon_drag_hotspot); -#endif - gtk_widget_show (root_drag_not_ok_window); - gtk_widget_show (root_drag_ok_window); - } - free (fname); - } -} - -static void -desktop_icon_drag_end (GtkWidget *widget, GdkEvent *event, desktop_icon_t *di) -{ - in_desktop_dnd = 0; - destroy_shaped_dnd_windows (); -} - -/* - * Bind the signals so that we can make this icon draggable - */ -static void -desktop_icon_make_draggable (desktop_icon_t *di) -{ - GtkObject *obj; - GList *child; - char *drag_types [] = { "icon/root", "url:ALL" }; - - child = gtk_container_children(GTK_CONTAINER(di->widget)); - obj = GTK_OBJECT (child->data); - /* To artificially start up drag and drop */ - -#ifdef OLD_DND -/* gtk_signal_connect (obj, "motion_notify_event", GTK_SIGNAL_FUNC (start_icon_drag), di); */ - gtk_widget_dnd_drag_set (GTK_WIDGET(child->data), TRUE, drag_types, ELEMENTS (drag_types)); - - gtk_signal_connect (obj, "drag_request_event", GTK_SIGNAL_FUNC (desktop_icon_drag_request), di); - gtk_signal_connect (obj, "drag_begin_event", GTK_SIGNAL_FUNC (desktop_icon_drag_start), di); - gtk_signal_connect (obj, "drag_end_event", GTK_SIGNAL_FUNC (desktop_icon_drag_end), di); -#endif -} - -/* Called by the pop up menu: removes the icon from the desktop */ -void -desktop_icon_delete (GtkWidget *widget, desktop_icon_t *di) -{ - desktop_icon_remove (di); -} - -GtkWidget * -create_desktop_icon (char *file, char *text) -{ - GtkWidget *w; - - if (g_file_exists (file)) - w = desktop_icon_new (file, text); - else { - static char *default_image; - - if (!default_image) - default_image = gnome_unconditional_pixmap_file ("launcher-program.png"); - - if (g_file_exists (default_image)) - w = desktop_icon_new (default_image, text); - else - w = NULL; - } - - return w; -} - -static GtkWidget * -get_desktop_icon_for_dentry (GnomeDesktopEntry *dentry) -{ - GtkWidget *dicon; - char *icon_label; - - icon_label = dentry->name ? dentry->name : x_basename (dentry->exec[0]); - - if (dentry->icon) - dicon = create_desktop_icon (dentry->icon, icon_label); - else { - static char *default_icon_path; - static char exists; - - if (!default_icon_path) { - default_icon_path = gnome_unconditional_pixmap_file ("launcher-program.png"); - if (g_file_exists (default_icon_path)) - exists = 1; - } - - if (exists) - dicon = create_desktop_icon (default_icon_path, icon_label); - else { - dicon = gtk_window_new (GTK_WINDOW_POPUP); - gtk_widget_set_usize (dicon, 20, 20); - } - } - - return dicon; -} - -static GtkWidget * -get_desktop_icon_for_di (desktop_icon_t *di) -{ - GtkWidget *window; - char *icon_label, *icon; - - icon_label = x_basename (di->pathname); - - icon = get_desktop_icon (di->pathname); - window = create_desktop_icon (icon, icon_label); - g_free (icon); - return window; -} - -static int -dentry_button_click (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di) -{ - if (event->button == 1){ - if (event->type == GDK_2BUTTON_PRESS) - desktop_icon_execute (widget, di); - - return TRUE; - } - - if (event->type == GDK_BUTTON_PRESS && event->button == 3){ - desktop_icon_context_popup (event, di); - return TRUE; - } - return FALSE; -} - -char *drop_types [] = { - "text/plain", - "url:ALL", -}; - -static void -post_setup_desktop_icon (desktop_icon_t *di, int show) -{ - GList *child; - desktop_icon_make_draggable (di); - - /* Setup the widget to make it useful: */ - -#ifdef OLD_DND - /* 1. Drag and drop functionality */ - - child = gtk_container_children(GTK_CONTAINER(di->widget)); - connect_drop_signals (GTK_WIDGET(child->data), di); - gtk_widget_dnd_drop_set (GTK_WIDGET(child->data), TRUE, drop_types, ELEMENTS (drop_types), FALSE); - - /* 2. Double clicking executes the command */ - gtk_signal_connect (GTK_OBJECT (child->data), "button_press_event", GTK_SIGNAL_FUNC (dentry_button_click), di); - -#endif - if (show) - gtk_widget_show (di->widget); -} - -/* Pops up the icon properties pages */ -void -desktop_icon_properties (GtkWidget *widget, desktop_icon_t *di) -{ - int retval; - - retval = item_properties (di->widget, di->pathname, di); - - if (retval & (GPROP_TITLE | GPROP_ICON | GPROP_FILENAME)) { - gtk_widget_destroy (di->widget); - - if (di->dentry) - di->widget = get_desktop_icon_for_dentry (di->dentry); - else - di->widget = get_desktop_icon_for_di (di); - - if (icons_snap_to_grid && di->grid_x != -1) - get_icon_screen_x_y (di, &di->x, &di->y); - - gtk_widget_set_uposition (di->widget, di->x, di->y); - - post_setup_desktop_icon (di, 1); - - if (di->dentry) - gnome_desktop_entry_save (di->dentry); - } -} - -/* - * Activates the context sensitive menu for this icon - */ -static void -desktop_icon_context_popup (GdkEventButton *event, desktop_icon_t *di) -{ - file_popup (event, NULL, di, 0, di->dentry->exec [0]); -} - -char *root_drop_types [] = { - "icon/root", - "url:ALL" -}; - -static void -desktop_load_from_dentry (GnomeDesktopEntry *dentry) -{ - GtkWidget *dicon; - desktop_icon_t *di; - - dicon = get_desktop_icon_for_dentry (dentry); - - if (!dicon) - return; - - di = xmalloc (sizeof (desktop_icon_t), "desktop_load_entry"); - di->dentry = dentry; - di->widget = dicon; - di->pathname = dentry->location; - - desktop_icons = g_list_prepend (desktop_icons, di); - - post_setup_desktop_icon (di, 0); - desktop_icon_set_position (di); -} - -/* - * Loads a .desktop file from FILENAME for the desktop. - */ -static void -desktop_load_dentry (char *filename) -{ - GnomeDesktopEntry *dentry; - - dentry = gnome_desktop_entry_load (filename); - - if (!dentry) - return; - - desktop_load_from_dentry (dentry); -} - -/* Set the drop position to NULL, we only drop the - * first icon on the spot it was dropped, th rest - * get auto-layouted. Perhaps this should be an option. - */ -static void -desktop_setup_geometry_from_point (GnomeDesktopEntry *dentry, GdkPoint **point) -{ - char buffer [40]; - - sprintf (buffer, "%d,%d", (*point)->x, (*point)->y); - dentry->geometry = g_strdup (buffer); - *point = NULL; -} - -/* - * Creates a new DIRECTORY/.directory file which is just a .dekstop - * on directories. And then loads it into the desktop - */ -static void -desktop_create_directory_entry (char *dentry_path, char *pathname, char *short_name, GdkPoint **pos) -{ - GnomeDesktopEntry *dentry; - - dentry = xmalloc (sizeof (GnomeDesktopEntry), "dcde"); - memset (dentry, 0, sizeof (GnomeDesktopEntry)); - dentry->name = g_strdup (short_name); - dentry->exec = (char **) malloc (2 * sizeof (char *)); - dentry->exec[0] = g_strdup (pathname); - dentry->exec[1] = NULL; - dentry->exec_length = 1; - dentry->icon = gnome_unconditional_pixmap_file ("gnome-folder.png"); - dentry->type = g_strdup ("Directory"); - dentry->location = g_strdup (dentry_path); - if (pos && *pos) - desktop_setup_geometry_from_point (dentry, pos); - - gnome_desktop_entry_save (dentry); - desktop_load_from_dentry (dentry); -} - -static int -file_is_executable (char *path) -{ - struct stat s; - - if (mc_stat (path, &s) == -1) - return 0; - - if (is_exe (s.st_mode)) - return 1; - return 0; - -} - -static int -desktop_file_exec (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di) -{ - if (event->type == GDK_2BUTTON_PRESS && event->button == 1){ - if (di->dentry){ - printf ("FIXME: No support for dentry loaded stuff yet\n"); - } else { - if (file_is_executable (di->pathname)){ - char *tmp = name_quote (di->pathname, 0); - - if (!confirm_execute || (query_dialog (_(" The Midnight Commander "), - _(" Do you really want to execute? "), - 0, 2, _("&Yes"), _("&No")) == 0)) - execute (tmp); - free (tmp); - } else { - char *result, *command; - - result = regex_command (di->pathname, "Open", NULL, 0); - if (result && (strcmp (result, "Success") == 0)) - return TRUE; - command = input_expand_dialog (_("Open with..."), - _("Enter extra arguments:"), - di->pathname); - if (command){ - execute (command); - free (command); - } - } - } - return TRUE; - } - - if (event->type == GDK_BUTTON_PRESS && event->button == 3){ - desktop_icon_context_popup (event, di); - return TRUE; - } - - return FALSE; -} - -static void -desktop_create_launch_entry (char *desktop_file, char *pathname, char *short_name, GdkPoint **pos) -{ - GnomeDesktopEntry *dentry; - GtkWidget *dicon; - desktop_icon_t *di; - char *icon; - struct stat s; - - stat (pathname, &s); - dentry = xmalloc (sizeof (GnomeDesktopEntry), "launch_entry"); - memset (dentry, 0, sizeof (GnomeDesktopEntry)); - - dentry->name = g_strdup (short_name); - dentry->exec = (char **) malloc (2 * sizeof (char *)); - dentry->exec[0] = g_strdup (pathname); - dentry->exec[1] = NULL; - dentry->exec_length = 1; - dentry->icon = get_desktop_icon (short_name); - dentry->type = g_strdup ("File"); - dentry->location = g_strdup (desktop_file); - dentry->terminal = 1; - if (pos && *pos) - desktop_setup_geometry_from_point (dentry, pos); - - gnome_desktop_entry_save (dentry); - desktop_load_from_dentry (dentry); -#if 0 - dicon = create_desktop_icon (icon, x_basename (pathname)); - g_free (icon); - if (!dicon) - return; - - di = xmalloc (sizeof (desktop_icon_t), "dcle"); - di->dentry = NULL; - di->widget = dicon; - di->pathname = strdup (pathname); - - desktop_icon_set_position (di); - desktop_icon_make_draggable (di); - - desktop_icons = g_list_prepend (desktop_icons, (gpointer) di); - - /* Double clicking executes the command, single clicking brings up context menu */ - gtk_signal_connect (GTK_OBJECT (dicon), "button_press_event", GTK_SIGNAL_FUNC (desktop_file_exec), di); - gtk_widget_realize (dicon); - - gtk_signal_connect (GTK_OBJECT (dicon), "drop_data_available_event", - GTK_SIGNAL_FUNC (drop_on_launch_entry), di); - - gtk_widget_dnd_drop_set (dicon, TRUE, drop_types, ELEMENTS (drop_types), FALSE); -#endif -} - -static int -desktop_pathname_loaded (char *pathname) -{ - GList *p = desktop_icons; - - for (; p; p = p->next){ - desktop_icon_t *di = p->data; - - if (strcmp (di->pathname, pathname) == 0) - return 1; - } - return 0; -} - -static void -desktop_setup_icon (char *filename, char *full_pathname, GdkPoint **desired_position) -{ - struct stat s; - - if (mc_stat (full_pathname, &s) == -1) - return; - - if (S_ISDIR (s.st_mode)){ - char *dir_full = concat_dir_and_file (full_pathname, ".directory"); - - if (!desktop_pathname_loaded (dir_full)){ - if (exist_file (dir_full)) - desktop_load_dentry (dir_full); - else - desktop_create_directory_entry (dir_full, full_pathname, filename, desired_position); - } - free (dir_full); - } else { - if (strstr (filename, ".desktop")){ - if (!desktop_pathname_loaded (full_pathname)) - desktop_load_dentry (full_pathname); - } else { - char *desktop_version; - - desktop_version = copy_strings (full_pathname, ".desktop", NULL); - if (!exist_file (desktop_version) && !desktop_pathname_loaded (full_pathname)) - desktop_create_launch_entry (desktop_version, full_pathname, filename, desired_position); - free (desktop_version); - } - } -} - - -/* - * Load all of the entries available on the ~/desktop directory - * So far, we support: .desktop files; directories (they get a .directory file); - * sylinks to directories; other programs. - */ -static void -desktop_reload (char *desktop_dir, GdkPoint *drop_position) -{ - struct dirent *dent; - GList *l; - DIR *dir; - - dir = mc_opendir (desktop_dir); - if (dir == NULL){ - message (1, _(" Warning "), _(" Could not open %s directory"), desktop_dir, NULL); - return; - } - - while ((dent = mc_readdir (dir)) != NULL){ - char *full; - - /* ignore '.' */ - if (dent->d_name [0] == '.' && dent->d_name [1] == 0) - continue; - - /* ignore `..' */ - if (dent->d_name [0] == '.' && dent->d_name [1] == '.' && dent->d_name [2] == 0) - continue; - - full = concat_dir_and_file (desktop_dir, dent->d_name); - desktop_setup_icon (dent->d_name, full, &drop_position); - - free (full); - } - mc_closedir (dir); - - /* Show all of the widgets */ - for (l = desktop_icons; l; l = l->next){ - desktop_icon_t *di = l->data; - - gtk_widget_show (di->widget); - } -} - -static void -desktop_load (char *desktop_dir) -{ - desktop_reload (desktop_dir, NULL); -} - -/* - * Copy the system defaults to the user ~/desktop directory and setup a - * Home directory link - */ -static void -desktop_setup_default (char *desktop_dir) -{ - char *mc_desktop_dir; - char *desktop_dir_home_link; - - desktop_dir_home_link = concat_dir_and_file (desktop_dir, "Home directory.desktop"); - - mc_desktop_dir = concat_dir_and_file (mc_home, MC_LIB_DESKTOP); - - if (exist_file (mc_desktop_dir)){ - create_op_win (OP_COPY, 0); - file_mask_defaults (); - copy_dir_dir (mc_desktop_dir, desktop_dir, 1, 0, 0, 0); - destroy_op_win (); - } else - mkdir (desktop_dir, 0777); - - desktop_create_directory_entry (desktop_dir_home_link, "~", "Home directory", NULL); - free (desktop_dir_home_link); - free (mc_desktop_dir); -} - -/* - * configures the root window dropability - */ -void -desktop_root (void) -{ - GtkWidget *rw; - - rw = gnome_rootwin_new (); -#ifdef OLD_DND - connect_drop_signals (rw, NULL); - gtk_widget_dnd_drop_set (rw, TRUE, root_drop_types, ELEMENTS (root_drop_types), FALSE); - gtk_widget_realize (rw); - gtk_widget_show (rw); - root_window = GNOME_ROOTWIN (rw); -#endif -} - -/* - * entry point to start up the gnome desktop - */ -void -start_desktop (void) -{ - init_spot_list (); - desktop_directory = concat_dir_and_file (home_dir, "desktop"); - - if (!exist_file (desktop_directory)) - desktop_setup_default (desktop_directory); - - desktop_root (); - desktop_load (desktop_directory); -} - -/* - * shutdown the desktop - */ -void -stop_desktop (void) -{ - GList *p; - - for (p = desktop_icons; p; p = p->next){ - desktop_icon_t *di = p->data; - - desktop_release_desktop_icon_t (di, 0); - } - image_cache_destroy (); -} - -#endif diff --git a/gnome/gmetadata.c b/gnome/gmetadata.c index 7a4b0941c..664e9758c 100644 --- a/gnome/gmetadata.c +++ b/gnome/gmetadata.c @@ -13,44 +13,9 @@ #include "../vfs/vfs.h" -#define ICON_FILENAME "icon-filename" #define ICON_POSITION "icon-position" -/** - * gmeta_get_icon_for_file - * @filename: The name of the file to get the icon for. - * - * Computes the name of the file that holds the icon for the specified file. The - * resulting string is guaranteed to be non-NULL. You have to free this string - * on your own. - * - * Returns the icon's file name. - */ -char * -gmeta_get_icon_for_file (char *filename) -{ - int size; - char *buf; - struct stat s; - int retval; - - g_return_val_if_fail (filename != NULL, NULL); - - if (gnome_metadata_get (filename, ICON_FILENAME, &size, &buf) != 0) { - /* Return a default icon */ - - retval = mc_stat (filename, &s); - - if (!retval && S_ISDIR (s.st_mode)) - return gnome_unconditional_pixmap_file ("gnome-folder.png"); - else - return gnome_unconditional_pixmap_file ("gnome-unknown.png"); - } - - return buf; -} - /** * gmeta_get_icon_pos * @filename: The file under ~/desktop for which to get the icon position diff --git a/gnome/gmetadata.h b/gnome/gmetadata.h index 11382a209..1eb526b5d 100644 --- a/gnome/gmetadata.h +++ b/gnome/gmetadata.h @@ -9,9 +9,6 @@ #define GMETADATA_H -/* Returns the icon filename for the specified file. You must free the name. */ -char *gmeta_get_icon_for_file (char *filename); - /* Returns the coordinates of the icon corresponding to the specified file. If no position * has been set, returns FALSE. Else it returns TRUE and sets the *x and *y values. */ diff --git a/gnome/olddnd.c b/gnome/olddnd.c index bbbc12e65..48281de9c 100644 --- a/gnome/olddnd.c +++ b/gnome/olddnd.c @@ -233,3 +233,1489 @@ panel_icon_list_drop_data_available (GtkWidget *widget, GdkEventDropDataAvailabl panel_update_contents (panel); } #endif + + + + +#ifdef THIS_WAS_THE_OLD_DND_FOR_DESKTOP_DOT_C + +#include +#include "fs.h" +#include +#include "gdesktop-icon.h" +#include "gdesktop.h" +#include "../vfs/vfs.h" +#include +#include "mad.h" +#include "main.h" +#include "file.h" +#include "global.h" +#include "panel.h" +#include "gscreen.h" +#include "ext.h" +#include "dialog.h" +#include "gpageprop.h" +#include +#include +#include "gcache.h" +#include "gmain.h" + +/* places used in the grid */ +static char *spot_array; + +/* number of icons that fit along the x and y axis */ +static int x_spots, y_spots; + +/* operations on drops */ +enum { + OPER_COPY, + OPER_MOVE, + OPER_LINK +}; + +/* The X11 root window */ +static GnomeRootWin *root_window; + + +/* The full name of the desktop directory ~/desktop */ +char *desktop_directory; + +static void desktop_reload (char *desktop_dir, GdkPoint *drop_position); +static void desktop_icon_context_popup (GdkEventButton *event, desktop_icon_t *di); + +/* The list with the filenames we have actually loaded */ +static GList *desktop_icons; + +#define ELEMENTS(x) (sizeof (x) / sizeof (x[0])) + +static void +init_spot_list (void) +{ + int size; + + x_spots = gdk_screen_width () / SNAP_X; + y_spots = gdk_screen_height () / SNAP_Y; + size = (x_spots * y_spots) / 8; + spot_array = xmalloc (size+1, "spot_array"); + memset (spot_array, 0, size); +} + +static int +is_spot_set (int x, int y) +{ + int o = (x * x_spots + y); + int idx = o / 8; + int bit = o % 8; + + return spot_array [idx] & (1 << bit); +} + +static void +set_spot_val (int x, int y, int set) +{ + int o = (x * x_spots + y); + int idx = o / 8; + int bit = o % 8; + + if (set) + spot_array [idx] |= (1 << bit); + else + spot_array [idx] &= ~(1 << bit); +} + +static void +allocate_free_spot (int *rx, int *ry) +{ + int x, y; + + for (x = 0; x < x_spots; x++) + for (y = 0; y < y_spots; y++) + if (!is_spot_set (x, y)){ + *rx = x; + *ry = y; + set_spot_val (x, y, 1); + return; + } +} + +static void +snap_to (desktop_icon_t *di, int absolute, int x, int y) +{ + int nx = x/SNAP_X; + int ny = y/SNAP_Y; + + if (!absolute && is_spot_set (nx, ny)) + allocate_free_spot (&di->grid_x, &di->grid_y); + else { + set_spot_val (nx, ny, 1); + di->grid_x = nx; + di->grid_y = ny; + } + +} + +/* Get snapped position for an icon */ +static void +get_icon_screen_x_y (desktop_icon_t *di, int *x, int *y) +{ + int w, h; + + w = DESKTOP_ICON (di->widget)->width; + h = DESKTOP_ICON (di->widget)->height; + + if (di->grid_x != -1){ + *x = di->grid_x * SNAP_X; + *y = di->grid_y * SNAP_Y; + + *x = *x + (SNAP_X - w) / 2; + if (*x < 0) + *x = 0; + + if (h > SNAP_Y) + *y = *y + (SNAP_Y - h) / 2; + else + *y = *y + (SNAP_Y - h); + } else { + *x = di->x; + *y = di->y; + } +} + +/* + * If the dentry is zero, then no information from the on-disk .desktop file is used + * In this case, we probably will have to store the geometry for a file somewhere + * else. + */ +static int current_x, current_y; + +static void +desktop_icon_set_position (desktop_icon_t *di) +{ + static int x, y = 10; + + x = -1; + if (di->dentry && di->dentry->geometry){ + char *comma = strchr (di->dentry->geometry, ','); + + if (comma){ + x = atoi (di->dentry->geometry); + comma++; + y = atoi (comma); + } + } + + if (icons_snap_to_grid){ + if (x == -1){ + x = current_x; + y = current_y; + + current_y += SNAP_Y; + if (current_y > gdk_screen_height ()) + current_x += SNAP_X; + + snap_to (di, 1, x, y); + } else + snap_to (di, 0, x, y); + + get_icon_screen_x_y (di, &x, &y); + } else { + /* This find-spot routine can obviously be improved, left as an excercise + * to the hacker + */ + if (x == -1){ + x = current_x; + y = current_y; + + current_y += DESKTOP_ICON (di)->height + 8; + if (current_y > gdk_screen_height ()){ + current_x += SNAP_X; + current_y = 0; + } + } + x += 6; + di->grid_x = di->grid_y = -1; + } + + di->x = x; + di->y = y; + + gtk_widget_set_uposition (di->widget, x, y); +} + +/* + * Returns the icon associated with the given file name, or app.xpm + * if no icon is defined for this application + */ +static char * +get_desktop_icon (char *pathname) +{ + char *fname, *full_fname; + + fname = regex_command (x_basename (pathname), "Icon", 0, 0); + + /* Try the GNOME icon */ + if (fname){ + full_fname = gnome_unconditional_pixmap_file (fname); + free (fname); + if (exist_file (full_fname)) + return full_fname; + g_free (full_fname); + } + + /* Try a mc icon */ + if (fname){ + full_fname = concat_dir_and_file (ICONDIR, fname); + if (exist_file (full_fname)) + return full_fname; + + free (full_fname); + } + + return gnome_unconditional_pixmap_file ("launcher-program.png"); +} + +/* + * Hackisigh routine taken from GDK + */ +#ifdef OLD_DND +static void +gdk_dnd_drag_begin (GdkWindow *initial_window) +{ + GdkEventDragBegin tev; + tev.type = GDK_DRAG_BEGIN; + tev.window = initial_window; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + + gdk_event_put ((GdkEvent *) &tev); +} + +void +artificial_drag_start (GdkWindow *window, int x, int y) +{ + GdkWindowPrivate *wp = (GdkWindowPrivate *) window; + + if (!wp->dnd_drag_enabled) + return; +#if 1 + if (!gdk_dnd.drag_perhaps) + return; + if (gdk_dnd.dnd_grabbed) + return; + if (gdk_dnd.drag_really) + return; + gdk_dnd_drag_addwindow (window); + gdk_dnd_drag_begin (window); + XGrabPointer (gdk_display, wp->xwindow, False, + ButtonMotionMask | ButtonPressMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, gdk_root_window, + None, CurrentTime); + gdk_dnd.dnd_grabbed = TRUE; + gdk_dnd.drag_really = 1; + gdk_dnd_display_drag_cursor (x, y, FALSE, TRUE); +#else + gdk_dnd.real_sw = wp; + gdk_dnd.dnd_drag_start.x = x; + gdk_dnd.dnd_drag_start.y = y; + gdk_dnd.drag_perhaps = 1; + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; + gdk_dnd.dnd_grabbed = FALSE; + { + /* Set motion mask for first DnD'd window, since it + will be the one that is actually dragged */ + XWindowAttributes dnd_winattr; + XSetWindowAttributes dnd_setwinattr; + + /* We need to get motion events while the button is down, so + we can know whether to really start dragging or not... */ + XGetWindowAttributes(gdk_display, (Window)wp->xwindow, + &dnd_winattr); + + wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; + dnd_setwinattr.event_mask = + wp->dnd_drag_eventmask = ButtonMotionMask | ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask; + XChangeWindowAttributes(gdk_display, wp->xwindow, + CWEventMask, &dnd_setwinattr); + } +#endif +} +#endif /* OLD_DND */ + +static GdkDragAction operation_value; + +static void +set_option (GtkWidget *widget, GdkDragAction value) +{ + operation_value = value; + gtk_main_quit (); +} + +static void +option_menu_gone () +{ + operation_value = GDK_ACTION_ASK; + gtk_main_quit (); +} + +static GdkDragAction +get_operation (guint32 timestamp, int x, int y) +{ + static GtkWidget *menu; + + if (!menu){ + GtkWidget *item; + + menu = gtk_menu_new (); + + item = gtk_menu_item_new_with_label (_("Copy")); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_COPY); + gtk_menu_append (GTK_MENU (menu), item); + gtk_widget_show (item); + + item = gtk_menu_item_new_with_label (_("Move")); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_MOVE); + gtk_menu_append (GTK_MENU (menu), item); + gtk_widget_show (item); + + /* Not yet implemented the Link bits, so better to not show what we dont have */ + item = gtk_menu_item_new_with_label (_("Link")); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_LINK); + gtk_menu_append (GTK_MENU (menu), item); + gtk_widget_show (item); + + gtk_signal_connect (GTK_OBJECT (menu), "hide", GTK_SIGNAL_FUNC(option_menu_gone), 0); + } + + gtk_widget_set_uposition (menu, x, y); + + /* FIXME: We should catch any events that escape this menu and cancel it */ + operation_value = GDK_ACTION_ASK; + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, 0, NULL, 1, timestamp); + gtk_grab_add (menu); + gtk_main (); + gtk_grab_remove (menu); + gtk_widget_hide (menu); + + return operation_value; +} + +/* + * Used by check_window_id_in_one_panel and find_panel_owning_window_id for finding + * the panel that contains the specified window id (used to figure where the drag + * started) + */ +static WPanel *temp_panel; + +static void +check_window_in_one_panel (gpointer data, gpointer user_data) +{ + PanelContainer *pc = (PanelContainer *) data; + GdkWindowPrivate *w = (GdkWindowPrivate *) user_data; + WPanel *panel = pc->panel; + + if (panel->list_type == list_icons){ + GnomeIconList *icon_list = GNOME_ICON_LIST (panel->icons); + GdkWindowPrivate *wp = (GdkWindowPrivate *) GTK_WIDGET (icon_list)->window; + + if (w->xwindow == wp->xwindow){ + temp_panel = panel; + return; + } + } else { + GtkCList *clist = GTK_CLIST (panel->list); + GdkWindowPrivate *wp = (GdkWindowPrivate *) clist->clist_window; + + if (w->xwindow == wp->xwindow){ + temp_panel = panel; + return; + } + } +} + +static WPanel * +find_panel_owning_window (GdkWindow *window) +{ + temp_panel = NULL; + + printf ("Looking for window %x\n", window); + + g_list_foreach (containers, check_window_in_one_panel, window); + + return temp_panel; +} + +static void +perform_drop_on_directory (WPanel *source_panel, GdkDragAction action, char *dest) +{ + switch (action){ + case GDK_ACTION_COPY: + panel_operate (source_panel, OP_COPY, dest); + break; + + case GDK_ACTION_MOVE: + panel_operate (source_panel, OP_MOVE, dest); + break; + } +} + +static void +perform_drop_manually (GList *names, GdkDragAction action, char *dest) +{ + struct stat buf; + + switch (action){ + case GDK_ACTION_COPY: + create_op_win (OP_COPY, 0); + break; + + case GDK_ACTION_MOVE: + create_op_win (OP_MOVE, 0); + break; + + default: + g_assert_not_reached (); + } + + file_mask_defaults (); + + for (; names; names = names->next){ + char *p = names->data; + char *tmpf; + int res, v; + + if (strncmp (p, "file:", 5) == 0) + p += 5; + + switch (action){ + case GDK_ACTION_COPY: + tmpf = concat_dir_and_file (dest, x_basename (p)); + do { + res = mc_stat (p, &buf); + if (res != 0){ + v = file_error (" Could not stat %s \n %s ", tmpf); + if (v != FILE_RETRY) + res = 0; + } else { + if (S_ISDIR (buf.st_mode)) + copy_dir_dir (p, tmpf, 1, 0, 0, 0); + else + copy_file_file (p, tmpf, 1); + } + } while (res != 0); + free (tmpf); + break; + + case GDK_ACTION_MOVE: + tmpf = concat_dir_and_file (dest, x_basename (p)); + do { + res = mc_stat (p, &buf); + if (res != 0){ + v = file_error (" Could not stat %s \n %s ", tmpf); + if (v != FILE_RETRY) + res = 0; + } else { + if (S_ISDIR (buf.st_mode)) + move_dir_dir (p, tmpf); + else + move_file_file (p, tmpf); + } + } while (res != 0); + free (tmpf); + break; + + default: + g_assert_not_reached (); + } + } + + destroy_op_win (); +} + +static void +do_symlinks (GList *names, char *dest) +{ + for (; names; names = names->next){ + char *full_dest_name; + char *name = names->data; + + full_dest_name = concat_dir_and_file (dest, x_basename (name)); + if (strncmp (name, "file:", 5) == 0) + mc_symlink (name+5, full_dest_name); + else + mc_symlink (name, full_dest_name); + + free (full_dest_name); + } +} + +#if OLD_DND +static char ** +drops_from_event (GdkEventDropDataAvailable *event, int *argc) +{ + int count, i, len; + int arguments; + char *p, **argv; + + /* Count the number of file names received */ + count = event->data_numbytes; + p = event->data; + arguments = 0; + while (count){ + arguments++; + len = strlen (p) + 1; + count -= len; + p += len; + } + + /* Create the exec vector with all of the filenames */ + argv = (char **) xmalloc (sizeof (char *) * arguments + 1, "arguments"); + count = event->data_numbytes; + p = event->data; + i = 0; + do { + len = 1 + strlen (p); + count -= len; + argv [i++] = p; + p += len; + } while (count); + argv [i] = 0; + *argc = i; + + return argv; +} +#endif /* OLD_DND */ + +void +drop_on_directory (GtkSelectionData *sel_data, GdkDragContext *context, + GdkDragAction action, char *dest, int force_manually) +{ + WPanel *source_panel; + GList *names; + + gdk_flush (); + g_warning ("Figure out the data type\n"); + if (sel_data->data == NULL) + return; + + printf ("action=%d\n", action); + if (action == GDK_ACTION_ASK){ + g_warning ("I need the event here\n"); +#if 0 + action = get_operation (event->timestamp, event->coords.x, event->coords.y); +#endif + } + + printf ("action=%d\n", action); + if (action == GDK_ACTION_ASK) + return; + + /* + * Optimization: if we are dragging from the same process, we can + * display a nicer status bar. + */ + source_panel = find_panel_owning_window (context->source_window); + + printf ("SOurce_Panel=%p\n", source_panel); + + names = gnome_uri_list_extract_uris ((char *)sel_data->data); + + /* Symlinks do not use any panel/file.c optimization */ + if (action == GDK_ACTION_LINK){ + do_symlinks (names, dest); + gnome_uri_list_free_strings (names); + return; + } + + if (source_panel && !force_manually){ + perform_drop_on_directory (source_panel, action, dest); + update_one_panel_widget (source_panel, 0, UP_KEEPSEL); + panel_update_contents (source_panel); + } else + perform_drop_manually (names, action, dest); + + gnome_uri_list_free_strings (names); + return; +} + +/* + * destroys a desktop_icon_t structure and anything that was held there, + * including the desktop widget. + */ +static void +desktop_release_desktop_icon_t (desktop_icon_t *di, int destroy_dentry) +{ + if (di->dentry){ + if (destroy_dentry) + gnome_desktop_entry_destroy (di->dentry); + else + gnome_desktop_entry_free (di->dentry); + } else { + free (di->pathname); + di->pathname = 0; + } + + if (di->widget){ + gtk_widget_destroy (di->widget); + di->widget = 0; + } + free (di); +} + +static int +remove_directory (char *path) +{ + int i; + + if (confirm_delete){ + char *buffer; + + if (know_not_what_am_i_doing) + query_set_sel (1); + buffer = copy_strings (_("Do you want to delete "), path, "?", NULL); + i = query_dialog (_("Delete"), buffer, + D_ERROR, 2, _("&Yes"), _("&No")); + free (buffer); + if (i != 0) + return 0; + } + create_op_win (OP_DELETE, 0); + erase_dir (path); + destroy_op_win (); + update_panels (UP_OPTIMIZE, UP_KEEPSEL); + return 1; +} + +/* + * Removes an icon from the desktop and kills the ~/desktop file associated with it + */ +static void +desktop_icon_remove (desktop_icon_t *di) +{ + desktop_icons = g_list_remove (desktop_icons, di); + + if (di->dentry == NULL){ + /* launch entry */ + mc_unlink (di->pathname); + } else { + /* a .destop file or a directory */ + /* Remove the .desktop */ + mc_unlink (di->dentry->location); + + if (strcmp (di->dentry->type, "Directory") == 0){ + struct stat s; + + if (mc_lstat (di->dentry->exec[0], &s) == 0){ + if (S_ISLNK (s.st_mode)) + mc_unlink (di->dentry->exec[0]); + else + if (!remove_directory (di->dentry->exec[0])) + return; + } + } else { + if (strncmp (di->dentry->exec [0], desktop_directory, strlen (desktop_directory)) == 0) + mc_unlink (di->dentry->exec [0]); + } + } + desktop_release_desktop_icon_t (di, 1); +} + +#ifdef OLD_DN +static void +drop_on_launch_entry (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) +{ + struct stat s; + char *r; + char **drops; + int drop_count; + + /* try to stat it, if it fails, remove it from desktop */ + if (!mc_stat (di->dentry->exec [0], &s) == 0){ + desktop_icon_remove (di); + return; + } + + drops = drops_from_event (event, &drop_count); + + r = regex_command (di->pathname, "Drop", drops, 0); + if (r && strcmp (r, "Success") == 0){ + free (drops); + return; + } + + if (is_exe (s.st_mode)) + gnome_desktop_entry_launch_with_args (di->dentry, drop_count, drops); + + free (drops); +} + +static void +url_dropped (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) +{ + char *p; + int count; + int len; + int is_directory = 0; + + /* if DI is set to zero, then it is a drop on the root window */ + if (di) + is_directory = strcasecmp (di->dentry->type, "directory") == 0; + else { + char *drop_location; + + drop_on_directory (event, desktop_directory, 1); + desktop_reload (desktop_directory, &event->coords); + return; + } + + if (is_directory){ + drop_on_directory (event, di->dentry->exec[0], 0); + return; + } + + /* Last case: regular desktop stuff */ + drop_on_launch_entry (widget, event, di); +} + +static int +drop_cb (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) +{ + if (strcmp (event->data_type, "icon/root") == 0){ + printf ("ICON DROPPED ON ROOT!\n"); + } if (strcmp (event->data_type, "url:ALL") == 0 || + (strcmp (event->data_type, "file:ALL") == 0) || + (strcmp (event->data_type, "text/plain") == 0)){ + url_dropped (widget, event, di); + } else + return FALSE; + return TRUE; +} + +static void +drop_enter_leave () +{ +/* printf ("Enter/Leave\n"); */ +} + +static void +connect_drop_signals (GtkWidget *widget, desktop_icon_t *di) +{ + GtkObject *o = GTK_OBJECT (widget); + + gtk_signal_connect (o, "drop_enter_event", GTK_SIGNAL_FUNC (drop_enter_leave), di); + gtk_signal_connect (o, "drop_leave_event", GTK_SIGNAL_FUNC (drop_enter_leave), di); + gtk_signal_connect (o, "drop_data_available_event", GTK_SIGNAL_FUNC (drop_cb), di); +} +#endif /* OLD DND */ + +void +desktop_icon_execute (GtkWidget *ignored, desktop_icon_t *di) +{ + /* Ultra lame-o execute. This should be replaced by the fixed regexp_command + * invocation + */ + + if (strcmp (di->dentry->type, "Directory") == 0) + new_panel_at (di->dentry->exec[0]); + else + gnome_desktop_entry_launch (di->dentry); +} + +static void +start_icon_drag (GtkWidget *wi, GdkEventMotion *event) +{ + printf ("MOTION NOTIF!\n"); +#ifdef OLD_DND + artificial_drag_start (wi->window, event->x, event->y); +#endif +} + +GdkPoint root_icon_drag_hotspot = { 15, 15 }; + +static void +desktop_icon_configure_position (desktop_icon_t *di, int x, int y) +{ + gtk_widget_set_uposition (di->widget, x, y); + + if (di->dentry){ + char buffer [40]; + + sprintf (buffer, "%d,%d", x, y); + if (di->dentry->geometry) + g_free (di->dentry->geometry); + di->dentry->geometry = g_strdup (buffer); + gnome_desktop_entry_save (di->dentry); + } +} + +#ifdef OLD_DND +static void +desktop_icon_drag_request (GtkWidget *widget, GdkEventDragRequest *event, desktop_icon_t *di) +{ + printf ("Drag type: %s\n", event->data_type); + + if (strcmp (event->data_type, "url:ALL") == 0){ + gdk_window_dnd_data_set (widget->window, (GdkEvent *)event, di->pathname, strlen (di->pathname) + 1); + } else { + int drop_x, drop_y; + + drop_x = event->drop_coords.x - root_icon_drag_hotspot.x; + drop_y = event->drop_coords.y - root_icon_drag_hotspot.y; + + /* Icon dropped on root. We take care of it */ + printf ("Dropped at %d %d\n", drop_x, drop_y); + + if (di->grid_x != -1) + set_spot_val (di->grid_x, di->grid_y, 0); + + if (icons_snap_to_grid){ + snap_to (di, 0, drop_x, drop_y); + get_icon_screen_x_y (di, &drop_x, &drop_y); + } + + desktop_icon_configure_position (di, drop_x, drop_y); + } +} +#endif + +static GtkWidget *root_drag_ok_window; +static GtkWidget *root_drag_not_ok_window; + +static void +destroy_shaped_dnd_windows (void) +{ + if (root_drag_not_ok_window){ + gtk_widget_destroy (root_drag_not_ok_window); + root_drag_not_ok_window = 0; + } + + if (root_drag_ok_window){ + gtk_widget_destroy (root_drag_ok_window); + root_drag_ok_window = 0; + } +} + +void +gnome_arrange_icons (void) +{ + GList *l; + + current_x = current_y = 0; + memset (spot_array, 0, (x_spots * y_spots)/8); + + for (l = desktop_icons; l; l = l->next){ + desktop_icon_t *di = l->data; + int x, y; + + snap_to (di, 1, current_x, current_y); + get_icon_screen_x_y (di, &x, &y); + desktop_icon_configure_position (di, x, y); + + current_y += SNAP_Y; + if (current_y == gdk_screen_height ()){ + current_y = 0; + current_x += SNAP_X; + } + } +} + +/* As Elliot can not be bothered to fix his DnD code in Gdk and it is an absolute mess */ +static int in_desktop_dnd; + +static void +desktop_icon_drag_start (GtkWidget *widget, GdkEvent *event, desktop_icon_t *di) +{ + char *fname; + + if (in_desktop_dnd) + return; + + in_desktop_dnd = 1; + + /* This should not happen, as the drag end routine should destroy those widgets */ + destroy_shaped_dnd_windows (); + + if (di->dentry) + fname = strdup (di->dentry->icon); + else + fname = get_desktop_icon (di->pathname); + + if (fname){ + /* FIXME: we are using the same icon for ok and not ok drags */ + root_drag_ok_window = make_transparent_window (fname); + root_drag_not_ok_window = make_transparent_window (fname); + if (root_drag_not_ok_window && root_drag_ok_window){ +#ifdef OLD_DND + gdk_dnd_set_drag_shape (root_drag_ok_window->window, &root_icon_drag_hotspot, + root_drag_not_ok_window->window, &root_icon_drag_hotspot); +#endif + gtk_widget_show (root_drag_not_ok_window); + gtk_widget_show (root_drag_ok_window); + } + free (fname); + } +} + +static void +desktop_icon_drag_end (GtkWidget *widget, GdkEvent *event, desktop_icon_t *di) +{ + in_desktop_dnd = 0; + destroy_shaped_dnd_windows (); +} + +/* + * Bind the signals so that we can make this icon draggable + */ +static void +desktop_icon_make_draggable (desktop_icon_t *di) +{ + GtkObject *obj; + GList *child; + char *drag_types [] = { "icon/root", "url:ALL" }; + + child = gtk_container_children(GTK_CONTAINER(di->widget)); + obj = GTK_OBJECT (child->data); + /* To artificially start up drag and drop */ + +#ifdef OLD_DND +/* gtk_signal_connect (obj, "motion_notify_event", GTK_SIGNAL_FUNC (start_icon_drag), di); */ + gtk_widget_dnd_drag_set (GTK_WIDGET(child->data), TRUE, drag_types, ELEMENTS (drag_types)); + + gtk_signal_connect (obj, "drag_request_event", GTK_SIGNAL_FUNC (desktop_icon_drag_request), di); + gtk_signal_connect (obj, "drag_begin_event", GTK_SIGNAL_FUNC (desktop_icon_drag_start), di); + gtk_signal_connect (obj, "drag_end_event", GTK_SIGNAL_FUNC (desktop_icon_drag_end), di); +#endif +} + +/* Called by the pop up menu: removes the icon from the desktop */ +void +desktop_icon_delete (GtkWidget *widget, desktop_icon_t *di) +{ + desktop_icon_remove (di); +} + +GtkWidget * +create_desktop_icon (char *file, char *text) +{ + GtkWidget *w; + + if (g_file_exists (file)) + w = desktop_icon_new (file, text); + else { + static char *default_image; + + if (!default_image) + default_image = gnome_unconditional_pixmap_file ("launcher-program.png"); + + if (g_file_exists (default_image)) + w = desktop_icon_new (default_image, text); + else + w = NULL; + } + + return w; +} + +static GtkWidget * +get_desktop_icon_for_dentry (GnomeDesktopEntry *dentry) +{ + GtkWidget *dicon; + char *icon_label; + + icon_label = dentry->name ? dentry->name : x_basename (dentry->exec[0]); + + if (dentry->icon) + dicon = create_desktop_icon (dentry->icon, icon_label); + else { + static char *default_icon_path; + static char exists; + + if (!default_icon_path) { + default_icon_path = gnome_unconditional_pixmap_file ("launcher-program.png"); + if (g_file_exists (default_icon_path)) + exists = 1; + } + + if (exists) + dicon = create_desktop_icon (default_icon_path, icon_label); + else { + dicon = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_set_usize (dicon, 20, 20); + } + } + + return dicon; +} + +static GtkWidget * +get_desktop_icon_for_di (desktop_icon_t *di) +{ + GtkWidget *window; + char *icon_label, *icon; + + icon_label = x_basename (di->pathname); + + icon = get_desktop_icon (di->pathname); + window = create_desktop_icon (icon, icon_label); + g_free (icon); + return window; +} + +static int +dentry_button_click (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di) +{ + if (event->button == 1){ + if (event->type == GDK_2BUTTON_PRESS) + desktop_icon_execute (widget, di); + + return TRUE; + } + + if (event->type == GDK_BUTTON_PRESS && event->button == 3){ + desktop_icon_context_popup (event, di); + return TRUE; + } + return FALSE; +} + +char *drop_types [] = { + "text/plain", + "url:ALL", +}; + +static void +post_setup_desktop_icon (desktop_icon_t *di, int show) +{ + GList *child; + desktop_icon_make_draggable (di); + + /* Setup the widget to make it useful: */ + +#ifdef OLD_DND + /* 1. Drag and drop functionality */ + + child = gtk_container_children(GTK_CONTAINER(di->widget)); + connect_drop_signals (GTK_WIDGET(child->data), di); + gtk_widget_dnd_drop_set (GTK_WIDGET(child->data), TRUE, drop_types, ELEMENTS (drop_types), FALSE); + + /* 2. Double clicking executes the command */ + gtk_signal_connect (GTK_OBJECT (child->data), "button_press_event", GTK_SIGNAL_FUNC (dentry_button_click), di); + +#endif + if (show) + gtk_widget_show (di->widget); +} + +/* Pops up the icon properties pages */ +void +desktop_icon_properties (GtkWidget *widget, desktop_icon_t *di) +{ + int retval; + + retval = item_properties (di->widget, di->pathname, di); + + if (retval & (GPROP_TITLE | GPROP_ICON | GPROP_FILENAME)) { + gtk_widget_destroy (di->widget); + + if (di->dentry) + di->widget = get_desktop_icon_for_dentry (di->dentry); + else + di->widget = get_desktop_icon_for_di (di); + + if (icons_snap_to_grid && di->grid_x != -1) + get_icon_screen_x_y (di, &di->x, &di->y); + + gtk_widget_set_uposition (di->widget, di->x, di->y); + + post_setup_desktop_icon (di, 1); + + if (di->dentry) + gnome_desktop_entry_save (di->dentry); + } +} + +/* + * Activates the context sensitive menu for this icon + */ +static void +desktop_icon_context_popup (GdkEventButton *event, desktop_icon_t *di) +{ + file_popup (event, NULL, di, 0, di->dentry->exec [0]); +} + +char *root_drop_types [] = { + "icon/root", + "url:ALL" +}; + +static void +desktop_load_from_dentry (GnomeDesktopEntry *dentry) +{ + GtkWidget *dicon; + desktop_icon_t *di; + + dicon = get_desktop_icon_for_dentry (dentry); + + if (!dicon) + return; + + di = xmalloc (sizeof (desktop_icon_t), "desktop_load_entry"); + di->dentry = dentry; + di->widget = dicon; + di->pathname = dentry->location; + + desktop_icons = g_list_prepend (desktop_icons, di); + + post_setup_desktop_icon (di, 0); + desktop_icon_set_position (di); +} + +/* + * Loads a .desktop file from FILENAME for the desktop. + */ +static void +desktop_load_dentry (char *filename) +{ + GnomeDesktopEntry *dentry; + + dentry = gnome_desktop_entry_load (filename); + + if (!dentry) + return; + + desktop_load_from_dentry (dentry); +} + +/* Set the drop position to NULL, we only drop the + * first icon on the spot it was dropped, th rest + * get auto-layouted. Perhaps this should be an option. + */ +static void +desktop_setup_geometry_from_point (GnomeDesktopEntry *dentry, GdkPoint **point) +{ + char buffer [40]; + + sprintf (buffer, "%d,%d", (*point)->x, (*point)->y); + dentry->geometry = g_strdup (buffer); + *point = NULL; +} + +/* + * Creates a new DIRECTORY/.directory file which is just a .dekstop + * on directories. And then loads it into the desktop + */ +static void +desktop_create_directory_entry (char *dentry_path, char *pathname, char *short_name, GdkPoint **pos) +{ + GnomeDesktopEntry *dentry; + + dentry = xmalloc (sizeof (GnomeDesktopEntry), "dcde"); + memset (dentry, 0, sizeof (GnomeDesktopEntry)); + dentry->name = g_strdup (short_name); + dentry->exec = (char **) malloc (2 * sizeof (char *)); + dentry->exec[0] = g_strdup (pathname); + dentry->exec[1] = NULL; + dentry->exec_length = 1; + dentry->icon = gnome_unconditional_pixmap_file ("gnome-folder.png"); + dentry->type = g_strdup ("Directory"); + dentry->location = g_strdup (dentry_path); + if (pos && *pos) + desktop_setup_geometry_from_point (dentry, pos); + + gnome_desktop_entry_save (dentry); + desktop_load_from_dentry (dentry); +} + +static int +file_is_executable (char *path) +{ + struct stat s; + + if (mc_stat (path, &s) == -1) + return 0; + + if (is_exe (s.st_mode)) + return 1; + return 0; + +} + +static int +desktop_file_exec (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di) +{ + if (event->type == GDK_2BUTTON_PRESS && event->button == 1){ + if (di->dentry){ + printf ("FIXME: No support for dentry loaded stuff yet\n"); + } else { + if (file_is_executable (di->pathname)){ + char *tmp = name_quote (di->pathname, 0); + + if (!confirm_execute || (query_dialog (_(" The Midnight Commander "), + _(" Do you really want to execute? "), + 0, 2, _("&Yes"), _("&No")) == 0)) + execute (tmp); + free (tmp); + } else { + char *result, *command; + + result = regex_command (di->pathname, "Open", NULL, 0); + if (result && (strcmp (result, "Success") == 0)) + return TRUE; + command = input_expand_dialog (_("Open with..."), + _("Enter extra arguments:"), + di->pathname); + if (command){ + execute (command); + free (command); + } + } + } + return TRUE; + } + + if (event->type == GDK_BUTTON_PRESS && event->button == 3){ + desktop_icon_context_popup (event, di); + return TRUE; + } + + return FALSE; +} + +static void +desktop_create_launch_entry (char *desktop_file, char *pathname, char *short_name, GdkPoint **pos) +{ + GnomeDesktopEntry *dentry; + GtkWidget *dicon; + desktop_icon_t *di; + char *icon; + struct stat s; + + stat (pathname, &s); + dentry = xmalloc (sizeof (GnomeDesktopEntry), "launch_entry"); + memset (dentry, 0, sizeof (GnomeDesktopEntry)); + + dentry->name = g_strdup (short_name); + dentry->exec = (char **) malloc (2 * sizeof (char *)); + dentry->exec[0] = g_strdup (pathname); + dentry->exec[1] = NULL; + dentry->exec_length = 1; + dentry->icon = get_desktop_icon (short_name); + dentry->type = g_strdup ("File"); + dentry->location = g_strdup (desktop_file); + dentry->terminal = 1; + if (pos && *pos) + desktop_setup_geometry_from_point (dentry, pos); + + gnome_desktop_entry_save (dentry); + desktop_load_from_dentry (dentry); +#if 0 + dicon = create_desktop_icon (icon, x_basename (pathname)); + g_free (icon); + if (!dicon) + return; + + di = xmalloc (sizeof (desktop_icon_t), "dcle"); + di->dentry = NULL; + di->widget = dicon; + di->pathname = strdup (pathname); + + desktop_icon_set_position (di); + desktop_icon_make_draggable (di); + + desktop_icons = g_list_prepend (desktop_icons, (gpointer) di); + + /* Double clicking executes the command, single clicking brings up context menu */ + gtk_signal_connect (GTK_OBJECT (dicon), "button_press_event", GTK_SIGNAL_FUNC (desktop_file_exec), di); + gtk_widget_realize (dicon); + + gtk_signal_connect (GTK_OBJECT (dicon), "drop_data_available_event", + GTK_SIGNAL_FUNC (drop_on_launch_entry), di); + + gtk_widget_dnd_drop_set (dicon, TRUE, drop_types, ELEMENTS (drop_types), FALSE); +#endif +} + +static int +desktop_pathname_loaded (char *pathname) +{ + GList *p = desktop_icons; + + for (; p; p = p->next){ + desktop_icon_t *di = p->data; + + if (strcmp (di->pathname, pathname) == 0) + return 1; + } + return 0; +} + +static void +desktop_setup_icon (char *filename, char *full_pathname, GdkPoint **desired_position) +{ + struct stat s; + + if (mc_stat (full_pathname, &s) == -1) + return; + + if (S_ISDIR (s.st_mode)){ + char *dir_full = concat_dir_and_file (full_pathname, ".directory"); + + if (!desktop_pathname_loaded (dir_full)){ + if (exist_file (dir_full)) + desktop_load_dentry (dir_full); + else + desktop_create_directory_entry (dir_full, full_pathname, filename, desired_position); + } + free (dir_full); + } else { + if (strstr (filename, ".desktop")){ + if (!desktop_pathname_loaded (full_pathname)) + desktop_load_dentry (full_pathname); + } else { + char *desktop_version; + + desktop_version = copy_strings (full_pathname, ".desktop", NULL); + if (!exist_file (desktop_version) && !desktop_pathname_loaded (full_pathname)) + desktop_create_launch_entry (desktop_version, full_pathname, filename, desired_position); + free (desktop_version); + } + } +} + + +/* + * Load all of the entries available on the ~/desktop directory + * So far, we support: .desktop files; directories (they get a .directory file); + * sylinks to directories; other programs. + */ +static void +desktop_reload (char *desktop_dir, GdkPoint *drop_position) +{ + struct dirent *dent; + GList *l; + DIR *dir; + + dir = mc_opendir (desktop_dir); + if (dir == NULL){ + message (1, _(" Warning "), _(" Could not open %s directory"), desktop_dir, NULL); + return; + } + + while ((dent = mc_readdir (dir)) != NULL){ + char *full; + + /* ignore '.' */ + if (dent->d_name [0] == '.' && dent->d_name [1] == 0) + continue; + + /* ignore `..' */ + if (dent->d_name [0] == '.' && dent->d_name [1] == '.' && dent->d_name [2] == 0) + continue; + + full = concat_dir_and_file (desktop_dir, dent->d_name); + desktop_setup_icon (dent->d_name, full, &drop_position); + + free (full); + } + mc_closedir (dir); + + /* Show all of the widgets */ + for (l = desktop_icons; l; l = l->next){ + desktop_icon_t *di = l->data; + + gtk_widget_show (di->widget); + } +} + +static void +desktop_load (char *desktop_dir) +{ + desktop_reload (desktop_dir, NULL); +} + +/* + * Copy the system defaults to the user ~/desktop directory and setup a + * Home directory link + */ +static void +desktop_setup_default (char *desktop_dir) +{ + char *mc_desktop_dir; + char *desktop_dir_home_link; + + desktop_dir_home_link = concat_dir_and_file (desktop_dir, "Home directory.desktop"); + + mc_desktop_dir = concat_dir_and_file (mc_home, MC_LIB_DESKTOP); + + if (exist_file (mc_desktop_dir)){ + create_op_win (OP_COPY, 0); + file_mask_defaults (); + copy_dir_dir (mc_desktop_dir, desktop_dir, 1, 0, 0, 0); + destroy_op_win (); + } else + mkdir (desktop_dir, 0777); + + desktop_create_directory_entry (desktop_dir_home_link, "~", "Home directory", NULL); + free (desktop_dir_home_link); + free (mc_desktop_dir); +} + +/* + * configures the root window dropability + */ +void +desktop_root (void) +{ + GtkWidget *rw; + + rw = gnome_rootwin_new (); +#ifdef OLD_DND + connect_drop_signals (rw, NULL); + gtk_widget_dnd_drop_set (rw, TRUE, root_drop_types, ELEMENTS (root_drop_types), FALSE); + gtk_widget_realize (rw); + gtk_widget_show (rw); + root_window = GNOME_ROOTWIN (rw); +#endif +} + +/* + * entry point to start up the gnome desktop + */ +void +start_desktop (void) +{ + init_spot_list (); + desktop_directory = concat_dir_and_file (home_dir, "desktop"); + + if (!exist_file (desktop_directory)) + desktop_setup_default (desktop_directory); + + desktop_root (); + desktop_load (desktop_directory); +} + +/* + * shutdown the desktop + */ +void +stop_desktop (void) +{ + GList *p; + + for (p = desktop_icons; p; p = p->next){ + desktop_icon_t *di = p->data; + + desktop_release_desktop_icon_t (di, 0); + } + image_cache_destroy (); +} + +#endif