/* * Controls the desktop contents * (C) 1998 the Free Software Foundation * * Author: Miguel de Icaza (miguel@gnu.org) */ #include #include "fs.h" #include #include "util.h" #include "gdesktop.h" #include "../vfs/vfs.h" #include #include "main.h" #include "file.h" #include "global.h" #include "panel.h" #include "gscreen.h" #include /* Types of desktop icons: * * o Application: Double click: start up application; * Dropping: start up program with arguments. * * o Directory: Double click: opens the directory in a panel. * Double click: copies/moves files. * * o File: Opens the application according to regex_command */ typedef enum { application, directory, file } icon_t; /* A structure that describes each icon on the desktop */ typedef struct { GnomeDesktopEntry *dentry; GtkWidget *widget; icon_t type; int x, y; char *title; char *pathname; } desktop_icon_t; /* operations on drops */ enum { OPER_COPY, OPER_MOVE, OPER_LINK }; /* The list of icons on the desktop */ static GList *desktop_icons; /* * 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 void desktop_icon_set_position (desktop_icon_t *di, GtkWidget *widget) { static int x, y = 10; static int current_x, current_y; 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); } } /* This find-spot routine can obviously be improved, left as an excercise * to the hacker */ if (x == -1){ x = current_x; y = current_y; gtk_widget_size_request (widget, &widget->requisition); current_y += widget->requisition.height + 8; if (current_y > gdk_screen_height ()){ current_x += 0; current_y = 0; } } di->x = x; di->y = y; gtk_widget_set_uposition (widget, 6 + x, y); } static int operation_value; static void set_option (GtkWidget *widget, int value) { operation_value = value; gtk_main_quit (); } static void option_menu_gone () { operation_value = -1; gtk_main_quit (); } static int get_operation (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 *) OPER_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 *) OPER_MOVE); gtk_menu_append (GTK_MENU (menu), item); gtk_widget_show (item); #if 0 /* 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 *) OPER_LINK); gtk_menu_append (GTK_MENU (menu), item); gtk_widget_show (item); #endif gtk_signal_connect (GTK_OBJECT (menu), "hide", GTK_SIGNAL_FUNC(option_menu_gone), 0); } /* Here, we could set the mask parameter (the last NULL) to a valid variable * and find out if the shift/control keys were set and do something smart * about that */ gtk_widget_set_uposition (menu, x, y); /* FIXME: We should catch any events that escape this menu and cancel it */ operation_value = -1; gtk_menu_popup (GTK_MENU (menu), NULL, NULL, 0, NULL, 1, GDK_CURRENT_TIME); 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_id_in_one_panel (gpointer data, gpointer user_data) { PanelContainer *pc = (PanelContainer *) data; int id = (int) user_data; WPanel *panel = pc->panel; GtkCList *clist = GTK_CLIST (panel->list); GdkWindowPrivate *gdk_wp; gdk_wp = (GdkWindowPrivate *) clist->clist_window; if (gdk_wp->xwindow == id){ temp_panel = panel; return; } gdk_wp = (GdkWindowPrivate *) GTK_WIDGET (clist)->window; if (gdk_wp->xwindow == id){ temp_panel = panel; return; } } static WPanel * find_panel_owning_window_id (int id) { temp_panel = NULL; g_list_foreach (containers, check_window_id_in_one_panel, (gpointer) id); return temp_panel; } static void make_symlinks (WPanel *source_panel, char *target_dir); static void perform_drop_on_panel (WPanel *source_panel, int operation, char *dest) { switch (operation){ case OPER_COPY: panel_operate (source_panel, OP_COPY, dest); break; case OPER_MOVE: panel_operate (source_panel, OP_MOVE, dest); break; case OPER_LINK: make_symlinks (source_panel, dest); break; } } static void perform_drop_manually (int operation, GdkEventDropDataAvailable *event, char *dest) { int count = event->data_numbytes; char *p = event->data; int len; switch (operation){ case OPER_COPY: create_op_win (OP_COPY, 0); break; case OPER_MOVE: create_op_win (OP_MOVE, 0); break; } file_mask_defaults (); do { char *tmpf; len = 1 + strlen (event->data); count -= len; switch (operation){ case OPER_COPY: tmpf = concat_dir_and_file (dest, x_basename (p)); copy_file_file (p, tmpf, 1); free (tmpf); break; case OPER_MOVE: create_op_win (OP_MOVE, 0); file_mask_defaults (); tmpf = concat_dir_and_file (dest, x_basename (p)); move_file_file (p, tmpf); free (tmpf); break; } p += len; } while (count > 0); destroy_op_win (); } void drop_on_panel (GdkEventDropDataAvailable *event, char *dest) { WPanel *source_panel; int x, y; int operation; operation = get_operation (event->coords.x, event->coords.y); source_panel = find_panel_owning_window_id (event->requestor); if (source_panel) perform_drop_on_panel (source_panel, operation, dest); else perform_drop_manually (operation, event, dest); return; } static void drop_cb (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) { char *p; int count; int len; int is_directory = strcasecmp (di->dentry->type, "directory") == 0; if (is_directory){ drop_on_panel (event, di->dentry->exec); return; } count = event->data_numbytes; p = event->data; do { len = 1 + strlen (event->data); count -= len; printf ("Receiving: %s\n", p); p += len; } while (count); printf ("Receiving: %s %d\n", event->data, event->data_numbytes); } 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 (gtk_true), di); gtk_signal_connect (o, "drop_leave_event", GTK_SIGNAL_FUNC (gtk_true), di); gtk_signal_connect (o, "drop_data_available_event", GTK_SIGNAL_FUNC (drop_cb), di); } static void dentry_execute (desktop_icon_t *di) { GnomeDesktopEntry *dentry = di->dentry; /* 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); } else gnome_desktop_entry_launch (dentry); } static void dentry_properties (desktop_icon_t *di) { printf ("Edit this widget properties\n"); } static void dentry_button_click (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di) { if (event->type == GDK_2BUTTON_PRESS && event->button == 1) dentry_execute (di); if (event->type == GDK_BUTTON_PRESS && event->button == 3) dentry_properties (di); } char *drop_types [] = { "text/plain", "url:ALL", }; #define ELEMENTS(x) (sizeof (x) / sizeof (x[0])) static void desktop_load_dentry (char *filename) { GnomeDesktopEntry *dentry; desktop_icon_t *di; GtkWidget *window; char *icon_label; dentry = gnome_desktop_entry_load (filename); if (!dentry) return; icon_label = dentry->name ? dentry->name : x_basename (dentry->exec); if (dentry->icon) window = create_transparent_text_window (dentry->icon, icon_label, GDK_BUTTON_PRESS_MASK); else { static char *default_icon_path; static char exists; if (!default_icon_path){ default_icon_path = gnome_unconditional_pixmap_file ("launcher-program.xpm"); if (g_file_exists (default_icon_path)) exists = 1; } if (exists) window = create_transparent_text_window (default_icon_path, icon_label, GDK_BUTTON_PRESS_MASK); else { window = gtk_window_new (GTK_WINDOW_POPUP); gtk_widget_set_usize (window, 20, 20); } } if (!window) return; di = xmalloc (sizeof (desktop_icon_t), "desktop_load_entry"); di->dentry = dentry; di->widget = window; desktop_icon_set_position (di, window); desktop_icons = g_list_prepend (desktop_icons, (gpointer) di); /* Setup the widget to make it useful: */ /* 1. Drag and drop functionality */ connect_drop_signals (window, di); gtk_widget_dnd_drop_set (window, TRUE, drop_types, ELEMENTS (drop_types), FALSE); /* 2. Double clicking executes the command */ gtk_signal_connect (GTK_OBJECT (window), "button_press_event", GTK_SIGNAL_FUNC (dentry_button_click), di); gtk_widget_show (window); } static void desktop_create_directory_entry (char *dentry_path, char *pathname, char *short_name) { GnomeDesktopEntry *dentry; dentry = xmalloc (sizeof (GnomeDesktopEntry), "dcde"); dentry->name = g_strdup (short_name); dentry->comment = NULL; dentry->tryexec = NULL; dentry->exec = g_strdup (pathname); dentry->icon = gnome_unconditional_pixmap_file ("gnome-folder.png"); dentry->docpath = NULL; dentry->type = g_strdup ("Directory"); dentry->location = g_strdup (dentry_path); gnome_desktop_entry_save (dentry); gnome_desktop_entry_load (dentry_path); } /* * 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 (pathname, "Icon", 0, 0); /* Try the system icon */ full_fname = gnome_unconditional_pixmap_file (fname); if (full_fname) return full_fname; return gnome_unconditional_pixmap_file ("launcher-program.xpm"); } static void desktop_file_exec (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di) { if (!(event->type == GDK_2BUTTON_PRESS && event->button == 1)) return; if (di->dentry){ printf ("FIXME: No support for dentry loaded stuff yet\n"); } else regex_command (di->pathname, "Open", 0, 0); } static void drop_on_launch_entry (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di) { if (strcmp (event->data_type, "url:ALL") == 0){ } } static void desktop_create_launch_entry (char *pathname, char *short_name) { GtkWidget *window; desktop_icon_t *di; char *icon; icon = get_desktop_icon (pathname); window = create_transparent_text_window (icon, x_basename (pathname), GDK_BUTTON_PRESS_MASK); g_free (icon); di = xmalloc (sizeof (desktop_icon_t), "dcle"); di->dentry = NULL; di->widget = window; di->pathname = strdup (pathname); desktop_icon_set_position (di, window); desktop_icons = g_list_prepend (desktop_icons, (gpointer) di); /* Double clicking executes the command */ gtk_signal_connect (GTK_OBJECT (window), "button_press_event", GTK_SIGNAL_FUNC (desktop_file_exec), di); gtk_widget_realize (window); gtk_signal_connect (GTK_OBJECT (window), "drop_data_available_event", GTK_SIGNAL_FUNC (drop_on_launch_entry), di); gtk_widget_dnd_drop_set (window, TRUE, drop_types, ELEMENTS (drop_types), FALSE); gtk_widget_show (window); } /* * Desktop initialization code */ static void desktop_load (char *desktop_dir) { struct dirent *dent; DIR *dir; GnomeDesktopEntry *entry; 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){ struct stat s; 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); mc_stat (full, &s); if (S_ISDIR (s.st_mode)){ char *dir_full = concat_dir_and_file (full, ".directory"); if (exist_file (dir_full)) desktop_load_dentry (dir_full); else desktop_create_directory_entry (dir_full, full, dent->d_name); free (dir_full); } else { if (strstr (dent->d_name, ".desktop")) desktop_load_dentry (full); else { char *desktop_version; desktop_version = copy_strings (full, ".desktop", NULL); if (!exist_file (desktop_version)) desktop_create_launch_entry (full, dent->d_name); free (desktop_version); } } free (full); } } static void make_symlinks (WPanel *source_panel, char *target_dir) { printf ("weee! you are right, creating symbolic links by dnd is still not working\n"); } static void desktop_setup_default (char *desktop_dir) { char *mc_desktop_dir; 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); destroy_op_win (); } free (mc_desktop_dir); } void start_desktop (void) { char *f = concat_dir_and_file (home_dir, "desktop"); if (!exist_file (f)) desktop_setup_default (f); desktop_load (f); free (f); }