1
1

1999-02-01 Federico Mena Quintero <federico@nuclecu.unam.mx>

* gdesktop.c (desktop_drag_motion): If the user is dragging a
	Netscape url, allow ACTION_LINK.
	(setup_desktop_dnd): Now we use a single GtkInvisible widget to
	proxy both DnD and clicks on the desktop.
	(setup_motif_dnd_proxy): New function to set up a widow as a Motif
	DnD proxy (to allow drops from Netscape, for example).
	(setup_desktop_click_proxy_window): Use the proxy_invisible widget.
	(drop_url): Reload desktop icons after creating the url entry.
	(desktop_icon_info_place): Allow a drop from something other than
	a desktop icon to be placed where the user wants.
	(desktop_drag_motion): Unconditionally specify ACTION_MOVE if we
	are dragging a desktop icon.
	(desktop_icon_info_place): Remove the icon from its slot before
	calling the smart-positioning routines.
Этот коммит содержится в:
Miguel de Icaza 1999-02-02 02:34:46 +00:00
родитель db7260e57a
Коммит 64aeddb117
2 изменённых файлов: 160 добавлений и 111 удалений

Просмотреть файл

@ -1,3 +1,20 @@
1999-02-01 Federico Mena Quintero <federico@nuclecu.unam.mx>
* gdesktop.c (desktop_drag_motion): If the user is dragging a
Netscape url, allow ACTION_LINK.
(setup_desktop_dnd): Now we use a single GtkInvisible widget to
proxy both DnD and clicks on the desktop.
(setup_motif_dnd_proxy): New function to set up a widow as a Motif
DnD proxy (to allow drops from Netscape, for example).
(setup_desktop_click_proxy_window): Use the proxy_invisible widget.
(drop_url): Reload desktop icons after creating the url entry.
(desktop_icon_info_place): Allow a drop from something other than
a desktop icon to be placed where the user wants.
(desktop_drag_motion): Unconditionally specify ACTION_MOVE if we
are dragging a desktop icon.
(desktop_icon_info_place): Remove the icon from its slot before
calling the smart-positioning routines.
1999-01-31 Federico Mena Quintero <federico@nuclecu.unam.mx>
* gdesktop.c (reload_desktop_icons): Reload the icon image for a

Просмотреть файл

