From 510d0ded294fb637cc1859af36b128e01becd9ef Mon Sep 17 00:00:00 2001 From: sleuth Date: Thu, 6 Dec 2001 02:50:17 +0000 Subject: [PATCH] Preliminary dnd support. Dragging from and to views works, with a default mode of move. Hold 'shift' for copy. No visible feedback of actions occurs yet, but you'll see the view update as soon as efsd reports the file changes. Tested, but be careful around files you care about. Moves and copys use efsd_move and efsd_copy, without the force option. So source files will not overwrite the destination if it exists. Kevin Brosius SVN revision: 5747 --- src/icons.c | 21 +++ src/util.c | 47 ++++++ src/util.h | 1 + src/view.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/view.h | 11 ++ 5 files changed, 479 insertions(+), 1 deletion(-) diff --git a/src/icons.c b/src/icons.c index c5cc84f6a..bc261a391 100644 --- a/src/icons.c +++ b/src/icons.c @@ -85,6 +85,16 @@ e_icon_up_cb(void *_data, Evas _e, Evas_Object _o, int _b, int _x, int _y) e_icon_update_state(ic); ecore_window_destroy(ic->view->drag.win); ic->view->drag.started = 0; + if(e->mods & ECORE_EVENT_KEY_MODIFIER_SHIFT) + ic->view->drag.drop_mode = E_DND_COPY; + else + ic->view->drag.drop_mode = E_DND_MOVE; + + /* Handle dnd motion(drop) - dragging==0 */ + ecore_window_dnd_handle_motion( ic->view->win.base, + _x - ic->view->drag.offset.x, + _y - ic->view->drag.offset.y, + 0); D_RETURN; } if (_b == 1) @@ -349,6 +359,10 @@ e_icon_move_cb(void *_data, Evas _e, Evas_Object _o, int _b, int _x, int _y) ecore_window_show(ic->view->drag.win); ecore_pixmap_free(pmap); ecore_pixmap_free(mask); + + /* Initiate dnd */ + ecore_dnd_own_selection(ic->view->win.base); + ic->view->drag.started = 1; } } @@ -363,6 +377,13 @@ e_icon_move_cb(void *_data, Evas _e, Evas_Object _o, int _b, int _x, int _y) ic->view->drag.y = y; ic->view->drag.update = 1; ic->view->changed = 1; + if(e->mods & ECORE_EVENT_KEY_MODIFIER_SHIFT) + ic->view->drag.drop_mode = E_DND_COPY; + else + ic->view->drag.drop_mode = E_DND_MOVE; + + /* Handle dnd motion - dragging==1 */ + ecore_window_dnd_handle_motion( ic->view->win.base, x, y, 1); } D_RETURN; diff --git a/src/util.c b/src/util.c index 4513a9521..1af51862b 100644 --- a/src/util.c +++ b/src/util.c @@ -53,3 +53,50 @@ e_util_glob_matches(char *str, char *glob) D_RETURN_(0); } + +/* + * Function to take a URL of the form + * file://hostname/dir1/dir2/file + * + * Test that 'file://' exists. + * Test that hostname matches passed value + * Return a pointer to /dir1/... + * + * todo: + * - dir or filename which matches hostname will + * fool the hostname match + * - file://dir1/dir2/file is also legal but rejected by + * this presently + */ +char * +e_util_de_url_and_verify( const char *fi, const char *hostn ) +{ + char *wk; + + D_ENTER; + + wk = strstr( fi, "file://" ); + + /* Valid URL contains "file://" */ + if( !wk ) + D_RETURN_ (NULL); + + /* Need some form of hostname to continue */ + if( !hostn ) + D_RETURN_ (NULL); + + /* Do we contain hostname? */ + wk = strstr( fi, hostn ); + + /* Hostname mismatch, reject file */ + if( !wk ) + D_RETURN_ (NULL); + + /* Local file name starts after "hostname" */ + wk = strchr( wk, '/' ); + + if( !wk ) + D_RETURN_ (NULL); + + D_RETURN( wk ); +} diff --git a/src/util.h b/src/util.h index 0d9ee5b6b..ff33c1077 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,7 @@ void e_util_set_env(char *variable, char *content); char *e_util_get_user_home(void); void *e_util_memdup(void *data, int size); int e_util_glob_matches(char *str, char *glob); +char *e_util_de_url_and_verify( const char *fi, const char *hostn ); #define e_strdup(__dest, __var) \ { \ diff --git a/src/view.c b/src/view.c index fb1e24b86..9e3013a3a 100644 --- a/src/view.c +++ b/src/view.c @@ -14,6 +14,10 @@ static Ecore_Event *current_ev = NULL; +static char **dnd_files = NULL; +static int dnd_num_files = 0; +static E_dnd_enum dnd_pending_mode; + static void e_bg_down_cb(void *_data, Evas _e, Evas_Object _o, int _b, int _x, int _y); static void e_bg_up_cb(void *_data, Evas _e, Evas_Object _o, int _b, int _x, int _y); static void e_bg_move_cb(void *_data, Evas _e, Evas_Object _o, int _b, int _x, int _y); @@ -34,6 +38,14 @@ static void e_visibility(Ecore_Event * ev); static void e_focus_in(Ecore_Event * ev); static void e_focus_out(Ecore_Event * ev); static void e_delete(Ecore_Event * ev); +static void e_dnd_status(Ecore_Event * ev); +static void e_dnd_data_request(Ecore_Event * ev); +static void e_dnd_drop_end(Ecore_Event * ev); +static void e_dnd_drop_position(Ecore_Event * ev); +static void e_dnd_drop(Ecore_Event * ev); +static void e_dnd_drop_request(Ecore_Event * ev); +static void e_dnd_drop_request_free(void); +static void e_dnd_handle_drop( E_View *v, E_dnd_enum dnd_pending_mode ); static void e_view_handle_fs(EfsdEvent *ev); static void e_view_handle_fs_restart(void *data); static void e_view_resort_timeout(int val, void *data); @@ -1031,6 +1043,43 @@ e_delete(Ecore_Event * ev) D_RETURN; } + +/* + * dnd status handler + * + */ +static void +e_dnd_status(Ecore_Event * ev) +{ + Ecore_Event_Dnd_Drop_Status *e; + /* + typedef struct _ecore_event_dnd_drop_status + { + Window win, root, source_win; + int x, y, w, h; + int ok; + } Ecore_Event_Dnd_Drop_Status; + */ + Evas_List l; + + D_ENTER; + + e = ev->event; + for (l = views; l; l = l->next) + { + E_View *v; + + v = l->data; + if (e->win == v->win.base) + { + ecore_window_dnd_ok(e->ok); + } + } + + D_RETURN; +} + + static void e_wheel(Ecore_Event * ev) { @@ -1886,7 +1935,9 @@ e_view_realize(E_View *v) e_scrollbar_resize(v->scrollbar.v, 12, v->size.h - 12); e_scrollbar_move(v->scrollbar.h, 0, v->size.h - 12); e_scrollbar_resize(v->scrollbar.h, v->size.w - 12, 12); - + + /* I support dnd */ + ecore_window_dnd_advertise(v->win.base); ecore_window_show(v->win.main); @@ -2465,8 +2516,355 @@ e_view_init(void) ecore_event_filter_handler_add(ECORE_EVENT_WINDOW_FOCUS_IN, e_focus_in); ecore_event_filter_handler_add(ECORE_EVENT_WINDOW_FOCUS_OUT, e_focus_out); ecore_event_filter_handler_add(ECORE_EVENT_WINDOW_DELETE, e_delete); + /* dnd source handlers */ + ecore_event_filter_handler_add(ECORE_EVENT_DND_DROP_STATUS, e_dnd_status); + ecore_event_filter_handler_add(ECORE_EVENT_DND_DATA_REQUEST, e_dnd_data_request); + ecore_event_filter_handler_add(ECORE_EVENT_DND_DROP_END, e_dnd_drop_end); + /* dnd target handlers */ + ecore_event_filter_handler_add(ECORE_EVENT_DND_DROP_POSITION, e_dnd_drop_position); + ecore_event_filter_handler_add(ECORE_EVENT_DND_DROP, e_dnd_drop); + ecore_event_filter_handler_add(ECORE_EVENT_DND_DROP_REQUEST, e_dnd_drop_request); + ecore_event_filter_idle_handler_add(e_idle, NULL); e_fs_add_event_handler(e_view_handle_fs); D_RETURN; } + + + + +/* + * send the dnd data to the target app + * + * URL formatting per RFC 1738 + */ +static void +e_dnd_data_request(Ecore_Event * ev) +{ + Ecore_Event_Dnd_Data_Request *e; + /* + * typedef struct _ecore_event_dnd_data_request + * { + * Window win, root, source_win; + * int plain_text; + * Atom destination_atom; + * } Ecore_Event_Dnd_Data_Request; + */ + Evas_List l; + char hostname[PATH_MAX]; + + D_ENTER; + + /* Need hostname for URL (file://hostname/...) */ + if(gethostname( hostname, PATH_MAX)) + { + /* failed... Default to 'localhost' */ + strcpy( hostname, "localhost"); + } + + e = ev->event; + for (l = views; l; l = l->next) + { + E_View *v; + Evas_List ll; + char *data = NULL; + int size = 3; + int idx = 0; + + /* Me, my null, and an extra for the end '/r/n'... */ + data = NEW(char, size); + *data = 0; + + v = l->data; + if (e->win == v->win.base) + { + for (ll = v->icons; ll; ll = ll->next) + { + E_Icon *ic; + + ic = ll->data; + if (ic->state.selected) + { + int ic_size; + + /* Size = 'file://' + 3 strings + host delimiter '/' and '\r\n' end. */ + ic_size = 7 + strlen(hostname) + strlen(v->dir) + strlen(ic->file)+3; + size += ic_size; + + + REALLOC(data, char, size); + + sprintf( data+idx, "file://%s%s/%s\r\n", hostname, v->dir, ic->file); + idx += ic_size; + } + } + + if(v->drag.drop_mode == E_DND_COPY) + ecore_dnd_set_mode_copy(); + else + ecore_dnd_set_mode_move(); + ecore_dnd_set_data(e->win); + + + ecore_dnd_send_data( + e->source_win, e->win, + data, size, + e->destination_atom, + /* uri-list, not plain-text */ + 0 + ); + } + FREE(data); + } + + D_RETURN; +} + + + +static void +e_dnd_drop_end(Ecore_Event * ev) +{ + Ecore_Event_Dnd_Drop_End *e; + /* + * typedef struct _ecore_event_dnd_drop_end + * { + * Window win, root, source_win; + * } Ecore_Event_Dnd_Drop_End; + */ + Evas_List l; + + D_ENTER; + + e = ev->event; + for (l = views; l; l = l->next) + { + E_View *v; + + v = l->data; + if (e->win == v->win.base) + { + ecore_window_dnd_finished(); + e_dnd_drop_request_free(); + } + } + + D_RETURN; +} + + + +static void +e_dnd_drop_position(Ecore_Event * ev) +{ + Ecore_Event_Dnd_Drop_Position *e; + /* + * typedef struct _ecore_event_dnd_drop_position + * { + * Window win, root, source_win; + * int x, y; + * } Ecore_Event_Dnd_Drop_Position; + */ + Evas_List l; + + D_ENTER; + + e = ev->event; + for (l = views; l; l = l->next) + { + E_View *v; + + v = l->data; + if (e->win == v->win.base) + { + + if( e->win != e->source_win ) + { + /* send XdndStatus */ + ecore_window_dnd_send_status_ok(v->win.base, e->source_win, + v->location.x, v->location.y, + v->size.w, v->size.h + ); + } + /* todo - cache window extents, don't send again within these extents. */ + } + } + + D_RETURN; +} + + + +static void +e_dnd_drop(Ecore_Event * ev) +{ + Ecore_Event_Dnd_Drop *e; + /* + * typedef struct _ecore_event_dnd_drop + * { + * Window win, root, source_win; + * } Ecore_Event_Dnd_Drop; + */ + Evas_List l; + + D_ENTER; + + e = ev->event; + for (l = views; l; l = l->next) + { + E_View *v; + + v = l->data; + if (e->win == v->win.base) + { + /* Dropped! Handle data */ + e_dnd_handle_drop( v, dnd_pending_mode ); + + ecore_window_dnd_finished(); + + e_dnd_drop_request_free(); + } + } + + D_RETURN; +} + + + +static void +e_dnd_drop_request(Ecore_Event * ev) +{ + Ecore_Event_Dnd_Drop_Request *e; + /* + * typedef struct _ecore_event_dnd_drop_request + * { + * Window win, root, source_win; + * int num_files; + * char **files; + * int copy, link, move; + * } Ecore_Event_Dnd_Drop_Request; + */ + Evas_List l; + + D_ENTER; + + e = ev->event; + for (l = views; l; l = l->next) + { + E_View *v; + + v = l->data; + if (e->win == v->win.base) + { + /* if it exists, we already have the data... */ + if( !dnd_files ) + { + int i; + + dnd_files = NEW_PTR(e->num_files); + + /* copy the file list locally, for use in a dnd_drop */ + for( i=0; i < e->num_files; i++ ) + dnd_files[i] = strdup( e->files[i] ); + + dnd_num_files = e->num_files; + + if( e->copy ) + dnd_pending_mode = E_DND_COPY; + else if( e->move ) + dnd_pending_mode = E_DND_MOVE; + else if( e->link ) + dnd_pending_mode = E_DND_LINK; + else + dnd_pending_mode = E_DND_ASK; + } + /* + printf( "drop-req %d-[c%dm%dl%d]--%s--\n", e->num_files, + e->copy, e->move, e->link, + e->num_files ? e->files[0] : "None" + ); + */ + } + } + + D_RETURN; +} + + + +static void +e_dnd_drop_request_free(void) +{ + + if (dnd_files) + { + int i; + + for (i = 0; i < dnd_num_files; i++) + FREE(dnd_files[i]); + + FREE(dnd_files); + + dnd_num_files = 0; + } +} + + + +static void +e_dnd_handle_drop( E_View *v, E_dnd_enum dnd_pending_mode ) +{ + char hostname[PATH_MAX]; + int in, out; + char *filename; + + D_ENTER; + + /* Need hostname for URL (file://hostname/...) */ + if(gethostname( hostname, PATH_MAX)) + { + /* failed... Default to 'localhost' */ + strcpy( hostname, "localhost"); + } + + /* Make space for destination in file list */ + dnd_num_files++; + REALLOC_PTR(dnd_files, dnd_num_files); + dnd_files[dnd_num_files-1] = NULL; + + /* Verify files are local, convert to non-URL */ + for( in=0, out=0; indir ); + + switch( dnd_pending_mode ) + { + case E_DND_COPY: + /* Copy files */ + efsd_copy( e_fs_get_connection(), out, dnd_files, + efsd_ops(0) ); + break; + case E_DND_MOVE: + efsd_move( e_fs_get_connection(), out, dnd_files, + efsd_ops(0) ); + break; + default: + /* nothing yet */ + break; + } + + D_RETURN; +} + + diff --git a/src/view.h b/src/view.h index 3f7929e28..3e4fbcdc1 100644 --- a/src/view.h +++ b/src/view.h @@ -24,6 +24,16 @@ typedef struct _E_Icon E_Icon; typedef struct _E_Iconbar E_Iconbar; #endif +#ifndef E_DND_TYPEDEF +#define E_DND_TYPEDEF +typedef enum { + E_DND_NONE, + E_DND_COPY, + E_DND_MOVE, + E_DND_LINK, + E_DND_ASK +} E_dnd_enum; +#endif struct _E_View { @@ -117,6 +127,7 @@ struct _E_View int x, y; } offset; int update; + int drop_mode; } drag; struct { int valid;