forked from enlightenment/enlightenment
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 <cobra@compuserve.com> SVN revision: 5747
This commit is contained in:
parent
b37fcf166e
commit
510d0ded29
21
src/icons.c
21
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;
|
||||
|
|
47
src/util.c
47
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 );
|
||||
}
|
||||
|
|
|
@ -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) \
|
||||
{ \
|
||||
|
|
400
src/view.c
400
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; in<dnd_num_files-1; in++ )
|
||||
{
|
||||
filename = e_util_de_url_and_verify( dnd_files[in], hostname );
|
||||
/* Need a overlap safe copy here, like memmove() */
|
||||
if( filename )
|
||||
memmove( dnd_files[out++], filename, strlen(filename)+1 );
|
||||
}
|
||||
|
||||
/* Append destination for efsd */
|
||||
if( dnd_files[out] )
|
||||
FREE( dnd_files[out] );
|
||||
|
||||
dnd_files[out++] = strdup( v->dir );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
11
src/view.h
11
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;
|
||||
|
|
Loading…
Reference in New Issue