@ -6,13 +6,6 @@
* Miguel de Icaza <miguel@nuclecu.unam.mx>
*/
/*
* TO-DO list for the desktop;
*
* - Put an InputOnly window over icons to be able to select them even if the user clicks on
* the transparent area.
*/
#include <config.h>
#include "global.h"
#include <gdk/gdkx.h>
@ -83,17 +76,17 @@ static GtkTargetEntry dnd_icon_targets[] = {
};
static GtkTargetEntry dnd_desktop_targets[] = {
{ "_NETSCAPE_URL", 0, TARGET_URL },
{ TARGET_MC_DESKTOP_ICON_TYPE, 0, TARGET_MC_DESKTOP_ICON },
{ TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST }
{ TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST },
{ TARGET_URL_TYPE, 0, TARGET_URL }
};
static int dnd_icon_nsources = sizeof (dnd_icon_sources) / sizeof (dnd_icon_sources[0]);
static int dnd_icon_ntargets = sizeof (dnd_icon_targets) / sizeof (dnd_icon_targets[0]);
static int dnd_desktop_ntargets = sizeof (dnd_desktop_targets) / sizeof (dnd_desktop_targets[0]);
/* Proxy window for DnD on the root window */
static GtkWidget *dnd_proxy_window;
/* Proxy window for DnD and clicks on the desktop */
static GtkWidget *proxy_invisible;
/* Offsets for the DnD cursor hotspot */
static int dnd_press_x, dnd_press_y;
@ -112,7 +105,6 @@ static int icon_select_on_text;
/* Proxy window for clicks on the root window */
static GdkWindow *click_proxy_gdk_window;
static GtkWidget *click_proxy_invisible;
/* GC for drawing the rubberband rectangle */
static GdkGC *click_gc;
@ -130,7 +122,7 @@ static int click_dragging;
static DesktopIconInfo *desktop_icon_info_new (char *filename, char *url,
int auto_pos, int xpos, int ypos);
int user_pos, int auto_pos, int xpos, int ypos);
/* Looks for a free slot in the layout_slots array and returns the coordinates that coorespond to
@ -218,23 +210,24 @@ remove_from_slot (DesktopIconInfo *dii)
layout_slots[dii->slot].icons = g_list_remove (layout_slots[dii->slot].icons, dii);
}
/*
* Places a desktop icon. If auto_pos is true, then the function will
* look for a place to position the icon automatically, else it will
* use the specified coordinates, snapped to the grid if the global
* desktop_snap_icons flag is set.
/* Places a desktop icon. If auto_pos is true, then the function will look for
* a place to position the icon automatically, else it will use the specified
* coordinates, snapped to the grid if the global desktop_snap_icons flag is
* set.
*/
static void
desktop_icon_info_place (DesktopIconInfo *dii, int auto_pos, int xpos, int ypos)
desktop_icon_info_place (DesktopIconInfo *dii, int user_pos, int auto_pos, int xpos, int ypos)
{
int u, v;
char *filename;
if (auto_pos) {
if (desktop_auto_placement || !desktop_snap_icons)
get_icon_auto_pos (&xpos, &ypos);
else if (desktop_snap_icons)
remove_from_slot (dii);
if (!user_pos && auto_pos) {
if (desktop_snap_icons)
get_icon_snap_pos (&xpos, &ypos);
else
get_icon_auto_pos (&xpos, &ypos);
}
if (xpos < 0)
@ -249,8 +242,6 @@ desktop_icon_info_place (DesktopIconInfo *dii, int auto_pos, int xpos, int ypos)
/* Increase the number of icons in the corresponding slot */
remove_from_slot (dii);
u = xpos / DESKTOP_SNAP_X;
v = ypos / DESKTOP_SNAP_Y;
@ -332,13 +323,13 @@ typedef struct {
} file_and_url_t;
/*
* Reloads the desktop icons efficiently. If there are "new" files
* for which no icons have been created, then icons for them will be
* created started at the specified position -- this is used when
* dragging new icons to the desktop.
* Reloads the desktop icons efficiently. If there are "new" files for which no
* icons have been created, then icons for them will be created started at the
* specified position if user_pos is TRUE. If it is FALSE, the icons will be
* auto-placed.
*/
static void
reload_desktop_icons (int xpos, int ypos)
reload_desktop_icons (int user_pos, int xpos, int ypos)
{
struct dirent *dirent;
DIR *dir;
@ -391,7 +382,7 @@ reload_desktop_icons (int xpos, int ypos)
g_free (full_name);
dii = l->data;
desktop_icon_set_icon (dii->dicon, im);
desktop_icon_set_icon (DESKTOP_ICON (dii->dicon), im);
/* Leave the icon in the desktop by removing it from the list */
@ -406,7 +397,7 @@ reload_desktop_icons (int xpos, int ypos)
desktop_url = NULL;
if (have_pos) {
dii = desktop_icon_info_new (dirent->d_name, desktop_url, FALSE, x, y);
dii = desktop_icon_info_new (dirent->d_name, desktop_url, FALSE, FALSE, x, y);
gtk_widget_show (dii->dicon);
g_free (full_name);
@ -452,7 +443,7 @@ reload_desktop_icons (int xpos, int ypos)
for (sl = need_position_list; sl; sl = sl->next) {
file_and_url_t *fau = sl->data;
dii = desktop_icon_info_new (fau->filename, fau->url, TRUE, xpos, ypos);
dii = desktop_icon_info_new (fau->filename, fau->url, user_pos, TRUE, xpos, ypos);
gtk_widget_show (dii->dicon);
g_free (fau->url);
@ -691,7 +682,7 @@ text_changed_url (GnomeIconTextItem *iti, gpointer data)
fullname = g_concat_dir_and_file (desktop_directory, dii->filename);
new_text = gnome_icon_text_item_get_text (iti);
gnome_metadata_set (fullname, "desktop-url", strlen (new_text)+1, new_text);
gnome_metadata_set (fullname, "desktop-url", strlen (new_text) + 1, new_text);
return TRUE;
}
@ -858,7 +849,7 @@ do_popup_menu (DesktopIconInfo *dii, GdkEventButton *event)
filename = g_concat_dir_and_file (desktop_directory, dii->filename);
if (gpopup_do_popup (event, NULL, dii, 0, filename) != -1)
reload_desktop_icons (0, 0);
reload_desktop_icons (FALSE, 0, 0);
g_free (filename);
}
@ -1290,7 +1281,10 @@ drop_desktop_icons (GdkDragContext *context, GtkSelectionData *data, int x, int
for (sl = sel_icons; sl; sl = sl->next) {
dii = sl->data;
desktop_icon_info_place (dii, FALSE, dii->x + dx, dii->y + dy);
desktop_icon_info_place (dii,
!desktop_auto_placement,
desktop_auto_placement,
dii->x + dx, dii->y + dy);
}
/* Clean up */
@ -1309,72 +1303,70 @@ desktop_icon_drop_uri_list (DesktopIconInfo *dii, GdkDragContext *context, GtkSe
int size;
char *buf;
const char *mime_type;
filename = g_concat_dir_and_file (desktop_directory, dii->filename);
fe = file_entry_from_file (filename);
if (!fe)
return; /* eek */
/*
* 1. If it is directory, drop the files there
*/
if (fe->f.link_to_dir){
/* 1. If it is a directory, drop the files there */
if (fe->f.link_to_dir) {
gdnd_drop_on_directory (context, data, filename);
goto out;
}
/*
* 2. Try to use a metadata-based drop action
*/
if (gnome_metadata_get (filename, "drop-action", &size, &buf) == 0){
/* 2. Try to use a metadata-based drop action */
if (gnome_metadata_get (filename, "drop-action", &size, &buf) == 0) {
/*action_drop (filename, buf, context, data);*/ /* Fixme: i'm undefined */
g_free (buf);
goto out;
}
/*
* 3. Try a drop action from the mime-type
*/
/* 3. Try a drop action from the mime-type */
mime_type = gnome_mime_type_or_default (filename, NULL);
if (mime_type){
if (mime_type) {
char *action;
action = gnome_mime_get_value (mime_type, "drop-action");
if (action){
if (action) {
/*action_drop (filename, action, context, data);*/ /* Fixme: i'm undefined */
goto out;
}
}
/*
* 4. Executable. Try metadata keys for "open".
*/
if (is_exe (fe->buf.st_mode) && if_link_is_exe (fe)){
/* 4. Executable. Try metadata keys for "open" */
if (is_exe (fe->buf.st_mode) && if_link_is_exe (fe)) {
GList *names, *l;
int len, i;
char **drops;
/* Convert the list of filenames into an array of char */
names = gnome_uri_list_extract_uris (data->data);
len = g_list_length (names);
drops = (char **) g_malloc (sizeof (char *) * (len+1));
for (l = names, i = 0; i < len; i++, l = l->next){
for (l = names, i = 0; i < len; i++, l = l->next) {
char *text = l->data;
if (strncmp (text, "file:", 5) == 0)
text += 5;
drops [i] = text;
}
drops [i] = NULL;
if (gnome_metadata_get (filename, "open", &size, &buf) == 0){
if (gnome_metadata_get (filename, "open", &size, &buf) == 0) {
exec_extension (filename, buf, drops, NULL, 0);
goto out2;
}
exec_extension (filename, "%f %q", drops, NULL, 0);
g_free (drops);
@ -1433,22 +1425,18 @@ setup_icon_dnd_dest (DesktopIconInfo *dii)
dii);
}
/*
* Creates a new desktop icon. The filename is the pruned filename
* inside the desktop directory. If auto_pos is false, it will use
* the specified coordinates for the icon. Else, it will use auto-
* positioning trying to start at the specified coordinates. It does
* not show the icon.
/* Creates a new desktop icon. The filename is the pruned filename inside the
* desktop directory. It does not show the icon.
*/
static DesktopIconInfo *
desktop_icon_info_new (char *filename, char *url, int auto_pos, int xpos, int ypos)
desktop_icon_info_new (char *filename, char *url, int user_pos, int auto_pos, int xpos, int ypos)
{
DesktopIconInfo *dii;
file_entry *fe;
char *full_name;
GdkImlibImage *icon_im;
GtkSignalFunc text_changed_func;
/* Create the icon structure */
full_name = g_concat_dir_and_file (desktop_directory, filename);
@ -1518,7 +1506,7 @@ desktop_icon_info_new (char *filename, char *url, int auto_pos, int xpos, int yp
/* Place the icon and append it to the list */
desktop_icon_info_place (dii, auto_pos, xpos, ypos);
desktop_icon_info_place (dii, user_pos, auto_pos, xpos, ypos);
return dii;
}
@ -1562,7 +1550,7 @@ setup_trashcan (char *desktop_dir)
if (!g_file_exists (trashcan_dir)){
mkdir (trashcan_dir, 0777);
gnome_metadata_set (
trashcan_dir, "icon-filename", strlen (trash_pix)+1, trash_pix);
trashcan_dir, "icon-filename", strlen (trash_pix) + 1, trash_pix);
}
g_free (trashcan_dir);
@ -1600,6 +1588,18 @@ create_desktop_dir (void)
/* setup_trashcan (desktop_directory); */
}
/* Property placed on target windows */
typedef struct {
guint8 byte_order;
guint8 protocol_version;
guint8 protocol_style;
guint8 pad;
guint32 proxy_window;
guint16 num_drop_sites;
guint16 padding;
guint32 total_size;
} MotifDragReceiverInfo;
/* Sets up a proxy window for DnD on the specified X window. Courtesy of Owen Taylor */
static gboolean
setup_xdnd_proxy (guint32 xid, GdkWindow *proxy_window)
@ -1683,12 +1683,40 @@ setup_xdnd_proxy (guint32 xid, GdkWindow *proxy_window)
xdnd_proxy_atom, gdk_atom_intern ("WINDOW", FALSE),
32, PropModeReplace,
(guchar *) &proxy_xid, 1);
return TRUE;
} else
return FALSE;
}
/* Sets up a window as a Motif DnD proxy */
static void
setup_motif_dnd_proxy (guint32 xid, GdkWindow *proxy_window)
{
guint32 proxy_xid;
MotifDragReceiverInfo info;
Atom receiver_info_atom;
guint32 myint;
myint = 0x01020304;
proxy_xid = GDK_WINDOW_XWINDOW (proxy_window);
receiver_info_atom = gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE);
info.byte_order = (*((gchar *) &myint) == 1) ? 'B' : 'l';
info.protocol_version = 0;
info.protocol_style = 5; /* XmDRAG_DYNAMIC */
info.proxy_window = proxy_xid;
info.num_drop_sites = 0;
info.total_size = sizeof(info);
XChangeProperty (gdk_display, xid,
receiver_info_atom,
receiver_info_atom,
8, PropModeReplace,
(guchar *)&info,
sizeof (info));
}
/* Callback used when we get a drag_motion event from the desktop. We must
* decide what kind of operation can be performed with what the user is
* dragging.
@ -1702,25 +1730,27 @@ desktop_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
action = context->suggested_action; /* this is the default */
if (gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON)) {
if (context->actions & GDK_ACTION_MOVE)
action = GDK_ACTION_MOVE;
} else if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) {
if (gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON))
action = GDK_ACTION_MOVE;
else if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) {
source_widget = gtk_drag_get_source_widget (context);
/* If it comes from ourselves, make move the default unless the
* user is explicitly asking for ASK.
*/
printf ("%s\t%s\t%s\t%s\n",
(context->actions & GDK_ACTION_COPY) ? "copy" : "",
(context->actions & GDK_ACTION_MOVE) ? "move" : "",
(context->actions & GDK_ACTION_LINK) ? "link" : "",
(context->actions & GDK_ACTION_ASK) ? "ask" : "");
if (source_widget
&& context->suggested_action != GDK_ACTION_ASK
&& (context->actions & GDK_ACTION_MOVE))
action = GDK_ACTION_MOVE;
} else if (gdnd_drag_context_has_target (context, TARGET_URL)) {
/* FIXME: right now we only allow links. We should see if we
* can move or copy stuff instead (for ftp instead of http
* sites, for example).
*/
if (context->actions & GDK_ACTION_LINK)
action = GDK_ACTION_LINK;
else
action = 0;
} else
action = 0; /* we cannot handle that type of data */
@ -1739,7 +1769,7 @@ drop_url (GdkDragContext *context, GtkSelectionData *data, gint x, gint y)
template = g_concat_dir_and_file (desktop_directory, "urlXXXXXX");
if (mktemp (template)){
if (mktemp (template)) {
FILE *f;
f = fopen (template, "w");
@ -1748,7 +1778,10 @@ drop_url (GdkDragContext *context, GtkSelectionData *data, gint x, gint y)
fclose (f);
gnome_metadata_set (template, "desktop-url",
strlen (data->data)+1, data->data);
strlen (data->data) + 1,
data->data);
reload_desktop_icons (TRUE, x, y);
}
}
@ -1769,7 +1802,6 @@ desktop_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x,
x += dx;
y += dy;
printf ("Drag!!\n");
switch (info) {
case TARGET_MC_DESKTOP_ICON:
drop_desktop_icons (context, data, x, y);
@ -1778,14 +1810,13 @@ desktop_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x,
case TARGET_URI_LIST:
retval = gdnd_drop_on_directory (context, data, desktop_directory);
if (retval)
reload_desktop_icons (x, y);
reload_desktop_icons (TRUE, x, y);
break;
case TARGET_URL:
printf ("Aqui!\n");
drop_url (context, data, x, y);
break;
default:
break;
}
@ -1795,22 +1826,21 @@ desktop_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x,
static void
setup_desktop_dnd (void)
{
dnd_proxy_window = gtk_invisible_new ();
gtk_widget_show (dnd_proxy_window);
if (!setup_xdnd_proxy (GDK_ROOT_WINDOW (), proxy_invisible->window))
g_warning ("There is already a process taking drops on the desktop!\n");
if (!setup_xdnd_proxy (GDK_ROOT_WINDOW (), dnd_proxy_window->window))
g_warning ("There is already a process taking drop windows on the desktop\n");
setup_motif_dnd_proxy (GDK_ROOT_WINDOW (), proxy_invisible->window);
gtk_drag_dest_set (dnd_proxy_window,
gtk_drag_dest_set (proxy_invisible,
GTK_DEST_DEFAULT_DROP,
dnd_desktop_targets,
dnd_desktop_ntargets,
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
gtk_signal_connect (GTK_OBJECT (dnd_proxy_window), "drag_motion",
gtk_signal_connect (GTK_OBJECT (proxy_invisible), "drag_motion",
(GtkSignalFunc) desktop_drag_motion,
NULL);
gtk_signal_connect (GTK_OBJECT (dnd_proxy_window), "drag_data_received",
gtk_signal_connect (GTK_OBJECT (proxy_invisible), "drag_data_received",
(GtkSignalFunc) desktop_drag_data_received,
NULL);
}
@ -2122,7 +2152,7 @@ click_proxy_motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)
/*
* Filter that translates proxied events from virtual root windows into normal
* Gdk events for the click_proxy_invisible widget.
* Gdk events for the proxy_invisible widget.
*/
static GdkFilterReturn
click_proxy_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
@ -2187,7 +2217,7 @@ setup_desktop_click_proxy_window (void)
}
/* Make the proxy window send events to the invisible proxy widget */
gdk_window_set_user_data (click_proxy_gdk_window, click_proxy_invisible);
gdk_window_set_user_data (click_proxy_gdk_window, proxy_invisible);
/* Add our filter to get events */
gdk_window_add_filter (click_proxy_gdk_window, click_proxy_filter, NULL);
@ -2239,11 +2269,8 @@ setup_desktop_clicks (void)
GdkColor color;
GdkBitmap *stipple;
click_proxy_invisible = gtk_invisible_new ();
gtk_widget_show (click_proxy_invisible);
/* Make the root window send events to the invisible proxy widget */
gdk_window_set_user_data (GDK_ROOT_PARENT (), click_proxy_invisible);
gdk_window_set_user_data (GDK_ROOT_PARENT (), proxy_invisible);
/* Add our filter to get button press/release events (they are sent by
* the WM * with the window set to the root). Our filter will translate
@ -2260,17 +2287,17 @@ setup_desktop_clicks (void)
/* Connect the signals */
gtk_signal_connect (GTK_OBJECT (click_proxy_invisible), "button_press_event",
gtk_signal_connect (GTK_OBJECT (proxy_invisible), "button_press_event",
(GtkSignalFunc) click_proxy_button_press,
NULL);
gtk_signal_connect (GTK_OBJECT (click_proxy_invisible), "button_release_event",
gtk_signal_connect (GTK_OBJECT (proxy_invisible), "button_release_event",
(GtkSignalFunc) click_proxy_button_release,
NULL);
gtk_signal_connect (GTK_OBJECT (click_proxy_invisible), "motion_notify_event",
gtk_signal_connect (GTK_OBJECT (proxy_invisible), "motion_notify_event",
(GtkSignalFunc) click_proxy_motion,
NULL);
gtk_signal_connect (GTK_OBJECT (click_proxy_invisible), "property_notify_event",
gtk_signal_connect (GTK_OBJECT (proxy_invisible), "property_notify_event",
(GtkSignalFunc) click_proxy_property_notify,
NULL);
@ -2306,7 +2333,13 @@ desktop_init (void)
gdnd_init ();
create_layout_info ();
create_desktop_dir ();
reload_desktop_icons (0, 0);
reload_desktop_icons (FALSE, 0, 0);
/* Create the proxy window and initialize all proxying stuff */
proxy_invisible = gtk_invisible_new ();
gtk_widget_show (proxy_invisible);
setup_desktop_dnd ();
setup_desktop_clicks ();
}
@ -2333,13 +2366,12 @@ desktop_destroy (void)
g_free (desktop_directory);
desktop_directory = NULL;
/* Remove DnD crap */
gtk_widget_destroy (dnd_proxy_window);
XDeleteProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (), gdk_atom_intern ("XdndProxy", FALSE));
/* Remove click-on-desktop crap */
gdk_window_unref (click_proxy_gdk_window);
gtk_widget_destroy (click_proxy_invisible);
/* Remove DnD crap */
gtk_widget_destroy (proxy_invisible);
XDeleteProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (), gdk_atom_intern ("XdndProxy", FALSE));
}