diff --git a/.ci/ci-configure.sh b/.ci/ci-configure.sh index 773e536aa1..cd7f9eb889 100755 --- a/.ci/ci-configure.sh +++ b/.ci/ci-configure.sh @@ -13,12 +13,11 @@ if [ "$DISTRO" != "" ] ; then # TODO: # - No libelogind package in fedora 30 repo - # - RPM fusion repo for xine and libvlc # - Ibus ENABLED_LINUX_COPTS=" -Dfb=true -Dsdl=true -Dbuffer=true -Dbuild-id=travis-build \ -Ddebug-threads=true -Dglib=true -Dg-mainloop=true -Dxpresent=true -Dxinput22=true \ - -Devas-loaders-disabler=json -Decore-imf-loaders-disabler= -Demotion-loaders-disabler=libvlc,xine \ - -Demotion-generic-loaders-disabler=vlc -Dharfbuzz=true -Dpixman=true -Dhyphen=true \ + -Devas-loaders-disabler=json -Decore-imf-loaders-disabler= \ + -Dharfbuzz=true -Dpixman=true -Dhyphen=true \ -Dvnc-server=true -Dbindings=luajit,cxx,mono -Delogind=false -Dinstall-eo-files=true -Dphysics=true" # Enabled png, jpeg evas loader for in tree edje file builds @@ -27,8 +26,8 @@ if [ "$DISTRO" != "" ] ; then -Dcrypto=gnutls -Dglib=false -Dgstreamer=false -Dsystemd=false -Dpulseaudio=false \ -Dnetwork-backend=connman -Dxinput2=false -Dtslib=false \ -Devas-loaders-disabler=gst,pdf,ps,raw,svg,xcf,bmp,dds,eet,generic,gif,ico,jp2k,json,pmaps,psd,tga,tgv,tiff,wbmp,webp,xpm \ - -Decore-imf-loaders-disabler=xim,ibus,scim -Demotion-loaders-disabler=gstreamer1,libvlc,xine \ - -Demotion-generic-loaders-disabler=vlc -Dfribidi=false -Dfontconfig=false \ + -Decore-imf-loaders-disabler=xim,ibus,scim \ + -Dfribidi=false -Dfontconfig=false \ -Dedje-sound-and-video=false -Dembedded-lz4=false -Dlibmount=false -Dv4l2=false \ -Delua=true -Dnls=false -Dbindings= -Dlua-interpreter=luajit -Dnative-arch-optimization=false" #evas_filter_parser.c:(.text+0xc59): undefined reference to `lua_getglobal' with interpreter lua @@ -98,7 +97,7 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then export PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:/usr/local/Cellar/libffi/$LIBFFI_VER/lib/pkgconfig" export CC="ccache gcc" travis_fold meson meson - mkdir build && meson build -Dopengl=full -Decore-imf-loaders-disabler=scim,ibus -Dx11=false -Davahi=false -Deeze=false -Dsystemd=false -Dnls=false -Dcocoa=true -Demotion-loaders-disabler=gstreamer1,libvlc,xine + mkdir build && meson build -Dopengl=full -Decore-imf-loaders-disabler=scim,ibus -Dx11=false -Davahi=false -Deeze=false -Dsystemd=false -Dnls=false -Dcocoa=true -Dgstreamer=false travis_endfold meson else travis_fold meson meson diff --git a/.ci/ubuntu-bionic-install-deps.sh b/.ci/ubuntu-bionic-install-deps.sh index 998e74b084..9eefa7d7fc 100755 --- a/.ci/ubuntu-bionic-install-deps.sh +++ b/.ci/ubuntu-bionic-install-deps.sh @@ -1,4 +1,4 @@ #!/bin/sh sudo apt-get update -y -sudo apt-get install -y build-essential autoconf automake autopoint doxygen check luajit libharfbuzz-dev libpng-dev libudev-dev libwebp-dev libssl-dev libluajit-5.1-dev libfribidi-dev libcogl-gles2-dev libgif-dev libtiff5-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libdbus-1-dev libmount-dev libblkid-dev libpulse-dev libxrandr-dev libxtst-dev libxcursor-dev libxcomposite-dev libxinerama-dev libxkbfile-dev libbullet-dev libvlc-dev libsndfile1-dev libraw-dev libspectre-dev libpoppler-cpp-dev libpam0g-dev liblz4-dev faenza-icon-theme gettext git imagemagick libasound2-dev libbluetooth-dev libfontconfig1-dev libfreetype6-dev libibus-1.0-dev libiconv-hook-dev libjpeg-dev libjpeg-turbo8-dev libpoppler-dev libpoppler-private-dev libproxy-dev librsvg2-dev libscim-dev libsystemd-dev libtool libudisks2-dev libunibreak-dev libxcb-keysyms1-dev libxine2-dev libxss-dev linux-tools-common libcurl4-openssl-dev systemd ccache git binutils-gold python3-pip ninja-build dbus-x11 libavahi-client-dev python3-setuptools libopenjp2-7-dev +sudo apt-get install -y build-essential autoconf automake autopoint doxygen check luajit libharfbuzz-dev libpng-dev libudev-dev libwebp-dev libssl-dev libluajit-5.1-dev libfribidi-dev libcogl-gles2-dev libgif-dev libtiff5-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libdbus-1-dev libmount-dev libblkid-dev libpulse-dev libxrandr-dev libxtst-dev libxcursor-dev libxcomposite-dev libxinerama-dev libxkbfile-dev libbullet-dev libsndfile1-dev libraw-dev libspectre-dev libpoppler-cpp-dev libpam0g-dev liblz4-dev faenza-icon-theme gettext git imagemagick libasound2-dev libbluetooth-dev libfontconfig1-dev libfreetype6-dev libibus-1.0-dev libiconv-hook-dev libjpeg-dev libjpeg-turbo8-dev libpoppler-dev libpoppler-private-dev libproxy-dev librsvg2-dev libscim-dev libsystemd-dev libtool libudisks2-dev libunibreak-dev libxcb-keysyms1-dev libxss-dev linux-tools-common libcurl4-openssl-dev systemd ccache git binutils-gold python3-pip ninja-build dbus-x11 libavahi-client-dev python3-setuptools libopenjp2-7-dev sudo pip3 install meson diff --git a/README b/README index d94127bce0..ec3b27a737 100644 --- a/README +++ b/README @@ -328,15 +328,11 @@ runtime library being refactored to be extremely small. //BSD 2-Clause license// -This is a wrapper around Gstreamer and/or Xine and/or external -pluggable decoder binaries (generic binaries provided by Emotion -Generic Players or any suitable drop-in replacement). This glues in -the decoder library, and its output into a smart Evas object that will -display the playback for you as the video plays, as well as providing -higher level controls to seek, play, pause and query the stream -regardless of the back-end used. Note that using the Xine module may -effectively make this library GPL v2, so be aware of that before -turning that on. +This is a wrapper around Gstreamer 1.x pluggable decoder libraries +This glues in the decoder library, and its output into a smart Evas object +that will display the playback for you as the video plays, as well as +providing higher level controls to seek, play, pause and query the stream +regardless of the back-end used. diff --git a/meson.build b/meson.build index 27216dff31..29123222a3 100644 --- a/meson.build +++ b/meson.build @@ -456,9 +456,6 @@ endforeach subdir(join_paths('src', 'bin', 'efl')) subdir(join_paths('src', 'generic', 'evas')) -if sys_windows == false - subdir(join_paths('src', 'generic', 'emotion')) -endif subdir('cmakeconfig') subdir(join_paths('src', 'bindings')) subdir(join_paths('src', 'edje_external')) diff --git a/meson_options.txt b/meson_options.txt index 1a3461a1f3..9d2b0a7e7a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -122,7 +122,7 @@ option('g-mainloop', option('gstreamer', type : 'boolean', value : true, - description : 'GStreamer 1.0+ support in efl' + description : 'GStreamer support in efl' ) option('systemd', @@ -200,20 +200,6 @@ option('ecore-imf-loaders-disabler', value : ['scim'] ) -option('emotion-loaders-disabler', - type : 'array', - description : 'List of video back-ends to disable in efl', - choices : ['gstreamer1', 'libvlc', 'xine'], - value : ['libvlc', 'xine'] -) - -option('emotion-generic-loaders-disabler', - type : 'array', - description : 'List of out-of-process generic binary video loaders to disable in efl', - choices : ['vlc'], - value : ['vlc'] -) - option('harfbuzz', type : 'boolean', value : true, diff --git a/src/generic/emotion/meson.build b/src/generic/emotion/meson.build deleted file mode 100644 index 58cd5294aa..0000000000 --- a/src/generic/emotion/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -generic_loaders = ['vlc'] - -foreach loader : generic_loaders - if get_option('emotion-generic-loaders-disabler').contains(loader) == false - subdir(loader) - endif -endforeach - diff --git a/src/generic/emotion/vlc/emotion_generic_vlc.c b/src/generic/emotion/vlc/emotion_generic_vlc.c deleted file mode 100644 index dcfcbe9e8c..0000000000 --- a/src/generic/emotion/vlc/emotion_generic_vlc.c +++ /dev/null @@ -1,789 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -static int _em_vlc_log_dom = -1; -#define ERR(...) EINA_LOG_DOM_ERR(_em_vlc_log_dom, __VA_ARGS__) -#define DBG(...) EINA_LOG_DOM_DBG(_em_vlc_log_dom, __VA_ARGS__) -#define INF(...) EINA_LOG_DOM_INFO(_em_vlc_log_dom, __VA_ARGS__) -#define WRN(...) EINA_LOG_DOM_WARN(_em_vlc_log_dom, __VA_ARGS__) -#define CRIT(...) EINA_LOG_DOM_CRIT(_em_vlc_log_dom, __VA_ARGS__) - - -typedef struct _App App; -struct _App { - Emotion_Generic_Video_Shared *vs; - Emotion_Generic_Video_Frame vf; - - libvlc_instance_t *libvlc; - libvlc_media_t *m; - libvlc_media_player_t *mp; - libvlc_event_manager_t *event_mgr; - - Ecore_Pipe *fd_read; // read commands from emotion here - Ecore_Pipe *fd_write; // write commands for emotion here - Eina_Lock cmd_mutex;// lock used to send just one command at a time - int last_order; // current command received from emotion - - char *filename; - char *subtitle_path; - char *shmname; - unsigned w, h; - int volume; - Eina_Bool audio_muted; - - Eina_Bool opening; - Eina_Bool closing; - Eina_Bool playing; - Eina_Bool inited; -}; - -static void _player_setup(App *app); - - -/* Utilities to send commands back to emotion */ -#define SEND_CMD_PARAM(app, i) \ - if ((app)->fd_write) \ - if (!ecore_pipe_write((app)->fd_write, &(i), sizeof((i)))) \ - ecore_main_loop_quit(); - -static void -_send_cmd(App *app, int cmd) -{ - if (!app->fd_write) - return; - - eina_lock_take(&app->cmd_mutex); /* LOCK HERE */ - - if (!ecore_pipe_write(app->fd_write, &cmd, sizeof(cmd))) - ecore_main_loop_quit(); -} - -static void -_send_cmd_str(App *app, const char *str) -{ - int len; - - len = str ? strlen(str) + 1 : 0; - if (app->fd_write) - if (!ecore_pipe_write(app->fd_write, &len, sizeof(len))) - ecore_main_loop_quit(); - if (app->fd_write) - if (!ecore_pipe_write(app->fd_write, str, len)) - ecore_main_loop_quit(); -} - -static void -_send_cmd_finish(App *app) -{ - eina_lock_release(&app->cmd_mutex); /* UNLOCK HERE */ -} - -/* Commands sent to the emotion pipe */ -static void -_send_file_closed(App *app) -{ - _send_cmd(app, EM_RESULT_FILE_CLOSE); - _send_cmd_finish(app); -} - -static void -_send_time_changed(App *app) -{ - float new_time; - - if (app->vs->frame_drop > 1) - return; - - new_time = libvlc_media_player_get_time(app->mp); - new_time /= 1000; - _send_cmd(app, EM_RESULT_POSITION_CHANGED); - SEND_CMD_PARAM(app, new_time); - _send_cmd_finish(app); -} - -static void -_send_resize(App *app, int width, int height) -{ - _send_cmd(app, EM_RESULT_FRAME_SIZE); - SEND_CMD_PARAM(app, width); - SEND_CMD_PARAM(app, height); - _send_cmd_finish(app); -} - -static void -_send_track_info(App *app, int cmd, int current, int count, libvlc_track_description_t *desc) -{ - _send_cmd(app, cmd); - SEND_CMD_PARAM(app, current); - SEND_CMD_PARAM(app, count); - while (desc) - { - int tid = desc->i_id; - const char *name = desc->psz_name; - SEND_CMD_PARAM(app, tid); - _send_cmd_str(app, name); - desc = desc->p_next; - } - _send_cmd_finish(app); -} - -static void -_send_all_track_info(App *app) -{ - int track_count, current; - libvlc_track_description_t *desc; - - current = libvlc_audio_get_track(app->mp); - track_count = libvlc_audio_get_track_count(app->mp); - desc = libvlc_audio_get_track_description(app->mp); - - _send_track_info(app, EM_RESULT_AUDIO_TRACK_INFO, - current, track_count, desc); - - current = libvlc_video_get_track(app->mp); - track_count = libvlc_video_get_track_count(app->mp); - desc = libvlc_video_get_track_description(app->mp); - - _send_track_info(app, EM_RESULT_VIDEO_TRACK_INFO, - current, track_count, desc); - - current = libvlc_video_get_spu(app->mp); - track_count = libvlc_video_get_spu_count(app->mp); - desc = libvlc_video_get_spu_description(app->mp); - - _send_track_info(app, EM_RESULT_SPU_TRACK_INFO, - current, track_count, desc); -} - -static void -_send_all_meta_info(App *app) -{ - const char *meta; - - _send_cmd(app, EM_RESULT_META_INFO); - - /* - * Will send in this order: title, artist, album, year, - * genre, comments, disc id and track count. - */ - meta = libvlc_media_get_meta(app->m, libvlc_meta_Title); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Artist); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Album); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Date); - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_Genre); - _send_cmd_str(app, meta); - meta = NULL; // sending empty comments - _send_cmd_str(app, meta); - meta = NULL; // sending empty disc id - _send_cmd_str(app, meta); - meta = libvlc_media_get_meta(app->m, libvlc_meta_TrackNumber); - _send_cmd_str(app, meta); - - _send_cmd_finish(app); -} - -static void -_send_length_changed(App *app) -{ - float length = libvlc_media_player_get_length(app->mp); - - length /= 1000; - _send_cmd(app, EM_RESULT_LENGTH_CHANGED); - SEND_CMD_PARAM(app, length); - _send_cmd_finish(app); -} - -static void -_send_seekable_changed(App *app, const struct libvlc_event_t *ev) -{ - int seekable = ev->u.media_player_seekable_changed.new_seekable; - - _send_cmd(app, EM_RESULT_SEEKABLE_CHANGED); - SEND_CMD_PARAM(app, seekable); - _send_cmd_finish(app); -} - -static void -_send_playback_started(App *app) -{ - _send_cmd(app, EM_RESULT_PLAYBACK_STARTED); - _send_cmd_finish(app); -} - -static void -_send_playback_stopped(App *app) -{ - _send_cmd(app, EM_RESULT_PLAYBACK_STOPPED); - _send_cmd_finish(app); -} - -static void -_send_init(App *app) -{ - _send_cmd(app, EM_RESULT_INIT); - _send_cmd_finish(app); -} - -static void -_send_file_set(App *app) -{ - _send_cmd(app, EM_RESULT_FILE_SET); - _send_cmd_finish(app); -} - -static void -_send_file_set_done(App *app, int success) -{ - _send_cmd(app, EM_RESULT_FILE_SET_DONE); - SEND_CMD_PARAM(app, success); - _send_cmd_finish(app); -} - - -/* VLC events and callbacks */ -static void -_event_cb(const struct libvlc_event_t *ev, void *data) -{ - App *app = data; - - ecore_thread_main_loop_begin(); - switch (ev->type) - { - case libvlc_MediaPlayerTimeChanged: - // DBG("libvlc_MediaPlayerTimeChanged"); - _send_time_changed(app); - break; - case libvlc_MediaPlayerLengthChanged: - DBG("libvlc_MediaPlayerLengthChanged"); - _send_length_changed(app); - break; - case libvlc_MediaPlayerSeekableChanged: - DBG("libvlc_MediaPlayerSeekableChanged"); - _send_seekable_changed(app, ev); - break; - case libvlc_MediaPlayerPlaying: - DBG("libvlc_MediaPlayerPlaying"); - libvlc_audio_set_volume(app->mp, app->volume); - libvlc_audio_set_mute(app->mp, app->audio_muted); - _send_playback_started(app); - break; - case libvlc_MediaPlayerStopped: - DBG("libvlc_MediaPlayerStopped"); - _send_playback_stopped(app); - if (app->closing) - { - free(app->filename); - app->filename = NULL; - free(app->subtitle_path); - app->subtitle_path = NULL; - libvlc_media_release(app->m); - app->m = NULL; - libvlc_media_player_release(app->mp); - app->mp = NULL; - emotion_generic_shm_free(app->vs); - app->playing = EINA_FALSE; - app->closing = EINA_FALSE; - _send_file_closed(app); - } - break; - case libvlc_MediaPlayerEndReached: - DBG("libvlc_MediaPlayerEndReached"); - app->playing = EINA_FALSE; - /* vlc had released the media_playere here, we create a new one */ - app->mp = libvlc_media_player_new_from_media(app->m); - _player_setup(app); - _send_playback_stopped(app); - break; - } - ecore_thread_main_loop_end(); -} - -static void -_tmp_playing_event_cb(const struct libvlc_event_t *ev, void *data) -{ - App *app = data; - - if (ev->type != libvlc_MediaPlayerPlaying) - return; - - /* pause and stop listening the temporary event */ - libvlc_event_detach(app->event_mgr,libvlc_MediaPlayerPlaying, - _tmp_playing_event_cb, app); - libvlc_media_player_set_pause(app->mp, 1); - - /* sending size info */ - libvlc_video_get_size(app->mp, 0, &app->w, &app->h); - _send_resize(app, app->w, app->h); - - /* sending total lenght */ - _send_length_changed(app); - - /* sending audio track info */ - _send_all_track_info(app); - - /* sending meta info */ - _send_all_meta_info(app); - - /* ok, we are done! Now let emotion create the shmem for us */ - _send_file_set(app); -} - -static void * -_lock(void *data, void **pixels) -{ - App *app = data; - - if (app->playing) - *pixels = app->vf.frames[app->vs->frame.player]; - else - *pixels = NULL; - - return NULL; // picture identifier, not needed here -} - -static void -_unlock(void *data EINA_UNUSED, void *id EINA_UNUSED, void *const *pixels EINA_UNUSED) -{ -} - -static void -_display(void *data, void *id EINA_UNUSED) -{ - App *app = data; - - if (!app->playing) - return; - - eina_semaphore_lock(&app->vs->lock); - app->vs->frame.last = app->vs->frame.player; - app->vs->frame.player = app->vs->frame.next; - app->vs->frame.next = app->vs->frame.last; - if (!app->vs->frame_drop++) - { - _send_cmd(app, EM_RESULT_FRAME_NEW); - _send_cmd_finish(app); - } - eina_semaphore_release(&app->vs->lock, 1); -} - -static void -_player_setup(App *app) -{ - - libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4); - libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app); - - app->event_mgr = libvlc_media_player_event_manager(app->mp); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerEndReached, - _event_cb, app); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped, - _event_cb, app); -} - -/* Commands received from the emotion pipe */ -static void -_file_set(App *app) -{ - DBG("Path: %s", app->filename); - app->m = libvlc_media_new_path(app->libvlc, app->filename); - if (!app->m) - { - ERR("could not open path: \"%s\"", app->filename); - return; - } - - app->mp = libvlc_media_player_new_from_media(app->m); - if (!app->mp) - { - ERR("could not create new player from media."); - return; - } - - app->opening = EINA_TRUE; - - /* Here we start playing and connect a temporary callback to know when - * the file is parsed and ready to be played for real. - */ - app->event_mgr = libvlc_media_player_event_manager(app->mp); - libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying, - _tmp_playing_event_cb, app); - - libvlc_media_player_play(app->mp); -} - -static void -_file_set_done(App *app) -{ - int r; - - DBG("Path: %s", app->filename); - app->opening = EINA_FALSE; - - r = emotion_generic_shm_get(app->shmname, &app->vs, &app->vf); - if (!r) - { - free(app->filename); - libvlc_media_release(app->m); - libvlc_media_player_release(app->mp); - app->filename = NULL; - app->m = NULL; - app->mp = NULL; - } - else - { - _player_setup(app); - } - - _send_file_set_done(app, r); -} - -static void -_file_close(App *app) -{ - DBG("closing file"); - - if (!app->mp) - return; - - app->closing = EINA_TRUE; - libvlc_media_player_stop(app->mp); -} - -static void -_stop(App *app) -{ - DBG("Stop"); - if (app->mp) - libvlc_media_player_set_pause(app->mp, 1); -} - -static void -_play(App *app, float pos) -{ - DBG("Play at %.3f", pos); - - if (!app->mp) - return; - - if (app->playing) - { - libvlc_media_player_set_pause(app->mp, 0); - } - else - { - libvlc_time_t new_time = pos * 1000; - libvlc_media_player_set_time(app->mp, new_time); - libvlc_media_player_play(app->mp); - - if (app->subtitle_path) - libvlc_video_set_subtitle_file(app->mp, app->subtitle_path); - - app->playing = EINA_TRUE; - } -} - -static void -_position_set(App *app, float position) -{ - libvlc_time_t new_time; - - DBG("Position set %.3f", position); - if (!app->mp) - return; - - new_time = position * 1000; - libvlc_media_player_set_time(app->mp, new_time); - - if (libvlc_media_player_get_state(app->mp) == libvlc_Paused) - _send_time_changed(app); -} - -static void -_speed_set(App *app, float rate) -{ - DBG("Speed set %.3f", rate); - if (!app->mp) - return; - - libvlc_media_player_set_rate(app->mp, rate); -} - -static void -_mute_set(App *app, int mute) -{ - DBG("Mute %d", mute); - if (!app->mp) - return; - - app->audio_muted = mute; - libvlc_audio_set_mute(app->mp, mute); -} - -static void -_volume_set(App *app, float volume) -{ - DBG("Volume set %.2f", volume); - if (!app->mp) - return; - - app->volume = volume * 100; - libvlc_audio_set_volume(app->mp, app->volume); -} - -static void -_spu_track_set(App *app, int track) -{ - DBG("SPU track %d", track); - libvlc_video_set_spu(app->mp, track); -} - -static void -_audio_track_set(App *app, int track) -{ - DBG("Audio track %d", track); - libvlc_audio_set_track(app->mp, track); -} - -static void -_video_track_set(App *app, int track) -{ - DBG("Video Track %d", track); - libvlc_video_set_track(app->mp, track); -} - -static void -_remote_command(void *data, void *buffer, unsigned int nbyte) -{ - App *app = data; - - if (nbyte == 0) - { - ecore_main_loop_quit(); - return ; - } - - if (app->last_order == EM_CMD_LAST) - { - if (nbyte != sizeof (int)) - { - ERR("didn't receive a valid command from emotion (%i) !", nbyte); - ecore_main_loop_quit(); - return ; - } - - app->last_order = *((int*) buffer); - - if (!app->inited && - app->last_order != EM_CMD_INIT) - { - ERR("wrong init command!"); - ecore_main_loop_quit(); - return ; - } - - switch (app->last_order) - { - case EM_CMD_FILE_SET: - if (app->opening) - { - libvlc_media_release(app->m); - libvlc_media_player_release(app->mp); - free(app->filename); - app->opening = EINA_FALSE; - } - break; - case EM_CMD_FILE_SET_DONE: - _file_set_done(app); - app->last_order = EM_CMD_LAST; - break; - case EM_CMD_FILE_CLOSE: - _file_close(app); - app->last_order = EM_CMD_LAST; - break; - case EM_CMD_STOP: - _stop(app); - app->last_order = EM_CMD_LAST; - break; - } - } - else - { - switch (app->last_order) - { - case EM_CMD_INIT: - app->shmname = strdup(buffer); - app->inited = EINA_TRUE; - _send_init(app); - break; - case EM_CMD_FILE_SET: - app->filename = strdup(buffer); - _file_set(app); - break; - case EM_CMD_SUBTITLE_SET: - app->subtitle_path = strdup(buffer); - break; - case EM_CMD_PLAY: - _play(app, *(float*) buffer); - break; - case EM_CMD_POSITION_SET: - _position_set(app, *(float*) buffer); - break; - case EM_CMD_SPEED_SET: - _speed_set(app, *(float*) buffer); - break; - case EM_CMD_AUDIO_MUTE_SET: - _mute_set(app, *(int*) buffer); - break; - case EM_CMD_VOLUME_SET: - _volume_set(app, *(float*) buffer); - break; - case EM_CMD_SPU_TRACK_SET: - _spu_track_set(app, *(int*) buffer); - break; - case EM_CMD_AUDIO_TRACK_SET: - _audio_track_set(app, *(int*) buffer); - break; - case EM_CMD_VIDEO_TRACK_SET: - _video_track_set(app, *(int*) buffer); - break; - } - app->last_order = EM_CMD_LAST; - } -} - -static void -_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int nbyte EINA_UNUSED) -{ - /* This function is useless for the pipe we use to send message back - to emotion, but still needed */ -} - -/* Main */ -static Eina_Bool -exit_func(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED) -{ - DBG("Quit signal received !"); - ecore_main_loop_quit(); - return EINA_TRUE; -} - -int -main(int argc, const char *argv[]) -{ - App app; - Ecore_Event_Handler *hld; - int vlc_argc; - - const char *vlc_argv[] = - { - "--quiet", - "--intf", "dummy", /* no interface */ - "--vout", "dummy", /* we don't want video (output) */ - "--no-video-title-show", /* nor the filename displayed */ - "--no-sub-autodetect-file", /* we don't want automatic subtitles */ - "--no-stats", /* no stats */ - "--no-inhibit", /* we don't want interfaces */ - "--no-disable-screensaver", /* we don't want interfaces */ -// XXX: causes newer vlcs to segv! -// "--codec", "avcodec", -// XXX: disable this just in case -// "--demux", "avformat" - }; - vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv); - - memset(&app, 0, sizeof(app)); - if (!eina_init()) - { - EINA_LOG_CRIT("Can't initialize generic vlc player, eina failed."); - return -1; - } - - _em_vlc_log_dom = eina_log_domain_register("emotion_generic_vlc", - EINA_COLOR_CYAN); - if (_em_vlc_log_dom < 0) - { - EINA_LOG_CRIT("Unable to register emotion_generic_vlc log domain."); - goto error; - } - - if (!eina_log_domain_level_check(_em_vlc_log_dom, EINA_LOG_LEVEL_WARN)) - eina_log_domain_level_set("emotion_generic_vlc", EINA_LOG_LEVEL_WARN); - - if (argc < 3) - { - ERR("missing parameters."); - ERR("syntax:\n\t%s ", argv[0]); - goto error; - } - - ecore_init(); - - eina_lock_new(&app.cmd_mutex); - - app.fd_read = ecore_pipe_full_add(_remote_command, &app, - atoi(argv[1]), -1, EINA_FALSE, EINA_FALSE); - app.fd_write = ecore_pipe_full_add(_dummy, NULL, - -1, atoi(argv[2]), EINA_FALSE, EINA_FALSE); - - hld = ecore_event_handler_add(ECORE_EVENT_SIGNAL_HUP, exit_func, NULL); - - app.libvlc = libvlc_new(vlc_argc, vlc_argv); - app.mp = NULL; - app.filename = NULL; - app.subtitle_path = NULL; - app.w = 0; - app.h = 0; - app.opening = EINA_FALSE; - app.playing = EINA_FALSE; - app.inited = EINA_FALSE; - app.last_order = EM_CMD_LAST; - - ecore_main_loop_begin(); - - libvlc_release(app.libvlc); - ecore_pipe_del(app.fd_read); - ecore_pipe_del(app.fd_write); - ecore_event_handler_del(hld); - eina_lock_free(&app.cmd_mutex); - - ecore_shutdown(); - eina_shutdown(); - return 0; - - error: - eina_shutdown(); - return -1; -} -#undef SEND_CMD_PARAM diff --git a/src/generic/emotion/vlc/meson.build b/src/generic/emotion/vlc/meson.build deleted file mode 100644 index b21f4a16df..0000000000 --- a/src/generic/emotion/vlc/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -vlc = dependency('libvlc') - -executable('vlc', - 'emotion_generic_vlc.c', - dependencies: [emotion_generic, eina, ecore, rt, vlc], - install: true, - install_dir: join_paths(dir_lib, 'emotion', 'generic_players', version_name) -) diff --git a/src/generic/evas/meson.build b/src/generic/evas/meson.build index 2e5b58ae4c..e651b8b16a 100644 --- a/src/generic/evas/meson.build +++ b/src/generic/evas/meson.build @@ -1,8 +1,8 @@ -generic_loaders = ['gst', 'pdf', -'ps', -'raw', -'rsvg', -'xcf'] +generic_loaders = [ 'pdf', 'ps', 'raw', 'rsvg', 'xcf' ] + +if get_option('gstreamer') == true + generic_loaders += [ 'gst' ] +endif generic_src = [] generic_deps = [] diff --git a/src/lib/ecore_cocoa/Ecore_Cocoa.h b/src/lib/ecore_cocoa/Ecore_Cocoa.h index 36f17b490b..ca0a835be2 100644 --- a/src/lib/ecore_cocoa/Ecore_Cocoa.h +++ b/src/lib/ecore_cocoa/Ecore_Cocoa.h @@ -196,22 +196,6 @@ struct _Ecore_Cocoa_Event_Window_Destroy Ecore_Cocoa_Object *cocoa_window; /**< Handler of the Cocoa window */ }; -/** - * @typedef Ecore_Cocoa_Cnp_Type - * Type used to interact with the Cocoa pasteboard. - * It holds types that can apply to a context. - * @since 1.18 - */ -typedef enum -{ - ECORE_COCOA_CNP_TYPE_UNKNOWN = 0, /**< Undefined type */ - ECORE_COCOA_CNP_TYPE_STRING = (1 << 0), /**< String type (pure text) */ - ECORE_COCOA_CNP_TYPE_MARKUP = (1 << 1), /**< Elementary markup */ - ECORE_COCOA_CNP_TYPE_IMAGE = (1 << 2), /**< Image (all formats) */ - ECORE_COCOA_CNP_TYPE_HTML = (1 << 3) /**< HTML */ -} Ecore_Cocoa_Cnp_Type; - - /*============================================================================* * Core * *============================================================================*/ @@ -561,27 +545,22 @@ EAPI void ecore_cocoa_terminate_cb_set(Ecore_Cocoa_Terminate_Cb cb) * Sets the clipboard of Cocoa (NSPasteboard) * @param data The contents to be set in the clipboard * @param size The size in bytes of @c data - * @param type + * @param mine_type * @return EINA_TRUE on success, EINA_FALSE on failure */ EAPI Eina_Bool ecore_cocoa_clipboard_set(const void *data, - int size, - Ecore_Cocoa_Cnp_Type type); + int size, + const char *mime_type); /* * Gets the contents of the Cocoa clipboard * @param size Pointer used to retrieve the size of the received contents - * @param type The type of object to retrieve from the clipboard - * @param retrieved_types The types of objects retrieved from the clipboard + * @param mine_type The type of object to retrieve from the clipboard * @return The data retrieved from the clipboard. NULL on failure * - * If @c type was ECORE_COCOA_CNP_TYPE_STRING or ECORE_COCOA_CNP_TYPE_MARKUP, - * @c retrieved_types will contain ECORE_COCOA_CNP_TYPE_STRING and the data - * will be a C string (char*) that must be freed after use. */ EAPI void *ecore_cocoa_clipboard_get(int *size, - Ecore_Cocoa_Cnp_Type type, - Ecore_Cocoa_Cnp_Type *retrieved_types) + const char *mime_type) EINA_WARN_UNUSED_RESULT; /* @@ -589,6 +568,11 @@ EAPI void *ecore_cocoa_clipboard_get(int *size, */ EAPI void ecore_cocoa_clipboard_clear(void); +/* + * Returns true when the clipboard contains data that can be received. + */ +EAPI Eina_Bool ecore_cocoa_clipboard_exists(void); + #endif /* EFL_BETA_API_SUPPORT */ #ifdef __cplusplus diff --git a/src/lib/ecore_cocoa/ecore_cocoa_cnp.m b/src/lib/ecore_cocoa/ecore_cocoa_cnp.m index c5fd22e99d..fabfc8c5a5 100644 --- a/src/lib/ecore_cocoa/ecore_cocoa_cnp.m +++ b/src/lib/ecore_cocoa/ecore_cocoa_cnp.m @@ -9,16 +9,17 @@ #import "ecore_cocoa_app.h" EAPI Eina_Bool -ecore_cocoa_clipboard_set(const void *data, - int size, - Ecore_Cocoa_Cnp_Type type) +ecore_cocoa_clipboard_set(const void *data, + int size, + const char *raw_mime_type) { NSMutableArray *objects; NSString *str = nil; BOOL ok = YES; + NSString *mime_type = [NSString stringWithUTF8String:raw_mime_type]; objects = [[NSMutableArray alloc] init]; - if (type & ECORE_COCOA_CNP_TYPE_STRING) + if ([mime_type hasPrefix:@"text/"]) { str = [[NSString alloc] initWithBytes: data length: size @@ -26,18 +27,9 @@ ecore_cocoa_clipboard_set(const void *data, if (str) [objects addObject: str]; } - if (type & ECORE_COCOA_CNP_TYPE_MARKUP) + else { - WRN("Markup CNP: NOT IMPLEMENTED"); - } - - if (type & ECORE_COCOA_CNP_TYPE_IMAGE) - { - WRN("Image CNP: NOT IMPLEMENTED"); - } - if (type & ECORE_COCOA_CNP_TYPE_HTML) - { - WRN("HTML CNP: NOT IMPLEMENTED"); + ERR("Mimetype %s is not handled yet", raw_mime_type); } /* Write to pasteboard */ @@ -54,35 +46,45 @@ ecore_cocoa_clipboard_set(const void *data, return (ok) ? EINA_TRUE : EINA_FALSE; } +EAPI Eina_Bool +ecore_cocoa_clipboard_exists(void) +{ + NSDictionary *options; + NSPasteboard *pb; + NSArray *items; + NSMutableArray *classes; + + classes = [[NSMutableArray alloc] init]; + [classes addObject: [NSString class]]; // we only support strings for now + pb = [NSPasteboard generalPasteboard]; + options = [NSDictionary dictionary]; + return [pb canReadItemWithDataConformingToTypes: classes]; +} EAPI void * -ecore_cocoa_clipboard_get(int *size, - Ecore_Cocoa_Cnp_Type type, - Ecore_Cocoa_Cnp_Type *retrieved_types) +ecore_cocoa_clipboard_get(int *size, + const char *raw_mime_type) { NSMutableArray *classes; - void *data; + void *data = NULL; NSDictionary *options; NSPasteboard *pb; NSArray *items; unsigned int len; BOOL string_class = NO; - Ecore_Cocoa_Cnp_Type types = 0; + NSString *mime_type = [NSString stringWithUTF8String:raw_mime_type]; classes = [[NSMutableArray alloc] init]; - if (type & ECORE_COCOA_CNP_TYPE_STRING) + if ([mime_type hasPrefix:@"text/"]) { string_class = YES; [classes addObject: [NSString class]]; } - if (type & ECORE_COCOA_CNP_TYPE_IMAGE) + else { - WRN("Image CNP: NOT IMPLEMENTED"); - } - if (type & ECORE_COCOA_CNP_TYPE_HTML) - { - WRN("HTML CNP: NOT IMPLEMENTED"); + ERR("Mimetype %s is not handled yet", raw_mime_type); + goto fail; } if ([classes count] <= 0) @@ -120,7 +122,6 @@ ecore_cocoa_clipboard_get(int *size, (const char *)data, len); goto remove_fail; } - types |= ECORE_COCOA_CNP_TYPE_STRING; #if 0 if (type & ECORE_COCOA_CNP_TYPE_MARKUP) @@ -139,7 +140,7 @@ ecore_cocoa_clipboard_get(int *size, #endif } - if (!types) + if (!data) { ERR("No types retrieved!"); goto remove_fail; @@ -148,14 +149,12 @@ ecore_cocoa_clipboard_get(int *size, [classes removeAllObjects]; if (size) *size = len; - if (retrieved_types) *retrieved_types = types; return data; remove_fail: [classes removeAllObjects]; fail: if (size) *size = 0; - if (retrieved_types) *retrieved_types = 0; return NULL; } diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h index d59900d788..e3e8b63000 100644 --- a/src/lib/ecore_evas/Ecore_Evas.h +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -3669,6 +3669,216 @@ EAPI unsigned long ecore_evas_pixmap_colormap_get(const Ecore_Evas *ee); */ EAPI int ecore_evas_pixmap_depth_get(const Ecore_Evas *ee); +typedef enum { + ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER = 0, /**< Stores selected / highlighted selection */ + ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER = 1, /**< Stores copied things (Ctrl + C) */ + ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER = 2, /**< Stores dragged things while drag and drop is happening. */ + ECORE_EVAS_SELECTION_BUFFER_LAST = 3, +} Ecore_Evas_Selection_Buffer; + +/** + * @brief Callback called when the content of one of the selection buffers changes. + * + * @param[in] ee The Ecore_Evas that handles this selection. + * @param[in] selection The selection buffer that has changed. + */ +typedef void (*Ecore_Evas_Selection_Changed_Cb)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); + +/** + * @brief Sets a callback for Ecore_Evas to be called when a selection buffer changes. + * + * @param[in] ee The Ecore_Evas to set the callback on. + * @param[in] cb The function to call. + * + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee selections change. + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @p func to stop being notified. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_selection_changed_set(Ecore_Evas *ee, Ecore_Evas_Selection_Changed_Cb cb); + +/** + * @brief Sets the content of the specified selection buffer. + * + * @param[in] ee The Ecore_Evas to set the selection buffer on. + * @param[in] buffer The selection buffer to set. + * @param[in] content Content to set to the selection buffer. The Eina_Content specifies the MIME type of the data. + * Ownership of the content is transferred. + * + * @note Only ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER and ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER + * buffers can be set. Drag and drop operations use a different set of methods. + */ +EAPI Eina_Bool ecore_evas_selection_set(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Content *content); + +/** + * @brief Checks if the specified selection buffer has content. + * + * @param[in] ee The ecore evas to query + * @param[in] buffer Which selection buffer to ask + * + * @return EINA_TRUE if there is an available selection for the specified buffer. + * + * EINA_TRUE is also returned when the selection is in the window associated with @p ee + * + * @note Due to the asynchronous nature of selection buffers, this method might not return + * the right result when invoked from the selection callback set with ecore_evas_callback_selection_changed_set. + */ +EAPI Eina_Bool ecore_evas_selection_exists(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer); + +/** + * @brief Retrieves the content of the specified selection buffer. + * + * @param[in] ee The ecore evas to query. + * @param[in] buffer Selection buffer to retrieve. + * @param[in] acceptable_types MIME types which are acceptable for the returned Eina_Content. + * The iterator contains plain strings (char *). Ownership is transferred for the iterator but not for the strings. + * This is convenient for the usual case of a hard-coded array of strings, since the iterator can be generated + * on the fly, used and forgotten. + * + * @return An Eina_Future containing an Eina_Content which has one of the types in @p acceptable_type. + * An error is delivered when no matching type is found or when the requested selection buffer is empty. + * + * This method is time consuming, therefore, it is recommended to verify the existence of a selection + * using ecore_evas_selection_exists before calling it. + */ +EAPI Eina_Future* ecore_evas_selection_get(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Iterator *acceptable_types); + +/** + * @brief This method is called when the mouse pointer enters or exits the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * @param[in] inside @c EINA_TRUE if the pointer just entered this window. @c EINA_FALSE if it has just exited. + * + * Set this callback using ecore_evas_callback_drop_state_changed_set. + */ +typedef void (*Ecore_Evas_Drag_Finished_Cb)(Ecore_Evas *ee, unsigned int seat, void *data, Eina_Bool accepted); + +/** + * @brief Starts a new drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] content The content to delivery at the drop site (ownership is transferred). + * The Eina_Content has data and its associated MIME type, plus a list of alternate types that can be provided. + * @param[in] drag_rep An Ecore_Evas used as a visual representation of the content being dragged. + * It must have the same type as @p ee. This is the transparent object dragged along the mouse pointer to indicate that + * a drag operation is in progress. + * @p terminate_cb will be called when @p drag_rep is not needed anymore and it must be disposed of. + * Use @p data to convey @p drag_rep to @p terminate_cb. For example, if @p drag_rep is owned by an Efl_Window, @p data + * can point to that window. + * @param[in] action Action the target application should perform upon receiving this content. It is entirely up to the + * target application to honor (or even understand) this request. + * @return @c EINA_TRUE if the drag operation has been successfully started. + * + * This method must be called when a drag operation is initiated in order to provide the necessary information. + */ +EAPI Eina_Bool ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, + const char* action, Ecore_Evas_Drag_Finished_Cb terminate_cb, void *data); + +/** + * @brief Cancels an ongoing drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @return @c EINA_TRUE if the drag operation has been successfully cancelled. + * + * The initiator of a drag operation can call this method to abort it. + */ +EAPI Eina_Bool ecore_evas_drag_cancel(Ecore_Evas *ee, unsigned int seat); + +/** + * @brief This method is called when the mouse pointer enters or exits the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * @param[in] inside @c EINA_TRUE if the pointer just entered this window. @c EINA_FALSE if it has just exited. + * + * Set this callback using ecore_evas_callback_drop_state_changed_set. + */ +typedef void (*Ecore_Evas_Drag_State_Changed_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, Eina_Bool inside); + +/** + * @brief Sets the method (callback) to call when the mouse pointer enters or exits the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] cb Method to call when the events are received. + * + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @cb func to stop being notified. + */ +EAPI void ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_Drag_State_Changed_Cb cb); + +/** + * @brief This method is called when the mouse pointer moves over the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * + * Set this callback using ecore_evas_callback_drop_motion_set. + */ + +typedef void (*Ecore_Evas_Drag_Motion_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p); +/** + * @brief Sets the method (callback) to call when the mouse pointer moves over the specified window while + * performing a drag operation. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] cb Method to call when the events are received. + * + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @cb func to stop being notified. + */ +EAPI void ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Drag_Motion_Cb cb); + +/** + * @brief This method is called when the mouse pointer is released over the specified window while + * performing a drag operation (thus dropping the dragged content over the window). + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] p Position (in window coordinates) where the event occurred. + * + * The dropped data can be retrieved using ecore_evas_selection_get and the + * ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER buffer. + * + * Set this callback using ecore_evas_callback_drop_drop_set. + */ +typedef void (*Ecore_Evas_Drop_Cb)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, const char *action); + +/** + * @brief Sets the method (callback) to call when the mouse pointer is released over the specified window while + * performing a drag operation (thus dropping the dragged content over the window). + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @param[in] cb Method to call when the events are received. + * + * Only one such callback can exist for each Ecore_Evas. Calling this method multiple + * times overwrites previous functions. Use a NULL @cb func to stop being notified. + */ +EAPI void ecore_evas_callback_drop_drop_set(Ecore_Evas *ee, Ecore_Evas_Drop_Cb cb); + +/** + * @brief Retrieves the list of types the data currently being dragged can be automatically converted to. + * + * @param[in] ee The Ecore Evas the drag operation started on. + * @return + * + * This can be used in any of the drag and drop callbacks (Ecore_Evas_Drag_State_Changed_Cb, Ecore_Evas_Drag_Motion_Cb + * and Ecore_Evas_Drop_Cb) to check if the data being dragged is acceptable and give the user some early feedback + * before the data is actually dropped on the window. + * + * This is functionally equivalent to calling ecore_evas_selection_get and examining the available types in the + * returned Eina_Content, but much faster since the actual data does not have to be asynchronously requested to the + * initiator application. + */ +EAPI Eina_Accessor* ecore_evas_drop_available_types_get(Ecore_Evas *ee, unsigned int seat); + + /** * @} */ @@ -3685,3 +3895,4 @@ EAPI int ecore_evas_pixmap_depth_get(const Ecore_Evas *ee); #define EAPI #endif + diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c index d3c26ddb19..ab28af1a2f 100644 --- a/src/lib/ecore_evas/ecore_evas.c +++ b/src/lib/ecore_evas/ecore_evas.c @@ -652,6 +652,10 @@ ecore_evas_init(void) iface.del = _ecore_evas_animator_del; ecore_evas_object_animator_init(&iface); + ecore_evas_no_matching_type = eina_error_msg_register("No fitting type could be found"); + ecore_evas_no_selection = eina_error_msg_register("No selection available"); + ecore_evas_request_replaced = eina_error_msg_register("Selection request replaced"); + return _ecore_evas_init_count; shutdown_ecore: @@ -2818,7 +2822,7 @@ ecore_evas_shadow_geometry_get(const Ecore_Evas *ee, int *l, int *r, int *t, int if (b) *b = ee->shadow.b; } -EAPI void +EAPI void ecore_evas_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) { if (x) *x = 0; @@ -2828,7 +2832,7 @@ ecore_evas_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) IFE; } -EAPI Eina_Bool +EAPI Eina_Bool ecore_evas_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) { ECORE_EVAS_CHECK(ee, EINA_FALSE); @@ -2905,7 +2909,7 @@ ecore_evas_pixmap_visual_get(const Ecore_Evas *ee) return NULL; } -EAPI unsigned long +EAPI unsigned long ecore_evas_pixmap_colormap_get(const Ecore_Evas *ee) { ECORE_EVAS_CHECK(ee, 0); @@ -2932,7 +2936,7 @@ ecore_evas_pixmap_colormap_get(const Ecore_Evas *ee) return 0; } -EAPI int +EAPI int ecore_evas_pixmap_depth_get(const Ecore_Evas *ee) { ECORE_EVAS_CHECK(ee, 0); @@ -3524,6 +3528,9 @@ _ecore_evas_free(Ecore_Evas *ee) free(iface); ee->engine.ifaces = NULL; + + if (ee->fallback_interface) + fallback_selection_shutdown(ee); free(ee); } @@ -3542,7 +3549,7 @@ _ecore_evas_idle_timeout_update(Ecore_Evas *ee) { if (ee->engine.idle_flush_timer) ecore_timer_del(ee->engine.idle_flush_timer); - ee->engine.idle_flush_timer = + ee->engine.idle_flush_timer = ecore_timer_loop_add(IDLE_FLUSH_TIME, _ecore_evas_cb_idle_flush, ee); } @@ -4007,7 +4014,7 @@ ecore_evas_software_x11_pixmap_new(const char *disp_name, Ecore_X_Window parent, } -EAPI Ecore_X_Pixmap +EAPI Ecore_X_Pixmap ecore_evas_software_x11_pixmap_get(const Ecore_Evas *ee) { Ecore_Evas_Interface_Software_X11 *iface; @@ -4082,7 +4089,7 @@ ecore_evas_gl_x11_pixmap_new(const char *disp_name, Ecore_X_Window parent, int x } -EAPI Ecore_X_Pixmap +EAPI Ecore_X_Pixmap ecore_evas_gl_x11_pixmap_get(const Ecore_Evas *ee) { Ecore_Evas_Interface_Gl_X11 *iface; @@ -5449,3 +5456,344 @@ _ecore_evas_animator_thaw(Ecore_Animator *in) EINA_INLIST_GET(animator)); _ticking_start(ee); } + +EAPI void +ecore_evas_callback_selection_changed_set(Ecore_Evas *ee, Ecore_Evas_Selection_Changed_Cb func) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_selection_changed = func; +} + +static Ecore_Evas_Selection_Seat_Buffers* +_fetch_selection_buffers_of_seat(Ecore_Evas *ee, unsigned int seat, Eina_Bool create) +{ + Ecore_Evas_Selection_Seat_Buffers *buffers; + if (!ee->selection_buffers) + ee->selection_buffers = eina_hash_int32_new(free); + + buffers = eina_hash_find(ee->selection_buffers, &seat); + + if (!buffers && create) + { + buffers = calloc(1, sizeof(Ecore_Evas_Selection_Seat_Buffers)); + buffers->seat = seat; + eina_hash_add(ee->selection_buffers, &seat, buffers); + } + return buffers; +} + +static Eina_Bool +_deliver_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice) +{ + Ecore_Evas_Selection_Seat_Buffers *buffers; + Eina_Content *content; + Eina_Content *converted = NULL; + Eina_Bool result = EINA_FALSE; + + INF("Delivery request on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE); + EINA_SAFETY_ON_NULL_GOTO(buffers, free_everything); + content = buffers->selection_buffer[buffer]; + EINA_SAFETY_ON_NULL_GOTO(content, free_everything); + if (!eina_streq(type, eina_content_type_get(content))) + converted = eina_content_convert(content, type); + else + converted = content; + + EINA_SAFETY_ON_NULL_GOTO(converted, free_everything); + *slice = eina_slice_dup(eina_content_data_get(converted)); + result = EINA_TRUE; + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + ee->drag.accepted = EINA_TRUE; + } + +free_everything: + if (converted && content && !eina_streq(type, eina_content_type_get(content))) + eina_content_free(converted); + + return result; +} + +static void +_cancel_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer) +{ + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Cancel request on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN(buffers); + EINA_SAFETY_ON_FALSE_RETURN(buffers->selection_buffer[buffer]); + eina_content_free(buffers->selection_buffer[buffer]); + buffers->selection_buffer[buffer] = NULL; + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + ee->drag.rep = NULL; + if (ee->drag.free) + ee->drag.free(ee, seat, ee->drag.data, EINA_FALSE); + ee->drag.free = NULL; + } +} + +#define CALL(call) (ee->engine.func->fn_ ##call ? : fallback_ ##call) + +static Eina_Array* +_iterator_to_array(Eina_Iterator *iter, const char *existing_type) +{ + Eina_Array *ret = eina_array_new(10); + const char *type; + + if (existing_type) + eina_array_push(ret, existing_type); + + EINA_ITERATOR_FOREACH(iter, type) + { + eina_array_push(ret, type); + } + eina_iterator_free(iter); + + return ret; +} + +EAPI Eina_Bool +ecore_evas_selection_set(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Content *content) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffer >= 0 && buffer < ECORE_EVAS_SELECTION_BUFFER_LAST, EINA_FALSE); + Eina_Iterator *available_type = NULL; + Eina_Bool success; + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Selection set on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_TRUE); + + if (content) + available_type = eina_content_possible_conversions(content); + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + ERR("You cannot set a selection with this API, please use the API to start a drag operation"); + return EINA_FALSE; + } + + success = CALL(selection_claim)(ee, seat, buffer, _iterator_to_array(available_type, content ? eina_content_type_get(content) : NULL), content ? _deliver_cb : NULL, content ? _cancel_cb : NULL); + if (success) + { + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffers->selection_buffer[buffer] == NULL, EINA_FALSE); + //keep this after the claim, the claim might call cancel, which would overwrite this. + buffers->selection_buffer[buffer] = content; + } + else + { + eina_content_free(content); + } + + return success; +} + +EAPI Eina_Bool +ecore_evas_selection_exists(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffer >= 0 && buffer < ECORE_EVAS_SELECTION_BUFFER_LAST, EINA_FALSE); + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Exists request on seat %d in buffer %d", seat, buffer); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_TRUE); + if (buffers->selection_buffer[buffer]) + return EINA_TRUE; + else + { + return CALL(selection_has_owner)(ee, seat, buffer); + } +} + +static Eina_Array* +_iterator_to_array_stringshared(Eina_Iterator *iter) +{ + Eina_Array *ret = eina_array_new(10); + const char *type; + + EINA_ITERATOR_FOREACH(iter, type) + { + eina_array_push(ret, eina_stringshare_add(type)); + } + eina_iterator_free(iter); + + return ret; +} + +EAPI Eina_Future* +ecore_evas_selection_get(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, Eina_Iterator *acceptable_types) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, NULL); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffer >= 0 && buffer < ECORE_EVAS_SELECTION_BUFFER_LAST, NULL); + + INF("Selection get request on seat %d in buffer %d", seat, buffer); + + return CALL(selection_request)(ee, seat, buffer, _iterator_to_array_stringshared(acceptable_types)); +} + +EAPI Eina_Bool +ecore_evas_drag_start(Ecore_Evas *ee, unsigned int seat, Eina_Content *content, Ecore_Evas *drag_rep, const char* action, Ecore_Evas_Drag_Finished_Cb terminate_cb, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(content, EINA_FALSE); + Eina_Iterator *available_type = eina_content_possible_conversions(content); + Eina_Bool success; + Ecore_Evas_Selection_Seat_Buffers *buffers; + + INF("Drag start on seat %d", seat); + + buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_TRUE); + success = CALL(dnd_start)(ee, seat, _iterator_to_array(available_type, eina_content_type_get(content)), drag_rep, _deliver_cb, _cancel_cb, action); + EINA_SAFETY_ON_FALSE_RETURN_VAL(buffers->selection_buffer[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER] == NULL, EINA_FALSE); + //keep this after the claim, the claim might call cancel, which would overwrite this. + buffers->selection_buffer[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER] = content; + + ee->drag.rep = drag_rep; + ee->drag.free = terminate_cb; + ee->drag.data = data; + ee->drag.accepted = EINA_FALSE; + + return success; +} + +EAPI Eina_Bool +ecore_evas_drag_cancel(Ecore_Evas *ee, unsigned int seat) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ee, EINA_FALSE); + + INF("Drag cancel on seat %d", seat); + + return CALL(dnd_stop)(ee, seat); +} + +EAPI void +ecore_evas_callback_drop_motion_set(Ecore_Evas *ee, Ecore_Evas_Drag_Motion_Cb cb) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_dnd_motion = cb; +} + +EAPI void +ecore_evas_callback_drop_state_changed_set(Ecore_Evas *ee, Ecore_Evas_Drag_State_Changed_Cb cb) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_dnd_state_change = cb; +} + +EAPI void +ecore_evas_callback_drop_drop_set(Ecore_Evas *ee, Ecore_Evas_Drop_Cb cb) +{ + ECORE_EVAS_CHECK(ee); + ee->func.fn_dnd_drop = cb; +} + +typedef struct { + Eina_Array *available_mime_types; + Eina_Position2D pos; +} Ecore_Evas_Active_Dnd; + +static void +_ecore_evas_active_dnd_free(Ecore_Evas_Active_Dnd *dnd) +{ + eina_array_free(dnd->available_mime_types); + free(dnd); +} + +EAPI void +ecore_evas_dnd_enter(Ecore_Evas *ee, unsigned int seat, Eina_Iterator *available_types, Eina_Position2D pos) +{ + Eina_Stringshare *s; + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK(ee); + if (!ee->active_drags) + { + ee->active_drags = eina_hash_int32_new((Eina_Free_Cb)_ecore_evas_active_dnd_free); + } + + dnd = calloc(1, sizeof(Ecore_Evas_Active_Dnd)); + dnd->available_mime_types = eina_array_new(5); + eina_hash_add(ee->active_drags, &seat, dnd); + + EINA_ITERATOR_FOREACH(available_types, s) + { + eina_array_push(dnd->available_mime_types, s); + } + eina_iterator_free(available_types); + + if (ee->func.fn_dnd_state_change) + ee->func.fn_dnd_state_change(ee, seat, pos, EINA_TRUE); +} + +EAPI void +ecore_evas_dnd_position_set(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK(ee); + EINA_SAFETY_ON_NULL_RETURN(ee->active_drags); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN(dnd); + dnd->pos = pos; + if (ee->func.fn_dnd_motion) + ee->func.fn_dnd_motion(ee, seat, pos); +} + +EAPI void +ecore_evas_dnd_leave(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK(ee); + EINA_SAFETY_ON_NULL_RETURN(ee->active_drags); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN(dnd); + + if (ee->func.fn_dnd_state_change) + ee->func.fn_dnd_state_change(ee, seat, pos, EINA_FALSE); + eina_hash_del(ee->active_drags, &seat, dnd); + if (eina_hash_population(ee->active_drags) == 0) + { + eina_hash_free(ee->active_drags); + ee->active_drags = NULL; + } +} + +EAPI Eina_Position2D +ecore_evas_dnd_pos_get(Ecore_Evas *ee, unsigned int seat) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK_GOTO(ee, err); + EINA_SAFETY_ON_NULL_RETURN_VAL(ee->active_drags, EINA_POSITION2D(0, 0)); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN_VAL(dnd, EINA_POSITION2D(0, 0)); + + return dnd->pos; +err: + return EINA_POSITION2D(0, 0); +} + +EAPI Eina_Accessor* +ecore_evas_drop_available_types_get(Ecore_Evas *ee, unsigned int seat) +{ + Ecore_Evas_Active_Dnd *dnd; + + ECORE_EVAS_CHECK_GOTO(ee, err); + EINA_SAFETY_ON_NULL_RETURN_VAL(ee->active_drags, NULL); + dnd = eina_hash_find(ee->active_drags, &seat); + EINA_SAFETY_ON_NULL_RETURN_VAL(dnd, NULL); + + return eina_array_accessor_new(dnd->available_mime_types); +err: + return NULL; +} diff --git a/src/lib/ecore_evas/ecore_evas_fallback_selection.c b/src/lib/ecore_evas/ecore_evas_fallback_selection.c new file mode 100644 index 0000000000..b3f59c7921 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_fallback_selection.c @@ -0,0 +1,115 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "ecore_private.h" +#include "Ecore_Evas.h" +#include "ecore_evas_private.h" +#include + +typedef struct { + Ecore_Evas_Selection_Callbacks callbacks[ECORE_EVAS_SELECTION_BUFFER_LAST]; + int seat; +} Ecore_Evas_Fallback_Selection_Data; + +static Ecore_Evas_Fallback_Selection_Data data[ECORE_EVAS_SELECTION_BUFFER_LAST]; + +void +fallback_selection_shutdown(Ecore_Evas *ee) +{ + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (data->callbacks[i].cancel) + data->callbacks[i].cancel(ee, data->seat, i); + } +} + +Eina_Bool +fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) +{ + Ecore_Evas_Selection_Callbacks *callbacks = &data->callbacks[selection]; + + if (callbacks->cancel) + { + callbacks->cancel(ee, data->seat, selection); + eina_array_free(callbacks->available_types); + } + + callbacks->delivery = delivery; + callbacks->cancel = cancel; + callbacks->available_types = available_types; + data->seat = seat; + + if (ee->func.fn_selection_changed) + ee->func.fn_selection_changed(ee, seat, selection); + + return EINA_TRUE; +} + +Eina_Bool +fallback_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection EINA_UNUSED) +{ + return EINA_FALSE; //if the real selection buffer does not contain it, then we dont know it either. +} + +Eina_Stringshare* +available_types(Eina_Array *acceptable_types, Eina_Array *available_types) +{ + unsigned int found_type_id = INT_MAX; + Eina_Stringshare *found_type = NULL; + Eina_Stringshare *type; + + for (unsigned int i = 0; i < eina_array_count_get(acceptable_types); ++i) + { + unsigned int out = -1; + + type = eina_array_data_get(acceptable_types, i); + + if (!eina_array_find(available_types, type, &out)) + continue; + if (out >= found_type_id) + continue; + found_type_id = out; + found_type = type; + eina_stringshare_del(type); + } + eina_array_free(acceptable_types); + + return found_type; +} + +Eina_Future* +fallback_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Ecore_Evas_Selection_Callbacks callbacks = data->callbacks[selection]; + Eina_Content *result; + Eina_Stringshare *serving_type; + Eina_Rw_Slice slice_data; + Eina_Value value; + + if (!callbacks.delivery) + return eina_future_resolved(efl_loop_future_scheduler_get(efl_main_loop_get()), eina_value_int_init(0)); + + serving_type = available_types(acceptable_type, callbacks.available_types); + if (!serving_type) + return NULL; //Silent return cause we cannot deliver a good type + + EINA_SAFETY_ON_FALSE_RETURN_VAL(callbacks.delivery(ee, seat, selection, serving_type, &slice_data), NULL); + result = eina_content_new(eina_rw_slice_slice_get(slice_data), serving_type); + value = eina_value_content_init(result); + eina_content_free(result); + + return eina_future_resolved(efl_loop_future_scheduler_get(efl_main_loop_get()), value); +} +Eina_Bool +fallback_dnd_start(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Eina_Array *available_types EINA_UNUSED, Ecore_Evas *drag_rep EINA_UNUSED, Ecore_Evas_Selection_Internal_Delivery delivery EINA_UNUSED, Ecore_Evas_Selection_Internal_Cancel cancel EINA_UNUSED, const char* action EINA_UNUSED) +{ + return EINA_FALSE; +} + +Eina_Bool +fallback_dnd_stop(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED) +{ + return EINA_FALSE; +} diff --git a/src/lib/ecore_evas/ecore_evas_private.h b/src/lib/ecore_evas/ecore_evas_private.h index 474b7a35ed..6fb2c988b5 100644 --- a/src/lib/ecore_evas/ecore_evas_private.h +++ b/src/lib/ecore_evas/ecore_evas_private.h @@ -33,6 +33,10 @@ EAPI extern int _ecore_evas_log_dom; +EAPI Eina_Error ecore_evas_no_matching_type; +EAPI Eina_Error ecore_evas_no_selection; +EAPI Eina_Error ecore_evas_request_replaced; + #ifdef ECORE_EVAS_DEFAULT_LOG_COLOR # undef ECORE_EVAS_DEFAULT_LOG_COLOR #endif @@ -78,6 +82,13 @@ typedef struct _Ecore_Evas_Interface Ecore_Evas_Interface; typedef struct _Ecore_Evas_Aux_Hint Ecore_Evas_Aux_Hint; typedef struct _Ecore_Evas_Cursor Ecore_Evas_Cursor; +typedef Eina_Bool (*Ecore_Evas_Selection_Internal_Delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice); +typedef void (*Ecore_Evas_Selection_Internal_Cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer); +typedef struct { + Ecore_Evas_Selection_Internal_Delivery delivery; + Ecore_Evas_Selection_Internal_Cancel cancel; + Eina_Array *available_types; +} Ecore_Evas_Selection_Callbacks; /* Engines interfaces */ struct _Ecore_Evas_Engine_Func { @@ -171,6 +182,12 @@ struct _Ecore_Evas_Engine_Func Eina_Bool (*fn_prepare)(Ecore_Evas *ee); double (*fn_last_tick_get)(Ecore_Evas *ee); + + Eina_Bool (*fn_selection_claim)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel); + Eina_Bool (*fn_selection_has_owner)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); + Eina_Future* (*fn_selection_request)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_types); // a future containing a Eina_Content, type must be in acceptable_types + Eina_Bool (*fn_dnd_start)(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel, const char *action); + Eina_Bool (*fn_dnd_stop)(Ecore_Evas *ee, unsigned int seat); }; struct _Ecore_Evas_Interface @@ -202,6 +219,11 @@ struct _Ecore_Evas_Cursor { int pos_y; }; +typedef struct { + unsigned int seat; + Eina_Content *selection_buffer[ECORE_EVAS_SELECTION_BUFFER_LAST]; +} Ecore_Evas_Selection_Seat_Buffers; + struct _Ecore_Evas { EINA_INLIST; @@ -224,6 +246,8 @@ struct _Ecore_Evas Eina_List *vnc_server; /* @since 1.19 */ + Eina_Hash *selection_buffers; + struct { int x, y, w, h; } req; @@ -259,7 +283,7 @@ struct _Ecore_Evas Eina_Bool supported; // indicate that the underlying window system supports window manager rotation protocol Eina_Bool app_set; // indicate that the ee supports window manager rotation protocol Eina_Bool win_resize; // indicate that the ee will be resized by the WM - int angle; // rotation value which is decided by the WM + int angle; // rotation value which is decided by the WM int w, h; // window size to rotate int preferred_rot; // preferred rotation hint int *available_rots; // array of avaialable rotation values @@ -323,6 +347,10 @@ struct _Ecore_Evas void (*fn_focus_device_out) (Ecore_Evas *ee, Efl_Input_Device *seat); void (*fn_device_mouse_in) (Ecore_Evas *ee, Efl_Input_Device *mouse); void (*fn_device_mouse_out) (Ecore_Evas *ee, Efl_Input_Device *mouse); + void (*fn_selection_changed) (Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); + void (*fn_dnd_motion) (Ecore_Evas *ee, unsigned int seat, Eina_Position2D p); + void (*fn_dnd_state_change) (Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, Eina_Bool inside); + void (*fn_dnd_drop)(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p, const char *action); } func; Ecore_Evas_Engine engine; @@ -353,6 +381,14 @@ struct _Ecore_Evas unsigned char rotation_changed : 1; } delayed; + Eina_Hash *active_drags; + struct { + Ecore_Evas *rep; + void *data; + Ecore_Evas_Drag_Finished_Cb free; + Eina_Bool accepted; + } drag; + int refcount; //#define ECORE_EVAS_ASYNC_RENDER_DEBUG 1 /* TODO: remove me */ #ifdef ECORE_EVAS_ASYNC_RENDER_DEBUG @@ -374,6 +410,7 @@ struct _Ecore_Evas unsigned char first_frame : 1; unsigned char self_del : 1; unsigned char evas_dying : 1; + unsigned char fallback_interface : 1; }; struct _Ecore_Evas_Aux_Hint @@ -486,6 +523,20 @@ EAPI Eina_Bool ecore_evas_render(Ecore_Evas *ee); EAPI Evas *ecore_evas_evas_new(Ecore_Evas *ee, int w, int h); EAPI void ecore_evas_done(Ecore_Evas *ee, Eina_Bool single_window); +EAPI void ecore_evas_dnd_position_set(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos); +EAPI void ecore_evas_dnd_leave(Ecore_Evas *ee, unsigned int seat, Eina_Position2D pos); +EAPI void ecore_evas_dnd_enter(Ecore_Evas *ee, unsigned int seat, Eina_Iterator *available_types, Eina_Position2D pos); +EAPI Eina_Position2D ecore_evas_dnd_pos_get(Ecore_Evas *ee, unsigned int seat); + + +void fallback_selection_init(Ecore_Evas *ee); +void fallback_selection_shutdown(Ecore_Evas *ee); +Eina_Bool fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel); +Eina_Bool fallback_selection_has_owner(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection); +Eina_Future* fallback_selection_request(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type); +Eina_Bool fallback_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel, const char* action); +Eina_Bool fallback_dnd_stop(Ecore_Evas *ee, unsigned int seat); + #ifdef IPA_YLNO_ESU_LANRETNI_MLE EAPI Ecore_Evas *_wayland_shm_new(const char *disp_name, Ecore_Window parent, int x, int y, int w, int h, Eina_Bool frame); EAPI Ecore_Evas *_wayland_egl_new(const char *disp_name, Ecore_Window parent, int x, int y, int w, int h, Eina_Bool frame, const int *opt); diff --git a/src/lib/ecore_evas/meson.build b/src/lib/ecore_evas/meson.build index c0fb459a56..890e3c42b3 100644 --- a/src/lib/ecore_evas/meson.build +++ b/src/lib/ecore_evas/meson.build @@ -23,7 +23,8 @@ ecore_evas_src = [ 'ecore_evas_cocoa.h', 'ecore_evas_win32.h', 'ecore_evas_x11.h', - 'ecore_evas_util.c' + 'ecore_evas_util.c', + 'ecore_evas_fallback_selection.c' ] diff --git a/src/lib/ecore_win32/Ecore_Win32.h b/src/lib/ecore_win32/Ecore_Win32.h index 91274ba74a..722f0aa124 100644 --- a/src/lib/ecore_win32/Ecore_Win32.h +++ b/src/lib/ecore_win32/Ecore_Win32.h @@ -215,21 +215,6 @@ typedef enum ECORE_WIN32_DND_EVENT_DROP = 4 /**< Drop */ } Ecore_Win32_DnD_State; -/** - * @typedef Ecore_Win32_Selection - * Type of the selection. - * - * @since 1.16 - */ -typedef enum -{ - ECORE_WIN32_SELECTION_PRIMARY, - ECORE_WIN32_SELECTION_SECONDARY, - ECORE_WIN32_SELECTION_DND, - ECORE_WIN32_SELECTION_CLIPBOARD, - ECORE_WIN32_SELECTION_OTHER -} Ecore_Win32_Selection; - /** * @typedef Ecore_Win32_Window * Abstract type for a window. @@ -326,7 +311,7 @@ typedef struct _Ecore_Win32_Event_Window_Delete_Request Ecore_Win32_Event_Window * @typedef Ecore_Win32_Event_Selection_Clear * Event sent when the content of the clipboard has been removed. * - * @since 1.16 + * @since 1.24 */ typedef struct _Ecore_Win32_Event_Selection_Clear Ecore_Win32_Event_Selection_Clear; @@ -334,7 +319,7 @@ typedef struct _Ecore_Win32_Event_Selection_Clear Ecore_Win32_Event_Selection_Cl * @typedef Ecore_Win32_Event_Selection_Notify * Event sent when the content of the clipboard has been added. * - * @since 1.16 + * @since 1.24 */ typedef struct _Ecore_Win32_Event_Selection_Notify Ecore_Win32_Event_Selection_Notify; @@ -490,26 +475,26 @@ struct _Ecore_Win32_Event_Window_Delete_Request * @struct _Ecore_Win32_Event_Selection_Clear * Event sent when the content of the clipboard has been removed. * - * @since 1.16 + * @since 1.24 */ struct _Ecore_Win32_Event_Selection_Clear { Ecore_Win32_Window *window; /**< The window that received the event */ unsigned long timestamp; /**< The time the event occurred */ - Ecore_Win32_Selection selection; /**< The type of the selection */ + char *selection; /**< The type of the selection */ }; /** * @struct _Ecore_Win32_Event_Selection_Notify * Event sent when the content of the clipboard has been added. * - * @since 1.16 + * @since 1.24 */ struct _Ecore_Win32_Event_Selection_Notify { Ecore_Win32_Window *window; /**< The window that received the event */ unsigned long timestamp; /**< The time the event occurred */ - Ecore_Win32_Selection selection; /**< The type of the selection */ + char *selection; /**< The type of the selection */ void *data; /**< The data of the selection */ }; @@ -698,6 +683,7 @@ EAPI void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window * @param[in] window The window that owns the clipboard. * @param[in] data The data to set. * @param[in] size The size of the data. + * @param[in] mime_type The mime type describing the data in the clipboard. * @return #EINA_TRUE on success, #EINA_FALSE otherwise. * * This function sets @p data of size @p size in the clipboard owned by @@ -705,11 +691,12 @@ EAPI void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window * #EINA_FALSE otherwise. If @p window or @p data are @c NULL, or @p size * is less than or equal to 0, this function returns #EINA_FALSE. * - * @since 1.16 + * @since 1.24 */ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, const void *data, - int size); + size_t size, + const char *mime_type); /** * @brief Get data from the clipboard. @@ -717,6 +704,7 @@ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, * @param[in] window The window that owns the clipboard. * @param[out] data The retrieved data. * @param[out] size The size of the data. + * @param[in] mime_type The mime type describing the data in the clipboard. * @return #EINA_TRUE on success, #EINA_FALSE otherwise. * * This function gets @p data of size @p size from the clipboard owned by @@ -724,25 +712,24 @@ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, * #EINA_FALSE otherwise. If @p window is @c NULL, this function returns * #EINA_FALSE. @p data and @p size must be valid buffers. * - * @since 1.16 + * @since 1.24 */ -EAPI Eina_Bool ecore_win32_clipboard_get(const Ecore_Win32_Window *window, - void **data, - int *size); +EAPI void * ecore_win32_clipboard_get(const Ecore_Win32_Window *window, + size_t *size, + const char *mime_type); /** * @brief Cleat the clipboard. * * @param[in] window The window that owns the clipboard. - * @return #EINA_TRUE on success, #EINA_FALSE otherwise. * * This function clears the clipboard owned by @p window. This * function returns #EINA_TRUE on success, and #EINA_FALSE otherwise. * If @p window is @c NULL, this function returns #EINA_FALSE. * - * @since 1.16 + * @since 1.24 */ -EAPI Eina_Bool ecore_win32_clipboard_clear(const Ecore_Win32_Window *window); +EAPI void ecore_win32_clipboard_clear(const Ecore_Win32_Window *window); /** * @typedef Ecore_Win32_Monitor diff --git a/src/lib/ecore_win32/ecore_win32_clipboard.c b/src/lib/ecore_win32/ecore_win32_clipboard.c index a20be680c0..da4960370a 100644 --- a/src/lib/ecore_win32/ecore_win32_clipboard.c +++ b/src/lib/ecore_win32/ecore_win32_clipboard.c @@ -6,6 +6,7 @@ #include #undef WIN32_LEAN_AND_MEAN +#include /* utf-8 and utf-16 conversion */ #include #include "Ecore_Win32.h" @@ -39,10 +40,13 @@ EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window, const void *data, - int size) + size_t size, + const char *mime_type) { HGLOBAL global; char *d; + Eina_Bool supported_mime_text; + Eina_Bool res = EINA_FALSE; /* * See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016%28v=vs.85%29.aspx#_win32_Copying_Information_to_the_Clipboard @@ -54,47 +58,77 @@ ecore_win32_clipboard_set(const Ecore_Win32_Window *window, INF("setting data to the clipboard"); - if (!window || !data || (size <= 0)) - return EINA_FALSE; + supported_mime_text = eina_str_has_prefix(mime_type, "text/"); + if (!supported_mime_text) + { + ERR("Mimetype %s is not handled yet", mime_type); + return EINA_FALSE; + } - if (!OpenClipboard(window->window)) + if (!window || !data || (size <= 0) || !OpenClipboard(window->window)) return EINA_FALSE; if (!EmptyClipboard()) goto close_clipboard; - global = GlobalAlloc(GMEM_MOVEABLE, size + 1); - if (!global) - goto close_clipboard; + if (supported_mime_text) + { + wchar_t *text16; + size_t size16; - d = (char *)GlobalLock(global); - if (!d) - goto unlock_global; + /* CF_TEXT (UTF-8) */ - memcpy(d, data, size); - d[size] = '\0'; - GlobalUnlock(global); - SetClipboardData(CF_TEXT, global); - CloseClipboard(); + global = GlobalAlloc(GMEM_MOVEABLE, size); + if (global) + { + d = (char *)GlobalLock(global); + if (d) + { + memcpy(d, data, size); + SetClipboardData(CF_TEXT, global); + res = EINA_TRUE; + GlobalUnlock(global); + } + } - return EINA_TRUE; + /* CF_UNICODETEXT (UTF-16) */ + + text16 = evil_utf8_to_utf16(data); + if (text16) + { + size16 = (wcslen(text16) + 1) * sizeof(wchar_t); + + global = GlobalAlloc(GMEM_MOVEABLE, size16); + if (global) + { + d = (char *)GlobalLock(global); + if (d) + { + memcpy(d, text16, size16); + SetClipboardData(CF_UNICODETEXT, global); + res = EINA_TRUE; + GlobalUnlock(global); + } + } + + free(text16); + } + } - unlock_global: - GlobalUnlock(global); close_clipboard: CloseClipboard(); - return EINA_FALSE; + return res; } -EAPI Eina_Bool +EAPI void * ecore_win32_clipboard_get(const Ecore_Win32_Window *window, - void **data, - int *size) + size_t *size, + const char *mime_type) { HGLOBAL global; + void *data; void *d; - void *p; /* * See https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016%28v=vs.85%29.aspx#_win32_Pasting_Information_from_the_Clipboard @@ -107,80 +141,100 @@ ecore_win32_clipboard_get(const Ecore_Win32_Window *window, INF("getting data from the clipboard"); - if (!window) - return EINA_FALSE; + if (!eina_str_has_prefix(mime_type, "text/")) + { + ERR("Mimetype %s is not handled yet", mime_type); + return NULL; + } - if (!IsClipboardFormatAvailable(CF_TEXT)) - return EINA_FALSE; + if (!window || !size || !OpenClipboard(window->window)) + return NULL; - if (!OpenClipboard(window->window)) - goto set_val; - - /* { */ - /* UINT fmt = 0; */ - - /* while (1) */ - /* { */ - /* fmt = EnumClipboardFormats(fmt); */ - /* printf(" $ Format : %x\n", fmt); */ - /* if (!fmt) */ - /* break; */ - /* } */ - /* } */ - - global = GetClipboardData(CF_TEXT); - if (!global) - goto close_clipboard; - - d = GlobalLock(global); - if (!d) - goto unlock_global; - - *size = strlen(d); - p = malloc(*size); - if (!p) - goto unlock_global; - - memcpy(p, d, *size); - *data = p; - GlobalUnlock(global); - CloseClipboard(); - - return EINA_TRUE; - - unlock_global: - GlobalUnlock(global); - close_clipboard: - CloseClipboard(); - set_val: - *data = NULL; *size = 0; - return EINA_FALSE; +#if 0 + { + UINT fmt = 0; + + while (1) + { + char name[4096]; + int res; + fmt = EnumClipboardFormats(fmt); + res = GetClipboardFormatName(fmt, name, sizeof(name)); + fprintf(stderr, " $ Format2 : %x %d\n", fmt, res); + if (res) + fprintf(stderr, " $ Format2 : %s\n", name); + else + fprintf(stderr, " $ Format2 : error %ld\n", GetLastError()); + fflush(stderr); + if (!fmt) + break; + } + } +#endif + + if (eina_str_has_prefix(mime_type, "text/")) + { + /* first check if UTF-16 text is available */ + global = GetClipboardData(CF_UNICODETEXT); + if (global) + { + d = GlobalLock(global); + if (d) + { + data = evil_utf16_to_utf8(d); + if (data) + { + *size = strlen(data); + GlobalUnlock(global); + CloseClipboard(); + return data; + } + GlobalUnlock(global); + } + /* otherwise, we try CF_TEXT (UTF-8/ANSI) */ + } + + /* second, check if UTF-8/ANSI text is available */ + global = GetClipboardData(CF_TEXT); + if (global) + { + d = GlobalLock(global); + if (d) + { + *size = strlen(d) + 1; + data = malloc(*size); + if (data) + { + memcpy(data, d, *size); + GlobalUnlock(global); + CloseClipboard(); + return data; + } + else + *size = 0; + + GlobalUnlock(global); + } + } + } + + CloseClipboard(); + + return NULL; } -EAPI Eina_Bool +EAPI void ecore_win32_clipboard_clear(const Ecore_Win32_Window *window) { INF("clearing the clipboard"); - if (!window) - return EINA_FALSE; - - if (!OpenClipboard(window->window)) - return EINA_FALSE; - - if (!EmptyClipboard()) - goto close_clipboard; + if (!window || !OpenClipboard(window->window)) + return; + EmptyClipboard(); CloseClipboard(); - - return EINA_TRUE; - - close_clipboard: - CloseClipboard(); - - return EINA_FALSE; } /** diff --git a/src/lib/ecore_win32/ecore_win32_event.c b/src/lib/ecore_win32/ecore_win32_event.c index 0c232e7bc3..28a5b1f07e 100644 --- a/src/lib/ecore_win32/ecore_win32_event.c +++ b/src/lib/ecore_win32/ecore_win32_event.c @@ -1958,66 +1958,103 @@ _ecore_win32_event_handle_selection_notify(Ecore_Win32_Callback_Data *msg) { Ecore_Win32_Event_Selection_Notify *e; HGLOBAL global; - char *str; INF("selection_notify"); + e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Notify)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->timestamp = _ecore_win32_event_last_time; + /* - * we have text data in clipboard but no data before, - * so text data has just been added + * we have data in clipboard but no data before, + * so data has just been added */ - if (IsClipboardFormatAvailable(CF_TEXT) && !_ecore_win32_clipboard_has_data) + if (!_ecore_win32_clipboard_has_data) { - e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Notify)); - if (!e) return; - - e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->timestamp = _ecore_win32_event_last_time; - e->selection = ECORE_WIN32_SELECTION_CLIPBOARD; - + /* if case someone else is owning the clipboard, we can't do anything */ if (!OpenClipboard(msg->window)) - goto free_e; - - global = GetClipboardData(CF_TEXT); - if (!global) - goto close_clipboard; - - str = GlobalLock(global); - if (str) { - e->data = strdup(str); - GlobalUnlock(global); + free(e); + return; } + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + global = GetClipboardData(CF_UNICODETEXT); + if (global) + { + e->selection = strdup("text/plain;charset=utf-8"); + if (e->selection) + { + wchar_t *d; + + d = (wchar_t *)GlobalLock(global); + if (d) + e->data = evil_utf16_to_utf8(d); + + GlobalUnlock(global); + if (e->data) + { + ecore_event_add(ECORE_WIN32_EVENT_SELECTION_NOTIFY, e, NULL, NULL); + _ecore_win32_clipboard_has_data = EINA_TRUE; + CloseClipboard(); + return; + } + } + } + } + + if (IsClipboardFormatAvailable(CF_TEXT)) + { + global = GetClipboardData(CF_TEXT); + if (global) + { + e->selection = strdup("text/plain;charset=utf-8"); + if (e->selection) + { + char *d; + + d = (char *)GlobalLock(global); + if (d) + e->data = strdup(d); + + GlobalUnlock(global); + if (e->data) + { + ecore_event_add(ECORE_WIN32_EVENT_SELECTION_NOTIFY, e, NULL, NULL); + + _ecore_win32_clipboard_has_data = EINA_TRUE; + CloseClipboard(); + return; + } + } + } + } + free(e->data); + free(e->selection); + free(e); CloseClipboard(); - - ecore_event_add(ECORE_WIN32_EVENT_SELECTION_NOTIFY, e, NULL, NULL); - - _ecore_win32_clipboard_has_data = EINA_TRUE; } - /* - * we have no more text data in clipboard and data before, + * otherwise, we have no more text data in clipboard and data before, * so text data has just been removed */ - if (!IsClipboardFormatAvailable(CF_TEXT) && _ecore_win32_clipboard_has_data) + else { - e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Clear)); - if (!e) return; - - e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->timestamp = _ecore_win32_event_last_time; - e->selection = ECORE_WIN32_SELECTION_CLIPBOARD; - - ecore_event_add(ECORE_WIN32_EVENT_SELECTION_CLEAR, e, NULL, NULL); - - _ecore_win32_clipboard_has_data = EINA_FALSE; + if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && + !IsClipboardFormatAvailable(CF_TEXT)) + { + e->selection = strdup("text/plain;charset=utf-8"); + if (e->selection) + { + ecore_event_add(ECORE_WIN32_EVENT_SELECTION_CLEAR, e, NULL, NULL); + _ecore_win32_clipboard_has_data = EINA_FALSE; + return; + } + } } - return; - - close_clipboard: - CloseClipboard(); - free_e: free(e); } diff --git a/src/lib/ecore_x/Ecore_X.h b/src/lib/ecore_x/Ecore_X.h index bb5aedf39e..94b612abc6 100644 --- a/src/lib/ecore_x/Ecore_X.h +++ b/src/lib/ecore_x/Ecore_X.h @@ -2444,6 +2444,15 @@ EAPI void ecore_x_root_screen_barriers_set(Ecore_X_Rectangle *scre */ EAPI Eina_Bool ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection); +/** + * xfixes selection notification request. + * + * In addition to ecore_x_fixes_selection_notification_request you can also specify for which window you want to get them + * @since 1.24 + */ +EAPI Eina_Bool ecore_x_fixes_window_selection_notification_request(Ecore_X_Window window, Ecore_X_Atom selection); + + /* XComposite Extension Support */ EAPI Eina_Bool ecore_x_composite_query(void); EAPI void ecore_x_composite_redirect_window(Ecore_X_Window win, Ecore_X_Composite_Update_Type type); diff --git a/src/lib/ecore_x/ecore_x_fixes.c b/src/lib/ecore_x/ecore_x_fixes.c index 5582c3e3ef..4b659c2d8b 100644 --- a/src/lib/ecore_x/ecore_x_fixes.c +++ b/src/lib/ecore_x/ecore_x_fixes.c @@ -112,6 +112,26 @@ ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection) return EINA_FALSE; } +EAPI Eina_Bool +ecore_x_fixes_window_selection_notification_request(Ecore_X_Window window, Ecore_X_Atom selection) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(_ecore_x_disp, EINA_FALSE); + +#ifdef ECORE_XFIXES + if (_fixes_available) + { + XFixesSelectSelectionInput (_ecore_x_disp, + window, + selection, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + EAPI Ecore_X_Region ecore_x_region_new(Ecore_X_Rectangle *rects, int num) diff --git a/src/lib/ecore_x/ecore_x_selection.c b/src/lib/ecore_x/ecore_x_selection.c index 22cd5c8c7f..733b799244 100644 --- a/src/lib/ecore_x/ecore_x_selection.c +++ b/src/lib/ecore_x/ecore_x_selection.c @@ -990,15 +990,15 @@ _ecore_x_selection_parser_targets(const char *target EINA_UNUSED, if (!sel) return NULL; targets = data; - sel->num_targets = size - 2; - sel->targets = malloc((size - 2) * sizeof(char *)); + sel->num_targets = size; + sel->targets = malloc((sel->num_targets) * sizeof(char *)); if (!sel->targets) { free(sel); return NULL; } - for (i = 2; i < size; i++) - sel->targets[i - 2] = XGetAtomName(_ecore_x_disp, targets[i]); + for (i = 0; i < size; i++) + sel->targets[i] = XGetAtomName(_ecore_x_disp, targets[i]); ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_targets_free; ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS; diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index d2f5d4543d..23366d629a 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h @@ -272,6 +272,7 @@ extern "C" { #include #include #include +#include #undef EAPI #define EAPI diff --git a/src/lib/eina/eina_abstract_content.c b/src/lib/eina/eina_abstract_content.c new file mode 100644 index 0000000000..4b74256d25 --- /dev/null +++ b/src/lib/eina/eina_abstract_content.c @@ -0,0 +1,443 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "eina_abstract_content.h" + +struct _Eina_Content +{ + Eina_Rw_Slice data; + const char *type; + const char *file; + EINA_REFCOUNT; +}; +EAPI const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT; + +static int _eina_abstract_content_log_domain = -1; + +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_eina_abstract_content_log_domain, __VA_ARGS__) + +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_eina_abstract_content_log_domain, __VA_ARGS__) + +static Eina_Hash *conversion_callbacks; + +typedef struct { + const char *to; + Eina_Content_Conversion_Callback callback; +} Eina_Content_Conversion_Node; + +static void +_eina_content_ref(Eina_Content *content) +{ + EINA_REFCOUNT_REF(content); +} + +EAPI Eina_Bool +eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback conversion) +{ + Eina_Content_Conversion_Node *node = calloc(1, sizeof(Eina_Content_Conversion_Node)); + + Eina_Stringshare *shared_from = eina_stringshare_add(from); + + if (eina_content_converter_convert_can(from, to)) + { + ERR("Convertion from %s to %s is already possible", from, to); + return EINA_FALSE; + } + + node->to = eina_stringshare_add(to); + node->callback = conversion; + + eina_hash_list_append(conversion_callbacks, shared_from, node); + + return EINA_TRUE; +} + +static inline Eina_List* +_conversion_callback_fetch_possible(const char *from) +{ + Eina_Stringshare *shared_from = eina_stringshare_add(from); + Eina_List *res = eina_hash_find(conversion_callbacks, shared_from); + eina_stringshare_del(shared_from); + return res; +} + +static inline Eina_Content_Conversion_Callback +_conversion_callback_fetch(const char *from, const char *to) +{ + Eina_List *possibilities = _conversion_callback_fetch_possible(from); + Eina_Content_Conversion_Node *n; + Eina_Content_Conversion_Callback result = NULL; + Eina_List *l; + Eina_Stringshare *shared_to = eina_stringshare_add(to); + + EINA_LIST_FOREACH(possibilities, l, n) + { + if (n->to == shared_to) + { + result = n->callback; + goto end; + } + } +end: + eina_stringshare_del(shared_to); + return result; +} + +EAPI Eina_Bool +eina_content_converter_convert_can(const char *from, const char *to) +{ + return !!_conversion_callback_fetch(from, to); +} + +static const void* +_process_cb(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED) +{ + Eina_Content_Conversion_Node *n = data; + + return n->to; + } + +EAPI Eina_Iterator* +eina_content_converter_possible_conversions(const char *from) +{ + Eina_List *possibilities = _conversion_callback_fetch_possible(from); + + return eina_iterator_processed_new(eina_list_iterator_new(possibilities) , EINA_PROCESS_CB(_process_cb), NULL, possibilities); +} + +EAPI Eina_Content* +eina_content_new(Eina_Slice data, const char *type) +{ + Eina_Content *content; + + if (!strncmp(type, "text", strlen("text"))) + { + //last char in the mem must be \0 + if (((char*)data.mem)[data.len - 1] != '\0') + { + ERR("Last character is not a null character! but type is text!"); + return NULL; + } + } + + content = calloc(1, sizeof(Eina_Content)); + EINA_SAFETY_ON_NULL_RETURN_VAL(content, NULL); + content->data = eina_slice_dup(data); + content->type = eina_stringshare_add(type); + EINA_SAFETY_ON_NULL_RETURN_VAL(content->data.mem, NULL); + + _eina_content_ref(content); + return content; +} + +EAPI void +eina_content_free(Eina_Content *content) +{ + EINA_REFCOUNT_UNREF(content) + { + if (content->file) + eina_tmpstr_del(content->file); + free(content->data.mem); + free(content); + } +} + +EAPI const char* +eina_content_as_file(Eina_Content *content) +{ + if (!content->file) + { + Eina_Tmpstr *path; + int fd = eina_file_mkstemp("prefixXXXXXX.ext", &path); + + if (fd < 0) + { + ERR("Failed to create tmp file"); + return NULL; + } + + if (write(fd, content->data.mem, content->data.len) < 0) + { + ERR("Failed to write to a file"); + eina_tmpstr_del(path); + close(fd); + return NULL; + } + + content->file = path; + close(fd); + } + return content->file; +} + +EAPI const char* +eina_content_type_get(Eina_Content *content) +{ + return content->type; +} + +EAPI const Eina_Slice +eina_content_data_get(Eina_Content *content) +{ + return eina_rw_slice_slice_get(content->data); +} + +EAPI Eina_Content* +eina_content_convert(Eina_Content *content, const char *new_type) +{ + Eina_Content_Conversion_Callback callback = _conversion_callback_fetch(content->type, new_type); + + if (!callback) + { + ERR("No suitable conversion found"); + return NULL; + } + + return callback(content, new_type); +} + +static Eina_Content* +_copy_converter(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + return eina_content_new(slice, to_type); +} + +static Eina_Content* +_latin1_to_utf8_converter(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + Eina_Strbuf *out = eina_strbuf_new(); + + for (unsigned int i = 0; i < slice.len; ++i) + { + const unsigned char c = ((char*)slice.mem)[i]; + if (c < 128) + eina_strbuf_append_char(out, c); + else + { + eina_strbuf_append_char(out, 0xc0 | c >> 6); + eina_strbuf_append_char(out, 0x80 | (c & 0x3f)); + } + } + Eina_Slice new; + new.len = eina_strbuf_length_get(out); + new.mem = eina_strbuf_string_get(out); + Eina_Content *c = eina_content_new(new, to_type); + eina_strbuf_free(out); + return c; +} + +static Eina_Bool +_eina_value_type_content_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem) +{ + memset(mem, 0, sizeof(Eina_Content*)); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_flush(const Eina_Value_Type *type EINA_UNUSED, + void *mem EINA_UNUSED) +{ + Eina_Content **content = mem; + + eina_content_free(*content); + + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_copy(const Eina_Value_Type *type EINA_UNUSED, const void *src, void *dst) +{ + Eina_Content * const *srcc = src; + Eina_Content **dstc = dst; + + *dstc = *srcc; + _eina_content_ref(*dstc); + return EINA_TRUE; +} + +static int +_eina_value_type_content_compare(const Eina_Value_Type *type EINA_UNUSED, const void *a, const void *b) +{ + Eina_Content * const *ra = a; + Eina_Content * const *rb = b; + + if ((*ra)->type != (*rb)->type) + return -1; + + return eina_rw_slice_compare((*ra)->data, (*rb)->data); +} + +static Eina_Bool +_eina_value_type_content_convert_to(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert EINA_UNUSED, const void *type_mem EINA_UNUSED, void *convert_mem EINA_UNUSED) +{ + Eina_Content * const *ra = type_mem; + + if (convert == EINA_VALUE_TYPE_STRINGSHARE || + convert == EINA_VALUE_TYPE_STRING) + { + const char *type = eina_content_type_get(*ra); + if (eina_streq(type, "text/plain;charset=utf-8")) + { + Eina_Slice data = eina_content_data_get(*ra); + return eina_value_type_pset(convert, convert_mem, &data.mem); + } + else + { + Eina_Iterator *iter = eina_content_possible_conversions(*ra); + const char *type; + + EINA_ITERATOR_FOREACH(iter, type) + { + if (eina_streq(type, "text/plain;charset=utf-8")) + { + Eina_Content *conv_result = eina_content_convert(*ra, type); + + Eina_Slice data = eina_content_data_get(conv_result); + Eina_Bool success = eina_value_type_pset(convert, convert_mem, &data.mem); + eina_content_free(conv_result); + return success; + } + } + //create some fallback + { + char buf[PATH_MAX]; + char *tmp = (char*) &buf; + snprintf(buf, sizeof(buf), "Content %p cannot be converted to \"text/plain;charset=utf-8\"", *ra); + return eina_value_type_pset(convert, convert_mem, &tmp); + } + } + } + return EINA_FALSE; +} + +static Eina_Bool +_eina_value_type_content_convert_from(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert EINA_UNUSED, void *type_mem EINA_UNUSED, const void *convert_mem EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Bool +_eina_value_type_content_pset(const Eina_Value_Type *type EINA_UNUSED, void *mem, const void *ptr) +{ + Eina_Content * const *srcc = ptr; + Eina_Content **dstc = mem; + + *dstc = *srcc; + _eina_content_ref(*dstc); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_vset(const Eina_Value_Type *type EINA_UNUSED, void *mem, va_list args) +{ + Eina_Content **dst = mem; + Eina_Content *content = va_arg(args, Eina_Content*); + + *dst = content; + _eina_content_ref(*dst); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_pget(const Eina_Value_Type *type EINA_UNUSED, const void *mem, void *ptr) +{ + Eina_Content * const *src = mem; + Eina_Content **dst = ptr; + + *dst = *src; + _eina_content_ref(*dst); + return EINA_TRUE; +} + +EAPI const Eina_Value_Type _EINA_VALUE_TYPE_CONTENT ={ + EINA_VALUE_TYPE_VERSION, + sizeof(Eina_Content*), + "Eina_Abstract_Content", + _eina_value_type_content_setup, + _eina_value_type_content_flush, + _eina_value_type_content_copy, + _eina_value_type_content_compare, + _eina_value_type_content_convert_to, + _eina_value_type_content_convert_from, + _eina_value_type_content_vset, + _eina_value_type_content_pset, + _eina_value_type_content_pget +}; + +static void +_free_node(void *v) +{ + Eina_Content_Conversion_Node *n; + EINA_LIST_FREE(v, n) + { + eina_stringshare_del(n->to); + free(n); + } +} + +Eina_Bool +eina_abstract_content_init(void) +{ + _eina_abstract_content_log_domain = eina_log_domain_register("eina_abstract_content", "white"); + conversion_callbacks = eina_hash_stringshared_new(_free_node); + + EINA_VALUE_TYPE_CONTENT = &_EINA_VALUE_TYPE_CONTENT; + + // text/plain is assumed to be charset "US-ASCII" + + eina_content_converter_conversion_register("text/plain", "text/plain;charset=utf-8", _copy_converter); + eina_content_converter_conversion_register("text/plain", "text/plain;charset=iso-8859-1", _copy_converter); + eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain;charset=utf-8", _latin1_to_utf8_converter); + eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain", _copy_converter); + + return EINA_TRUE; +} + +Eina_Bool +eina_abstract_content_shutdown(void) +{ + eina_hash_free(conversion_callbacks); + + return EINA_TRUE; +} + +Eina_Value* +eina_value_content_new(Eina_Content *content) +{ + Eina_Value *v = eina_value_new(EINA_VALUE_TYPE_CONTENT); + + eina_value_pset(v, &content); + return v; +} + + +Eina_Value +eina_value_content_init(Eina_Content *content) +{ + Eina_Value v; + + eina_value_setup(&v, EINA_VALUE_TYPE_CONTENT); + eina_value_pset(&v, &content); + + return v; +} + + +Eina_Content* +eina_value_to_content(const Eina_Value *value) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_get(value) == EINA_VALUE_TYPE_CONTENT, NULL); + Eina_Content *result = calloc(1, sizeof(Eina_Content)); + eina_value_pget(value, &result); + return result; +} diff --git a/src/lib/eina/eina_abstract_content.h b/src/lib/eina/eina_abstract_content.h new file mode 100644 index 0000000000..9b723d553f --- /dev/null +++ b/src/lib/eina/eina_abstract_content.h @@ -0,0 +1,154 @@ +#ifndef EINA_ABSTRACT_CONTENT_H +#define EINA_ABSTRACT_CONTENT_H + + +/** + * @typedef Eina_Content + * Container for any type of content. + * + * Each Eina_Content is made of an Eina_Slice of memory and an IANA MIME type: + * https://www.iana.org/assignments/media-types/media-types.xhtml + * + * @note If the type is any kind of text the last byte of the slice must be \0. + * + * @since 1.24 + */ +typedef struct _Eina_Content Eina_Content; + +/** + * @typedef Eina_Content_Conversion_Callback + * + * Method called when conversion from one type to another is requested. + * The from and to types are specified when the callback is registered. + * The to type is also passed in the callback here. + * The type of the from pointer does not need to be checked. + */ +typedef Eina_Content* (*Eina_Content_Conversion_Callback)(Eina_Content *from, const char *to_type); + +/** + * Get the path to a file, containing the slice memory as content. + * + * @param[in] content The content that will be in the file. + * + * @return The path to the file. Do not free this. + * + */ +EAPI const char* eina_content_as_file(Eina_Content *content); + +/** + * Convert the content of the object to another type. + * + * In case the conversion cannot be performed, NULL is returned. + * + * @param[in] content The content to convert. + * @param[in] new_type The new type the returned content will have. + * + * @return A new content object. The caller of this function is owning this. + */ +EAPI Eina_Content* eina_content_convert(Eina_Content *content, const char *new_type); + +/** + * Get the type of the passed content. + * + * @param[in] content The content to fetch the type from. + * + * @return The type of this content. Do no free this. + */ +EAPI const char* eina_content_type_get(Eina_Content *content); + +/** + * Get the Eina_Slice of the passed content. + * + * @param[in] content The content to fetch the data from. + * + * @return An Eina_Slice containing the data. Do not free. + */ +EAPI const Eina_Slice eina_content_data_get(Eina_Content *content); + +/** + * Create a new content object, with the provided data and type. + * + * @param[in] data A slice of memory. The memory is copied. + * @param[in] type The type this data represents. + * + * @return The new content object. The caller owns this object. + */ +EAPI Eina_Content* eina_content_new(Eina_Slice data, const char *type); + +/** + * Free the content object. + * + * @param[in] content The content to free. + */ +EAPI void eina_content_free(Eina_Content *content); + +/** + * Register a new conversion callback. + * + * @param[in] from The type to convert from. + * @param[in] to The type to convert to. + * + * @return True if the callback was successfully registered. + */ +EAPI Eina_Bool eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback convertion); + +/** + * Check if a specific conversion can be performed. + * + * A conversion can only be performed if a callback is registered. + * + * @param[in] from The type to convert from. + * @param[in] to The type to convert to. + * + * @return True if the conversion can be performed. + */ +EAPI Eina_Bool eina_content_converter_convert_can(const char *from, const char *to); + +/** + * Returns an iterator containing all the target types that the provided source type can be converted to. + * + * @param[in] from The type to convert from. + * + * @return An Iterator containing MIME type strings. Free this via eina_iterator_free. + */ +EAPI Eina_Iterator* eina_content_converter_possible_conversions(const char *from); + +EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT; + +/** + * Convert the Eina_Content object to an Eina_Value. + * + * @param[in] content The Eina_Content struct that will be converted to an Eina_Value. + * + * @return An newly-allocated Eina_Value. Caller owns it. + */ +EAPI Eina_Value* eina_value_content_new(Eina_Content *content); + +/** + * Creates an Eina_Value from an Eina_Content. + * + * @param[in] content The Eina_Content struct that will be converted to an Eina_Value. + * + * @return An Eina_Value with type EINA_VALUE_TYPE_CONTENT. + */ +EAPI Eina_Value eina_value_content_init(Eina_Content *content); + +/** + * Gets the content from the Eina_Value. + * + * If the value is not of the type EINA_VALUE_TYPE_CONTENT, NULL will be returned and an error will be printed. + * + * @param[in] value The value to get the content from + * + * @return A newly-allocated Eina_Content. Caller owns it. + */ +EAPI Eina_Content* eina_value_to_content(const Eina_Value *value); + + +static inline Eina_Iterator* +eina_content_possible_conversions(Eina_Content *content) +{ + return eina_content_converter_possible_conversions(eina_content_type_get(content)); +} + +#endif diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index b8856474d3..47dd80a898 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c @@ -154,6 +154,7 @@ extern Eina_Lock _sysmon_lock; S(slstr); S(promise); S(vpath); + S(abstract_content); #undef S struct eina_desc_setup @@ -202,6 +203,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = { S(safepointer), S(slstr), S(promise), + S(abstract_content) #undef S }; static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / diff --git a/src/lib/eina/eina_slice.h b/src/lib/eina/eina_slice.h index a354eaa566..a597fe281e 100644 --- a/src/lib/eina/eina_slice.h +++ b/src/lib/eina/eina_slice.h @@ -464,6 +464,30 @@ static inline char *eina_rw_slice_strdup(const Eina_Rw_Slice rw_slice); #else #define EINA_SLICE_STR(str) {.len = strlen((str)), .mem = (str)} #endif +/** + * @def EINA_SLICE_STR_FULL(str) + * + * Same as EINA_SLICE_STR_FULL, but it also contains the \0 element of the string + * + * @param[in] str The string to create the slice from. + * @return The initialized slice object. + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * Eina_Slice ro_slice = EINA_SLICE_STR_FULL("hello world"); + * @endcode + * + * @see EINA_SLICE_STR_FULL() for specific version using literals. + * + * @since 1.24 + */ +#ifdef __cplusplus +#define EINA_SLICE_STR_FULL(str) {strlen((str)) + 1, (str)} +#else +#define EINA_SLICE_STR_FULL(str) {.len = strlen((str)) + 1, .mem = (str)} +#endif + /** * @def EINA_SLICE_STR_FMT diff --git a/src/lib/eina/meson.build b/src/lib/eina/meson.build index 97e1669c4f..d3d30fcf43 100644 --- a/src/lib/eina/meson.build +++ b/src/lib/eina/meson.build @@ -107,6 +107,7 @@ public_sub_headers = [ 'eina_freeq.h', 'eina_slstr.h', 'eina_vpath.h', +'eina_abstract_content.h' ] public_headers = [ @@ -188,7 +189,8 @@ sources = [ 'eina_freeq.c', 'eina_slstr.c', 'eina_vpath.c', -'eina_vpath_xdg.c' +'eina_vpath_xdg.c', +'eina_abstract_content.c', ] if sys_windows == true diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h index 5bed200264..81f4522c71 100644 --- a/src/lib/elementary/Efl_Ui.h +++ b/src/lib/elementary/Efl_Ui.h @@ -119,8 +119,6 @@ extern EAPI Eina_Error EFL_UI_THEME_APPLY_ERROR_NONE; // EO types. Defined for legacy-only builds as legacy uses typedef of EO types. #include "efl_ui.eot.h" -#include "efl_ui_selection_types.eot.h" -#include "efl_ui_dnd_types.eot.h" //define focus manager earlier since focus object and manager is circular typedef Eo Efl_Ui_Focus_Manager; @@ -322,7 +320,6 @@ typedef Eo Efl_Ui_Spotlight_Indicator; # include # include # include -# include # include # include diff --git a/src/lib/elementary/efl_ui_dnd.c b/src/lib/elementary/efl_ui_dnd.c index df79eb9762..e8bf19320b 100644 --- a/src/lib/elementary/efl_ui_dnd.c +++ b/src/lib/elementary/efl_ui_dnd.c @@ -12,838 +12,140 @@ #include #include "elm_priv.h" -typedef struct _Efl_Ui_Dnd_Container_Data Efl_Ui_Dnd_Container_Data; -struct _Efl_Ui_Dnd_Container_Data -{ - unsigned int drag_delay_time; -}; +typedef struct { + Ecore_Evas *ee; + Eina_Bool registered; +} Efl_Ui_Dnd_Data; -extern int _wl_default_seat_id_get(Evas_Object *obj); -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -#endif - -Eo* -_efl_ui_selection_manager_get(Eo *obj) -{ - if (!efl_isa(obj, EFL_UI_WIDGET_CLASS)) return NULL; - Eo *app = efl_app_main_get(); - Eo *sel_man = efl_key_data_get(app, "__selection_manager"); - if (!sel_man) - { - sel_man = efl_add(EFL_UI_SELECTION_MANAGER_CLASS, app); - efl_key_data_set(app, "__selection_manager", sel_man); - } - return sel_man; -} - -void -_efl_ui_dnd_shutdown(void) -{ - Eo *app = efl_app_main_get(); - Eo *sel_man = efl_key_data_get(app, "__selection_manager"); - - efl_del(sel_man); -} - -EOLIAN static void -_efl_ui_dnd_drag_start(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, Eina_Slice data, - Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_start(sel_man, obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - seat); -} - -EOLIAN static void -_efl_ui_dnd_drag_cancel(Eo *obj, void *pd EINA_UNUSED, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_cancel(sel_man, obj, seat); -} - -EOLIAN static void -_efl_ui_dnd_drag_action_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Action action, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drag_action_set(sel_man, obj, action, seat); -} - - -EOLIAN static void -_efl_ui_dnd_drop_target_add(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drop_target_add(sel_man, obj, format, seat); -} - -EOLIAN static void -_efl_ui_dnd_drop_target_del(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_drop_target_del(sel_man, obj, format, seat); -} - -EOLIAN static double -_efl_ui_dnd_container_drag_delay_time_get(const Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd) -{ - return pd->drag_delay_time; -} - -EOLIAN static void -_efl_ui_dnd_container_drag_delay_time_set(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd, double drag_delay_time) -{ - pd->drag_delay_time = drag_delay_time; -} - -EOLIAN static void -_efl_ui_dnd_container_drag_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd, - void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb, - void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb, - unsigned int seat) -{ - double drag_delay_time = pd->drag_delay_time; - double anim_time = elm_config_drag_anim_duration_get(); - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drag_item_add(sel_man, obj, drag_delay_time, anim_time, - data_func_data, data_func, data_func_free_cb, - item_func_data, item_func, item_func_free_cb, - icon_func_data, icon_func, icon_func_free_cb, - icon_list_func_data, icon_list_func, icon_list_func_free_cb, - seat); -} +typedef struct { + Eo *win; + Efl_Ui_Dnd *obj; +} Efl_Ui_Drag_Start; static void -_efl_ui_dnd_container_drag_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat) +_ecore_evas_drag_terminated(Ecore_Evas *ee EINA_UNUSED, unsigned int seat, void *data, Eina_Bool accepted) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seat); + Efl_Ui_Drag_Start *start = data; + Efl_Ui_Drag_Finished_Event ev = {seat, accepted}; + efl_event_callback_call(start->obj, EFL_UI_DND_EVENT_DRAG_FINISHED, &ev); + efl_del(start->win); + free(start); } -EOLIAN static void -_efl_ui_dnd_container_drop_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, - Efl_Ui_Selection_Format format, - void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb, - unsigned int seat) + +EOLIAN static Efl_Content* +_efl_ui_dnd_drag_start(Eo *obj, Efl_Ui_Dnd_Data *pd, Eina_Content *content, const char* action, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drop_item_add(sel_man, obj, format, item_func_data, item_func, item_func_free_cb, seat); + Eo *drag_win; + Efl_Ui_Drag_Start *start; + Efl_Ui_Drag_Started_Event ev = {seat}; + Ecore_Evas *drag_ee; + EINA_SAFETY_ON_NULL_RETURN_VAL(pd->ee, NULL); + + start = calloc(1, sizeof(Efl_Ui_Drag_Start)); + start->obj = obj; + start->win = drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); + elm_win_alpha_set(drag_win, EINA_TRUE); + elm_win_override_set(drag_win, EINA_TRUE); + elm_win_borderless_set(drag_win, EINA_TRUE); + drag_ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_win)); + + ecore_evas_drag_start(pd->ee, seat, content, drag_ee, action, _ecore_evas_drag_terminated, start); + + evas_object_show(drag_win); + + efl_event_callback_call(obj, EFL_UI_DND_EVENT_DRAG_STARTED, &ev); + + return drag_win; } EOLIAN static void -_efl_ui_dnd_container_drop_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat) +_efl_ui_dnd_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seat); + ecore_evas_drag_cancel(pd->ee, seat); } - -/////////// -typedef struct _Dnd_Icon_Create Dnd_Icon_Create; -typedef struct _Dnd_Drag_Pos Dnd_Drag_Pos; -typedef struct _Dnd_Drag_Accept Dnd_Drag_Accept; -typedef struct _Dnd_Drag_Done Dnd_Drag_Done; -typedef struct _Dnd_Drag_State Dnd_Drag_State; -typedef struct _Dnd_Drop Dnd_Drop; -typedef struct _Dnd_Cont_Drag_Pos Dnd_Cont_Drag_Pos; -typedef struct _Dnd_Cont_Drop Dnd_Cont_Drop; -typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info; - -struct _Dnd_Icon_Create +EOLIAN static Eina_Future* +_efl_ui_dnd_drop_data_get(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat, Eina_Iterator *acceptable_types) { - void *icon_data; - Elm_Drag_Icon_Create_Cb icon_cb; -}; - -struct _Dnd_Drag_Pos -{ - void *pos_data; - Elm_Drag_Pos pos_cb; -}; - -struct _Dnd_Drag_Accept -{ - void *accept_data; - Elm_Drag_Accept accept_cb; -}; - -struct _Dnd_Drag_Done -{ - void *done_data; - Elm_Drag_State done_cb; - - //for deleting - Dnd_Drag_Pos *pos; - Dnd_Drag_Accept *accept; -}; - -struct _Dnd_Drag_State -{ - void *state_data; - Elm_Drag_State state_cb; -}; - -struct _Dnd_Drop -{ - Efl_Object *obj; - Elm_Sel_Format format; - void *drop_data; - Elm_Drop_Cb drop_cb; - - //for deleting - Dnd_Drag_State *enter; - Dnd_Drag_State *leave; - Dnd_Drag_Pos *pos; -}; - -struct _Dnd_Cont_Drag_Pos -{ - void *pos_data; - Elm_Drag_Item_Container_Pos pos_cb; - Elm_Xy_Item_Get_Cb item_get_cb; -}; - -struct _Dnd_Cont_Drop -{ - Efl_Object *obj; - Elm_Sel_Format format; - void *drop_data; - Elm_Drop_Item_Container_Cb drop_cb; - Elm_Xy_Item_Get_Cb item_get_cb; - - //for deleting - Dnd_Drag_State *enter; - Dnd_Drag_State *leave; - Dnd_Cont_Drag_Pos *pos; -}; - -struct _Item_Container_Drag_Info -{ - Elm_Drag_User_Info user_info; - Elm_Object_Item *it; - Elm_Item_Container_Data_Get_Cb data_get_cb; - Elm_Xy_Item_Get_Cb item_get_cb; -}; - -static Efl_Object * -_dnd_icon_create_cb(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret) -{ - Dnd_Icon_Create *ic = data; - Efl_Object *ret = ic->icon_cb(ic->icon_data, win, &pos_ret->x, &pos_ret->y); - - free(ic); - return ret; + return ecore_evas_selection_get(pd->ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, acceptable_types); } -static void -_dnd_drag_pos_cb(void *data, const Efl_Event *event) +EOLIAN static Efl_Object * +_efl_ui_dnd_efl_object_constructor(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Drag_Pos *pos = data; - Efl_Dnd_Drag_Pos *ddata = event->info; + if (!efl_constructor(efl_super(obj, EFL_UI_DND_MIXIN))) + return NULL; - if (pos->pos_cb) - pos->pos_cb(pos->pos_data, event->object, ddata->pos.x, ddata->pos.y, - (Elm_Xdnd_Action)ddata->action); -} - -static void -_dnd_drag_accept_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_Accept *accept = data; - - if (accept->accept_cb) - accept->accept_cb(accept->accept_data, event->object, *(Eina_Bool *)event->info); -} - -static void -_dnd_drag_done_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_Done *done = data; - - if (done->done_cb) - done->done_cb(done->done_data, event->object); - - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, done->pos); - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_ACCEPT, - _dnd_drag_accept_cb, done->accept); - efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_DONE, - _dnd_drag_done_cb, done); - free(done->pos); - free(done->accept); - free(done); -} - -static void -_dnd_drag_enter_leave_cb(void *data, const Efl_Event *event) -{ - Dnd_Drag_State *state = data; - - if (state->state_cb) - state->state_cb(state->state_data, event->object); -} - -static void -_dnd_drop_cb(void *data, const Efl_Event *event) -{ - Dnd_Drop *drop = data; - Efl_Ui_Selection_Data *org_ddata = event->info; - Elm_Selection_Data ddata; - - ddata.x = org_ddata->pos.x; - ddata.y = org_ddata->pos.y; - ddata.format = (Elm_Sel_Format)org_ddata->format; - ddata.action = (Elm_Xdnd_Action)org_ddata->action; - ddata.data = calloc(1, org_ddata->content.len); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len); - ddata.len = org_ddata->content.len; - if (drop->drop_cb) - drop->drop_cb(drop->drop_data, event->object, &ddata); - free(ddata.data); -} - -EAPI Eina_Bool -elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, - Elm_Xdnd_Action action, - Elm_Drag_Icon_Create_Cb icon_create_cb, void *icon_create_data, - Elm_Drag_Pos drag_pos_cb, void *drag_pos_data, - Elm_Drag_Accept drag_accept_cb, void *drag_accept_data, - Elm_Drag_State drag_done_cb, void *drag_done_data) -{ - if (!data) return EINA_FALSE; - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Eina_Slice sl; - Dnd_Drag_Pos *pos = calloc(1, sizeof(Dnd_Drag_Pos)); - Dnd_Drag_Accept *accept = calloc(1, sizeof(Dnd_Drag_Accept)); - Dnd_Drag_Done *done = calloc(1, sizeof(Dnd_Drag_Done)); - Dnd_Icon_Create *ic = calloc(1, sizeof(Dnd_Icon_Create)); - if (!pos || !accept || !done || !ic) goto on_error; - - pos->pos_data = drag_pos_data; - pos->pos_cb = drag_pos_cb; - - accept->accept_data = drag_accept_data; - accept->accept_cb = drag_accept_cb; - - done->done_data = drag_done_data; - done->done_cb = drag_done_cb; - done->pos = pos; - done->accept = accept; - - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, _dnd_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, _dnd_drag_accept_cb, accept); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DONE, _dnd_drag_done_cb, done); - sl.mem = data; - sl.len = strlen(data); -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - ic->icon_data = icon_create_data; - ic->icon_cb = icon_create_cb; - efl_ui_selection_manager_drag_start(sel_man, obj, (Efl_Ui_Selection_Format)format, sl, - (Efl_Ui_Selection_Action)action, - ic, _dnd_icon_create_cb, NULL, seatid); - - return EINA_TRUE; - -on_error: - if (pos) free(pos); - if (accept) free(accept); - if (done) free(done); - if (ic) free(ic); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - efl_ui_selection_manager_drag_action_set(sel_man, obj, (Efl_Ui_Selection_Action)action, seatid); - - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_drag_cancel(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - efl_ui_selection_manager_drag_cancel(sel_man, obj, seatid); - - return EINA_TRUE; -} - -static void -_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Eina_List *drop_list; - Dnd_Drop *drop; - - drop_list = efl_key_data_get(obj, "__drop_list"); - EINA_LIST_FREE(drop_list, drop) - { - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - free(drop); - } - efl_key_data_set(obj, "__drop_list", NULL); -} - -EAPI Eina_Bool -elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Pos pos_cb, void *pos_data, - Elm_Drop_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Dnd_Drag_State *enter, *leave; - Dnd_Drag_Pos *pos; - Dnd_Drop *drop; - Eina_List *drop_list; - - enter = calloc(1, sizeof(Dnd_Drag_State)); - leave = calloc(1, sizeof(Dnd_Drag_State)); - pos = calloc(1, sizeof(Dnd_Drag_Pos)); - drop = calloc(1, sizeof(Dnd_Drop)); - if (!enter || !leave || !pos || !drop) goto on_error; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - enter->state_cb = enter_cb; - enter->state_data = enter_data; - leave->state_cb = leave_cb; - leave->state_data = leave_data; - pos->pos_cb = pos_cb; - pos->pos_data = pos_data; - drop->obj = obj; - drop->format = format; - drop->drop_cb = drop_cb; - drop->drop_data = drop_data; - drop->enter = enter; - drop->leave = leave; - drop->pos = pos; - - drop_list = efl_key_data_get(obj, "__drop_list"); - drop_list = eina_list_append(drop_list, drop); - efl_key_data_set(obj, "__drop_list", drop_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, - _drop_obj_del_cb, NULL); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, enter); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, leave); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - efl_ui_selection_manager_drop_target_add(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid); - - return EINA_TRUE; - -on_error: - if (enter) free(enter); - if (leave) free(leave); - if (pos) free(pos); - if (drop) free(drop); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Pos pos_cb, void *pos_data, - Elm_Drop_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - //Eina_List *l, *l2; - Eina_List *drop_list; - Dnd_Drop *drop; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - drop_list = efl_key_data_get(obj, "__drop_list"); - drop = eina_list_data_get(drop_list); - if (drop && - (drop->format == format) && - (drop->enter->state_cb == enter_cb) && - (drop->enter->state_data == enter_data) && - (drop->leave->state_cb == leave_cb) && - (drop->leave->state_data == leave_data) && - (drop->pos->pos_cb == pos_cb) && - (drop->pos->pos_data == pos_data) && - (drop->drop_cb == drop_cb) && - (drop->drop_data == drop_data)) - { - drop_list = eina_list_remove(drop_list, drop); - efl_key_data_set(obj, "__drop_list", drop_list); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _drop_obj_del_cb); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - free(drop); - } - efl_ui_selection_manager_drop_target_del(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid); - - return EINA_TRUE; -} - -static Efl_Object * -_dnd_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret) -{ - Elm_Xy_Item_Get_Cb item_get_cb = data; - Evas_Coord x, y; - Efl_Object *obj = NULL; - - x = y = 0; - if (item_get_cb) - obj = item_get_cb(item, pos.x, pos.y, &x, &y); - if (pos_ret) - { - pos_ret->x = x; - pos_ret->y = y; - } + pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); return obj; } -static void -_dnd_cont_drag_pos_cb(void *data, const Efl_Event *event) +EOLIAN static void +_efl_ui_dnd_efl_object_invalidate(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Cont_Drag_Pos *pos = data; - Efl_Dnd_Drag_Pos *ddata = event->info; - Evas_Coord xret = 0, yret = 0; - - if (pos->item_get_cb) + if (pd->registered) { - Evas_Coord x, y; - evas_object_geometry_get(event->object, &x, &y, NULL, NULL); - pos->item_get_cb(event->object, ddata->pos.x + x, ddata->pos.y + y, - &xret, &yret); + _drop_event_unregister(obj); } - if (pos->pos_cb) - pos->pos_cb(pos->pos_data, event->object, ddata->item, ddata->pos.x, ddata->pos.y, - xret, yret, (Elm_Xdnd_Action)ddata->action); + efl_invalidate(efl_super(obj, EFL_UI_DND_MIXIN)); + } -static void -_dnd_cont_drop_cb(void *data, const Efl_Event *event) +#define IS_DROP_EVENT(D) ( \ +(D == EFL_UI_DND_EVENT_DROP_POSITION_CHANGED) || \ +(D == EFL_UI_DND_EVENT_DROP_DROPPED) || \ +(D == EFL_UI_DND_EVENT_DROP_LEFT) || \ +(D == EFL_UI_DND_EVENT_DROP_ENTERED) \ +) + +EOLIAN static Efl_Object* +_efl_ui_dnd_efl_object_finalize(Eo *obj, Efl_Ui_Dnd_Data *pd) { - Dnd_Cont_Drop *drop = data; - Efl_Ui_Selection_Data *org_ddata = event->info; - Elm_Selection_Data ddata; - Evas_Coord xret = 0, yret = 0; + if (pd->registered) + _drop_event_register(obj); - ddata.x = org_ddata->pos.x; - ddata.y = org_ddata->pos.y; - ddata.format = (Elm_Sel_Format)org_ddata->format; - ddata.action = (Elm_Xdnd_Action)org_ddata->action; - ddata.data = calloc(1, org_ddata->content.len); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len); - ddata.len = org_ddata->content.len; + return efl_finalize(efl_super(obj, EFL_UI_DND_MIXIN)); +} - if (drop->item_get_cb) + +EOLIAN static Eina_Bool +_efl_ui_dnd_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd, + const Efl_Event_Description *desc, + Efl_Callback_Priority priority, + Efl_Event_Cb func, + const void *user_data) +{ + if (IS_DROP_EVENT(desc) && !pd->registered) + { + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _drop_event_register(obj); + } + + return efl_event_callback_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), desc, priority, func, user_data); +} + +EOLIAN static Eina_Bool +_efl_ui_dnd_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd, + const Efl_Callback_Array_Item *array, + Efl_Callback_Priority priority, + const void *user_data) +{ + for (int i = 0; array[i].desc; ++i) { - Evas_Coord x, y; - evas_object_geometry_get(event->object, &x, &y, NULL, NULL); - drop->item_get_cb(event->object, ddata.x + x, ddata.y + y, - &xret, &yret); - } - - if (drop->drop_cb) - drop->drop_cb(drop->drop_data, event->object, org_ddata->item, - &ddata, xret, yret); - free(ddata.data); -} - -static void -_cont_drop_free_data(Evas_Object *obj) -{ - Eina_List *cont_drop_list; - Dnd_Cont_Drop *drop; - - cont_drop_list = efl_key_data_get(obj, "__cont_drop_item"); - drop = eina_list_data_get(cont_drop_list); - if (drop) - { - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, drop->enter); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, drop->leave); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_cont_drag_pos_cb, drop->pos); - efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_cont_drop_cb, drop); - free(drop->enter); - free(drop->leave); - free(drop->pos); - cont_drop_list = eina_list_remove(cont_drop_list, drop); - efl_key_data_set(obj, "__cont_drop_item", cont_drop_list); - free(drop); - } -} - -static void -_cont_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - _cont_drop_free_data(obj); -} - -EAPI Eina_Bool -elm_drop_item_container_add(Evas_Object *obj, - Elm_Sel_Format format, - Elm_Xy_Item_Get_Cb item_get_cb, - Elm_Drag_State enter_cb, void *enter_data, - Elm_Drag_State leave_cb, void *leave_data, - Elm_Drag_Item_Container_Pos pos_cb, void *pos_data, - Elm_Drop_Item_Container_Cb drop_cb, void *drop_data) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Dnd_Drag_State *enter = NULL, *leave = NULL; - Dnd_Cont_Drag_Pos *pos = NULL; - Dnd_Cont_Drop *drop = NULL; - Eina_List *cont_drop_list; - - enter = calloc(1, sizeof(Dnd_Drag_State)); - leave = calloc(1, sizeof(Dnd_Drag_State)); - pos = calloc(1, sizeof(Dnd_Cont_Drag_Pos)); - drop = calloc(1, sizeof(Dnd_Cont_Drop)); - if (!enter || !leave || !pos || !drop) goto on_error; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - enter->state_cb = enter_cb; - enter->state_data = enter_data; - leave->state_cb = leave_cb; - leave->state_data = leave_data; - pos->pos_cb = pos_cb; - pos->pos_data = pos_data; - pos->item_get_cb = item_get_cb; - drop->obj = obj; - drop->format = format; - drop->drop_cb = drop_cb; - drop->drop_data = drop_data; - drop->enter = enter; - drop->leave = leave; - drop->pos = pos; - - cont_drop_list = efl_key_data_get(obj, "__cont_drop_item"); - cont_drop_list = eina_list_append(cont_drop_list, drop); - efl_key_data_set(obj, "__cont_drop_item", cont_drop_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, - _cont_drop_obj_del_cb, NULL); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER, - _dnd_drag_enter_leave_cb, enter); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE, - _dnd_drag_enter_leave_cb, leave); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, - _dnd_cont_drag_pos_cb, pos); - efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP, - _dnd_cont_drop_cb, drop); - efl_ui_selection_manager_container_drop_item_add(sel_man, obj, (Efl_Ui_Selection_Format)format, - item_get_cb, _dnd_item_func, NULL, - seatid); - - return EINA_TRUE; - -on_error: - if (enter) free(enter); - if (leave) free(leave); - if (pos) free(pos); - if (drop) free(drop); - - return EINA_FALSE; -} - -EAPI Eina_Bool -elm_drop_item_container_del(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - _cont_drop_free_data(obj); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drop_obj_del_cb); - efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seatid); - - return EINA_TRUE; -} - -static void -_cont_drag_data_func(void *data, Efl_Object *obj, Efl_Ui_Selection_Format *format, - Eina_Rw_Slice *drag_data, Efl_Ui_Selection_Action *action) -{ - Item_Container_Drag_Info *di; - - di = data; - if (!di) return; - di->data_get_cb(obj, di->it, &di->user_info); - if (format) *format = (Efl_Ui_Selection_Format)di->user_info.format; - if (drag_data) - { - if (di->user_info.data) + if (IS_DROP_EVENT(array[i].desc) && !pd->registered) { - drag_data->mem = (void *)di->user_info.data; - drag_data->len = strlen(di->user_info.data); + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _drop_event_register(obj); } } - if (action) *action = (Efl_Ui_Selection_Action)di->user_info.action; + return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), array, priority, user_data); } -static Eina_List * -_cont_drag_icon_list_create(void *data, Efl_Object *obj EINA_UNUSED) -{ - Item_Container_Drag_Info *di; - - di = data; - return di->user_info.icons; -} - -static Efl_Object * -_cont_drag_icon_create(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret) -{ - Item_Container_Drag_Info *di; - Elm_Object_Item *it = NULL; - - di = data; - if (!di) return NULL; - if (!di->user_info.createicon) return NULL; - it = di->user_info.createicon(di->user_info.createdata, win, &pos_ret->x, &pos_ret->y); - di->it = it; - return it; -} - -static Efl_Object * -_cont_drag_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret) -{ - Item_Container_Drag_Info *di = data; - Evas_Coord x, y; - Efl_Object *obj = NULL; - - x = y = 0; - if (di->item_get_cb) - obj = di->item_get_cb(item, pos.x, pos.y, &x, &y); - if (pos_ret) - { - pos_ret->x = x; - pos_ret->y = y; - } - di->it = obj; - - return obj; -} - -static void -_cont_drag_free_data(Evas_Object *obj) -{ - Eina_List *di_list; - Item_Container_Drag_Info *di; - - di_list = efl_key_data_get(obj, "__cont_drag_item"); - di = eina_list_data_get(di_list); - di_list = eina_list_remove(di_list, di); - efl_key_data_set(obj, "__cont_drag_item", di_list); - free(di); -} - -static void -_cont_drag_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) -{ - _cont_drag_free_data(obj); -} - -EAPI Eina_Bool -elm_drag_item_container_add(Evas_Object *obj, double anim_tm, double tm_to_drag, - Elm_Xy_Item_Get_Cb item_get_cb, Elm_Item_Container_Data_Get_Cb data_get_cb) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - Eina_List *di_list; - Item_Container_Drag_Info *di; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - di = calloc(1, sizeof(Item_Container_Drag_Info)); - if (!di) return EINA_FALSE; - di->data_get_cb = data_get_cb; - di->item_get_cb = item_get_cb; - di_list = efl_key_data_get(obj, "__cont_drag_item"); - di_list = eina_list_append(di_list, di); - efl_key_data_set(obj, "__cont_drag_item", di_list); - evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb, NULL); - efl_ui_selection_manager_container_drag_item_add(sel_man, obj, tm_to_drag, anim_tm, - di, _cont_drag_data_func, NULL, - di, _cont_drag_item_func, NULL, - di, _cont_drag_icon_create, NULL, - di, _cont_drag_icon_list_create, NULL, - seatid); - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_drag_item_container_del(Evas_Object *obj) -{ - Eo *sel_man = _efl_ui_selection_manager_get(obj); - int seatid = 1; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - _cont_drag_free_data(obj); - evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb); - efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seatid); - - return EINA_TRUE; -} +#define EFL_UI_DND_EXTRA_OPS \ + EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_dnd_efl_object_event_callback_priority_add), \ + EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_dnd_efl_object_event_callback_array_priority_add), \ #include "efl_ui_dnd.eo.c" -#include "efl_ui_dnd_container.eo.c" diff --git a/src/lib/elementary/efl_ui_dnd.eo b/src/lib/elementary/efl_ui_dnd.eo index 08f668856b..49ef148723 100644 --- a/src/lib/elementary/efl_ui_dnd.eo +++ b/src/lib/elementary/efl_ui_dnd.eo @@ -1,63 +1,93 @@ -import efl_ui_dnd_types; +import eina_types; -mixin @beta Efl.Ui.Dnd { - data: null; +struct @beta Efl.Ui.Drop_Event { + [[Information sent along with Drag & Drop events.]] + position : Eina.Position2D; [[The position where the drop event occurred, in window coordinates.]] + seat : uint; [[Which seat triggered the event.]] + available_types : accessor; [[Types with automatic conversion available. Use one of them in the call to + @Efl.Ui.Dnd.drop_data_get. + + Types are IANA MIME types: + https://www.iana.org/assignments/media-types/media-types.xhtml + ]] +} + +struct @beta Efl.Ui.Drop_Dropped_Event { + [[Information sent along with Drop events.]] + dnd : Efl.Ui.Drop_Event; [[Common information.]] + action : string; [[Requested action to perform upon reception of this data.]] +} + +struct @beta Efl.Ui.Drag_Started_Event { + [[Information sent along with @Efl.Ui.Drag_Started_Event events.]] + seat : uint; [[Which seat triggered the event.]] +} + +struct @beta Efl.Ui.Drag_Finished_Event { + [[Information sent along with @Efl.Ui.Drag_Finished_Event events.]] + seat : uint; [[Which seat triggered the event.]] + accepted : bool; [[$true if the operation completed with a Drop, or $false if it was cancelled.]] +} + +mixin @beta Efl.Ui.Dnd requires Efl.Object { + [[This mixin provides the ability to interact with the system's Drag & Drop facilities. + + Applications starting a Drag & Drop operation operation are said to perform a "Drag" and use + the methods prefixed "drag_". + On the other hand, applications receiving dragged content are said to perform a "Drop" operation and use + the methods prefixed "drop_". + ]] methods { drag_start { - [[Start a drag and drop process at the drag side. - During dragging, there are three events emitted as belows: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE + [[Starts a drag from this client. + + @[Efl.Ui.Dnd.drag,started] is emitted each time a successful drag is started. + @[Efl.Ui.Dnd.drag,finished] is emitted every time a drag is finished. ]] params { - @in format: Efl.Ui.Selection_Format; [[The data format]] - @in data: Eina.Slice; [[The drag data]] - @in action: Efl.Ui.Selection_Action; [[Action when data is transferred]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_action_set { - [[Set the action for the drag]] - params { - @in action: Efl.Ui.Selection_Action; [[Drag action]] - @in seat: uint; [[Specified seat for multiple seats case.]] + content : Eina.Content @by_ref; [[The content being dragged.]] + @in action: string; [[Requested action to perform by the receiver once content is transferred.]] + @in seat: uint; [[Seat starting the drag operation. When in doubt use 0.]] } + return : Efl.Content; [[An Efl.Ui element which you can use to render a visual representation + of the content being dragged (like a thumbnail, for example). + Use @Efl.Content.content.set on it to do so.]] } drag_cancel { - [[Cancel the on-going drag]] + [[Cancels an on-going drag operation.]] params { - @in seat: uint; [[Specified seat for multiple seats case.]] + @in seat: uint; [[Seat that started the drag operation. When in doubt use 0.]] } } - drop_target_add { - [[Make the current object as drop target. - There are four events emitted: - - EFL_UI_DND_EVENT_DRAG_ENTER - - EFL_UI_DND_EVENT_DRAG_LEAVE - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_DROP.]] + drop_data_get { + [[Retrieves the dropped data.]] params { - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_target_del { - [[Delete the dropable status from object]] - params { - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] + @in seat: uint; [[Seat that started the drag operation. When in doubt use 0.]] + @in acceptable_types : iterator; [[List of strings describing the type of content the application + can accept. Types are IANA MIME types: + https://www.iana.org/assignments/media-types/media-types.xhtml.]] } + return : future @move; [[This future is fulfilled when the content is received (asynchronously) + and ready to use. + The Eina.Content specifies the type of the data. + If no matching type was found it returns an error. + ]] } } events { - /* FIXME: This is not very future-proof. Better return a struct. */ - drag,accept: ptr(bool); [[accept drag data]] - drag,done: void; [[drag is done (mouse up)]] - drag,enter: void; [[called when the drag object enters this object]] - drag,leave: void; [[called when the drag object leaves this object]] - drag,pos: Efl.Dnd.Drag_Pos; [[called when the drag object changes drag position]] - drag,drop: Efl.Ui.Selection_Data; [[called when the drag object dropped on this object]] + drop,entered : Efl.Ui.Drop_Event; [[Dragged content entered the window. Its type can already be checked with + @.drop_data_get to react before it is dropped, for example.]] + drop,left : Efl.Ui.Drop_Event; [[Dragged content left the window.]] + drop,position,changed : Efl.Ui.Drop_Event; [[Dragged content moved over the window. Its type can already be + checked with @.drop_data_get to react before it is dropped, + for example.]] + drop,dropped : Efl.Ui.Drop_Dropped_Event; [[Dragged content was dropped over the window.]] + drag,started : Efl.Ui.Drag_Started_Event; [[A Drag operation started.]] + drag,finished : Efl.Ui.Drag_Finished_Event;[[A Drag operation finished.]] + } + implements { + Efl.Object.constructor; + Efl.Object.invalidate; + Efl.Object.finalize; } } diff --git a/src/lib/elementary/efl_ui_dnd_container.eo b/src/lib/elementary/efl_ui_dnd_container.eo deleted file mode 100644 index 0cc1f3f945..0000000000 --- a/src/lib/elementary/efl_ui_dnd_container.eo +++ /dev/null @@ -1,46 +0,0 @@ -import efl_ui_dnd_types; - -mixin @beta Efl.Ui.Dnd_Container { - methods { - @property drag_delay_time { - [[The time since mouse down happens to drag starts.]] - set { - } - get { - } - values { - time: double; [[The drag delay time]] - } - } - drag_item_add { - [[This registers a drag for items in a container. Many items can be - dragged at a time. During dragging, there are three events emitted: - EFL_DND_EVENT_DRAG_POS, EFL_DND_EVENT_DRAG_ACCEPT, EFL_DND_EVENT_DRAG_DONE.]] - params { - @in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]] - @in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]] - @in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations CHECKING ]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_item_del { - [[Remove drag function of items in the container object.]] - params { - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_item_add { - params { - @in format: Efl.Ui.Selection_Format; [[Accepted data formats]] - @in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drop_item_del { - params { - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - } -} diff --git a/src/lib/elementary/efl_ui_dnd_types.eot b/src/lib/elementary/efl_ui_dnd_types.eot deleted file mode 100644 index ace1c8de7b..0000000000 --- a/src/lib/elementary/efl_ui_dnd_types.eot +++ /dev/null @@ -1,60 +0,0 @@ -import efl_ui_selection_types; - -function @beta Efl.Dnd.Drag_Icon_Create { - [[Function pointer for creating icon at the drag side.]] - params { - @in win: Efl.Canvas.Object; [[The window to create the objects relative to]] - @in drag_obj: Efl.Canvas.Object; [[The drag object]] - @out off: Eina.Position2D; [[Offset from the icon position to the cursor]] - } - return: Efl.Canvas.Object; [[The drag icon object]] -}; - -function @beta Efl.Dnd.Drag_Data_Get { - [[Function pointer for getting data and format at the drag side.]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - @out format: Efl.Ui.Selection_Format; [[Data format]] - @out drag_data: Eina.Rw_Slice; [[Data]] - @out action: Efl.Ui.Selection_Action; [[The drag action]] - } -}; - -function @beta Efl.Dnd.Item_Get { - [[Function pointer to find out which item is under position (x, y)]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - @in pos: Eina.Position2D; [[The coordinates to get item]] - @out posret: Eina.Position2D; [[position relative to item (left (-1), middle (0), right (1)]] - } - return: Efl.Object; [[Object under x,y coordinates or NULL if not found]] -}; - -function @beta Efl.Dnd.Drag_Icon_List_Create { - [[Function pointer to create list of icons at the drag side. - These icons are used for animation on combining selection icons - to one icon.]] - params { - @in obj: Efl.Canvas.Object; [[The container object]] - } - return: list; -}; - -struct @beta Efl.Dnd.Drag_Accept { - accepted: bool; -} - -struct @beta Efl.Dnd.Drag_Pos { - [[Dragging position information.]] - pos: Eina.Position2D; [[Evas Coordinate]] - action: Efl.Ui.Selection_Action; [[The drag action]] - format: Efl.Ui.Selection_Format; [[The drag format]] - item: Efl.Canvas.Object; [[The item object. It is only available for container object.]] -} - -struct @beta Efl.Dnd.Drag_Item_Container_Drop { - [[Drop information for a drag&drop operation.]] - item: Efl.Canvas.Object; [[The item object]] - data: Efl.Ui.Selection_Data; [[The selection data]] - pos: Eina.Position2D; [[Position relative to item (left (-1), middle (0), right (1)]] -} diff --git a/src/lib/elementary/efl_ui_selection.c b/src/lib/elementary/efl_ui_selection.c index 675eb0cf99..d67d1f3fef 100644 --- a/src/lib/elementary/efl_ui_selection.c +++ b/src/lib/elementary/efl_ui_selection.c @@ -9,278 +9,115 @@ #define MY_CLASS EFL_UI_SELECTION_MIXIN #define MY_CLASS_NAME "Efl.Ui.Selection" -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -#endif +typedef struct { + Ecore_Evas *ee; + Eina_Bool registered : 1; +} Efl_Ui_Selection_Data; -EOLIAN static void -_efl_ui_selection_selection_get(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, unsigned int seat) +static inline Ecore_Evas_Selection_Buffer +_ee_buffer_get(Efl_Ui_Cnp_Buffer buffer) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_selection_get(sel_man, obj, type, format, - data_func_data, data_func, - data_func_free_cb, seat); + if (buffer == EFL_UI_CNP_BUFFER_SELECTION) + return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER; + else + return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; } -EOLIAN static Eina_Future * -_efl_ui_selection_selection_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, unsigned int seat) +EOLIAN static Eina_Future* +_efl_ui_selection_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat, Eina_Iterator *acceptable_types) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - return efl_ui_selection_manager_selection_set(sel_man, obj, type, format, data, seat); + return ecore_evas_selection_get(pd->ee, seat, _ee_buffer_get(buffer), acceptable_types); } EOLIAN static void -_efl_ui_selection_selection_clear(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) +_efl_ui_selection_selection_set(Eo *obj, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, Eina_Content *content, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - efl_ui_selection_manager_selection_clear(sel_man, obj, type, seat); + _register_selection_changed(obj); + ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), content); +} + +EOLIAN static void +_efl_ui_selection_selection_clear(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat) +{ + ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), NULL); } EOLIAN static Eina_Bool -_efl_ui_selection_has_owner(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) +_efl_ui_selection_has_selection(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat) { - Eo *sel_man = _efl_ui_selection_manager_get(obj); - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, type, seat); + return ecore_evas_selection_exists(pd->ee, seat, _ee_buffer_get(buffer)); } - -////////// Support legacy APIs - -//TODO: Clear this list (when sel_man is deleted) -Eina_List *lost_cb_list = NULL; - -#ifdef HAVE_ELEMENTARY_WL2 -static Ecore_Evas * -_wl_is_wl(const Evas_Object *obj) +EOLIAN static Efl_Object* +_efl_ui_selection_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Data *pd) { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; + if (!efl_constructor(efl_super(obj, EFL_UI_SELECTION_MIXIN))) + return NULL; - if (!(evas = evas_object_evas_get(obj))) - return NULL; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return NULL; + pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) + return obj; +} + +EOLIAN static void +_efl_ui_selection_efl_object_invalidate(Eo *obj, Efl_Ui_Selection_Data *pd) +{ + if (pd->registered) { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - engine_name = ecore_evas_engine_name_get(ee); + _selection_changed_event_unregister(obj); } - if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1)) - return ee; - return NULL; + efl_invalidate(efl_super(obj, EFL_UI_SELECTION_MIXIN)); } -int -_wl_default_seat_id_get(Evas_Object *obj) +EOLIAN static Eina_Bool +_efl_ui_selection_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd, + const Efl_Event_Description *desc, + Efl_Callback_Priority priority, + Efl_Event_Cb func, + const void *user_data) { - Ecore_Wl2_Window *win = _wl_window_get(obj); - Eo *seat, *parent2, *ewin; - Eina_Bool is_wl = EINA_FALSE; + if (desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered) + { - if (obj) + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _selection_changed_event_register(obj); + } + + return efl_event_callback_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), desc, priority, func, user_data); +} + +EOLIAN static Eina_Bool +_efl_ui_selection_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd, + const Efl_Callback_Array_Item *array, + Efl_Callback_Priority priority, + const void *user_data) +{ + for (int i = 0; array[i].desc; ++i) { - if (_wl_is_wl(obj)) is_wl = EINA_TRUE; - if (efl_isa(obj, EFL_UI_WIDGET_CLASS)) + if (array[i].desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered) { - Eo *top = elm_widget_top_get(obj); - if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS)) - { - parent2 = efl_ui_win_inlined_parent_get(top); - if (parent2) obj = elm_widget_top_get(parent2) ?: parent2; - } - /* fake win means canvas seat id will not match protocol seat id */ - ewin = elm_win_get(obj); - if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL; + pd->registered = EINA_TRUE; + if (efl_finalized_get(obj)) + _selection_changed_event_register(obj); } } - - if (!obj) - { - if (is_wl) - { - Ecore_Wl2_Input *input; - Eina_Iterator *it; - - it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win)); - EINA_ITERATOR_FOREACH(it, input) break; - eina_iterator_free(it); - if (input) - return ecore_wl2_input_seat_id_get(input); - } - } - - seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, 1); - return evas_device_seat_id_get(seat); -} -#endif - -typedef struct _Cnp_Data_Cb_Wrapper Cnp_Data_Cb_Wrapper; -struct _Cnp_Data_Cb_Wrapper -{ - void *udata; - Elm_Drop_Cb datacb; -}; - -static void -_selection_data_ready_cb(void *data, Efl_Object *obj, Efl_Ui_Selection_Data *seldata) -{ - Cnp_Data_Cb_Wrapper *wdata = data; - if (!wdata) return; - Elm_Selection_Data ddata; - - ddata.data = calloc(1, seldata->content.len + 1); - if (!ddata.data) return; - ddata.data = memcpy(ddata.data, seldata->content.mem, seldata->content.len); - ddata.len = seldata->content.len; - ddata.x = seldata->pos.x; - ddata.y = seldata->pos.y; - ddata.format = (Elm_Sel_Format)seldata->format; - ddata.action = (Elm_Xdnd_Action)seldata->action; - wdata->datacb(wdata->udata, obj, &ddata); - free(ddata.data); + return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), array, priority, user_data); } -typedef struct _Sel_Lost_Data Sel_Lost_Data; -struct _Sel_Lost_Data + +EOLIAN static Efl_Object* +_efl_ui_selection_efl_object_finalize(Eo *obj, Efl_Ui_Selection_Data *pd) { - const Evas_Object *obj; - Elm_Sel_Type type; - void *udata; - Elm_Selection_Loss_Cb loss_cb; -}; + if (pd->registered) + _selection_changed_event_register(obj); -static Eina_Value -_selection_lost_cb(void *data, const Eina_Value value) -{ - Eina_List *l, *l2; - Sel_Lost_Data *ldata, *ldata2; - - ldata = data; - EINA_LIST_FOREACH_SAFE(lost_cb_list, l, l2, ldata2) - { - if ((ldata->obj == ldata2->obj) && - (ldata->type == ldata2->type)) - { - ldata2->loss_cb(ldata2->udata, ldata2->type); - lost_cb_list = eina_list_remove(lost_cb_list, ldata2); - } - } - free(ldata); - - return value; + return efl_finalize(efl_super(obj, MY_CLASS)); } -EAPI Eina_Bool -elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type type, - Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - Cnp_Data_Cb_Wrapper *wdata = calloc(1, sizeof(Cnp_Data_Cb_Wrapper)); - if (!wdata) return EINA_FALSE; - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get((Evas_Object *)obj); -#endif - wdata->udata = udata; - wdata->datacb = datacb; - efl_ui_selection_manager_selection_get(sel_man, (Evas_Object *)obj, (Efl_Ui_Selection_Type)type, - (Efl_Ui_Selection_Format)format, - wdata, _selection_data_ready_cb, NULL, seatid); - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type type, - Elm_Sel_Format format, const void *selbuf, size_t buflen) -{ - int seatid = 1; - Eina_Future *f; - Sel_Lost_Data *ldata; - Eo *sel_man = _efl_ui_selection_manager_get(obj); - Eina_Slice data; - - ldata = calloc(1, sizeof(Sel_Lost_Data)); - if (!ldata) return EINA_FALSE; - data.mem = selbuf; - data.len = buflen; -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - f = efl_ui_selection_manager_selection_set(sel_man, obj, (Efl_Ui_Selection_Type)type, - (Efl_Ui_Selection_Format)format, data, seatid); - - ldata->obj = obj; - ldata->type = type; - eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata); - - return EINA_TRUE; -} - -EAPI Eina_Bool -elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type type) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - efl_ui_selection_manager_selection_clear(sel_man, obj, (Efl_Ui_Selection_Type)type, seatid); - - return EINA_TRUE; -} - -EAPI void -elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, - Elm_Selection_Loss_Cb func, const void *data) -{ - Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data)); -#if HAVE_ELEMENTARY_COCOA - // Currently, we have no way to track changes in Cocoa pasteboard. - // Therefore, don't track this... - return; -#endif - if (!ldata) return; - ldata->obj = obj; - ldata->type = type; - ldata->udata = (void *)data; - ldata->loss_cb = func; - lost_cb_list = eina_list_append(lost_cb_list, ldata); -} - -EAPI Eina_Bool -elm_selection_selection_has_owner(Evas_Object *obj) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, - EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid); -} - -EAPI Eina_Bool -elm_cnp_clipboard_selection_has_owner(Evas_Object *obj) -{ - int seatid = 1; - Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj); -#endif - return efl_ui_selection_manager_selection_has_owner(sel_man, obj, - EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid); -} +#define EFL_UI_SELECTION_EXTRA_OPS \ + EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_selection_efl_object_event_callback_priority_add), \ + EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_selection_efl_object_event_callback_array_priority_add), \ #include "efl_ui_selection.eo.c" diff --git a/src/lib/elementary/efl_ui_selection.eo b/src/lib/elementary/efl_ui_selection.eo index 20e42261d0..7e0814d348 100644 --- a/src/lib/elementary/efl_ui_selection.eo +++ b/src/lib/elementary/efl_ui_selection.eo @@ -1,45 +1,85 @@ -import efl_ui_selection_types; +import eina_types; -mixin @beta Efl.Ui.Selection { - [[Efl Ui Selection class]] - data: null; - methods { - selection_set { - [[Set the selection data to the object]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data: Eina.Slice; [[Selection data]] - @in seat: uint;[[Specified seat for multiple seats case.]] - } - return: future; [[Future for tracking when the selection is lost]] - } - selection_get { - [[Get the data from the object that has selection]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]] - @in seat: uint;[[Specified seat for multiple seats case.]] - } - } - selection_clear { - [[Clear the selection data from the object]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection Type]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - has_owner { - [[Determine whether the selection data has owner]] - params { - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - return: bool; [[EINA_TRUE if there is object owns selection, otherwise EINA_FALSE]] - } - } - events { - wm_selection,changed: Efl.Ui.Selection_Changed; [[Called when display server's selection has changed]] - } +enum @beta Efl.Ui.Cnp_Buffer { + [[System buffer to use in Copy & Paste operations.]] + selection = 0, [[Buffer typically used when the user selects (highlights) some text without explicitly + requesting to copy it.]] + copy_and_paste = 1, [[Buffer used when the user requests that the current selection is copied (using + Ctrl+C, for example).]] +} + +struct @beta Efl.Ui.Wm_Selection_Changed { + [[Information sent along the @[Efl.Ui.Selection.wm_selection,changed] event.]] + buffer : Efl.Ui.Cnp_Buffer; [[The system buffer that has changed.]] + caused_by : Efl.Ui.Selection; [[The EFL widget that triggered the change. $NULL if it is not an EFL widget.]] + seat : uint; [[The seat that triggered the change.]] +} + +mixin @beta Efl.Ui.Selection requires Efl.Object { + [[This mixin provides the ability to interact with the system's Copy & Paste facilities. + ]] + methods { + selection_set { + [[Sets the current selection. + + This sends the selected data to the system's specified buffer, making it available to other + applications for "pasting" it. + + This is typically used when the user requests a "copy" operation. + ]] + params { + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to use.]] + content : Eina.Content @by_ref; [[Data to copy.]] + seat : uint; [[Seat the data comes from. Use 0 when in doubt.]] + } + } + selection_clear { + [[Clears the current selection. + + No data will be available to other applications to paste (until something else is selected). + ]] + params { + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to clear.]] + seat : uint; [[Seat to clear. Use 0 when in doubt.]] + } + } + selection_get { + [[Retrieves the data currently held in the specified buffer. + + This is typically used when the user requests a "paste" operation. + + This method is time consuming (since data can potentially be provided by another application), therefore, + it is recommended to verify the existence of a selection using @.has_selection before calling it. + ]] + params { + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to use.]] + seat : uint; [[Seat where the data should be pasted. Use 0 when in doubt.]] + acceptable_types : iterator; [[List of accepted IANA MIME types: + https://www.iana.org/assignments/media-types/media-types.xhtml + If automatic conversion cannot be provided to any of the accepted + types, an error will be returned. + ]] + } + return : future @move; [[A future that will be resolved to the requested content, or to an + error if type conversion is not available or the requested buffer + is empty.]] + } + has_selection { + [[Checks if the specified system buffer has content.]] + params { + buffer : Efl.Ui.Cnp_Buffer; [[System buffer to query.]] + seat : uint; [[Seat to query. Use 0 when in doubt.]] + } + return : bool; [[$true if there is data available in the requested buffer.]] + } + } + implements { + Efl.Object.constructor; + Efl.Object.invalidate; + Efl.Object.finalize; + } + events { + wm_selection,changed : Efl.Ui.Wm_Selection_Changed; [[Event emitted when the content of one of the system's + buffers changes.]] + } } diff --git a/src/lib/elementary/efl_ui_selection_manager.c b/src/lib/elementary/efl_ui_selection_manager.c deleted file mode 100644 index 76f2c03002..0000000000 --- a/src/lib/elementary/efl_ui_selection_manager.c +++ /dev/null @@ -1,5678 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "elementary_config.h" -#endif - -#include -#include "elm_priv.h" - -#ifdef _WIN32 -# include /* mmap */ -#else -# include -#endif - -#include "efl_ui_selection_manager_private.h" - -#define MY_CLASS EFL_UI_SELECTION_MANAGER_CLASS - -//#define DEBUGON 1 -#ifdef DEBUGON -# define sel_debug(fmt, args...) fprintf(stderr, __FILE__":%s:%d : " fmt "\n", __FUNCTION__, __LINE__, ##args) -#else -# define sel_debug(x...) do { } while (0) -#endif - -static void _anim_data_free(Sel_Manager_Drag_Container *dc); -static void _cont_obj_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); -static void _cont_obj_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); -static void _item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full); - -void efl_ui_selection_manager_drop_target_del(Eo *obj, Efl_Object *target_obj, Efl_Ui_Selection_Format format, unsigned int seat); -void efl_ui_selection_manager_selection_clear(Eo *obj, Efl_Object *owner, Efl_Ui_Selection_Type type, unsigned int seat); -void efl_ui_selection_manager_drag_start(Eo *obj, Efl_Object *drag_obj, Efl_Ui_Selection_Format format, Eina_Slice data, Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, unsigned int seat); - -static Eina_List *managers; - -#ifdef HAVE_ELEMENTARY_X -static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel); -static Ecore_X_Atom _x11_dnd_action_rev_map(Efl_Ui_Selection_Action action); -static Ecore_X_Window _x11_xwin_get(const Evas_Object *obj); -#endif - -#ifdef HAVE_ELEMENTARY_WL2 -Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); -static Ecore_Wl2_Input *_wl_seat_get(Ecore_Wl2_Window *win, Evas_Object *obj, unsigned int seat_id); -#endif - -#ifdef HAVE_ELEMENTARY_WIN32 -static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel); -#endif - -EAPI int ELM_CNP_EVENT_SELECTION_CHANGED = -1; - -#ifdef HAVE_ELEMENTARY_X -static Sel_Manager_Seat_Selection * -_sel_manager_seat_selection_get(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Eina_List *l = NULL; - Sel_Manager_Seat_Selection *seat_sel = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if (seat_sel->seat == seat) - break; - } - if (!seat_sel) - ERR("Could not find request seat"); - - return seat_sel; -} -#endif - -static inline void -_owner_change_check(Efl_Ui_Selection_Manager *manager, Efl_Object *owner, - Sel_Manager_Seat_Selection *seat_sel, - Sel_Manager_Selection *sel, - Efl_Ui_Selection_Type type, Eina_Bool same_win) -{ - if (!same_win) - { - Eina_List *l, *l_next; - Eo *man; - - EINA_LIST_FOREACH_SAFE(managers, l, l_next, man) - { - if (man != manager) - { - Eina_List *l2, *l2_next, *l3, *l3_next; - Sel_Manager_Selection_Lost *sel_lost; - Sel_Manager_Seat_Selection *seat_sel2; - Efl_Ui_Selection_Manager_Data *pd = efl_data_scope_get(man, MY_CLASS); - - if (!pd) continue; - EINA_LIST_FOREACH_SAFE(pd->seat_list, l3, l3_next, seat_sel2) - { - EINA_LIST_FOREACH_SAFE(seat_sel2->sel_lost_list, l2, l2_next, sel_lost) - { - if ((sel_lost->request) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - seat_sel2->xwin = 0; -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WIN32) - if (seat_sel2->sel_list) - { - int i; - - for (i = 0; - i < (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) - ; i++) - { -#ifdef HAVE_ELEMENTARY_X - seat_sel2->sel_list[i].xwin = 0; -#elif defined (HAVE_ELEMENTARY_WIN32) - seat_sel2->sel_list[i].win = NULL; -#endif - seat_sel2->sel_list[i].active = EINA_FALSE; - } - } -#endif -#if defined(HAVE_ELEMENTARY_WL2) || defined(HAVE_ELEMENTARY_COCOA) - if (seat_sel2->sel) - { - seat_sel2->sel->win = 0; - seat_sel2->sel->active = EINA_FALSE; - } -#endif - } - } - } - } - if ((sel->owner != NULL) && - (sel->owner != owner) && same_win) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - } -} - -static Sel_Manager_Seat_Selection * -_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } -#ifdef HAVE_ELEMENTARY_X - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } -#endif - - return seat_sel; -} - -static void -_sel_manager_promise_cancel(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED) -{ - Sel_Manager_Selection_Lost *sel_lost = data; - sel_lost->seat_sel->sel_lost_list = eina_list_remove(sel_lost->seat_sel->sel_lost_list, sel_lost); - free(sel_lost); -} - -static inline Eina_Future * -_update_sel_lost_list(Efl_Object *obj, Efl_Ui_Selection_Type type, - Sel_Manager_Seat_Selection *seat_sel) -{ - Eina_Promise *p; - Sel_Manager_Selection_Lost *sel_lost; - - sel_lost = calloc(1, sizeof(Sel_Manager_Selection_Lost)); - if (!sel_lost) - return NULL; - sel_lost->request = obj; - sel_lost->type = type; - sel_lost->seat_sel = seat_sel; - seat_sel->sel_lost_list = eina_list_append(seat_sel->sel_lost_list, sel_lost); - - p = efl_loop_promise_new(obj); - if (!p) return NULL; - sel_lost->promise = p; - - return efl_future_then(obj, eina_future_new(p), - .data = sel_lost, - .free = _sel_manager_promise_cancel); -} - -/* TODO: this should not be an actual tempfile, but rather encode the object - * as http://dataurl.net/ if it's an image or similar. Evas should support - * decoding it as memfile. */ -static Tmp_Info * -_tempfile_new(int size) -{ -#ifdef HAVE_MMAP - Tmp_Info *info; - const char *tmppath = NULL; - mode_t cur_umask; - int len; - - info = calloc(1, sizeof(Tmp_Info)); - if (!info) return NULL; -#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) - if (getuid() == geteuid()) -#endif - tmppath = getenv("TMP"); - if (!tmppath) tmppath = P_tmpdir; - len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-"); - if (len < 0) goto on_error; - len++; - info->filename = malloc(len); - if (!info->filename) goto on_error; - snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-"); - cur_umask = umask(S_IRWXO | S_IRWXG); - info->fd = mkstemp(info->filename); - umask(cur_umask); - if (info->fd < 0) goto on_error; -# ifdef __linux__ - { - char *tmp; - /* And before someone says anything see POSIX 1003.1-2008 page 400 */ - long pid; - - pid = (long)getpid(); - /* Use pid instead of /proc/self: That way if can be passed around */ - len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd); - len++; - tmp = malloc(len); - if (tmp) - { - snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd); - unlink(info->filename); - free(info->filename); - info->filename = tmp; - } - } -# endif - sel_debug("filename is %s\n", info->filename); - if (size < 1) goto on_error; - /* Map it in */ - if (ftruncate(info->fd, size)) - { - perror("ftruncate"); - goto on_error; - } - eina_mmap_safety_enabled_set(EINA_TRUE); - info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0); - if (info->map == MAP_FAILED) - { - perror("mmap"); - goto on_error; - } - return info; - - on_error: - if (info->fd >= 0) close(info->fd); - info->fd = -1; - /* Set map to NULL and return */ - info->map = NULL; - info->len = 0; - free(info->filename); - free(info); - return NULL; -#else - (void) size; - return NULL; -#endif -} - -static int -_tmpinfo_free(Tmp_Info *info) -{ - if (!info) return 0; - free(info->filename); - free(info); - return 0; -} - -static inline void -_drop_target_cbs_del(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Efl_Object *obj) -{ - if (dropable) - { - Drop_Format *df; - while (dropable->format_list) - { - df = EINA_INLIST_CONTAINER_GET(dropable->format_list, Drop_Format); - efl_ui_selection_manager_drop_target_del(pd->sel_man, obj, - df->format, dropable->seat); - // If drop_target_del() happened to delete dropabale, then - // re-fetch it each loop to make sure it didn't - dropable = efl_key_data_get(obj, "__elm_dropable"); - if (!dropable) break; - } - } -} - -static void -_all_drop_targets_cbs_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Sel_Manager_Dropable *dropable = NULL; - - if (!pd) return; - dropable = efl_key_data_get(obj, "__elm_dropable"); - _drop_target_cbs_del(pd, dropable, obj); -} - -static void -_dropable_coords_adjust(Sel_Manager_Dropable *dropable, Eina_Position2D *pos) -{ - Ecore_Evas *ee; - Evas *evas = evas_object_evas_get(dropable->obj); - int ex = 0, ey = 0, ew = 0, eh = 0; - Evas_Object *win; - - ee = ecore_evas_ecore_evas_get(evas); - ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh); - pos->x = pos->x - ex; - pos->y = pos->y - ey; - - /* For Wayland, frame coords have to be subtracted. */ - Evas_Coord fx, fy; - evas_output_framespace_get(evas, &fx, &fy, NULL, NULL); - if (fx || fy) sel_debug("evas frame fx %d fy %d\n", fx, fy); - pos->x = pos->x - fx; - pos->y = pos->y - fy; - - if (elm_widget_is(dropable->obj)) - { - win = elm_widget_top_get(dropable->obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - { - Evas_Coord x2, y2; - int rot = elm_win_rotation_get(win); - switch (rot) - { - case 90: - x2 = ew - pos->y; - y2 = pos->x; - break; - case 180: - x2 = ew - pos->x; - y2 = eh - pos->y; - break; - case 270: - x2 = pos->y; - y2 = eh - pos->x; - break; - default: - x2 = pos->x; - y2 = pos->y; - break; - } - sel_debug("rotation %d, w %d, h %d - x:%d->%d, y:%d->%d\n", - rot, ew, eh, pos->x, x2, pos->y, y2); - pos->x = x2; - pos->y = y2; - } - } -} - -static Eina_Bool -_drag_cancel_animate(void *data, double pos) -{ /* Animation to "move back" drag-window */ - Sel_Manager_Seat_Selection *seat_sel = data; - sel_debug("in, pos: %f", pos); - if (pos >= 0.99) - { -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 0); -#endif - sel_debug("Delete drag_win"); - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - return ECORE_CALLBACK_CANCEL; - } - else - { - int x, y; - x = seat_sel->drag_win_end.x - (pos * (seat_sel->drag_win_end.x - seat_sel->drag_win_start.x)); - y = seat_sel->drag_win_end.y - (pos * (seat_sel->drag_win_end.y - seat_sel->drag_win_start.y)); - evas_object_move(seat_sel->drag_win, x, y); - } - - return ECORE_CALLBACK_RENEW; -} - -static Efl_Ui_Selection_Format -_dnd_types_to_format(Efl_Ui_Selection_Manager_Data *pd, const char **types, int ntypes) -{ - Efl_Ui_Selection_Format ret_type = 0; - int i; - for (i = 0; i < ntypes; i++) - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, types[i]); - if (atom) ret_type |= atom->format; - } - return ret_type; -} - -static Eina_List * -_dropable_list_geom_find(Efl_Ui_Selection_Manager_Data *pd, Evas *evas, Evas_Coord px, Evas_Coord py) -{ - Eina_List *itr, *top_objects_list = NULL, *dropable_list = NULL; - Evas_Object *top_obj; - Sel_Manager_Dropable *dropable = NULL; - - if (!pd->drop_list) return NULL; - - /* We retrieve the (non-smart) objects pointed by (px, py) */ - top_objects_list = evas_tree_objects_at_xy_get(evas, NULL, px, py); - /* We walk on this list from the last because if the list contains more than one - * element, all but the last will repeat events. The last one can repeat events - * or not. Anyway, this last one is the first that has to be taken into account - * for the determination of the drop target. - */ - EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj) - { - Evas_Object *object = top_obj; - /* We search for the dropable data into the object. If not found, we search into its parent. - * For example, if a button is a drop target, the first object will be an (internal) image. - * The drop target is attached to the button, i.e to image's parent. That's why we need to - * walk on the parents until NULL. - * If we find this dropable data, we found our drop target. - */ - while (object) - { - dropable = efl_key_data_get(object, "__elm_dropable"); - if (dropable) - { - Eina_Bool exist = EINA_FALSE; - Eina_List *l; - Sel_Manager_Dropable *d = NULL; - EINA_LIST_FOREACH(dropable_list, l, d) - { - if (d == dropable) - { - exist = EINA_TRUE; - break; - } - } - if (!exist) - dropable_list = eina_list_append(dropable_list, dropable); - object = evas_object_smart_parent_get(object); - if (dropable) - sel_debug("Drop target %p of type %s found\n", - dropable->obj, efl_class_name_get(efl_class_get(dropable->obj))); - } - else - object = evas_object_smart_parent_get(object); - } - } - eina_list_free(top_objects_list); - return dropable_list; -} - -#ifdef HAVE_ELEMENTARY_X -static Ecore_X_Window -_x11_xwin_get(const Efl_Object *obj) -{ - if (!obj) return 0; - - Ecore_X_Window xwin = 0; - //get top - const Evas_Object *top = obj; - const Evas_Object *parent = obj; - while(parent) - { - top = parent; - parent = efl_parent_get(parent); - } - if (efl_isa(top, EFL_UI_WIN_CLASS)) - { - xwin = elm_win_xwindow_get(top); - } - if (!xwin) - { - Ecore_Evas *ee; - Evas *evas = evas_object_evas_get(obj); - if (!evas) return 0; - ee = ecore_evas_ecore_evas_get(evas); - if (!ee) return 0; - - while(!xwin) - { - const char *engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return 0; - xwin = _elm_ee_xwin_get(ee); - } - else - { - xwin = _elm_ee_xwin_get(ee); - if (!xwin) return 0; - } - } - } - - return xwin; -} - -static Eina_Bool -_x11_is_uri_type_data(Sel_Manager_Selection *sel EINA_UNUSED, Ecore_X_Event_Selection_Notify *notify) -{ - Ecore_X_Selection_Data *data; - char *p; - - data = notify->data; - sel_debug("data->format is %d %p %p", data->format, notify, data); - if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE; - p = (char *)data->data; - if (!p) return EINA_TRUE; - sel_debug("Got %s", p); - if (strncmp(p, "file:/", 6)) - { - if (*p != '/') return EINA_FALSE; - } - return EINA_TRUE; -} - -static Sel_Manager_Seat_Selection * -_x11_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel_list) - { - //TODO: reduce memory (may be just need one common sel_list) - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } - - return seat_sel; -} - -static Eina_Bool -_x11_data_preparer_text(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("text data preparer"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -static Eina_Bool -_x11_data_preparer_markup(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("markup data preparer"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_MARKUP; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -/** - * So someone is pasting an image into my entry or widget... - */ -static Eina_Bool -_x11_data_preparer_uri(Sel_Manager_Seat_Selection *seat_sel, Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("uri data preparer"); - Ecore_X_Selection_Data *data; - Ecore_X_Selection_Data_Files *files; - char *p, *stripstr = NULL; - - data = notify->data; - sel_debug("data->format is %d %p %p\n", data->format, notify, data); - if (data->content == ECORE_X_SELECTION_CONTENT_FILES) - { - Efreet_Uri *uri; - Eina_Strbuf *strbuf; - int i; - - sel_debug("got a files list\n"); - files = notify->data; - /* - if (files->num_files > 1) - { - // Don't handle many items <- this makes mr bigglesworth sad :( - sel_debug("more then one file: Bailing\n"); - return EINA_FALSE; - } - stripstr = p = strdup(files->files[0]); - */ - - strbuf = eina_strbuf_new(); - if (!strbuf) - return EINA_FALSE; - - for (i = 0; i < files->num_files ; i++) - { - uri = efreet_uri_decode(files->files[i]); - if (uri) - { - eina_strbuf_append(strbuf, uri->path); - efreet_uri_free(uri); - } - else - { - eina_strbuf_append(strbuf, files->files[i]); - } - if (i < (files->num_files - 1)) - eina_strbuf_append(strbuf, "\n"); - } - stripstr = eina_strbuf_string_steal(strbuf); - eina_strbuf_free(strbuf); - } - else - { - Efreet_Uri *uri; - - p = (char *)eina_memdup((unsigned char *)data->data, data->length, EINA_TRUE); - if (!p) return EINA_FALSE; - uri = efreet_uri_decode(p); - if (!uri) - { - /* Is there any reason why we care of URI without scheme? */ - if (p[0] == '/') stripstr = p; - else free(p); - } - else - { - free(p); - stripstr = strdup(uri->path); - efreet_uri_free(uri); - } - } - - if (!stripstr) - { - sel_debug("Couldn't find a file\n"); - return EINA_FALSE; - } - free(seat_sel->saved_types->imgfile); -#if 0 // this seems to be broken - we should be handling uri lists as text - if (seat_sel->saved_types->textreq) - { - seat_sel->saved_types->textreq = 0; - seat_sel->saved_types->imgfile = stripstr; - } - else -#endif - { - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = stripstr; - ddata->content.len = strlen(stripstr); - seat_sel->saved_types->imgfile = NULL; - } - return EINA_TRUE; -} - -/** - * Just received an vcard, either through cut and paste, or dnd. - */ -static Eina_Bool -_x11_data_preparer_vcard(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("vcard receive\n"); - Ecore_X_Selection_Data *data = notify->data; - ddata->format = EFL_UI_SELECTION_FORMAT_VCARD; - ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE); - ddata->content.len = data->length; - return EINA_TRUE; -} - -static Eina_Bool -_x11_data_preparer_image(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED, - Ecore_X_Event_Selection_Notify *notify, - Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info) -{ - Ecore_X_Selection_Data *data = notify->data; - sel_debug("got a image file!\n"); - sel_debug("Size if %d\n", data->length); - - ddata->format = EFL_UI_SELECTION_FORMAT_IMAGE; - data = notify->data; - - Tmp_Info *tmp = _tempfile_new(data->length); - if (!tmp) return EINA_FALSE; - memcpy(tmp->map, data->data, data->length); - munmap(tmp->map, data->length); - ddata->content.mem = strdup(tmp->filename); - ddata->content.len = strlen(tmp->filename); - *tmp_info = tmp; - return EINA_TRUE; -} - -static Eina_Bool -_x11_win_filter(Eo *manager EINA_UNUSED, Ecore_X_Window xwin) -{ - Eo *win; - const Eina_List *l; - - EINA_LIST_FOREACH(_elm_win_list, l, win) - { - if (elm_win_window_id_get(win) == xwin) return EINA_FALSE; - } - return EINA_TRUE; -} - -/* - * Callback to handle a targets response on a selection request: - * So pick the format we'd like; and then request it. - */ -static Eina_Bool -_x11_notify_handler_targets(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Selection *sel, Ecore_X_Event_Selection_Notify *notify) -{ - sel_debug("notify handler targets"); - Ecore_X_Selection_Data_Targets *targets; - Ecore_X_Atom *atom_list; - int i, j; - - targets = notify->data; - atom_list = (Ecore_X_Atom *)(targets->data.data); - for (j = (SELECTION_ATOM_LISTING_ATOMS + 1); j < SELECTION_N_ATOMS; j++) - { - sel_debug("\t%s %d", pd->atom_list[j].name, pd->atom_list[j].x_atom); - if (!(pd->atom_list[j].format & sel->request_format)) continue; - for (i = 0; i < targets->data.length; i++) - { - if ((pd->atom_list[j].x_atom == atom_list[i]) && (pd->atom_list[j].x_data_preparer)) - { - if (j == SELECTION_ATOM_TEXT_URILIST) - { - if (!_x11_is_uri_type_data(sel, notify)) continue; - } - sel_debug("Atom %s matches", pd->atom_list[j].name); - goto done; - } - } - } - sel_debug("Couldn't find anything that matches"); - return ECORE_CALLBACK_PASS_ON; -done: - sel_debug("Sending request for %s, xwin=%#llx", - pd->atom_list[j].name, (unsigned long long)sel->xwin); - sel->request(sel->xwin, pd->atom_list[j].name); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_fixes_selection_notify(void *data, int t EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Efl_Ui_Selection_Changed e; - Elm_Cnp_Event_Selection_Changed *_e; - Ecore_X_Event_Fixes_Selection_Notify *ev = event; - Sel_Manager_Seat_Selection *seat_sel; - Efl_Ui_Selection_Type type; - Sel_Manager_Selection *sel; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - switch (ev->selection) - { - case ECORE_X_SELECTION_CLIPBOARD: - type = EFL_UI_SELECTION_TYPE_CLIPBOARD; - break; - case ECORE_X_SELECTION_PRIMARY: - type = EFL_UI_SELECTION_TYPE_PRIMARY; - break; - default: return ECORE_CALLBACK_RENEW; - } - seat_sel = _x11_sel_manager_seat_selection_init(pd, 1); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel_list + type; - if (sel->active && (sel->xwin != ev->owner)) - efl_ui_selection_manager_selection_clear(pd->sel_man, sel->owner, type, seat_sel->seat); - e.type = type; - e.seat = 1; /* under x11 this is always the default seat */ - e.exist = !!ev->owner; - - _e = calloc(1, sizeof(Elm_Cnp_Event_Selection_Changed)); - EINA_SAFETY_ON_NULL_RETURN_VAL(_e, ECORE_CALLBACK_RENEW); - _e->type = type; - _e->seat_id = 1; - _e->exists = e.exist; - - ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, _e, NULL, NULL); - efl_event_callback_call(sel->owner, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &e); - - return ECORE_CALLBACK_RENEW; -} - -/* - * Response to a selection notify: - * - So we have asked for the selection list. - * - If it's the targets list, parse it, and fire of what we want, - * else it's the data we want. - */ -//NB: x11 does not have seat, use 1 as default -static Eina_Bool -_efl_sel_manager_x11_selection_notify(void *udata, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = udata; - Ecore_X_Event_Selection_Notify *ev = event; - Sel_Manager_Selection *sel; - Sel_Manager_Seat_Selection *seat_sel = NULL; - int i; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - seat_sel = _sel_manager_seat_selection_get(pd, 1); - if (!seat_sel) - return EINA_FALSE; - - sel_debug("selection notify callback: %d", ev->selection); - switch (ev->selection) - { - case ECORE_X_SELECTION_PRIMARY: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_PRIMARY; - break; - case ECORE_X_SELECTION_SECONDARY: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_SECONDARY; - break; - case ECORE_X_SELECTION_XDND: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_DND; - break; - case ECORE_X_SELECTION_CLIPBOARD: - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_CLIPBOARD; - break; - default: - return ECORE_CALLBACK_PASS_ON; - } - sel_debug("Target is %s", ev->target); - if (!sel->asked) return ECORE_CALLBACK_PASS_ON; - sel->asked--; - - if (ev->selection != ECORE_X_SELECTION_XDND && - (!strcmp(ev->target, "TARGETS") || !strcmp(ev->target, "ATOMS"))) - { - _x11_notify_handler_targets(pd, sel, ev); - return ECORE_CALLBACK_PASS_ON; - } - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (!strcmp(ev->target, pd->atom_list[i].name)) - { - if (pd->atom_list[i].x_data_preparer) - { - Efl_Ui_Selection_Data ddata = { 0 }; - Tmp_Info *tmp_info = NULL; - Eina_Bool success; - sel_debug("Found something: %s", pd->atom_list[i].name); - - success = pd->atom_list[i].x_data_preparer(seat_sel, ev, &ddata, &tmp_info); - sel_debug("ddata: %s (%zd)", (const char *)ddata.content.mem, ddata.content.len); - if ((pd->atom_list[i].format == EFL_UI_SELECTION_FORMAT_IMAGE) && - (seat_sel->saved_types->imgfile)) - break; - if (ev->selection == ECORE_X_SELECTION_XDND) - { - if (success) - { - Sel_Manager_Dropable *dropable; - Eina_List *l; - sel_debug("drag & drop\n"); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->obj == sel->request_obj) break; - dropable = NULL; - } - if (dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - ddata.action = sel->action; - if (!dropable->is_container) - { - sel_debug("normal dnd, not container"); - ddata.pos = seat_sel->saved_types->pos; - } - else - { - sel_debug("Drop on container"); - Eina_Position2D pos, posret = {0, 0}; - evas_object_geometry_get(dropable->obj, &pos.x, &pos.y, NULL, NULL); - //get item - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + pos.x, - seat_sel->saved_types->pos.y + pos.y); - Efl_Object *it = NULL; - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, - dropable->obj, pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - sel_debug("calling Drop event on: %p", dropable->obj); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - } - } - else - { - sel_debug("dnd: has NO dropable"); - } - } - /* We have to finish DnD, no matter what */ - ecore_x_dnd_send_finished(); - } - else if (sel->data_func && success) - { - ddata.pos.x = ddata.pos.y = 0; - sel->data_func(sel->data_func_data, sel->request_obj, &ddata); - } - free((void *)ddata.content.mem); - if (tmp_info) _tmpinfo_free(tmp_info); - } - else sel_debug("Ignored: No handler!"); - break; - } - } - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_selection_clear(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Ecore_X_Event_Selection_Clear *ev = event; - Sel_Manager_Selection *sel; - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - unsigned int i; - - if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON; - - seat_sel = _sel_manager_seat_selection_get(pd, 1); - if (!seat_sel) - return EINA_FALSE; - - for (i = EFL_UI_SELECTION_TYPE_PRIMARY; i <= EFL_UI_SELECTION_TYPE_CLIPBOARD; i++) - { - if (seat_sel->sel_list[i].ecore_sel == ev->selection) break; - } - sel_debug("selection %d clear", i); - /* Not me... Don't care */ - if (i > EFL_UI_SELECTION_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON; - - sel = seat_sel->sel_list + i; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == i)) - { - sel_debug("resolve the promise: %p", sel_lost->promise); - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - sel->active = EINA_FALSE; - sel->owner = NULL; - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_x11_general_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - sel_debug("general converter"); - Sel_Manager_Selection *sel = *(Sel_Manager_Selection **)data; - if (sel->format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(sel->data.len * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, sel->data.mem, sel->data.len); - ((char**)(data_ret))[0][sel->data.len] = 0; - } - if (size_ret) *size_ret = sel->data.len; - } - else - { - if (sel->data.mem) - { - if (data_ret) - *data_ret = eina_memdup(sel->data.mem, sel->data.len, 1); - if (size_ret) *size_ret = sel->data.len; - } - else - { - if (data_ret) *data_ret = NULL; - if (size_ret) *size_ret = 0; - } - } - return EINA_TRUE; -} - -static Eina_Bool -_x11_targets_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) -{ - int i, count; - Ecore_X_Atom *aret; - Sel_Manager_Selection *sel; - Efl_Ui_Selection_Format seltype; - - sel_debug("target converter"); - if (!data_ret) return EINA_FALSE; - - sel = *(Sel_Manager_Selection **)data; - seltype = sel->format; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++) - { - if (seltype & pd->atom_list[i].format) count++; - } - aret = malloc(sizeof(Ecore_X_Atom) * count); - if (!aret) return EINA_FALSE; - for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++) - { - if (seltype & pd->atom_list[i].format) - aret[count ++] = pd->atom_list[i].x_atom; - } - - *data_ret = aret; - if (typesize) *typesize = 32 /* urk */; - if (ttype) *ttype = ECORE_X_ATOM_ATOM; - if (size_ret) *size_ret = count; - return EINA_TRUE; -} - -static Eina_Bool -_x11_image_converter(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret EINA_UNUSED, int *size_ret EINA_UNUSED, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - sel_debug("Image converter called"); - return EINA_TRUE; -} - -static Eina_Bool -_x11_vcard_send(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED) -{ - Sel_Manager_Selection *sel; - - sel_debug("Vcard send called"); - sel = *(Sel_Manager_Selection **)data; - if (data_ret) - { - char *s; - - s = malloc(sel->data.len + 1); - if (!s) return EINA_FALSE; - memcpy(s, sel->data.mem, sel->data.len); - s[sel->data.len] = 0; - *data_ret = s; - } - - if (size_ret) *size_ret = sel->data.len; - return EINA_TRUE; -} - -static Eina_Bool -_x11_text_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) -{ - Sel_Manager_Selection *sel; - - sel = *(Sel_Manager_Selection **)data; - if (!sel) return EINA_FALSE; - - sel_debug("text converter"); - if (sel->format == EFL_UI_SELECTION_FORMAT_NONE) - { - sel_debug("none"); - if (data_ret) - { - *data_ret = malloc(sel->data.len * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, sel->data.len); - ((char**)(data_ret))[0][sel->data.len] = 0; - } - if (size_ret) *size_ret = sel->data.len; - return EINA_TRUE; - } - - if (!sel->active) return EINA_TRUE; - - if ((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *tmp = malloc(sel->data.len + 1); - if (tmp) - { - strncpy(tmp, sel->data.mem, sel->data.len); - tmp[sel->data.len] = 0; - *data_ret = _elm_util_mkup_to_text(tmp); - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - free(tmp); - sel_debug("markup or html: %s", (const char *)*data_ret); - } - else return EINA_FALSE; - } - else if (sel->format & EFL_UI_SELECTION_FORMAT_TEXT) - { - ecore_x_selection_converter_text(target, sel->data.mem, - sel->data.len, - data_ret, size_ret, - ttype, typesize); - sel_debug("text"); - } - else if (sel->format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - efl_file_simple_get(sel->request_obj, (const char **)data_ret, NULL); - if (!*data_ret) *data_ret = strdup("No file"); - else *data_ret = strdup(*data_ret); - - if (!*data_ret) - { - ERR("Failed to allocate memory!"); - *size_ret = 0; - return EINA_FALSE; - } - - *size_ret = strlen(*data_ret); - } - return EINA_TRUE; -} - -static Eina_Future * -_x11_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *owner, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, - Ecore_X_Window xwin, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Eina_Bool same_win = EINA_FALSE; - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel_list + type; - //support 1 app with multiple window, 1 selection manager - if (seat_sel->xwin == xwin) - same_win = EINA_TRUE; - _owner_change_check(pd->sel_man, owner, seat_sel, sel, type, same_win); - seat_sel->xwin = xwin; - - sel->owner = owner; - free(sel->data.mem); - sel->xwin = xwin; - sel->data = eina_slice_dup(data); - sel->active = EINA_TRUE; - sel->format = format; - - sel->set(xwin, &sel, sizeof(Sel_Manager_Selection *)); - sel_debug("data: %p (%zu)", &sel, sizeof(Sel_Manager_Selection *)); - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_x11_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_X_Window xwin, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel;; - - sel_debug("request: %p, seat: %u, type: %d, format: %d", request, seat, type, format); - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel_list + type; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - sel->request_format = format; - sel->xwin = xwin; - - if (sel->active) - { - if (sel->data.mem && - ((format == sel->format) || (xwin == 0))) - { - sel_debug("use local data"); - Efl_Ui_Selection_Data seldata; - - seldata.content.mem = sel->data.mem; - seldata.content.len = sel->data.len; - seldata.pos.x = seldata.pos.y = 0; - seldata.format = sel->format; - sel->data_func(sel->data_func_data, sel->request_obj, &seldata); - return; - } - } - - sel->asked = 2; - sel->request(xwin, ECORE_X_SELECTION_TARGET_TARGETS); -} - -static void -_x11_win_rotation_changed_cb(void *data, const Efl_Event *event) -{ - Evas_Object *win = data; - int rot = elm_win_rotation_get(event->object); - elm_win_rotation_set(win, rot); -} - -static Eina_Bool -_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Window xwin = seat_sel->xwin; - Ecore_Event_Mouse_Button *ev = event; - - if ((ev->buttons == 1) && - (ev->event_window == xwin)) - { - Eina_Bool have_drop_list = EINA_FALSE; - Eina_List *l; - Sel_Manager_Dropable *dropable; - - ecore_x_pointer_ungrab(); - ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del); - ecore_x_dnd_self_drop(); - - sel_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin); - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_FALSE); - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL); - if (seat_sel->drag_win) - { - if (seat_sel->drag_obj) - { - if (elm_widget_is(seat_sel->drag_obj)) - { - Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - efl_event_callback_del(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - - if (!seat_sel->accept) - { /* Commit animation when drag cancelled */ - /* Record final position of dragwin, then do animation */ - ecore_evas_animator_timeline_add(seat_sel->drag_win, 0.3, - _drag_cancel_animate, seat_sel); - } - else - { /* No animation drop was committed */ - Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 0); - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - sel_debug("deleted drag_win"); - } - } - - seat_sel->drag_obj = NULL; - seat_sel->accept = EINA_FALSE; - } - return EINA_TRUE; -} - -static void -_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Dnd_Drag_Pos dp; - - evas_object_move(seat_sel->drag_win, - pos->position.x - seat_sel->drag_pos.x, - pos->position.y - seat_sel->drag_pos.y); - seat_sel->drag_win_end.x = pos->position.x - seat_sel->drag_pos.x; - seat_sel->drag_win_end.y = pos->position.y - seat_sel->drag_pos.y; - sel_debug("dragevas: %p -> %p\n", - seat_sel->drag_obj, - evas_object_evas_get(seat_sel->drag_obj)); - dp.pos.x = pos->position.x; - dp.pos.y = pos->position.y; - dp.action = seat_sel->drag_action; - //for drag side - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_POS, &dp); -} - -static void -_x11_drag_target_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Selection *sel = &seat_sel->sel_list[seat_sel->active_type]; - - if (seat_sel->drag_obj == obj) - { - sel->request_obj = NULL; - seat_sel->drag_obj = NULL; - } -} - -static Eina_Bool -_x11_dnd_status(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Ecore_X_Event_Xdnd_Status *status = ev; - - seat_sel->accept = EINA_FALSE; - - /* Only thing we care about: will accept */ - if ((status) && (status->will_accept)) - { - sel_debug("Will accept\n"); - seat_sel->accept = EINA_TRUE; - } - /* Won't accept */ - else - { - sel_debug("Won't accept accept\n"); - } - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept); - - return EINA_TRUE; -} - -static void -_x11_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Format format, - Eina_Slice data, Efl_Ui_Selection_Action action, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, - Eina_Free_Cb icon_func_free_cb EINA_UNUSED, - Ecore_X_Window xwin, unsigned int seat) -{ - Ecore_X_Window xdragwin; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Evas *ee; - int x, y, x2 = 0, y2 = 0, x3, y3; - Evas_Object *icon = NULL; - int w = 0, h = 0; - int ex, ey, ew, eh; - Ecore_X_Atom actx; - int i; - int xr, yr, rot; - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return; - seat_sel->active_type = EFL_UI_SELECTION_TYPE_DND; - - sel = &seat_sel->sel_list[seat_sel->active_type]; - ecore_x_dnd_types_set(xwin, NULL, 0); - for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++) - { - if (format == EFL_UI_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format)) - { - ecore_x_dnd_type_set(xwin, pd->atom_list[i].name, EINA_TRUE); - sel_debug("set dnd type: %s\n", pd->atom_list[i].name); - } - } - - sel->active = EINA_TRUE; - sel->request_obj = drag_obj; - sel->format = format; - if (sel->data.mem) free(sel->data.mem); - sel->data = eina_slice_dup(data); - sel->action = action; - seat_sel->drag_obj = drag_obj; - seat_sel->drag_action = action; - seat_sel->xwin = xwin; - - evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL, - _x11_drag_target_del, seat_sel); - /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */ - ecore_x_dnd_aware_set(xwin, EINA_TRUE); - ecore_x_dnd_callback_pos_update_set(_x11_drag_move, seat_sel); - ecore_x_dnd_self_begin(xwin, (unsigned char *)sel, sizeof(Sel_Manager_Selection)); - actx = _x11_dnd_action_rev_map(seat_sel->drag_action); - ecore_x_dnd_source_action_set(actx); - ecore_x_pointer_grab(xwin); - seat_sel->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, - _x11_drag_mouse_up, seat_sel); - seat_sel->dnd_status_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS, - _x11_dnd_status, seat_sel); - seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); - elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE); - elm_win_override_set(seat_sel->drag_win, EINA_TRUE); - xdragwin = _x11_xwin_get(seat_sel->drag_win); - ecore_x_window_ignore_set(xdragwin, 1); - - /* dragwin has to be rotated as the main window is */ - if (elm_widget_is(drag_obj)) - { - Evas_Object *win = elm_widget_top_get(drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - { - elm_win_rotation_set(seat_sel->drag_win, elm_win_rotation_get(win)); - efl_event_callback_add(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - - if (icon_func) - { - Eina_Position2D off; - - icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off); - if (icon) - { - x2 = off.x; - y2 = off.y; - evas_object_geometry_get(icon, NULL, NULL, &w, &h); - } - } - else - { - icon = elm_icon_add(seat_sel->drag_win); - evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - // need to resize - } - elm_win_resize_object_add(seat_sel->drag_win, icon); - - /* Position subwindow appropriately */ - ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj)); - ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh); - evas_object_resize(seat_sel->drag_win, w, h); - - evas_object_show(icon); - evas_object_show(seat_sel->drag_win); - evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3); - - rot = ecore_evas_rotation_get(ee); - switch (rot) - { - case 90: - xr = y3; - yr = ew - x3; - seat_sel->drag_pos.x = y3 - y2; - seat_sel->drag_pos.y = x3 - x2; - break; - case 180: - xr = ew - x3; - yr = eh - y3; - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - break; - case 270: - xr = eh - y3; - yr = x3; - seat_sel->drag_pos.x = y3 - y2; - seat_sel->drag_pos.y = x3 - x2; - break; - default: - xr = x3; - yr = y3; - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - break; - } - x = ex + xr - seat_sel->drag_pos.x; - y = ey + yr - seat_sel->drag_pos.y; - evas_object_move(seat_sel->drag_win, x, y); - seat_sel->drag_win_start = EINA_POSITION2D(x, y); - seat_sel->drag_win_end = EINA_POSITION2D(x, y); -} - -static void -_x11_dnd_dropable_handle(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Eina_Position2D pos, Efl_Ui_Selection_Action action) -{ - Sel_Manager_Dropable *d, *last_dropable = NULL; - Eina_List *l; - Eina_Inlist *itr; - - EINA_LIST_FOREACH(pd->drop_list, l, d) - { - if (d->last.in) - { - last_dropable = d; - break; - } - } - if (last_dropable) - { - if (last_dropable == dropable) // same - { - Evas_Coord ox, oy; - Drop_Format *df; - - sel_debug("same obj dropable %p\n", dropable->obj); - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - Efl_Dnd_Drag_Pos pos_data; - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy); - pos_data.item = NULL; - } - else - { - Eina_Position2D posret = {0, 0}; - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - pos_data.pos = posret; - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - else - { - if (dropable) // leave last obj and enter new one - { - sel_debug("leave %p\n", last_dropable->obj); - sel_debug("enter %p\n", dropable->obj); - last_dropable->last.in = EINA_FALSE; - last_dropable->last.type = NULL; - dropable->last.in = EINA_TRUE; - - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format &dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - } - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - else // leave last obj - { - sel_debug("leave %p\n", last_dropable->obj); - last_dropable->last.in = EINA_FALSE; - last_dropable->last.type = NULL; - - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - } - } - else - { - if (dropable) // enter new obj - { - Evas_Coord ox, oy; - - sel_debug("enter %p\n", dropable->obj); - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - dropable->last.in = EINA_TRUE; - - Drop_Format *df; - Efl_Dnd_Drag_Pos pos_data; - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy); - pos_data.item = NULL; - } - else - { - Eina_Position2D posret = {0, 0}; - Efl_Object *it = NULL; - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - pos_data.pos = posret; - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - } - else - { - sel_debug("both dropable & last_dropable are null\n"); - } - } -} - -static Sel_Manager_Dropable * -_x11_dropable_find(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!pd->drop_list) return NULL; - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (_x11_xwin_get(dropable->obj) == win) return dropable; - } - return NULL; -} - -static Evas * -_x11_evas_get_from_xwin(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win) -{ - /* Find the Evas connected to the window */ - Sel_Manager_Dropable *dropable = _x11_dropable_find(pd, win); - return dropable ? evas_object_evas_get(dropable->obj) : NULL; -} - -static Efl_Ui_Selection_Action -_x11_dnd_action_map(Ecore_X_Atom action) -{ - Efl_Ui_Selection_Action act = EFL_UI_SELECTION_ACTION_UNKNOWN; - - if (action == ECORE_X_ATOM_XDND_ACTION_COPY) - act = EFL_UI_SELECTION_ACTION_COPY; - else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE) - act = EFL_UI_SELECTION_ACTION_MOVE; - else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE) - act = EFL_UI_SELECTION_ACTION_PRIVATE; - else if (action == ECORE_X_ATOM_XDND_ACTION_ASK) - act = EFL_UI_SELECTION_ACTION_ASK; - else if (action == ECORE_X_ATOM_XDND_ACTION_LIST) - act = EFL_UI_SELECTION_ACTION_LIST; - else if (action == ECORE_X_ATOM_XDND_ACTION_LINK) - act = EFL_UI_SELECTION_ACTION_LINK; - else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION) - act = EFL_UI_SELECTION_ACTION_DESCRIPTION; - return act; -} - -static Ecore_X_Atom -_x11_dnd_action_rev_map(Efl_Ui_Selection_Action action) -{ - Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE; - - if (action == EFL_UI_SELECTION_ACTION_COPY) - act = ECORE_X_ATOM_XDND_ACTION_COPY; - else if (action == EFL_UI_SELECTION_ACTION_MOVE) - act = ECORE_X_ATOM_XDND_ACTION_MOVE; - else if (action == EFL_UI_SELECTION_ACTION_PRIVATE) - act = ECORE_X_ATOM_XDND_ACTION_PRIVATE; - else if (action == EFL_UI_SELECTION_ACTION_ASK) - act = ECORE_X_ATOM_XDND_ACTION_ASK; - else if (action == EFL_UI_SELECTION_ACTION_LIST) - act = ECORE_X_ATOM_XDND_ACTION_LIST; - else if (action == EFL_UI_SELECTION_ACTION_LINK) - act = ECORE_X_ATOM_XDND_ACTION_LINK; - else if (action == EFL_UI_SELECTION_ACTION_DESCRIPTION) - act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION; - return act; -} - -static Eina_Bool -_x11_dnd_enter(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Enter *enter = ev; - Sel_Manager_Dropable *dropable; - int i; - - sel_debug("In"); - if (!enter) return EINA_TRUE; - dropable = _x11_dropable_find(pd, enter->win); - if (dropable) - { - sel_debug("Enter %x\n", enter->win); - } - /* Skip it */ - sel_debug("enter types=%p (%d)\n", enter->types, enter->num_types); - if ((!enter->num_types) || (!enter->types)) return EINA_TRUE; - - sel_debug("Types\n"); - seat_sel->saved_types->ntypes = enter->num_types; - free(seat_sel->saved_types->types); - seat_sel->saved_types->types = malloc(sizeof(char *) * enter->num_types); - if (!seat_sel->saved_types->types) return EINA_FALSE; - - for (i = 0; i < enter->num_types; i++) - { - seat_sel->saved_types->types[i] = eina_stringshare_add(enter->types[i]); - sel_debug("Type is %s %p %p\n", enter->types[i], - seat_sel->saved_types->types[i], pd->text_uri); - if (seat_sel->saved_types->types[i] == pd->text_uri) - { - /* Request it, so we know what it is */ - sel_debug("Sending uri request\n"); - seat_sel->saved_types->textreq = 1; - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - ecore_x_selection_xdnd_request(enter->win, pd->text_uri); - } - } - - /* FIXME: Find an object and make it current */ - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_position(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Position *xpos = ev; - Ecore_X_Rectangle rect = { 0, 0, 0, 0 }; - Sel_Manager_Dropable *dropable; - Efl_Ui_Selection_Action act; - - sel_debug("In"); - /* Need to send a status back */ - /* FIXME: Should check I can drop here */ - /* FIXME: Should highlight widget */ - dropable = _x11_dropable_find(pd, xpos->win); - if (dropable) - { - Evas_Coord ox = 0, oy = 0; - Eina_Position2D pos; - - act = _x11_dnd_action_map(xpos->action); - pos.x = xpos->position.x; - pos.y = xpos->position.y; - _dropable_coords_adjust(dropable, &pos); - Evas *evas = _x11_evas_get_from_xwin(pd, xpos->win); - Eina_List *dropable_list = evas ? _dropable_list_geom_find(pd, evas, pos.x, pos.y) : NULL; - /* check if there is dropable (obj) can accept this drop */ - if (dropable_list) - { - Efl_Ui_Selection_Format saved_format = _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes); - Eina_List *l; - Eina_Bool found = EINA_FALSE; - - EINA_LIST_FOREACH(dropable_list, l, dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - Efl_Ui_Selection_Format common_fmt = saved_format & df->format; - if (common_fmt) - { - //We found a target that can accept this type of data - int i, min_index = SELECTION_N_ATOMS; - //We have to find the first atom that corresponds to one - //of the supported data types. - for (i = 0; i < seat_sel->saved_types->ntypes; i++) - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, seat_sel->saved_types->types[i]); - if (atom && (atom->format & common_fmt)) - { - int atom_idx = (atom - pd->atom_list); - if (min_index > atom_idx) min_index = atom_idx; - } - } - if (min_index != SELECTION_N_ATOMS) - { - sel_debug("Found atom %s\n", pd->atom_list[min_index].name); - found = EINA_TRUE; - dropable->last.type = pd->atom_list[min_index].name; - dropable->last.format = common_fmt; - break; - } - } - } - if (found) break; - } - if (found) - { - Sel_Manager_Dropable *d = NULL; - Eina_Rectangle inter_rect = {0, 0, 0, 0}; - int idx = 0; - EINA_LIST_FOREACH(dropable_list, l, d) - { - if (idx == 0) - { - evas_object_geometry_get(d->obj, &inter_rect.x, &inter_rect.y, - &inter_rect.w, &inter_rect.h); - } - else - { - Eina_Rectangle cur_rect; - evas_object_geometry_get(d->obj, &cur_rect.x, &cur_rect.y, - &cur_rect.w, &cur_rect.h); - if (!eina_rectangle_intersection(&inter_rect, &cur_rect)) continue; - } - idx++; - } - rect.x = inter_rect.x; - rect.y = inter_rect.y; - rect.width = inter_rect.w; - rect.height = inter_rect.h; - ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position %i %i %p\n", pos.x - ox, pos.y - oy, dropable); - pos.x = pos.x - ox; - pos.y = pos.y - oy; - _x11_dnd_dropable_handle(pd, dropable, pos, act); - // CCCCCCC: call dnd exit on last obj if obj != last - // CCCCCCC: call drop position on obj - } - else - { - //if not: send false status - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y); - _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act); - // CCCCCCC: call dnd exit on last obj - } - eina_list_free(dropable_list); - } - else - { - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - sel_debug("dnd position (%d, %d) has no drop\n", pos.x, pos.y); - _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act); - } - } - else - { - ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action); - } - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_leave(void *data, int etype EINA_UNUSED, void *ev) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - Eina_Position2D pos = {0, 0}; -#ifdef DEBUGON - sel_debug("Leave %x\n", ((Ecore_X_Event_Xdnd_Leave *)ev)->win); -#else - (void)ev; -#endif - _x11_dnd_dropable_handle(seat_sel->pd, NULL, pos, EFL_UI_SELECTION_ACTION_UNKNOWN); - // CCCCCCC: call dnd exit on last obj if there was one - // leave->win leave->source - return EINA_TRUE; -} - -static Eina_Bool -_x11_dnd_drop(void *data, int etype EINA_UNUSED, void *ev) -{ - sel_debug("In"); - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Ecore_X_Event_Xdnd_Drop *drop; - Sel_Manager_Dropable *dropable = NULL; - Evas_Coord x = 0, y = 0; - Efl_Ui_Selection_Action act = EFL_UI_SELECTION_ACTION_UNKNOWN; - Eina_List *l; - Sel_Manager_Selection *sel; - - drop = ev; - sel_debug("drop_list %p (%d)\n", pd->drop_list, eina_list_count(pd->drop_list)); - if (!(dropable = _x11_dropable_find(pd, drop->win))) return EINA_TRUE; - - /* Calculate real (widget relative) position */ - // - window position - // - widget position - seat_sel->saved_types->pos = EINA_POSITION2D(drop->position.x, drop->position.y); - _dropable_coords_adjust(dropable, &seat_sel->saved_types->pos); - - sel_debug("Drop position is %d,%d\n", seat_sel->saved_types->pos.x, seat_sel->saved_types->pos.y); - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->last.in) - { - evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL); - seat_sel->saved_types->pos.x -= x; - seat_sel->saved_types->pos.y -= y; - goto found; - } - } - - sel_debug("Didn't find a target\n"); - return EINA_TRUE; - -found: - sel_debug("0x%x\n", drop->win); - - act = _x11_dnd_action_map(drop->action); - - dropable->last.in = EINA_FALSE; - sel_debug("Last type: %s - Last format: %X\n", dropable->last.type, dropable->last.format); -#if 0 // this seems to be broken and causes dnd to stop working e.g. to/from - // rage even though iut used to work fine. - Efl_Ui_Selection_Data ddata; - Eina_Inlist *itr; - if ((!strcmp(dropable->last.type, pd->text_uri))) - { - sel_debug("We found a URI... (%scached) %s\n", - seat_sel->saved_types->imgfile ? "" : "not ", - seat_sel->saved_types->imgfile); - if (seat_sel->saved_types->imgfile) - { - Drop_Format *df; - - if (!dropable->is_container) - { - ddata.pos = seat_sel->saved_types->pos; - ddata.item = NULL; - } - else - { - //for container - Efl_Object *it = NULL; - Evas_Coord x0 = 0, y0 = 0; - Eina_Position2D pos, posret = {0, 0}; - - evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL); - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0, - seat_sel->saved_types->pos.y + y0); - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - ddata.action = act; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - sel_debug("Doing image insert (%s)\n", seat_sel->saved_types->imgfile); - ddata.format = EFL_UI_SELECTION_FORMAT_IMAGE; - ddata.content.mem = (char *)seat_sel->saved_types->imgfile; - ddata.content.len = strlen(ddata.content.mem); - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - else - { - sel_debug("Item doesn't support images... passing\n"); - } - } - ecore_x_dnd_send_finished(); - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - return EINA_TRUE; - } - else if (seat_sel->saved_types->textreq) - { - /* Already asked: Pretend we asked now, and paste immediately when - * it comes in */ - seat_sel->saved_types->textreq = 0; - ecore_x_dnd_send_finished(); - return EINA_TRUE; - } - } -#endif - sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_DND; - sel_debug("doing a request then: %s\n", dropable->last.type); - sel->xwin = drop->win; - sel->request_obj = dropable->obj; - sel->request_format = dropable->last.format; - sel->active = EINA_TRUE; - sel->action = act; - sel->asked++; - ecore_x_selection_xdnd_request(drop->win, dropable->last.type); - - return EINA_TRUE; -} - -static Eina_Bool -_x11_sel_manager_drop_target_add(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *target_obj, - Efl_Ui_Selection_Format format, Ecore_X_Window xwin, - unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Eina_List *l; - Eina_Bool have_drop_list = EINA_FALSE; - Sel_Manager_Seat_Selection *seat_sel = NULL; - - /* Is this the first? */ - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - dropable = NULL; // In case of error, we don't want to free it - - - Drop_Format *df = calloc(1, sizeof(Drop_Format)); - if (!df) return EINA_FALSE; - df->format = format; - - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (!dropable) - { - /* Create new drop */ - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) goto error; - dropable->last.in = EINA_FALSE; - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) goto error; - dropable->obj = target_obj; - efl_key_data_set(target_obj, "__elm_dropable", dropable); - } - dropable->format_list = eina_inlist_append(dropable->format_list, EINA_INLIST_GET(df)); - dropable->seat = seat; - - evas_object_event_callback_add(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del, pd); - if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_TRUE); - - seat_sel = _x11_sel_manager_seat_selection_init(pd, seat); - - if (seat_sel->enter_handler) return EINA_TRUE; - sel_debug("Adding drop target calls xwin=%#llx", (unsigned long long)xwin); - seat_sel->enter_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER, - _x11_dnd_enter, seat_sel); - seat_sel->leave_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE, - _x11_dnd_leave, seat_sel); - seat_sel->pos_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION, - _x11_dnd_position, seat_sel); - seat_sel->drop_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP, - _x11_dnd_drop, seat_sel); - return EINA_TRUE; -error: - free(df); - free(dropable); - return EINA_FALSE; -} - -#endif - -//Wayland -#ifdef HAVE_ELEMENTARY_WL2 -static Sel_Manager_Seat_Selection * -_wl_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } - - return seat_sel; -} - -static void -_wl_drag_source_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel = data; - if (seat_sel->drag_obj == obj) - seat_sel->drag_obj = NULL; -} - -static void -_wl_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, Efl_Object *drag_obj, - Efl_Ui_Selection_Format format, Eina_Slice data, - Efl_Ui_Selection_Action action, void *icon_func_data, - Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb EINA_UNUSED, - Ecore_Wl2_Window *win, unsigned int seat) -{ - Ecore_Evas *ee; - Evas_Object *icon = NULL; - int x, y, x2 = 0, y2 = 0, x3, y3, w = 0, h = 0; - const char *types[SELECTION_N_ATOMS + 1]; - int i, nb_types = 0; - Ecore_Wl2_Window *parent = NULL; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - sel_debug("In"); - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return; - seat_sel->active_type = EFL_UI_SELECTION_TYPE_DND; - sel = seat_sel->sel; - - sel_debug("checking drag_win: %p", seat_sel->drag_win); - /* if we already have a drag, get out */ - if (seat_sel->drag_win) return; - - for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++) - { - if (format == EFL_UI_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format)) - { - types[nb_types++] = pd->atom_list[i].name; - sel_debug("set dnd type: %s\n", pd->atom_list[i].name); - } - } - types[nb_types] = NULL; - - ecore_wl2_dnd_drag_types_set(_wl_seat_get(win, drag_obj, seat), types); - - /* set the drag data used when a drop occurs */ - free(sel->data.mem); - sel->data.len = 0; - sel->data = eina_slice_dup(data); - - /* setup callback to notify if this object gets deleted */ - evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL, - _wl_drag_source_del, sel); - - seat_sel->drag_obj = drag_obj; - seat_sel->drag_action = action; - - seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND); - elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE); - elm_win_borderless_set(seat_sel->drag_win, EINA_TRUE); - elm_win_override_set(seat_sel->drag_win, EINA_TRUE); - - win = elm_win_wl_window_get(seat_sel->drag_win); - - if (icon_func) - { - Eina_Position2D off; - - icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off); - if (icon) - { - x2 = off.x; - y2 = off.y; - evas_object_geometry_get(icon, NULL, NULL, &w, &h); - } - } - else - { - icon = elm_icon_add(seat_sel->drag_win); - evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, - EVAS_HINT_EXPAND); - } - - elm_win_resize_object_add(seat_sel->drag_win, icon); - evas_object_show(icon); - - /* Position subwindow appropriately */ - ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj)); - ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); - x += x2; - y += y2; - seat_sel->drag_win_start.x = seat_sel->drag_win_end.x = x; - seat_sel->drag_win_start.y = seat_sel->drag_win_end.y = y; - - evas_object_geometry_set(seat_sel->drag_win, x, y, w, h); - evas_object_show(seat_sel->drag_win); - - evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3); - seat_sel->drag_pos.x = x3 - x2; - seat_sel->drag_pos.y = y3 - y2; - - if (elm_widget_is(drag_obj)) - { - Evas_Object *top; - - top = elm_widget_top_get(drag_obj); - if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(drag_obj)); - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - parent = elm_win_wl_window_get(top); - } - if (!parent) - { - Evas *evas; - - if (!(evas = evas_object_evas_get(drag_obj))) - return; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return; - - parent = ecore_evas_wayland2_window_get(ee); - } - - sel->drag_serial = ecore_wl2_dnd_drag_start(_wl_seat_get(win, drag_obj, seat), parent, win); -} - -static Eina_Bool -_wl_is_uri_type_data(const char *data, int len) -{ - char *p; - if (len < 6) return EINA_FALSE; - - p = (char *)data; - if (!p) return EINA_FALSE; - if (strncmp(p, "file:/", 6)) - { - if (*p != '/') return EINA_FALSE; - } - return EINA_TRUE; -} - -static Efl_Ui_Selection_Action -_wl_to_elm(Ecore_Wl2_Drag_Action action) -{ - #define CONV(wl, elm) if (action == wl) return elm; - CONV(ECORE_WL2_DRAG_ACTION_COPY, EFL_UI_SELECTION_ACTION_COPY); - CONV(ECORE_WL2_DRAG_ACTION_MOVE, EFL_UI_SELECTION_ACTION_MOVE); - CONV(ECORE_WL2_DRAG_ACTION_ASK, EFL_UI_SELECTION_ACTION_ASK); - #undef CONV - return EFL_UI_SELECTION_ACTION_UNKNOWN; -} - -static Eina_Bool -_wl_targets_converter(char *target, Sel_Manager_Selection *sel, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret) -{ - sel_debug("in\n"); - if (!data_ret) return EINA_FALSE; - - const char *sep = "\n"; - char *aret; - int len = 0; - int i = 0; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Eina_Bool is_uri = EINA_FALSE; - - if (sel->format) - { - format = sel->format; - is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len); - } - else - { - Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - } - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - len += strlen(pd->atom_list[i].name) + strlen(sep); - } - } - len++; //terminating null byte - aret = calloc(1, len * sizeof(char)); - if (!aret) return EINA_FALSE; - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - { - aret = strcat(aret, pd->atom_list[i].name); - aret = strcat(aret, sep); - } - } - } - *data_ret = aret; - if (size_ret) *size_ret = len; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_general_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret) -{ - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Sel_Manager_Atom *atom = NULL; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - sel_debug("in\n"); - - atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - if (format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(size * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, size); - ((char**)(data_ret))[0][size] = 0; - } - if (size_ret) *size_ret = size; - } - else - { - if ((data) && (size > 0)) - { - char *tmp = malloc(size); - if (tmp) - { - memcpy(tmp, data, size); - if (data_ret) *data_ret = tmp; - if (size_ret) *size_ret = size; - if (!data_ret) free(tmp); - } - } - else - { - if (data_ret) *data_ret = NULL; - if (size_ret) *size_ret = 0; - } - } - - return EINA_TRUE; -} - -static Eina_Bool -_wl_text_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret) -{ - Efl_Ui_Selection_Format format = EFL_UI_SELECTION_FORMAT_NONE; - Sel_Manager_Atom *atom = NULL; - Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - - sel_debug("in\n"); - - atom = eina_hash_find(pd->type_hash, target); - if (atom) - format = atom->format; - if (format == EFL_UI_SELECTION_FORMAT_NONE) - { - if (data_ret) - { - *data_ret = malloc(size * sizeof(char) + 1); - if (!*data_ret) return EINA_FALSE; - memcpy(*data_ret, data, size); - ((char**)(data_ret))[0][size] = 0; - if (size_ret) *size_ret = size; - return EINA_TRUE; - } - } - else if ((format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *tmp = malloc(size + 1); - if (tmp) - { - strncpy(tmp, data, size); - tmp[size] = 0; - *data_ret = _elm_util_mkup_to_text(tmp); - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - free(tmp); - } - else return EINA_FALSE; - } - else if (format & EFL_UI_SELECTION_FORMAT_TEXT) - { - char *tmp = malloc(size + 1); - if (tmp) - { - strncpy(tmp, data, size); - tmp[size] = 0; - *data_ret = tmp; - if (size_ret && *data_ret) *size_ret = strlen(*data_ret); - } - else return EINA_FALSE; - } - else if (format & EFL_UI_SELECTION_FORMAT_IMAGE) - { - sel_debug("Image %s\n", evas_object_type_get(sel->request_obj)); - efl_file_simple_get(sel->request_obj, (const char **)data_ret, NULL); - if (!*data_ret) *data_ret = strdup("No file"); - else *data_ret = strdup(*data_ret); - - if (!*data_ret) - { - ERR("Failed to allocate memory!"); - *size_ret = 0; - return EINA_FALSE; - } - - if (size_ret) *size_ret = strlen(*data_ret); - } - return EINA_TRUE; -} - -static void -_wl_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) - { - sel->owner = NULL; - } - //if (dragwidget == obj) dragwidget = NULL; -} - -static Eina_Future * -_wl_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Wl2_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - int i = 0, count = 0; - Eina_Bool is_uri = EINA_FALSE; - const char **types; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - - if (data.len <= 0) - return NULL; - - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel; - - if (sel->owner != owner) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - } - - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _wl_sel_obj_del, sel); - sel->active = EINA_TRUE; - sel->owner = owner; - sel->win = win; - /* sel->set(win, &selection, sizeof(Elm_Sel_Type)); */ - sel->format = format; - - evas_object_event_callback_add - (sel->owner, EVAS_CALLBACK_DEL, _wl_sel_obj_del, &sel); - - sel->data = eina_slice_dup(data); - if (!sel->data.mem) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len); - types = malloc(sizeof(char *)); - if (!types) return NULL; - for (i = 0, count = 1; i < SELECTION_N_ATOMS; i++) - { - if (format & pd->atom_list[i].format) - { - if ((is_uri) || - ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list"))) - { - const char **t = NULL; - - types[count - 1] = pd->atom_list[i].name; - count++; - t = realloc(types, sizeof(char *) * count); - if (!t) - { - free(types); - return NULL; - } - types = t; - } - } - } - types[count - 1] = 0; - - sel->selection_serial = ecore_wl2_dnd_selection_set(_wl_seat_get(win, owner, seat_sel->seat), types); - DBG("serial: %d", sel->selection_serial); - - free(types); - //return _local_elm_cnp_selection_set(obj, selection, format, buf, buflen); - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_wl_selection_changed_free(void *data, void *ev) -{ - ecore_wl2_display_disconnect(data); - - free(ev); -} - -static Eina_Bool -_wl_selection_changed(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - Elm_Cnp_Event_Selection_Changed *_e; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Efl_Ui_Selection_Changed e; - Ecore_Wl2_Event_Seat_Selection *ev = event; - Ecore_Wl2_Input *seat; - - seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat); - sel_debug("seat: %d", ev->seat); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel; - - seat = ecore_wl2_display_input_find(ev->display, ev->seat); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, ECORE_CALLBACK_RENEW); - e.type = EFL_UI_SELECTION_TYPE_CLIPBOARD; - e.seat = ev->seat; - /* connect again to add ref */ - e.display = ecore_wl2_display_connect(ecore_wl2_display_name_get(ev->display)); - e.exist = !!ecore_wl2_dnd_selection_get(seat); - - _e = calloc(1, sizeof(Elm_Cnp_Event_Selection_Changed)); - EINA_SAFETY_ON_NULL_RETURN_VAL(_e, ECORE_CALLBACK_RENEW); - _e->type = e.type; - _e->seat_id = e.seat; - _e->display = e.display; - _e->exists = e.exist; - - ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, _e, _wl_selection_changed_free, ev->display); - efl_event_callback_call(sel->request_obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &e); - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_wl_selection_send(void *data, int type EINA_UNUSED, void *event) -{ - Efl_Ui_Selection_Manager_Data *pd = data; - char *buf; - int ret, len_remained; - int len_written = 0; - Ecore_Wl2_Event_Data_Source_Send *ev; - int seat; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - void *data_ret = NULL; - int len_ret = 0; - int i = 0; - - ev = event; - seat = ev->seat; - sel_debug("seat: %d, type: %d", seat, type); - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - if (!seat_sel) return ECORE_CALLBACK_RENEW; - sel = seat_sel->sel; - - if ((ev->serial != sel->selection_serial) && - (ev->serial != sel->drag_serial)) - return ECORE_CALLBACK_RENEW; - - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - if (!strcmp(pd->atom_list[i].name, ev->type)) - { - sel_debug("Found a type: %s\n", pd->atom_list[i].name); - Sel_Manager_Dropable *drop; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) - drop->last.type = pd->atom_list[i].name; - if (pd->atom_list[i].wl_converter) - { - pd->atom_list[i].wl_converter(ev->type, sel, sel->data.mem, - sel->data.len, &data_ret, &len_ret); - } - else - { - data_ret = eina_memdup(sel->data.mem, sel->data.len, 0); - len_ret = sel->data.len; - } - break; - } - } - - len_remained = len_ret; - buf = data_ret; - - while (len_written < len_ret) - { - ret = write(ev->fd, buf, len_remained); - if (ret == -1) break; - buf += ret; - len_written += ret; - len_remained -= ret; - } - free(data_ret); - - close(ev->fd); - ecore_wl2_display_flush(ev->display); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_end(void *data, int type EINA_UNUSED, void *event) -{ - sel_debug("In"); - Efl_Ui_Selection_Manager_Data *pd = data; - Ecore_Wl2_Event_Data_Source_End *ev; - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - ev = event; - seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat); - sel = seat_sel->sel; - if (ev->serial != sel->drag_serial) - return ECORE_CALLBACK_RENEW; - - if (seat_sel->active_type != EFL_UI_SELECTION_TYPE_DND) - return ECORE_CALLBACK_RENEW; - - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL); - if (seat_sel->drag_win) - { - if (!seat_sel->accept) - { - /* Commit animation when drag cancelled */ - /* Record final position of dragwin, then do animation */ - ecore_evas_animator_timeline_add(seat_sel->drag_win, 0.3, _drag_cancel_animate, seat_sel); - } - else - { - /* No animation drop was committed */ - evas_object_del(seat_sel->drag_win); - seat_sel->drag_win = NULL; - } - } - - seat_sel->accept = EINA_FALSE; - - ecore_wl2_display_flush(ev->display); - return ECORE_CALLBACK_PASS_ON; -} - -static Ecore_Wl2_Input * -_wl_seat_get(Ecore_Wl2_Window *win, Evas_Object *obj, unsigned int seat_id) -{ - Eo *seat, *parent2, *ewin; - Ecore_Wl2_Input *input = NULL; - - input = ecore_wl2_display_input_find(ecore_wl2_window_display_get(win), seat_id); - if (input) return input; - - if (obj) - { - // FIXME (there might be a better solution): - // In case of inwin, we want to use the main wl2 window for cnp, but obj - // obj belongs to the buffer canvas, so the default seat for obj does not - // match the window win. - Eo *top = elm_widget_top_get(obj); - if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS)) - { - parent2 = efl_ui_win_inlined_parent_get(top); - if (parent2) obj = elm_widget_top_get(parent2) ?: parent2; - } - /* fake win means canvas seat id will not match protocol seat id */ - ewin = elm_win_get(obj); - if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL; - } - - if (!obj) - { - Eina_Iterator *it; - it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win)); - EINA_ITERATOR_FOREACH(it, input) break; - eina_iterator_free(it); - return input; - } - - seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT); - EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL); - return ecore_wl2_display_input_find(ecore_wl2_window_display_get(win), - evas_device_seat_id_get(seat)); -} - -Ecore_Wl2_Window * -_wl_window_get(const Evas_Object *obj) -{ - Evas_Object *top; - Ecore_Wl2_Window *win = NULL; - - if (elm_widget_is(obj)) - { - top = elm_widget_top_get(obj); - if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj)); - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - win = elm_win_wl_window_get(top); - } - if (!win) - { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; - - if (!(evas = evas_object_evas_get(obj))) - return NULL; - if (!(ee = ecore_evas_ecore_evas_get(evas))) - return NULL; - - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - engine_name = ecore_evas_engine_name_get(ee); - } - if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1)) - { - /* In case the engine is not a buffer, we want to check once. */ - win = ecore_evas_wayland2_window_get(ee); - if (!win) return NULL; - } - } - - return win; -} - -static void -_wl_selection_receive_timeout(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - - if (sel->request_obj != obj) return; - - ecore_event_handler_del(sel->offer_handler); -} - -static Eina_Bool -_wl_selection_receive(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Offer_Data_Ready *ev = event; - Sel_Manager_Selection *sel = data; - - if (sel->sel_offer != ev->offer) return ECORE_CALLBACK_PASS_ON; - - if (sel->data_func) - { - Efl_Ui_Selection_Data sel_data; - - sel_data.pos.x = sel_data.pos.y = 0; - if (((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) && - (sel->want_format == EFL_UI_SELECTION_FORMAT_TEXT)) - { - char *tmp = malloc(ev->len + 1); - sel_data.format = sel->format; - sel_data.content.mem = NULL; - sel_data.content.len = 0; - if (tmp) - { - sel_data.format = sel->want_format; - strncpy(tmp, ev->data, ev->len); - tmp[ev->len] = 0; - sel_data.content.mem = _elm_util_mkup_to_text(tmp); - if (sel_data.content.mem) - sel_data.content.len = strlen(sel_data.content.mem); - free(tmp); - } - } - else - { - sel_data.format = sel->format; - sel_data.content.mem = ev->data; - sel_data.content.len = ev->len; - } - sel_data.action = _wl_to_elm(ecore_wl2_offer_action_get(sel->sel_offer)); - sel->data_func(sel->data_func_data, - sel->request_obj, - &sel_data); - } - else - { - char *stripstr, *mkupstr; - - stripstr = malloc(ev->len + 1); - if (!stripstr) return ECORE_CALLBACK_CANCEL; - strncpy(stripstr, (char *)ev->data, ev->len); - stripstr[ev->len] = '\0'; - mkupstr = _elm_util_text_to_mkup((const char *)stripstr); - /* TODO BUG: should never NEVER assume it's an elm_entry! */ - _elm_entry_entry_paste(sel->request_obj, mkupstr); - free(stripstr); - free(mkupstr); - } - - evas_object_event_callback_del_full(sel->request_obj, - EVAS_CALLBACK_DEL, - _wl_selection_receive_timeout, sel); - - ecore_event_handler_del(sel->offer_handler); - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_wl_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_Wl2_Window *win, unsigned int seat) -{ - sel_debug("In, format: %d", format); - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Wl2_Input *input; - Ecore_Wl2_Offer *offer; - int i = 0; - - if (type == EFL_UI_SELECTION_TYPE_DND) return EINA_FALSE; - - //if (sel->active) - //return _local_elm_cnp_selection_get(obj, selection, format, datacb, udata); - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - - input = _wl_seat_get(win, (Efl_Object *)request, seat_sel->seat); - offer = ecore_wl2_dnd_selection_get(input); - - //there can be no selection available - if (!offer) return EINA_FALSE; - - for (i = 0; sm_wl_convertion[i].translates; i++) - { - int j = 0; -// if (!(format & sm_wl_convertion[i].format)) continue; - - for (j = 0; sm_wl_convertion[i].translates[j]; j++) - { - if (!ecore_wl2_offer_supports_mime(offer, sm_wl_convertion[i].translates[j])) continue; - - //we have found matching mimetypes - sel->sel_offer = offer; - sel->format = sm_wl_convertion[i].format; - sel->want_format = format; - - sel_debug("request type: %s", (char *)sm_wl_convertion[i].translates[j]); - evas_object_event_callback_add(sel->request_obj, EVAS_CALLBACK_DEL, - _wl_selection_receive_timeout, sel); - sel->offer_handler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, - _wl_selection_receive, sel); - - ecore_wl2_offer_receive(offer, (char*)sm_wl_convertion[i].translates[j]); - ecore_wl2_display_flush(ecore_wl2_input_display_get(input)); - return EINA_TRUE; - } - } - - sel_debug("no type match"); - return EINA_FALSE; -} - -static void -_wl_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static Sel_Manager_Dropable * -_wl_dropable_find(Efl_Ui_Selection_Manager_Data *pd, Ecore_Wl2_Window *win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!pd->drop_list) return NULL; - - if (!win) return NULL; - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - if (_wl_window_get(dropable->obj) == win) - return dropable; - - return NULL; -} - -static Evas * -_wl_evas_get_from_win(Efl_Ui_Selection_Manager_Data *pd, Ecore_Wl2_Window *win) -{ - Sel_Manager_Dropable *dropable = _wl_dropable_find(pd, win); - return dropable ? evas_object_evas_get(dropable->obj) : NULL; -} - -static Eina_Bool -_wl_drops_accept(Sel_Manager_Seat_Selection *seat_sel, const char *type) -{ - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Selection *sel; - Eina_List *l; - Sel_Manager_Dropable *drop; - Eina_Bool will_accept = EINA_FALSE; - - if (!type) return EINA_FALSE; - - pd = seat_sel->pd; - sel = seat_sel->sel; - EINA_LIST_FOREACH(pd->drop_list, l, drop) - { - Drop_Format *df; - EINA_INLIST_FOREACH(drop->format_list, df) - { - for (int i = 0; sm_wl_convertion[i].translates ; ++i) - { - if (!(sm_wl_convertion[i].format & df->format)) continue; - - for (int j = 0; sm_wl_convertion[i].translates[j]; ++j) - { - if (!strncmp(type, sm_wl_convertion[i].translates[j], strlen(sm_wl_convertion[i].translates[j]))) - { - sel->request_obj = drop->obj; - return EINA_TRUE; - } - } - } - } - } - - return will_accept; -} - -static void -_wl_selection_parser(void *_data, int size, char ***ret_data, int *ret_count) -{ - char **files = NULL; - int num_files = 0; - char *data = NULL; - - data = malloc(size); - if (data && (size > 0)) - { - int i, is; - char *tmp; - char **t2; - - memcpy(data, _data, size); - if (data[size - 1]) - { - char *t; - - /* Isn't nul terminated */ - size++; - t = realloc(data, size); - if (!t) goto done; - data = t; - data[size - 1] = 0; - } - - tmp = malloc(size); - if (!tmp) goto done; - i = 0; - is = 0; - while ((is < size) && (data[is])) - { - if ((i == 0) && (data[is] == '#')) - for (; ((data[is]) && (data[is] != '\n')); is++) ; - else - { - if ((data[is] != '\r') && (data[is] != '\n')) - tmp[i++] = data[is++]; - else - { - while ((data[is] == '\r') || (data[is] == '\n')) - is++; - tmp[i] = 0; - num_files++; - t2 = realloc(files, num_files * sizeof(char *)); - if (t2) - { - files = t2; - files[num_files - 1] = strdup(tmp); - } - else - { - num_files--; - goto freetmp; - } - tmp[0] = 0; - i = 0; - } - } - } - if (i > 0) - { - tmp[i] = 0; - num_files++; - t2 = realloc(files, num_files * sizeof(char *)); - if (t2) - { - files = t2; - files[num_files - 1] = strdup(tmp); - } - else - { - num_files--; - goto freetmp; - } - } -freetmp: - free(tmp); - } -done: - free(data); - if (ret_data) *ret_data = files; - else - { - int i; - - for (i = 0; i < num_files; i++) free(files[i]); - free(files); - } - if (ret_count) *ret_count = num_files; -} - -static Eina_Bool -_wl_data_preparer_markup(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_MARKUP; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_uri(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - Sel_Manager_Seat_Selection *seat_sel; - char *p, *stripstr = NULL; - char *data = ev->data; - Sel_Manager_Dropable *drop; - const char *type = NULL; - - sel_debug("In\n"); - - seat_sel = sel->seat_sel; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) type = drop->last.type; - - if ((type) && (!strcmp(type, "text/uri-list"))) - { - int num_files = 0; - char **files = NULL; - Efreet_Uri *uri; - Eina_Strbuf *strbuf; - int i; - - strbuf = eina_strbuf_new(); - if (!strbuf) return EINA_FALSE; - - _wl_selection_parser(ev->data, ev->len, &files, &num_files); - sel_debug("got a files list\n"); - - for (i = 0; i < num_files; i++) - { - uri = efreet_uri_decode(files[i]); - if (uri) - { - eina_strbuf_append(strbuf, uri->path); - efreet_uri_free(uri); - } - else - { - eina_strbuf_append(strbuf, files[i]); - } - if (i < (num_files - 1)) - eina_strbuf_append(strbuf, "\n"); - free(files[i]); - } - free(files); - stripstr = eina_strbuf_string_steal(strbuf); - eina_strbuf_free(strbuf); - } - else - { - Efreet_Uri *uri; - - p = (char *)eina_memdup((unsigned char *)data, ev->len, EINA_TRUE); - if (!p) return EINA_FALSE; - uri = efreet_uri_decode(p); - if (!uri) - { - /* Is there any reason why we care of URI without scheme? */ - if (p[0] == '/') stripstr = p; - else free(p); - } - else - { - free(p); - stripstr = strdup(uri->path); - efreet_uri_free(uri); - } - } - - if (!stripstr) - { - sel_debug("Couldn't find a file\n"); - return EINA_FALSE; - } - free(seat_sel->saved_types->imgfile); - - ddata->content.mem = stripstr; - ddata->content.len = strlen(stripstr); - ddata->action = sel->action; - ddata->format = sel->request_format; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_vcard(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_VCARD; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_image(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info) -{ - sel_debug("In\n"); - Tmp_Info *tmp; - int len = 0; - - tmp = _tempfile_new(ev->len); - if (!tmp) - return EINA_FALSE; - memcpy(tmp->map, ev->data, ev->len); - munmap(tmp->map, ev->len); - - len = strlen(tmp->filename); - ddata->format = EFL_UI_SELECTION_FORMAT_IMAGE; - ddata->content.mem = eina_memdup((unsigned char*)tmp->filename, len, EINA_TRUE); - ddata->content.len = len; - ddata->action = sel->action; - *tmp_info = tmp; - - return EINA_TRUE; -} - -static Eina_Bool -_wl_data_preparer_text(Sel_Manager_Selection *sel, Efl_Ui_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED) -{ - sel_debug("In\n"); - - ddata->format = EFL_UI_SELECTION_FORMAT_TEXT; - ddata->content.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE); - ddata->content.len = ev->len; - ddata->action = sel->action; - - return EINA_TRUE; -} - - -static void -_wl_dropable_handle(Sel_Manager_Seat_Selection *seat_sel, Sel_Manager_Dropable *dropable, Evas_Coord x, Evas_Coord y) -{ - Sel_Manager_Dropable *d, *last_dropable = NULL; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Sel_Manager_Selection *sel; - Eina_Inlist *itr; - Eina_List *l; - Eina_Position2D pos; - - EINA_LIST_FOREACH(pd->drop_list, l, d) - { - if (d->last.in) - { - last_dropable = d; - break; - } - } - - sel = seat_sel->sel; - pos = EINA_POSITION2D(x, y); - /* If we are on the same object, just update the position */ - if ((dropable) && (last_dropable == dropable)) - { - Evas_Coord ox, oy; - Efl_Dnd_Drag_Pos pos_data; - Drop_Format *df; - - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(x - ox, y - oy); - pos_data.item = NULL; - } - else - { - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &pos_data.pos); - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = sel->action; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - - return; - } - /* We leave the last dropable */ - if (last_dropable) - { - Drop_Format *df; - sel_debug("leave %p\n", last_dropable->obj); - last_dropable->last.in = EINA_FALSE; - - EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df) - { - if (df->format & last_dropable->last.format) - efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL); - } - } - /* We enter the new dropable */ - if (dropable) - { - sel_debug("enter %p\n", dropable->obj); - Evas_Coord ox, oy; - Efl_Dnd_Drag_Pos pos_data; - Drop_Format *df; - - dropable->last.in = EINA_TRUE; - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - if (!dropable->is_container) - { - pos_data.pos = EINA_POSITION2D(x - ox, y - oy); - pos_data.item = NULL; - } - else - { - Efl_Object *it = NULL; - - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &pos_data.pos); - pos_data.item = it; - } - pos_data.format = dropable->last.format; - pos_data.action = sel->action; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - { - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL); - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data); - } - } - } -} - -static void -_wl_dropable_all_clean(Sel_Manager_Seat_Selection *seat_sel, Ecore_Wl2_Window *win) -{ - Eina_List *l; - Sel_Manager_Dropable *dropable; - - if (!win) return; - - EINA_LIST_FOREACH(seat_sel->pd->drop_list, l, dropable) - { - if (_wl_window_get(dropable->obj) == win) - { - dropable->last.pos.x = 0; - dropable->last.pos.y = 0; - dropable->last.in = EINA_FALSE; - } - } -} - -static void -_wl_dropable_data_handle(Sel_Manager_Selection *sel, Ecore_Wl2_Event_Offer_Data_Ready *ev) -{ - Sel_Manager_Seat_Selection *seat_sel; - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Dropable *drop; - Ecore_Wl2_Window *win; - - sel_debug("In\n"); - seat_sel = sel->seat_sel; - pd = seat_sel->pd; - drop = efl_key_data_get(sel->request_obj, "__elm_dropable"); - if (drop) - { - Sel_Manager_Atom *atom = NULL; - - atom = eina_hash_find(pd->type_hash, drop->last.type); - if (atom && atom->wl_data_preparer) - { - Efl_Ui_Selection_Data ddata; - Tmp_Info *tmp_info = NULL; - Eina_Bool success; - - sel_debug("Call notify for: %s\n", atom->name); - success = atom->wl_data_preparer(sel, &ddata, ev, &tmp_info); - if (success) - { - Sel_Manager_Dropable *dropable; - Eina_List *l; - - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (dropable->obj == sel->request_obj) break; - dropable = NULL; - } - if (dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - if (!dropable->is_container) - { - ddata.pos.x = seat_sel->saved_types->pos.x; - ddata.pos.y = seat_sel->saved_types->pos.y; - } - else - { - //for container - Efl_Object *it = NULL; - Evas_Coord x0 = 0, y0 = 0; - Eina_Position2D pos, posret = {}; - - evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL); - pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0, - seat_sel->saved_types->pos.y + y0); - if (dropable->item_func) - it = dropable->item_func(dropable->item_func_data, dropable->obj, - pos, &posret); - ddata.pos = posret; - ddata.item = it; - } - ddata.action = seat_sel->drag_action; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format & dropable->last.format) - efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata); - } - } - } - win = _wl_window_get(sel->request_obj); - ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat)); - if (tmp_info) _tmpinfo_free(tmp_info); - return; - } - } - - win = _wl_window_get(sel->request_obj); - ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat)); - seat_sel->saved_types->textreq = 0; -} - -static Eina_Bool -_wl_dnd_enter(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Enter *ev; - Eina_Array *known, *available; - Sel_Manager_Seat_Selection *seat_sel = data; - unsigned int i = 0; - - ev = event; - - available = ecore_wl2_offer_mimes_get(ev->offer); - - free(seat_sel->saved_types->types); - - seat_sel->saved_types->ntypes = eina_array_count(available); - seat_sel->saved_types->types = malloc(sizeof(char *) * seat_sel->saved_types->ntypes); - if (!seat_sel->saved_types->types) return EINA_FALSE; - - known = eina_array_new(5); - - for (i = 0; i < eina_array_count(available); i++) - { - seat_sel->saved_types->types[i] = - eina_stringshare_add(eina_array_data_get(available, i)); - if (seat_sel->saved_types->types[i] == seat_sel->pd->text_uri) - { - seat_sel->saved_types->textreq = 1; - ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free); - } - } - - seat_sel->accept = EINA_FALSE; - for (i = 0; i < eina_array_count(available); i++) - { - if (_wl_drops_accept(seat_sel, eina_array_data_get(available, i))) - { - eina_array_push(known, strdup(eina_array_data_get(available, i))); - } - } - - ecore_wl2_offer_mimes_set(ev->offer, known); - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_leave(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Leave *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Dropable *drop; - sel_debug("In\n"); - - ev = event; - if ((drop = _wl_dropable_find(seat_sel->pd, ev->win))) - { - _wl_dropable_handle(seat_sel, NULL, 0, 0); - _wl_dropable_all_clean(seat_sel, ev->win); - } - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_position(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Motion *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd; - Sel_Manager_Dropable *drop; - Eina_Bool will_accept = EINA_FALSE; - - ev = event; - - sel_debug("mouse pos %i %i\n", ev->x, ev->y); - seat_sel->drag_win_end.x = ev->x - seat_sel->drag_pos.x; - seat_sel->drag_win_end.y = ev->y - seat_sel->drag_pos.y; - - drop = _wl_dropable_find(pd, ev->win); - - if (drop) - { - Eina_Position2D pos = EINA_POSITION2D(ev->x, ev->y); - Evas *evas = NULL; - Eina_List *dropable_list = NULL; - - _dropable_coords_adjust(drop, &pos); - evas = _wl_evas_get_from_win(pd, ev->win); - if (evas) - dropable_list = _dropable_list_geom_find(pd, evas, pos.x, pos.y); - - /* check if there is dropable (obj) can accept this drop */ - if (dropable_list) - { - Efl_Ui_Selection_Format saved_format; - Eina_List *l; - Eina_Bool found = EINA_FALSE; - Sel_Manager_Dropable *dropable = NULL; - - saved_format = - _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes); - - EINA_LIST_FOREACH(dropable_list, l, dropable) - { - Drop_Format *df; - Eina_Inlist *itr; - - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - Efl_Ui_Selection_Format common_fmt = saved_format & df->format; - - if (common_fmt) - { - /* We found a target that can accept this type of data */ - int i, min_index = SELECTION_N_ATOMS; - - /* We have to find the first atom that corresponds to one - * of the supported data types. */ - for (i = 0; i < seat_sel->saved_types->ntypes; i++) - { - Sel_Manager_Atom *atom; - - atom = eina_hash_find(pd->type_hash, - seat_sel->saved_types->types[i]); - - if (atom && (atom->format & common_fmt)) - { - int atom_idx = (atom - pd->atom_list); - - if (min_index > atom_idx) - min_index = atom_idx; - } - } - if (min_index != SELECTION_N_ATOMS) - { - sel_debug("Found atom %s\n", pd->atom_list[min_index].name); - found = EINA_TRUE; - dropable->last.type = pd->atom_list[min_index].name; - dropable->last.format = common_fmt; - break; - } - } - } - if (found) break; - } - if (found) - { - Sel_Manager_Selection *sel = seat_sel->sel; - Evas_Coord ox = 0, oy = 0; - - evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL); - - sel_debug("Candidate %p (%s)\n", - dropable->obj, efl_class_name_get(efl_class_get(dropable->obj))); - _wl_dropable_handle(seat_sel, dropable, pos.x - ox, pos.y - oy); - sel->request_obj = dropable->obj; - will_accept = EINA_TRUE; - } - else - { - //if not: send false status - sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y); - _wl_dropable_handle(seat_sel, NULL, 0, 0); - // CCCCCCC: call dnd exit on last obj - } - eina_list_free(dropable_list); - } - } - - seat_sel->accept = will_accept; - efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept); - - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_dnd_receive(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Offer_Data_Ready *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Sel_Manager_Selection *sel; - Ecore_Wl2_Offer *offer; - sel_debug("In\n"); - - ev = event; - sel = seat_sel->sel; - offer = sel->dnd_offer; - - if (offer != ev->offer) return ECORE_CALLBACK_PASS_ON; - - if (sel->request_obj) - { - Ecore_Wl2_Drag_Action action; - - action = ecore_wl2_offer_action_get(ev->offer); - if (action == ECORE_WL2_DRAG_ACTION_ASK) - ecore_wl2_offer_actions_set(ev->offer, ECORE_WL2_DRAG_ACTION_COPY, ECORE_WL2_DRAG_ACTION_COPY); - action = ecore_wl2_offer_action_get(ev->offer); - sel->action = _wl_to_elm(action); - - _wl_dropable_data_handle(sel, ev); - evas_object_event_callback_del_full(sel->request_obj, - EVAS_CALLBACK_DEL, - _wl_sel_obj_del2, sel); - sel->request_obj = NULL; - } - - ecore_wl2_offer_finish(ev->offer); - - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_wl_dnd_drop(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Wl2_Event_Dnd_Drop *ev; - Sel_Manager_Seat_Selection *seat_sel = data; - Efl_Ui_Selection_Manager_Data *pd; - Sel_Manager_Selection *sel; - Sel_Manager_Dropable *drop; - Eina_List *l; - - sel_debug("In\n"); - ev = event; - seat_sel->saved_types->pos = EINA_POSITION2D(ev->x, ev->y); - pd = seat_sel->pd; - sel = seat_sel->sel; - sel->dnd_offer = ev->offer; - - EINA_LIST_FOREACH(pd->drop_list, l, drop) - { - if (drop->last.in) - { - sel_debug("Request data of type %s; drop: %p\n", drop->last.type, drop); - sel->request_obj = drop->obj; - sel->request_format = drop->last.format; - evas_object_event_callback_add(sel->request_obj, - EVAS_CALLBACK_DEL, _wl_sel_obj_del2, - sel); - ecore_wl2_offer_receive(ev->offer, (char*)drop->last.type); - ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, _wl_dnd_receive, seat_sel); - - return ECORE_CALLBACK_PASS_ON; - } - } - - ecore_wl2_dnd_drag_end(_wl_seat_get(ev->win, NULL, seat_sel->seat)); - return ECORE_CALLBACK_PASS_ON; -} - -static Eina_Bool -_wl_sel_manager_drop_target_add(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *target_obj, - Efl_Ui_Selection_Format format, unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Sel_Manager_Seat_Selection *seat_sel = NULL; - Drop_Format *df; - - df = calloc(1, sizeof(Drop_Format)); - if (!df) return EINA_FALSE; - df->format = format; - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (!dropable) - { - //Create new drop - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) - { - free(df); - return EINA_FALSE; - } - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) - { - free(dropable); - free(df); - return EINA_FALSE; - } - dropable->obj = target_obj; - efl_key_data_set(target_obj, "__elm_dropable", dropable); - } - - dropable->format_list = eina_inlist_append(dropable->format_list, EINA_INLIST_GET(df)); - dropable->seat = seat; - seat_sel = _wl_sel_manager_seat_selection_init(pd, seat); - - evas_object_event_callback_add(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del, pd); - - if (!seat_sel->enter_handler) - { - seat_sel->enter_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_ENTER, - _wl_dnd_enter, seat_sel); - seat_sel->leave_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_LEAVE, - _wl_dnd_leave, seat_sel); - seat_sel->pos_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, - _wl_dnd_position, seat_sel); - seat_sel->drop_handler = - ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, - _wl_dnd_drop, seat_sel); - } - - return EINA_TRUE; -} -#endif - -#ifdef HAVE_ELEMENTARY_COCOA -static Sel_Manager_Seat_Selection * -_cocoa_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel) - { - Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection)); - if (!sel) - { - ERR("failed to allocate selection"); - return NULL; - } - sel->seat_sel = seat_sel; - seat_sel->sel = sel; - } - - return seat_sel; -} - -static Ecore_Cocoa_Window * -_cocoa_window_get(const Evas_Object *obj) -{ - Ecore_Cocoa_Window *win = NULL; - Evas_Object *_win; - - _win = elm_win_get(obj); - if (_win) - { - win = elm_win_cocoa_window_get(_win); - } - - if (!win) - { - CRI("WIN has not been retrieved!!!"); - } - - return win; -} - -static Ecore_Cocoa_Cnp_Type -_sel_format_to_ecore_cocoa_cnp_type(Efl_Ui_Selection_Format fmt) -{ - Ecore_Cocoa_Cnp_Type type = 0; - - if ((fmt & EFL_UI_SELECTION_FORMAT_TEXT) || - (fmt & EFL_UI_SELECTION_FORMAT_VCARD)) - type |= ECORE_COCOA_CNP_TYPE_STRING; - if (fmt & EFL_UI_SELECTION_FORMAT_HTML) - type |= ECORE_COCOA_CNP_TYPE_HTML; - if (fmt & EFL_UI_SELECTION_FORMAT_IMAGE) - type |= ECORE_COCOA_CNP_TYPE_IMAGE; - - return type; -} - -static void -_cocoa_sel_obj_del_req_cb(void *data, - Evas *e EINA_UNUSED, - Evas_Object *obj, - void *ev_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static void -_cocoa_sel_obj_del_cb(void *data, - Evas *e EINA_UNUSED, - Evas_Object *obj, - void *ev_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) - { - sel->owner = NULL; - } - //if (dragwidget == obj) dragwidget = NULL; -} - -static void -_job_pb_cb(void *data) -{ - Sel_Manager_Selection *sel = data; - Efl_Ui_Selection_Data ddata; - Ecore_Cocoa_Cnp_Type type, get_type; - void *pbdata; - int pbdata_len; - - if (sel->data_func) - { - ddata.pos.x = 0; - ddata.pos.y = 0; - - /* Pass to cocoa clipboard */ - type = _sel_format_to_ecore_cocoa_cnp_type(sel->request_format); - pbdata = ecore_cocoa_clipboard_get(&pbdata_len, type, &get_type); - - ddata.format = EFL_UI_SELECTION_FORMAT_NONE; - if (get_type & ECORE_COCOA_CNP_TYPE_STRING) - ddata.format |= EFL_UI_SELECTION_FORMAT_TEXT; - if (get_type & ECORE_COCOA_CNP_TYPE_IMAGE) - ddata.format |= EFL_UI_SELECTION_FORMAT_IMAGE; - if (get_type & ECORE_COCOA_CNP_TYPE_HTML) - ddata.format |= EFL_UI_SELECTION_FORMAT_HTML; - - ddata.content.mem = pbdata; - ddata.content.len = pbdata_len; - ddata.action = EFL_UI_SELECTION_ACTION_UNKNOWN; - sel->data_func(sel->data_func_data, sel->request_obj, &ddata); - free(pbdata); - } -} - -static Eina_Future * -_cocoa_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Cocoa_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - Ecore_Cocoa_Cnp_Type ecore_type; - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - seat_sel = _cocoa_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - if (data.len <= 0) return NULL; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - - sel->owner = owner; - sel->win = win; - sel->format = format; - - evas_object_event_callback_add(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - ELM_SAFE_FREE(sel->data.mem, free); - - if (format == EFL_UI_SELECTION_FORMAT_MARKUP) - { - //FIXME this code assumes that sel->data.mem has a \0 at the end - sel->data.mem = evas_textblock_text_markup_to_utf8(NULL, data.mem); - sel->data.len = strlen(sel->data.mem); - //set the new text - format = EFL_UI_SELECTION_FORMAT_TEXT; - } - else - { - sel->data = eina_slice_dup(data); - } - - if (sel->data.mem) - { - ecore_type = _sel_format_to_ecore_cocoa_cnp_type(format); - ecore_cocoa_clipboard_set(sel->data.mem, sel->data.len, ecore_type); - } - else - { - CRI("Failed to allocate memory!"); - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_cocoa_efl_sel_manager_selection_get(const Efl_Object *request, - Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type EINA_UNUSED, - Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, - Ecore_Cocoa_Window *win, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel; - sel->request_format = format; - sel->request_obj = (Efl_Object *)request; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); - - sel->win = win; - ecore_job_add(_job_pb_cb, sel); - - evas_object_event_callback_add(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); -} - -#endif - -// win32 specific stuff -//////////////////////////////////////////////////////////////////////////// -#ifdef HAVE_ELEMENTARY_WIN32 -static Sel_Manager_Seat_Selection * -_win32_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = NULL; - Eina_List *l = NULL; - - EINA_LIST_FOREACH(pd->seat_list, l, seat_sel) - { - if(seat_sel->seat == seat) - break; - } - if (!seat_sel) - { - seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection)); - if (!seat_sel) - { - ERR("Failed to allocate seat"); - return NULL; - } - seat_sel->saved_types = calloc(1, sizeof(Saved_Type)); - seat_sel->seat = seat; - seat_sel->pd = pd; - pd->seat_list = eina_list_append(pd->seat_list, seat_sel); - } - if (!seat_sel->sel_list) - { - seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection)); - if (!seat_sel->sel_list) - { - ERR("failed to allocate selection list"); - return NULL; - } - _set_selection_list(seat_sel->sel_list, seat_sel); - } - - return seat_sel; -} - -static char * -_win32_text_n_to_rn(char *intext) -{ - size_t size = 0, newlines = 0; - char *outtext = NULL, *p, *o; - - if (!intext) return NULL; - for (p = intext; *p; p++) - { - if (*p == '\n') newlines++; - size++; - } - outtext = malloc(size + newlines + 1); - if (!outtext) return intext; - for (p = intext, o = outtext; *p; p++, o++) - { - if (*p == '\n') - { - o++; - *p = '\r'; - } - *o = *p; - } - *o = '\0'; - free(intext); - return outtext; -} - -static void -_win32_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->owner == obj) sel->owner = NULL; -} - -static void -_win32_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) -{ - Sel_Manager_Selection *sel = data; - if (sel->request_obj == obj) sel->request_obj = NULL; -} - -static Ecore_Win32_Window * -_win32_window_get(const Evas_Object *obj) -{ - Evas_Object *top; - Ecore_Win32_Window *win = NULL; - - if (elm_widget_is(obj)) - { - top = elm_widget_top_get(obj); - if (!top) - { - Evas_Object *par; - par = elm_widget_parent_widget_get(obj); - if (par) top = elm_widget_top_get(par); - } - if (top && (efl_isa(top, EFL_UI_WIN_CLASS))) - win = elm_win_win32_window_get(top); - } - - if (!win) - { - Ecore_Evas *ee; - Evas *evas; - const char *engine_name; - - evas = evas_object_evas_get(obj); - if (!evas) return NULL; - - ee = ecore_evas_ecore_evas_get(evas); - if (!ee) return NULL; - - engine_name = ecore_evas_engine_name_get(ee); - if (!strcmp(engine_name, ELM_BUFFER)) - { - ee = ecore_evas_buffer_ecore_evas_parent_get(ee); - if (!ee) return NULL; - win = ecore_evas_win32_window_get(ee); - } - else - { - if ((strcmp(engine_name, ELM_SOFTWARE_WIN32) == 0) || - (strcmp(engine_name, ELM_SOFTWARE_DDRAW) == 0)) - return ecore_evas_win32_window_get(ee); - } - } - - return win; -} - -static Eina_Future * -_win32_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, - Ecore_Win32_Window *win, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return NULL; - - if ((!data.mem) && (format != EFL_UI_SELECTION_FORMAT_IMAGE)) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat); - return NULL; - } - - seat_sel = _win32_sel_manager_seat_selection_init(pd, seat); - seat_sel->active_type = type; - sel = seat_sel->sel_list + type; - if (sel->owner != owner) - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - - } - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _win32_sel_obj_del, sel); - sel->active = EINA_TRUE; - sel->owner = owner; - sel->win = win; - if (sel->set) sel->set(win, sel->data.mem, sel->data.len); - sel->format = format; - - evas_object_event_callback_add - (sel->owner, EVAS_CALLBACK_DEL, _win32_sel_obj_del, sel); - - ELM_SAFE_FREE(sel->data.mem, free); - sel->data = eina_slice_dup(data); - if (!sel->data.mem) - { - efl_ui_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat); - return NULL; - } - - return _update_sel_lost_list(owner, type, seat_sel); -} - -static void -_win32_efl_sel_manager_selection_clear(Efl_Ui_Selection_Manager_Data *pd, - Evas_Object *owner, - Efl_Ui_Selection_Type type, - Sel_Manager_Seat_Selection *seat_sel) -{ - Sel_Manager_Selection *sel; - Ecore_Win32_Window *win; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return; - - sel = seat_sel->sel_list + type; - - /* No longer this selection: Consider it gone! */ - if ((!sel->active) || (sel->owner != owner)) - return; - - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _win32_sel_obj_del, sel); - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _win32_sel_obj_del2, sel); - sel->owner = NULL; - sel->request_obj = NULL; - sel->active = EINA_FALSE; - ELM_SAFE_FREE(sel->data.mem, free); - /* sel->clear(win); */ -} - -static Eina_Bool -_win32_efl_sel_manager_selection_get(const Efl_Object *request, - Efl_Ui_Selection_Manager_Data *pd, - Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, - Eina_Free_Cb data_func_free_cb, - Ecore_Win32_Window *win, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel; - void *data; - int size; - - if (type != EFL_UI_SELECTION_TYPE_CLIPBOARD) - return EINA_FALSE; - - seat_sel = _sel_manager_seat_selection_init(pd, seat); - sel = seat_sel->sel_list + type; - - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _win32_sel_obj_del2, sel); - sel->request_format = format; - sel->request_obj = (Evas_Object *)request; - sel->win = win; - sel->data_func_data = data_func_data; - sel->data_func = data_func; - sel->data_func_free_cb = data_func_free_cb; - sel->get(win, &data, &size); - - if (!data || (size <= 0)) - goto cb_add; - - if ((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) || - (sel->format & EFL_UI_SELECTION_FORMAT_HTML)) - { - char *str; - - str = (char *)malloc(size + 1); - if (str) - { - memcpy(str, data, size); - str[size] = '\0'; - data = _win32_text_n_to_rn(_elm_util_mkup_to_text(str)); - free(str); - if (data) - size = strlen(data); - else - size = 0; - } - else - { - free(data); - data = NULL; - } - } - - if (sel->data_func && data && (size > 0)) - { - Efl_Ui_Selection_Data sdata; - - sdata.pos.x = sdata.pos.y = 0; - sdata.format = EFL_UI_SELECTION_FORMAT_TEXT; - sdata.content.mem = data; - sdata.content.len = size; - sdata.action = sel->action; - sel->data_func(sel->data_func_data, sel->request_obj, &sdata); - } - - if (data) - free(data); - - cb_add: - evas_object_event_callback_add - (sel->request_obj, EVAS_CALLBACK_DEL, _win32_sel_obj_del2, sel); - - return EINA_TRUE; -} - -#endif /* HAVE_ELEMENTARY_WIN32 */ - - -static int -_drop_item_container_cmp(const void *d1, const void *d2) -{ - const Item_Container_Drop_Info *di = d1; - return (((uintptr_t)di->obj) - ((uintptr_t)d2)); -} - -static Eina_Bool -_drop_item_container_del(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *cont, Eina_Bool full) -{ - Item_Container_Drop_Info *di; - - di = eina_list_search_unsorted(pd->drop_cont_list, - _drop_item_container_cmp, cont); - if (di) - { - _all_drop_targets_cbs_del(pd, NULL, cont, NULL); - di->item_func_data = NULL; - di->item_func = NULL; - - if (full) - { - pd->drop_cont_list = eina_list_remove(pd->drop_cont_list, di); - free(di); - } - return EINA_TRUE; - } - - return EINA_FALSE; -} - -static inline Eina_List * -_anim_icons_make(Sel_Manager_Drag_Container *dc) -{ - Eina_List *list = NULL, *icon_list = NULL; - Evas_Object *obj; - - if (dc->icon_list_func) - { - DBG("calling icon_list_func"); - icon_list = dc->icon_list_func(dc->icon_list_func_data, dc->cont); - } - EINA_LIST_FREE(icon_list, obj) - { - DBG("one obj in icon_list"); - Anim_Icon *ai = calloc(1, sizeof(Anim_Icon)); - if (!ai) - { - ERR("Failed to allocate for icon!"); - continue; - } - - evas_object_geometry_get(obj, &ai->start.x, &ai->start.y, &ai->start.w, &ai->start.h); - evas_object_show(obj); - ai->obj = obj; - list = eina_list_append(list, ai); - } - DBG("made icon list"); - - return list; -} - -static void -_cont_obj_drag_done_cb(void *data, const Efl_Event *ev EINA_UNUSED) -{ - Sel_Manager_Drag_Container *dc = data; - elm_widget_scroll_freeze_pop(dc->cont); -} - -static Eina_Bool -_cont_obj_drag_start(void *data) -{ - DBG("going to start draging"); - Sel_Manager_Drag_Container *dc = data; - - dc->timer = NULL; - efl_event_callback_add(dc->cont, EFL_UI_DND_EVENT_DRAG_DONE, _cont_obj_drag_done_cb, dc); - elm_widget_scroll_freeze_push(dc->cont); - efl_ui_selection_manager_drag_start(dc->pd->sel_man, dc->cont, dc->format, - eina_rw_slice_slice_get(dc->data), dc->action, - dc->icon_func_data, dc->icon_func, dc->icon_func_free_cb, - dc->seat); - - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_drag_anim_play(void *data, double pos) -{ - Sel_Manager_Drag_Container *dc = data; - - if (dc->animator) - { - Eina_List *l; - Anim_Icon *ai; - Evas_Coord xm, ym; - - if (pos > 0.99) - { - dc->animator = NULL; - EINA_LIST_FOREACH(dc->icons, l, ai) - evas_object_hide(ai->obj); - - _cont_obj_drag_start(dc); - return ECORE_CALLBACK_CANCEL; - } - - evas_pointer_canvas_xy_get(dc->e, &xm, &ym); - EINA_LIST_FOREACH(dc->icons, l, ai) - { - int x, y, w, h; - w = ai->start.w - ((dc->final_icon.w - ai->start.w) * pos); - h = ai->start.h - ((dc->final_icon.h - ai->start.h) * pos); - x = ai->start.x - (pos * (ai->start.x + (w / 2) - xm)); - y = ai->start.y - (pos * (ai->start.y + (h / 2) - ym)); - evas_object_geometry_set(ai->obj, x, y, w, h); - } - - return ECORE_CALLBACK_RENEW; - } - - return ECORE_CALLBACK_CANCEL; -} - -static inline void -_drag_anim_start(Sel_Manager_Drag_Container *dc) -{ - - dc->timer = NULL; - if (dc->icon_func) - { - Eina_Position2D pos_ret; - Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_DND); - Evas_Object *final_icon = dc->icon_func(dc->icon_func_data, temp_win, dc->cont, &pos_ret); - evas_object_geometry_get(final_icon, NULL, NULL, &dc->final_icon.w, &dc->final_icon.h); - evas_object_del(final_icon); - evas_object_del(temp_win); - } - dc->animator = ecore_evas_animator_timeline_add(dc->e, dc->anim_duration, _drag_anim_play, dc); -} - -static Eina_Bool -_cont_obj_anim_start(void *data) -{ - sel_debug("In"); - Sel_Manager_Drag_Container *dc = data; - Efl_Object *it = NULL; - Eina_Position2D posret; //does not use - - if (dc->item_get_func) - it = dc->item_get_func(dc->item_get_func_data, dc->cont, dc->down, &posret); - dc->timer = NULL; - dc->format = EFL_UI_SELECTION_FORMAT_TARGETS; //default - dc->data.len = 0; - dc->action = EFL_UI_SELECTION_ACTION_COPY; //default - dc->icons = NULL; - - //failed to get mouse-down item, abort drag - if (!it) - return ECORE_CALLBACK_CANCEL; - - if (dc->drag_data_func) - { - dc->drag_data_func(dc->drag_data_func_data, dc->cont, - &dc->format, &dc->data, &dc->action); - if (EINA_DBL_EQ(dc->anim_duration, 0.0)) - { - _cont_obj_drag_start(dc); - } - else - { - dc->icons = _anim_icons_make(dc); - if (dc->icons) - { - _drag_anim_start(dc); - } - else - { - // even if we don't manage the icons animation, we have - // to wait until it is finished before beginning drag. - dc->timer = ecore_timer_add(dc->anim_duration, - _cont_obj_drag_start, dc); - } - } - } - - return ECORE_CALLBACK_CANCEL; -} - -static void -_abort_drag(Evas_Object *obj EINA_UNUSED, Sel_Manager_Drag_Container *dc) -{ - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - _item_container_del_internal(dc, EINA_FALSE); - - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - _anim_data_free(dc); -} - -static void -_cont_obj_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - Evas_Event_Mouse_Move *ev = event_info; - - if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) - { - _abort_drag(obj, dc); - } - if (dc && - (evas_device_class_get(ev->dev) == EVAS_DEVICE_CLASS_TOUCH)) - { - int dx, dy; - int fs = elm_config_finger_size_get(); - - dx = ev->cur.canvas.x - dc->down.x; - dy = ev->cur.canvas.y - dc->down.y; - if ((dx * dx + dy * dy) > (fs * fs)) - { - sel_debug("mouse moved too much - have to cancel DnD"); - _abort_drag(obj, dc); - } - } -} - -static void -_anim_data_free(Sel_Manager_Drag_Container *dc) -{ - if (dc) - { - ELM_SAFE_FREE(dc->animator, ecore_animator_del); - Anim_Icon *ai; - - EINA_LIST_FREE(dc->icons, ai) - { - evas_object_del(ai->obj); - free(ai); - } - dc->icons = NULL; - } -} - -static void -_cont_obj_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - - if (((Evas_Event_Mouse_Up *)event_info)->button != 1) - return; - - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - - _anim_data_free(dc); -} - -static void -_cont_obj_mouse_down_cb(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info) -{ - Sel_Manager_Drag_Container *dc = data; - Evas_Event_Mouse_Down *ev = event_info; - if (ev->button != 1) - return; - - dc->e = e; - dc->down.x = ev->canvas.x; - dc->down.y = ev->canvas.y; - - evas_object_event_callback_add(dc->cont, EVAS_CALLBACK_MOUSE_UP, - _cont_obj_mouse_up_cb, dc); - ecore_timer_del(dc->timer); - if (dc->time_to_drag) - { - dc->timer = ecore_timer_add(dc->time_to_drag, _cont_obj_anim_start, dc); - evas_object_event_callback_add(dc->cont, EVAS_CALLBACK_MOUSE_MOVE, - _cont_obj_mouse_move_cb, dc); - } - else - { - _cont_obj_anim_start(dc); - } -} - -static void -_item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full) -{ - if (dc) - { - ELM_SAFE_FREE(dc->timer, ecore_timer_del); - if (dc->animator) - _anim_data_free(dc); - evas_object_event_callback_del_full(dc->cont, EVAS_CALLBACK_MOUSE_DOWN, - _cont_obj_mouse_down_cb, dc); - if (full) - { - dc->item_get_func = NULL; - dc->item_get_func_data = NULL; - free(dc); - } - } -} - -static int -_drag_item_container_cmp(const void *d1, const void *d2) -{ - const Sel_Manager_Drag_Container *dc = d1; - return (((uintptr_t)dc->cont) - ((uintptr_t)d2)); -} -//exposed APIs -EOLIAN static Eina_Future * -_efl_ui_selection_manager_selection_set(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - Eina_Slice data, unsigned int seat) -{ - Eina_Future *p = NULL; - - sel_debug("owner: %p, seat: %d, type: %d, format: %d", owner, seat, type, format); - if (type > EFL_UI_SELECTION_TYPE_CLIPBOARD) - { - ERR("Not supported format: %d", type); - return NULL; - } - -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(owner); - if (xwin) - p = _x11_efl_sel_manager_selection_set(pd, owner, type, format, data, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(owner); - if (win) - p = _wl_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(owner); - if (win) - p = _cocoa_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(owner); - if (win) - p = _win32_efl_sel_manager_selection_set(pd, owner, type, format, data, win, seat); -#endif - - return p; -} - -//TODO: add support for local -EOLIAN static void -_efl_ui_selection_manager_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - const Efl_Object *request, Efl_Ui_Selection_Type type, - Efl_Ui_Selection_Format format, - void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, - Eina_Free_Cb data_func_free_cb, unsigned int seat) -{ - sel_debug("request: %p, seat: %d, type: %d, format: %d", request, seat, type, format); -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(request); - if (xwin) - _x11_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(request); - if (win) - _wl_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(request); - if (win) - _cocoa_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(request); - if (win) - _win32_efl_sel_manager_selection_get(request, pd, type, format, data_func_data, - data_func, data_func_free_cb, win, seat); -#endif -} - -EOLIAN static void -_efl_ui_selection_manager_selection_clear(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *owner, Efl_Ui_Selection_Type type, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel; - Sel_Manager_Selection *sel = NULL; - - sel_debug("owner: %p, seat: %d, type: %d", owner, seat, type); - seat_sel = _sel_manager_seat_selection_init(pd, seat); -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(obj); - if (xwin) - { - sel = seat_sel->sel_list + type; - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(obj); - if (win) - { - sel = seat_sel->sel; - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - Ecore_Cocoa_Window *win = _cocoa_window_get(obj); - if (win) - { - sel = seat_sel->sel; - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - Ecore_Win32_Window *win = _win32_window_get(obj); - { - sel = seat_sel->sel_list + type; - } -#endif - if (!sel) return; - if ((!sel->active) && (sel->owner != owner)) - { - return; - } - sel->active = EINA_FALSE; -#ifdef HAVE_ELEMENTARY_X - if (xwin) - { - seat_sel->sel_list[type].data.len = 0; - if (seat_sel->sel_list[type].data.mem) - { - free(seat_sel->sel_list[type].data.mem); - seat_sel->sel_list[type].data.mem = NULL; - } - if (!sel->xwin) seat_sel->sel_list[type].clear(); - else - { - Eina_List *l, *l_next; - Sel_Manager_Selection_Lost *sel_lost; - - EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost) - { - if ((sel_lost->request == sel->owner) && - (sel_lost->type == type)) - { - eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type)); - } - } - seat_sel->sel_list[type].owner = NULL; - } - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - if (win) - { - sel->selection_serial = ecore_wl2_dnd_selection_clear(_wl_seat_get(_wl_window_get(owner), owner, seat)); - } -#endif -#ifdef HAVE_ELEMENTARY_COCOA - if (win) - { - if (sel->owner) - evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_cb, sel); - if (sel->request_obj) - evas_object_event_callback_del_full(sel->request_obj, EVAS_CALLBACK_DEL, - _cocoa_sel_obj_del_req_cb, sel); - sel->owner = NULL; - sel->request_obj = NULL; - ELM_SAFE_FREE(sel->data.mem, free); - sel->data.len = 0; - - ecore_cocoa_clipboard_clear(); - } -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - if (win) - { - _win32_efl_sel_manager_selection_clear(pd, owner, type, seat_sel); - } -#endif -} - -EOLIAN static Eina_Bool -_efl_ui_selection_manager_selection_has_owner(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd EINA_UNUSED, - Efl_Object *request, Efl_Ui_Selection_Type type, - unsigned int seat) -{ -#ifdef HAVE_ELEMENTARY_X - (void)seat; - if (_x11_xwin_get(request)) - { - Ecore_X_Atom xtype; - switch (type) - { - case EFL_UI_SELECTION_TYPE_PRIMARY: - xtype = ECORE_X_ATOM_SELECTION_PRIMARY; - break; - case EFL_UI_SELECTION_TYPE_SECONDARY: - xtype = ECORE_X_ATOM_SELECTION_SECONDARY; - break; - case EFL_UI_SELECTION_TYPE_DND: - xtype = ECORE_X_ATOM_SELECTION_XDND; - break; - default: - xtype = ECORE_X_ATOM_SELECTION_CLIPBOARD; - } - return !!ecore_x_selection_owner_get(xtype); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win; - - win = _wl_window_get(request); - if (win) - return !!ecore_wl2_dnd_selection_get(_wl_seat_get(win, request, seat)); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - // FIXME: need to check if there is clipboard data. Paste always enabled. - return EINA_TRUE; -#endif - return EINA_FALSE; -} - -EOLIAN static void -_efl_ui_selection_manager_drag_start(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Format format, - Eina_Slice data, Efl_Ui_Selection_Action action, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, - Eina_Free_Cb icon_func_free_cb, unsigned int seat) -{ -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - _x11_efl_sel_manager_drag_start(obj, pd, drag_obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(drag_obj); - if (win) - _wl_efl_sel_manager_drag_start(obj, pd, drag_obj, format, data, action, - icon_func_data, icon_func, icon_func_free_cb, - win, seat); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 -#endif -#ifdef HAVE_ELEMENTARY_COCOA -#endif -} - -EOLIAN static void -_efl_ui_selection_manager_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = _sel_manager_seat_selection_init(pd, seat); - -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - { - ecore_x_pointer_ungrab(); - ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del); - ecore_x_dnd_abort(xwin); - if (seat_sel->drag_obj) - { - if (elm_widget_is(seat_sel->drag_obj)) - { - Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj); - if (win && efl_isa(win, EFL_UI_WIN_CLASS)) - efl_event_callback_del(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED, - _x11_win_rotation_changed_cb, seat_sel->drag_win); - } - } - seat_sel->drag_obj = NULL; - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win; - - win = _wl_window_get(drag_obj); - if (win) - ecore_wl2_dnd_drag_end(_wl_seat_get(win, drag_obj, seat)); -#endif - - ELM_SAFE_FREE(seat_sel->drag_win, evas_object_del); -} - -EOLIAN static void -_efl_ui_selection_manager_drag_action_set(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *drag_obj, Efl_Ui_Selection_Action action, - unsigned int seat) -{ - Sel_Manager_Seat_Selection *seat_sel = _sel_manager_seat_selection_init(pd, seat); - if (seat_sel->drag_action == action) return; - seat_sel->drag_action = action; -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Atom actx; - Ecore_X_Window xwin = _x11_xwin_get(drag_obj); - if (xwin) - { - actx = _x11_dnd_action_rev_map(action); - ecore_x_dnd_source_action_set(actx); - } -#endif -} - -//drop side -EOLIAN static Eina_Bool -_efl_ui_selection_manager_drop_target_add(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *target_obj, Efl_Ui_Selection_Format format, - unsigned int seat) -{ - Eina_Bool ret = EINA_FALSE; -#ifdef HAVE_ELEMENTARY_X - Ecore_X_Window xwin = _x11_xwin_get(target_obj); - if (xwin) - ret = _x11_sel_manager_drop_target_add(pd, target_obj, format, xwin, seat); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Ecore_Wl2_Window *win = _wl_window_get(target_obj); - if (win) - ret = _wl_sel_manager_drop_target_add(pd, target_obj, format, seat); -#endif - return ret; -} - -EOLIAN static void -_efl_ui_selection_manager_drop_target_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *target_obj, Efl_Ui_Selection_Format format, - unsigned int seat) -{ - Sel_Manager_Dropable *dropable = NULL; - Sel_Manager_Seat_Selection *seat_sel; - Eina_Bool remove_handler = EINA_FALSE; - - dropable = efl_key_data_get(target_obj, "__elm_dropable"); - if (dropable) - { - Eina_Inlist *itr; - Drop_Format *df; - EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df) - { - if (df->format == format) - { - dropable->format_list = eina_inlist_remove(dropable->format_list, - EINA_INLIST_GET(df)); - free(df); - } - } - if (!dropable->format_list) - { - pd->drop_list = eina_list_remove(pd->drop_list, dropable); - efl_key_data_set(target_obj, "__elm_dropable", NULL); - free(dropable); - evas_object_event_callback_del(target_obj, EVAS_CALLBACK_DEL, - _all_drop_targets_cbs_del); - } - } - -#ifdef HAVE_ELEMENTARY_X - if (pd->drop_list) - { - Eina_List *l; - Ecore_X_Window xwin; - Eina_Bool have_drop_list = EINA_FALSE; - - xwin = _x11_xwin_get(target_obj); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - if (xwin == _x11_xwin_get(dropable->obj)) - { - have_drop_list = EINA_TRUE; - break; - } - } - if (!have_drop_list) - { - ecore_x_dnd_aware_set(xwin, EINA_FALSE); - remove_handler = EINA_TRUE; - } - } - else remove_handler = EINA_TRUE; -#endif - if (remove_handler) - { - seat_sel = _sel_manager_seat_selection_init(pd, seat); - ELM_SAFE_FREE(seat_sel->pos_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->drop_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->enter_handler, ecore_event_handler_del); - ELM_SAFE_FREE(seat_sel->leave_handler, ecore_event_handler_del); - } -} - -EOLIAN static void -_efl_ui_selection_manager_container_drop_item_add(Eo *obj, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, Efl_Ui_Selection_Format format, - void *item_func_data, Efl_Dnd_Item_Get item_func, - Eina_Free_Cb item_func_free_cb EINA_UNUSED, - unsigned int seat) -{ - Item_Container_Drop_Info *di; - Sel_Manager_Dropable *dropable = NULL; - - if (_drop_item_container_del(pd, cont, EINA_FALSE)) - { - di = eina_list_search_unsorted(pd->drop_cont_list, _drop_item_container_cmp, obj); - if (!di) return; - } - else - { - di = calloc(1, sizeof(Item_Container_Drop_Info)); - if (!di) return; - - di->obj = obj; - pd->drop_cont_list = eina_list_append(pd->drop_cont_list, di); - } - di->item_func = item_func; - di->item_func_data = item_func_data; - - dropable = efl_key_data_get(cont, "__elm_dropable"); - if (!dropable) - { - dropable = calloc(1, sizeof(Sel_Manager_Dropable)); - if (!dropable) return; - dropable->last.in = EINA_FALSE; - pd->drop_list = eina_list_append(pd->drop_list, dropable); - if (!pd->drop_list) return; - dropable->obj = cont; - efl_key_data_set(cont, "__elm_dropable", dropable); - } - dropable->is_container = EINA_TRUE; - dropable->item_func = item_func; - dropable->item_func_data = item_func_data; - _efl_ui_selection_manager_drop_target_add(obj, pd, cont, format, seat); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drop_item_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, unsigned int seat EINA_UNUSED) -{ - _drop_item_container_del(pd, cont, EINA_TRUE); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drag_item_add(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, double time_to_drag, double anim_duration, - void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb, - void *item_get_func_data, Efl_Dnd_Item_Get item_get_func, Eina_Free_Cb item_get_func_free_cb, - void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, - void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb, - unsigned int seat) -{ - //TODO: remove previous drag one - Sel_Manager_Drag_Container *dc = calloc(1, sizeof(Sel_Manager_Drag_Container)); - if (!dc) - { - ERR("Failed to allocate memory"); - return; - } - dc->cont = cont; - dc->time_to_drag = time_to_drag; - dc->anim_duration = anim_duration; - dc->drag_data_func_data = data_func_data; - dc->drag_data_func = data_func; - dc->drag_data_func_free_cb = data_func_free_cb; - dc->item_get_func_data = item_get_func_data; - dc->item_get_func = item_get_func; - dc->item_get_func_free_cb = item_get_func_free_cb; - dc->icon_func_data = icon_func_data; - dc->icon_func = icon_func; - dc->icon_func_free_cb = icon_func_free_cb; - dc->icon_list_func_data = icon_list_func_data; - dc->icon_list_func = icon_list_func; - dc->icon_list_func_free_cb = icon_list_func_free_cb; - dc->seat = seat; - dc->pd = pd; - - _sel_manager_seat_selection_init(pd, seat); - - pd->drag_cont_list = eina_list_append(pd->drag_cont_list, dc); - - evas_object_event_callback_add(cont, EVAS_CALLBACK_MOUSE_DOWN, - _cont_obj_mouse_down_cb, dc); -} - -EOLIAN static void -_efl_ui_selection_manager_container_drag_item_del(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd, - Efl_Object *cont, unsigned int seat EINA_UNUSED) -{ - Sel_Manager_Drag_Container *dc = eina_list_search_unsorted(pd->drag_cont_list, - _drag_item_container_cmp, cont); - if (dc) - _item_container_del_internal(dc, EINA_TRUE); -} - -static Eo * -_efl_ui_selection_manager_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Manager_Data *pd) -{ -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WL2) - const char *ev = getenv("ELM_DISPLAY"); -#endif - -#ifdef HAVE_ELEMENTARY_X - Eina_Bool init_x = EINA_FALSE; - Eina_Bool have_display = !!getenv("DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "x11")) /* and it is X11 */ - { - if (!have_display) /* if there is no $DISPLAY */ - { - ERR("$ELM_DISPLAY is set to x11 but $DISPLAY is not set"); - init_x = EINA_FALSE; - } - else /* if there is */ - init_x = EINA_TRUE; - } - else /* not X11 */ - init_x = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - if (have_display) /* If there is a $DISPLAY */ - init_x = EINA_TRUE; - else /* No $DISPLAY */ - init_x = EINA_FALSE; - } - if (init_x) - { - if (!ecore_x_init(NULL)) - { - ERR("Could not initialize Ecore_X"); - return NULL; - } - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Eina_Bool init_wl = EINA_FALSE; - Eina_Bool have_wl_display = !!getenv("WAYLAND_DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "wl")) /* and it is WL */ - { - /* always try to connect to wl when it is enforced */ - init_wl = EINA_TRUE; - } - else /* not wl */ - init_wl = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - /* If there is a $WAYLAND_DISPLAY */ - if ((have_wl_display) && (!getenv("DISPLAY"))) - init_wl = EINA_TRUE; - else /* No $WAYLAND_DISPLAY */ - init_wl = EINA_FALSE; - } - if (init_wl) - { - if (!ecore_wl2_init()) - { - ERR("Could not initialize Ecore_Wl2"); - return NULL; - } - _elm_wl_display = ecore_wl2_display_connect(NULL); - if (!_elm_wl_display) - { - ERR("Could not connect to Wayland Display"); - ecore_wl2_shutdown(); - return NULL; - } - } -#endif - - obj = efl_constructor(efl_super(obj, MY_CLASS)); - - pd->sel_man = obj; - pd->atom_list = calloc(1, SELECTION_N_ATOMS * sizeof(Sel_Manager_Atom)); - if (!pd->atom_list) - { - ERR("failed to allocate atom_list"); - return NULL; - } - pd->atom_list[SELECTION_ATOM_TARGETS].name = "TARGETS"; - pd->atom_list[SELECTION_ATOM_TARGETS].format = EFL_UI_SELECTION_FORMAT_TARGETS; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TARGETS].x_converter = _x11_targets_converter; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TARGETS].wl_converter = _wl_targets_converter; -#endif - pd->atom_list[SELECTION_ATOM_ATOM].name = "ATOM"; // for opera browser - pd->atom_list[SELECTION_ATOM_ATOM].format = EFL_UI_SELECTION_FORMAT_TARGETS; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_ATOM].x_converter = _x11_targets_converter; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_ATOM].wl_converter = _wl_targets_converter; -#endif - - pd->atom_list[SELECTION_ATOM_ELM].name = "application/x-elementary-markup"; - pd->atom_list[SELECTION_ATOM_ELM].format = EFL_UI_SELECTION_FORMAT_MARKUP; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_ELM].x_converter = _x11_general_converter; - pd->atom_list[SELECTION_ATOM_ELM].x_data_preparer = _x11_data_preparer_markup; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_ELM].wl_converter = _wl_general_converter; - pd->atom_list[SELECTION_ATOM_ELM].wl_data_preparer = _wl_data_preparer_markup; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].name = "text/uri-list"; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].x_converter = _x11_general_converter; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].x_data_preparer = _x11_data_preparer_uri; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].wl_converter = _wl_general_converter; - pd->atom_list[SELECTION_ATOM_TEXT_URILIST].wl_data_preparer = _wl_data_preparer_uri; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].name = "text/x-vcard"; - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].format = EFL_UI_SELECTION_FORMAT_VCARD; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].x_converter = _x11_vcard_send; - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].x_data_preparer = _x11_data_preparer_vcard; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_X_VCARD].wl_data_preparer = _wl_data_preparer_vcard; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].name = "image/png"; - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_PNG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].name = "image/jpeg"; - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_JPEG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].name = "image/x-ms-bmp"; - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_BMP].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].name = "image/gif"; - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_GIF].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].name = "image/tiff"; - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_TIFF].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].name = "image/svg+xml"; - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_SVG].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].name = "image/x-xpixmap"; - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_XPM].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].name = "image/x-tga"; - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_TGA].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].name = "image/x-portable-pixmap"; - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].format = EFL_UI_SELECTION_FORMAT_IMAGE; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].x_converter = _x11_image_converter; - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].x_data_preparer = _x11_data_preparer_image; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_IMAGE_PPM].wl_data_preparer = _wl_data_preparer_image; -#endif - - pd->atom_list[SELECTION_ATOM_UTF8STRING].name = "UTF8_STRING"; - pd->atom_list[SELECTION_ATOM_UTF8STRING].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_UTF8STRING].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_UTF8STRING].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_UTF8STRING].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_UTF8STRING].wl_data_preparer = _wl_data_preparer_text, -#endif - - pd->atom_list[SELECTION_ATOM_STRING].name = "STRING"; - pd->atom_list[SELECTION_ATOM_STRING].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_STRING].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_STRING].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_STRING].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_STRING].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].name = "COMPOUND_TEXT"; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_COMPOUND_TEXT].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT].name = "TEXT"; - pd->atom_list[SELECTION_ATOM_TEXT].format = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_HTML; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].name = "text/plain;charset=utf-8"; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN_UTF8].wl_data_preparer = _wl_data_preparer_text; -#endif - - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].name = "text/plain"; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].format = EFL_UI_SELECTION_FORMAT_TEXT; -#ifdef HAVE_ELEMENTARY_X - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].x_converter = _x11_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].x_data_preparer = _x11_data_preparer_text; -#endif -#ifdef HAVE_ELEMENTARY_WL2 - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].wl_converter = _wl_text_converter; - pd->atom_list[SELECTION_ATOM_TEXT_PLAIN].wl_data_preparer = _wl_data_preparer_text; -#endif - - - int i; -#ifdef HAVE_ELEMENTARY_X - if (ecore_x_display_get()) - { - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - pd->atom_list[i].x_atom = ecore_x_atom_get(pd->atom_list[i].name); - ecore_x_selection_converter_atom_add - (pd->atom_list[i].x_atom, pd->atom_list[i].x_converter); - } - pd->notify_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, - _efl_sel_manager_x11_selection_notify, pd); - pd->clear_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, - _x11_selection_clear, pd); - if (ECORE_X_EVENT_FIXES_SELECTION_NOTIFY) // If XFIXES is not available ECORE_X_EVENT_FIXES_SELECTION_NOTIFY would be NULL - pd->fix_handler = ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, - _x11_fixes_selection_notify, pd); - } -#endif - - pd->type_hash = eina_hash_string_small_new(NULL); - for (i = 0; i < SELECTION_N_ATOMS; i++) - { - eina_hash_add(pd->type_hash, pd->atom_list[i].name, &pd->atom_list[i]); - } - pd->text_uri = eina_stringshare_add("text/uri-list"); - -#ifdef HAVE_ELEMENTARY_WL2 - if (_elm_wl_display) - { - pd->send_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, - _wl_selection_send, pd); - pd->changed_handler = ecore_event_handler_add(ECORE_WL2_EVENT_SEAT_SELECTION, - _wl_selection_changed, pd); - pd->end_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_END, - _wl_dnd_end, pd); - } -#endif - managers = eina_list_append(managers, obj); - return obj; -} - -static void -_efl_ui_selection_manager_efl_object_destructor(Eo *obj, Efl_Ui_Selection_Manager_Data *pd) -{ - Sel_Manager_Seat_Selection *seat_sel; - Eina_List *l; - Sel_Manager_Dropable *dropable; - - managers = eina_list_remove(managers, obj); - EINA_LIST_FOREACH(pd->drop_list, l, dropable) - { - _drop_target_cbs_del(pd, dropable, dropable->obj); - } -#ifdef HAVE_ELEMENTARY_X - ecore_event_handler_del(pd->notify_handler); - ecore_event_handler_del(pd->clear_handler); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - ecore_event_handler_del(pd->send_handler); - ecore_event_handler_del(pd->changed_handler); - ecore_event_handler_del(pd->end_handler); -#endif - free(pd->atom_list); - EINA_LIST_FREE(pd->seat_list, seat_sel) - { - ecore_event_handler_del(seat_sel->pos_handler); - ecore_event_handler_del(seat_sel->drop_handler); - ecore_event_handler_del(seat_sel->enter_handler); - ecore_event_handler_del(seat_sel->leave_handler); -#ifdef HAVE_ELEMENTARY_X - free(seat_sel->sel_list); -#endif -#ifdef HAVE_ELEMENTARY_WL2 - free(seat_sel->sel); -#endif -#ifdef HAVE_ELEMENTARY_COCOA - free(seat_sel->sel); -#endif -#ifdef HAVE_ELEMENTARY_WIN32 - free(seat_sel->sel_list); -#endif - free(seat_sel->saved_types->types); - free(seat_sel->saved_types->imgfile); - free(seat_sel->saved_types); - } - eina_hash_free(pd->type_hash); - eina_stringshare_del(pd->text_uri); - - efl_destructor(efl_super(obj, MY_CLASS)); -#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WL2) || defined(HAVE_ELEMENTARY_WIN32) - const char *ev = getenv("ELM_DISPLAY"); -#endif - -#ifdef HAVE_ELEMENTARY_X - Eina_Bool init_x = EINA_FALSE; - Eina_Bool have_display = !!getenv("DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "x11")) /* and it is X11 */ - { - if (!have_display) /* if there is no $DISPLAY */ - { - ERR("$ELM_DISPLAY is set to x11 but $DISPLAY is not set"); - init_x = EINA_FALSE; - } - else /* if there is */ - init_x = EINA_TRUE; - } - else /* not X11 */ - init_x = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - if (have_display) /* If there is a $DISPLAY */ - init_x = EINA_TRUE; - else /* No $DISPLAY */ - init_x = EINA_FALSE; - } - if (init_x) - { - if (ecore_x_display_get()) - ecore_x_shutdown(); - } -#endif -#ifdef HAVE_ELEMENTARY_WL2 - Eina_Bool init_wl = EINA_FALSE; - Eina_Bool have_wl_display = !!getenv("WAYLAND_DISPLAY"); - - if (ev) /* If ELM_DISPLAY is specified */ - { - if (!strcmp(ev, "wl")) /* and it is WL */ - { - /* always try to connect to wl when it is enforced */ - init_wl = EINA_TRUE; - } - else /* not wl */ - init_wl = EINA_FALSE; - } - else /* ELM_DISPLAY not specified */ - { - /* If there is a $WAYLAND_DISPLAY */ - if ((have_wl_display) && (!getenv("DISPLAY"))) - init_wl = EINA_TRUE; - else /* No $WAYLAND_DISPLAY */ - init_wl = EINA_FALSE; - } - if (init_wl) - { - if (!managers) ecore_wl2_display_disconnect(_elm_wl_display); - ecore_wl2_shutdown(); - } -#endif -} - -#ifdef HAVE_ELEMENTARY_X -static void -_set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel) -{ - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].debug = "Primary"; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].ecore_sel = ECORE_X_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].set = ecore_x_selection_primary_set; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].clear = ecore_x_selection_primary_clear; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].request = ecore_x_selection_primary_request; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].debug = "Secondary"; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].ecore_sel = ECORE_X_SELECTION_SECONDARY; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].set = ecore_x_selection_secondary_set; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].clear = ecore_x_selection_secondary_clear; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].request = ecore_x_selection_secondary_request; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_DND].debug = "DnD"; - sel_list[EFL_UI_SELECTION_TYPE_DND].ecore_sel = ECORE_X_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_DND].request = ecore_x_selection_xdnd_request; - sel_list[EFL_UI_SELECTION_TYPE_DND].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].debug = "Clipboard"; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].ecore_sel = ECORE_X_SELECTION_CLIPBOARD; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].set = ecore_x_selection_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].clear = ecore_x_selection_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].request = ecore_x_selection_clipboard_request; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].seat_sel = seat_sel; -} -#endif -#ifdef HAVE_ELEMENTARY_WIN32 -static void -_set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel) -{ - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].debug = "Primary"; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].ecore_sel = ECORE_WIN32_SELECTION_PRIMARY; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].set = ecore_win32_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].clear = ecore_win32_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].get = ecore_win32_clipboard_get; - sel_list[EFL_UI_SELECTION_TYPE_PRIMARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].debug = "Secondary"; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].ecore_sel = ECORE_WIN32_SELECTION_OTHER; - sel_list[EFL_UI_SELECTION_TYPE_SECONDARY].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_DND].debug = "DnD"; - sel_list[EFL_UI_SELECTION_TYPE_DND].ecore_sel = ECORE_WIN32_SELECTION_OTHER; - sel_list[EFL_UI_SELECTION_TYPE_DND].seat_sel = seat_sel; - - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].debug = "Clipboard"; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].ecore_sel = ECORE_WIN32_SELECTION_CLIPBOARD; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].set = ecore_win32_clipboard_set; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].clear = ecore_win32_clipboard_clear; - sel_list[EFL_UI_SELECTION_TYPE_CLIPBOARD].seat_sel = seat_sel; -} -#endif - -#include "efl_ui_selection_manager.eo.c" diff --git a/src/lib/elementary/efl_ui_selection_manager.eo b/src/lib/elementary/efl_ui_selection_manager.eo deleted file mode 100644 index e7df9cce77..0000000000 --- a/src/lib/elementary/efl_ui_selection_manager.eo +++ /dev/null @@ -1,139 +0,0 @@ -import efl_ui_dnd_types; - -class @beta Efl.Ui.Selection_Manager extends Efl.Object { - methods { - selection_set @beta { - [[Set selection]] - params { - @in owner: Efl.Object; [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in format: Efl.Ui.Selection_Format; [[Selection format]] - @in data: Eina.Slice; [[Selection data]] - @in seat: uint @optional;[[Specified seat for multiple seats case.]] - } - return: future; [[Future for tracking when the selection is lost]] - } - selection_get @beta { - [[Get selection]] - params { - @in request: const(Efl.Object); [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in format: Efl.Ui.Selection_Format; [[Selection Format]] - @in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]] - @in seat: uint @optional;[[Specified seat for multiple seats case.]] - } - } - selection_clear @beta { - params { - @in owner: Efl.Object; [[Seleciton owner]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint @optional; [[Specified seat for multiple seats case.]] - } - } - selection_has_owner @beta { - [[Check if the request object has selection or not]] - params { - @in request: Efl.Object; [[Request object]] - @in type: Efl.Ui.Selection_Type; [[Selection type]] - @in seat: uint @optional; [[Specified seat for multiple seats case.]] - } - return: bool; [[EINA_TRUE if the request object has selection, otherwise, EINA_FALSE]] - } - drag_start @beta { - [[This starts a drag and drop process at the drag side. - During dragging, there are three events emitted as belows: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE - ]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in format: Efl.Ui.Selection_Format; [[Data format]] - @in data: Eina.Slice; [[Data to transfer]] - @in action: Efl.Ui.Selection_Action; [[Action when data is transferred]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_action_set @beta { - [[This sets the action for the drag]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in action: Efl.Ui.Selection_Action; [[Drag action]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - drag_cancel @beta { - [[This cancels the on-going drag]] - params { - @in drag_obj: Efl.Object; [[Drag object]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drag_item_add @beta { - [[This registers a drag for items in a container. Many items can be - dragged at a time. During dragging, there are three events emitted: - - EFL_UI_DND_EVENT_DRAG_POS - - EFL_UI_DND_EVENT_DRAG_ACCEPT - - EFL_UI_DND_EVENT_DRAG_DONE.]] - params { - @in cont: Efl.Object; [[Container object]] - @in time_to_drag: double; [[Time since mouse down happens to drag starts]] - @in anim_duration: double; [[animation duration]] - @in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]] - @in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]] - @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]] - @in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations]] - @in seat: uint; [[Specified seat for multiple seats case]] - } - } - container_drag_item_del @beta { - [[Remove drag function of items in the container object.]] - params { - @in cont: Efl.Object; [[Container object]] - @in seat: uint; [[Specified seat for multiple seats case]] - } - } - drop_target_add @beta { - [[Add a dropable target. There are four events emitted: - - EFL_UI_DND_DROP_DRAG_ENTER - - EFL_UI_DND_DROP_DRAG_LEAVE - - EFL_UI_DND_DROP_DRAG_POS - - EFL_UI_DND_DROP_DRAG_DROP.]] - params { - @in target_obj: Efl.Object; [[Drop target]] - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - return: bool; [[$true on success, $false otherwise]] - } - drop_target_del @beta { - [[Remove a dropable target]] - params { - @in target_obj: Efl.Object; [[Drop target]] - @in format: Efl.Ui.Selection_Format; [[Accepted data format]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drop_item_add @beta { - [[Add dropable target for a container in which items can drop to it]] - params { - @in cont: Efl.Object; [[Container object]] - @in format: Efl.Ui.Selection_Format; [[Accepted data formats]] - @in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - container_drop_item_del @beta { - [[Remove dropable target for the container]] - params { - @in cont: Efl.Object; [[Container object]] - @in seat: uint; [[Specified seat for multiple seats case.]] - } - } - } - implements { - Efl.Object.constructor; - Efl.Object.destructor; - } -} diff --git a/src/lib/elementary/efl_ui_selection_types.eot b/src/lib/elementary/efl_ui_selection_types.eot deleted file mode 100644 index cbe5e0dc7b..0000000000 --- a/src/lib/elementary/efl_ui_selection_types.eot +++ /dev/null @@ -1,60 +0,0 @@ -enum @beta Efl.Ui.Selection_Type -{ - [[Selection type]] - primary, [[Primary text selection (highlighted or selected text)]] - secondary, [[Used when primary selection is in use]] - dnd, [[Drag and Drop]] - clipboard [[Clipboard selection (ctrl+C)]] -} - -enum @beta Efl.Ui.Selection_Format -{ - [[Selection format]] - targets = -1, [[For matching every possible atom]] - none = 0x0, [[Content is from outside of EFL]] - text = 0x01, [[Plain unformatted text: Used for things that don't want rich markup]] - markup = 0x2, [[Edje textblock markup, including inline images]] - image = 0x4, [[Images]] - vcard = 0x08, [[Vcards]] - html = 0x10 [[Raw HTML-like data (eg. webkit)]] -} - -enum @beta Efl.Ui.Selection_Action -{ - [[Defines the kind of action associated with the drop data]] - unknown, [[Action type is unknown]] - copy, [[Copy the data]] - move, [[Move the data]] - private, [[Private action type]] - ask, [[Ask the user what to do]] - list, [[List the data]] - link, [[Link the data]] - description [[Describe the data]] -} - -struct @beta Efl.Ui.Selection_Data -{ - [[Structure holding the info about selected data]] - pos: Eina.Position2D; [[Coordinates of the drop (DND operations only)]] - format: Efl.Ui.Selection_Format; [[Format of the selection]] - content: Eina.Slice; [[Selection data]] - action: Efl.Ui.Selection_Action; [[Action to perform with the data]] - item: Efl.Object; [[Item under the drag position. It is only available for container]] -} - -function @beta Efl.Ui.Selection_Data_Ready { - [[Function pointer for getting selection]] - params { - @in obj: Efl.Object; [[Object which requested for the selection]] - @in seldata: ptr(Efl.Ui.Selection_Data); [[Selection data]] - } -}; - -struct @beta Efl.Ui.Selection_Changed -{ - [[Selection-changed specific information.]] // TODO: This needs to be filled in. - type: Efl.Ui.Selection_Type; [[Selection type]] - seat: int; [[The seat on which the selection changed, or NULL for "default"]] - display: void_ptr; [[The display connection object, NULL under X11]] - exist: bool; [[EINA_TRUE if the selection has an owner]] -} diff --git a/src/lib/elementary/efl_ui_tags.c b/src/lib/elementary/efl_ui_tags.c index 95c5ce59d7..5cc37badda 100644 --- a/src/lib/elementary/efl_ui_tags.c +++ b/src/lib/elementary/efl_ui_tags.c @@ -757,7 +757,7 @@ _view_init(Evas_Object *obj, Efl_Ui_Tags_Data *sd) sd->entry = efl_add(EFL_UI_TEXTBOX_CLASS, sd->box, efl_text_multiline_set(efl_added, EINA_FALSE), efl_text_set(efl_added, ""), - efl_ui_textbox_cnp_mode_set(efl_added, EFL_UI_SELECTION_FORMAT_MARKUP), + efl_ui_textbox_cnp_dnd_mode_set(efl_added, EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP), efl_input_text_input_panel_autoshow_set(efl_added, EINA_FALSE), efl_text_interactive_editable_set(efl_added, EINA_TRUE), efl_composite_attach(obj, efl_added)); diff --git a/src/lib/elementary/efl_ui_textbox.c b/src/lib/elementary/efl_ui_textbox.c index a53c265d38..3ffa3e096a 100644 --- a/src/lib/elementary/efl_ui_textbox.c +++ b/src/lib/elementary/efl_ui_textbox.c @@ -22,7 +22,6 @@ typedef struct _Efl_Ui_Textbox_Data Efl_Ui_Textbox_Data; typedef struct _Efl_Ui_Text_Rectangle Efl_Ui_Text_Rectangle; typedef struct _Anchor Anchor; -typedef struct _Selection_Loss_Data Selection_Loss_Data; /** * Base widget smart data extended with entry instance data. @@ -69,7 +68,7 @@ struct _Efl_Ui_Textbox_Data const char *hover_style; /**< style of a hover object */ } anchor_hover; - Efl_Ui_Selection_Format cnp_mode; + const char *cnp_mime_type; Elm_Sel_Format drop_format; struct { @@ -81,11 +80,7 @@ struct _Efl_Ui_Textbox_Data Eina_Size2D scroll; Eina_Size2D layout; } last; - struct - { - Eina_Future *primary; - Eina_Future *clipboard; - } sel_future; + Efl_Ui_Textbox_Cnp_Content content; Eina_Bool sel_handles_enabled : 1; Eina_Bool start_handler_down : 1; Eina_Bool start_handler_shown : 1; @@ -147,12 +142,6 @@ struct _Efl_Ui_Text_Rectangle Evas_Object *obj_bg, *obj_fg, *obj; }; -struct _Selection_Loss_Data -{ - Eo *obj; - Efl_Ui_Selection_Type stype; -}; - #define MY_CLASS EFL_UI_TEXTBOX_CLASS #define MY_CLASS_PFX efl_ui_textbox #define MY_CLASS_NAME "Efl.Ui.Textbox" @@ -208,7 +197,7 @@ static void _anchors_free(Efl_Ui_Textbox_Data *sd); static void _selection_defer(Eo *obj, Efl_Ui_Textbox_Data *sd); static Eina_Position2D _decoration_calc_offset(Efl_Ui_Textbox_Data *sd); static void _update_text_theme(Eo *obj, Efl_Ui_Textbox_Data *sd); -static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type); +static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type); static Eina_Bool _key_action_copy(Evas_Object *obj, const char *params); static Eina_Bool _key_action_paste(Evas_Object *obj, const char *params); @@ -407,16 +396,19 @@ _update_selection_handler(Eo *obj) } } -static void -_selection_data_cb(void *data EINA_UNUSED, Eo *obj, - Efl_Ui_Selection_Data *sel_data) +static Eina_Value +_selection_data_cb(Efl_Ui_Textbox *obj, void *data EINA_UNUSED, const Eina_Value value) { + Eina_Content *content; + Eina_Slice slice; Efl_Text_Cursor *cur, *start, *end; Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 }; - char *buf = eina_slice_strdup(sel_data->content); - size_t len = sel_data->content.len; + if (eina_value_type_get(&value) != EINA_VALUE_TYPE_CONTENT) + return EINA_VALUE_EMPTY; + content = eina_value_to_content(&value); + slice = eina_content_data_get(content); efl_text_interactive_selection_cursors_get(obj, &start, &end); if (!efl_text_cursor_equal(start, end)) { @@ -426,83 +418,130 @@ _selection_data_cb(void *data EINA_UNUSED, Eo *obj, cur = efl_text_interactive_main_cursor_get(obj); info.type = EFL_TEXT_CHANGE_TYPE_INSERT; info.position = efl_text_cursor_position_get(cur); - info.length = len; - info.content = buf; - if (sel_data->format == EFL_UI_SELECTION_FORMAT_MARKUP) + info.length = slice.len; + info.content = slice.mem; + if (eina_streq(eina_content_type_get(content), "application/x-elementary-markup")) { - efl_text_cursor_markup_insert(cur, buf); + efl_text_cursor_markup_insert(cur, slice.mem); + } + else if (!strncmp(eina_content_type_get(content), "image/", strlen("image/"))) + { + Eina_Strbuf *result = eina_strbuf_new(); + eina_strbuf_append_printf(result, ""); + efl_text_cursor_markup_insert(cur, eina_strbuf_string_get(result)); + eina_strbuf_free(result); } else // TEXT { - efl_text_cursor_text_insert(cur, buf); + efl_text_cursor_text_insert(cur, slice.mem); } efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info); - free(buf); + + return EINA_VALUE_EMPTY; +} + +static Eina_Array* +_figure_out_types(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) +{ + Eina_Array *types = eina_array_new(10); + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP) + eina_array_push(types, "application/x-elementary-markup"); + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE) + { + eina_array_push(types, "image/png"); + eina_array_push(types, "image/jpeg"); + eina_array_push(types, "image/x-ms-bmp"); + eina_array_push(types, "image/gif"); + eina_array_push(types, "image/tiff"); + eina_array_push(types, "image/svg+xml"); + eina_array_push(types, "image/x-xpixmap"); + eina_array_push(types, "image/x-tga"); + eina_array_push(types, "image/x-portable-pixmap"); + } + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT) + eina_array_push(types, "text/plain;charset=utf-8"); + return types; +} + +static Eina_Bool +_accepting_drops(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Accessor *mime_types) +{ + int i = 0; + const char *mime_type; + + if (efl_ui_widget_disabled_get(obj)) return EINA_FALSE; + + EINA_ACCESSOR_FOREACH(mime_types, i, mime_type) + { + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT && + eina_streq(mime_type, "text/plain;charset=utf-8")) + return EINA_TRUE; + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE && + strncmp(mime_type, "image/", strlen("image/"))) + return EINA_TRUE; + + if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP && + eina_streq(mime_type, "application/x-elementary-markup")) + return EINA_TRUE; + } + return EINA_FALSE; } static void _dnd_enter_cb(void *data EINA_UNUSED, - Evas_Object *obj) + const Efl_Event *ev) { - efl_ui_focus_util_focus(obj); + Efl_Ui_Drop_Event *dnd_enter = ev->info; + EFL_UI_TEXT_DATA_GET(ev->object, sd); + if (_accepting_drops(ev->object, sd, dnd_enter->available_types)) + efl_ui_focus_util_focus(ev->object); } static void -_dnd_leave_cb(void *data EINA_UNUSED, - Evas_Object *obj EINA_UNUSED) +_dnd_pos_cb(void *data EINA_UNUSED, const Efl_Event *ev) { -} + Efl_Ui_Drop_Event *dnd_pos = ev->info; + Eina_Position2D po, pe, pos; + EFL_UI_TEXT_DATA_GET(ev->object, sd); + int cursor_pos; -static void -_dnd_pos_cb(void *data EINA_UNUSED, - Evas_Object *obj, - Evas_Coord x, - Evas_Coord y, - Elm_Xdnd_Action action EINA_UNUSED) -{ - int pos; - Eina_Rect o, e; + if (!_accepting_drops(ev->object, sd, dnd_pos->available_types)) + return; - EFL_UI_TEXT_DATA_GET(obj, sd); - - o = efl_gfx_entity_geometry_get(obj); - e = efl_gfx_entity_geometry_get(sd->entry_edje); - x = x + o.x - e.x; - y = y + o.y - e.y; + po = efl_gfx_entity_position_get(ev->object); + pe = efl_gfx_entity_position_get(sd->entry_edje); + pos.x = dnd_pos->position.x + po.x - pe.x; + pos.y = dnd_pos->position.y + po.x - pe.y; edje_object_part_text_cursor_coord_set - (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, x, y); - pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, pos.x, pos.y); + cursor_pos = edje_object_part_text_cursor_pos_get (sd->entry_edje, "efl.text", EDJE_CURSOR_USER); edje_object_part_text_cursor_pos_set(sd->entry_edje, "efl.text", - EDJE_CURSOR_MAIN, pos); + EDJE_CURSOR_MAIN, cursor_pos); } -static Eina_Bool -_dnd_drop_cb(void *data EINA_UNUSED, - Evas_Object *obj, - Elm_Selection_Data *drop) +static void +_dnd_drop_cb(void *data EINA_UNUSED, const Efl_Event *ev) { - Eina_Bool rv; + Efl_Ui_Drop_Event *drop = ev->info; + Eina_Future *future; + Eina_Array *types; - EFL_UI_TEXT_DATA_GET(obj, sd); + EFL_UI_TEXT_DATA_GET(ev->object, sd); + types = _figure_out_types(ev->object, sd); - rv = edje_object_part_text_cursor_coord_set - (sd->entry_edje, "efl.text", EDJE_CURSOR_MAIN, drop->x, drop->y); + if (!_accepting_drops(ev->object, sd, drop->available_types)) + return; - if (!rv) WRN("Warning: Failed to position cursor: paste anyway"); + future = efl_ui_dnd_drop_data_get(ev->object, 0, eina_array_iterator_new(types)); + eina_array_free(types); - //rv = _selection_data_cb(NULL, obj, drop); - - return rv; -} - -static Elm_Sel_Format -_get_drop_format(Evas_Object *obj) -{ - if (efl_text_interactive_editable_get(obj) && (efl_text_multiline_get(obj)) && (!efl_text_password_get(obj)) && (!efl_ui_widget_disabled_get(obj))) - return EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE; - return EFL_UI_SELECTION_FORMAT_MARKUP; + efl_future_then(ev->object, future, _selection_data_cb); } /* we can't reuse layout's here, because it's on entry_edje only */ @@ -516,12 +555,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein efl_ui_widget_disabled_set(efl_super(obj, MY_CLASS), disabled); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - emission = efl_ui_widget_disabled_get(obj) ? "efl,state,disabled" : "efl,state,enabled"; efl_layout_signal_emit(sd->entry_edje, emission, "efl"); if (sd->scroll) @@ -529,15 +562,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein efl_ui_scrollable_scroll_freeze_set(obj, efl_ui_widget_disabled_get(obj)); } - if (!efl_ui_widget_disabled_get(obj)) - { - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - } _update_text_theme(obj, sd); } @@ -804,83 +828,36 @@ _popup_position(Evas_Object *obj) efl_gfx_entity_geometry_set(sd->popup, EINA_RECT(r.x + cx, r.y + cy, m.w, m.h)); } -static Eina_Value -_selection_lost_cb(void *data, const Eina_Value value) +static void +_selection_lost_cb(void *data EINA_UNUSED, const Efl_Event *ev) { - Selection_Loss_Data *sdata = data; - EFL_UI_TEXT_DATA_GET(sdata->obj, sd); + Efl_Ui_Wm_Selection_Changed *changed = ev->info; + EFL_UI_TEXT_DATA_GET(ev->object, sd); - efl_text_interactive_all_unselect(sdata->obj); - _selection_defer(sdata->obj, sd); - switch (sdata->stype) + if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && changed->caused_by != ev->object) { - case EFL_UI_SELECTION_TYPE_CLIPBOARD: - sd->sel_future.clipboard = NULL; - break; - case EFL_UI_SELECTION_TYPE_PRIMARY: - default: - sd->sel_future.primary = NULL; - break; + efl_text_interactive_all_unselect(ev->object); + _selection_defer(ev->object, sd); } - - return value; } static void -_selection_store(Efl_Ui_Selection_Type seltype, +_selection_store(Efl_Ui_Cnp_Buffer buffer, Evas_Object *obj) { char *sel; Efl_Text_Cursor *start, *end; - Efl_Ui_Selection_Format selformat = EFL_UI_SELECTION_FORMAT_MARKUP; - Eina_Slice slice; - Selection_Loss_Data *ldata; - Eina_Future *f; - - EFL_UI_TEXT_DATA_GET(obj, sd); + Eina_Content *content; efl_text_interactive_selection_cursors_get(obj, &start, &end); sel = efl_text_cursor_range_markup_get(start, end); if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */ - slice.len = strlen(sel); - slice.mem = sel; + content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(sel), "application/x-elementary-markup"); - switch (seltype) - { - case EFL_UI_SELECTION_TYPE_CLIPBOARD: - if (sd->sel_future.clipboard) - { - eina_future_cancel(sd->sel_future.clipboard); - } + efl_ui_selection_set(obj, buffer, content, 0); - f = sd->sel_future.clipboard = efl_ui_selection_set(obj, seltype, - selformat, slice, 1); - break; - - case EFL_UI_SELECTION_TYPE_PRIMARY: - default: - if (sd->sel_future.primary) - { - eina_future_cancel(sd->sel_future.primary); - } - - f = sd->sel_future.primary = efl_ui_selection_set(obj, seltype, - selformat, slice, 1); - break; - } - - ldata = calloc(1, sizeof(Selection_Loss_Data)); - if (!ldata) goto end; - - ldata->obj = obj; - eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata); - - //if (seltype == EFL_UI_SELECTION_TYPE_CLIPBOARD) - // eina_stringshare_replace(&sd->cut_sel, sel); - -end: free(sel); } @@ -956,7 +933,7 @@ _menu_call(Evas_Object *obj) { Eina_Bool ownersel; - ownersel = elm_selection_selection_has_owner(obj); + ownersel = elm_cnp_clipboard_selection_has_owner(obj); /* prevent stupid blank hoversel */ if (efl_text_interactive_have_selection_get(obj) && efl_text_password_get(obj)) return; if (_elm_config->desktop_entry && (!efl_text_interactive_have_selection_get(obj)) && ((!efl_text_interactive_editable_get(obj)) || (!ownersel))) @@ -1133,7 +1110,7 @@ _mouse_down_cb(void *data, const Efl_Event *event) if (ev->button == 2) { - _efl_ui_textbox_selection_paste_type(data, EFL_UI_SELECTION_TYPE_PRIMARY); + _efl_ui_textbox_selection_paste_type(data, sd, EFL_UI_CNP_BUFFER_SELECTION); } /* If right button is pressed and context menu disabled is true, @@ -1654,10 +1631,18 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd) { Eo *text_obj; + sd->content = EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP; + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); if (!elm_widget_theme_klass_get(obj)) elm_widget_theme_klass_set(obj, "text"); + + efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_lost_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_ENTERED, _dnd_enter_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, _dnd_pos_cb, NULL); + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_DROPPED, _dnd_drop_cb, NULL); + obj = efl_constructor(efl_super(obj, MY_CLASS)); efl_event_callback_add(obj, EFL_INPUT_EVENT_LONGPRESSED, _long_press_cb, obj); @@ -1674,11 +1659,9 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd) efl_composite_attach(obj, text_obj); sd->entry_edje = wd->resize_obj; - sd->cnp_mode = EFL_UI_SELECTION_FORMAT_TEXT; sd->context_menu_enabled = EINA_TRUE; efl_text_interactive_editable_set(obj, EINA_TRUE); efl_text_interactive_selection_allowed_set(obj, EINA_TRUE); - sd->drop_format = EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE; sd->last.scroll = EINA_SIZE2D(0, 0); sd->sel_handles_enabled = EINA_FALSE; @@ -1691,12 +1674,6 @@ _efl_ui_textbox_efl_object_finalize(Eo *obj, { obj = efl_finalize(efl_super(obj, MY_CLASS)); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY); _update_guide_text(obj, sd); @@ -1805,11 +1782,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E efl_text_replacement_char_set(obj, ENTRY_PASSWORD_MASK_CHARACTER_UTF8); efl_text_password_set(sd->text_obj, password); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (password) { efl_text_multiline_set(obj, EINA_FALSE); @@ -1819,12 +1791,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E else { efl_text_multiline_set(obj, EINA_TRUE); - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); efl_input_text_input_content_type_set(obj, ((efl_input_text_input_content_type_get(obj) | EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE) & ~EFL_INPUT_TEXT_CONTENT_TYPE_SENSITIVE_DATA)); efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY); } @@ -1891,19 +1857,8 @@ _efl_ui_textbox_efl_text_interactive_editable_set(Eo *obj, Efl_Ui_Textbox_Data * efl_ui_widget_theme_apply(obj); efl_ui_widget_focus_allow_set(obj, editable); - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (editable) { - sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); if (sd->cursor) { efl_gfx_entity_visible_set(sd->cursor, EINA_TRUE); @@ -1961,7 +1916,7 @@ _efl_ui_textbox_selection_cut(Eo *obj, Efl_Ui_Textbox_Data *sd) /*In password mode, cut will remove text only*/ if (!efl_text_password_get(obj)) - _selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj); + _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj); efl_text_interactive_selection_cursors_get(obj, &start, &end); start_pos = efl_text_cursor_position_get(start); @@ -1993,25 +1948,27 @@ _efl_ui_textbox_selection_copy(Eo *obj, Efl_Ui_Textbox_Data *sd) efl_layout_signal_emit(sd->entry_edje, "efl,state,select,off", "efl"); efl_ui_widget_scroll_hold_pop(obj); } - _selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj); + _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj); efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_COPY, NULL); } - static void -_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type) +_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type) { - Efl_Ui_Selection_Format formats = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP; + Eina_Future *future; + Eina_Array *types = _figure_out_types(obj, sd); - efl_ui_selection_get(obj, type, formats, - NULL, _selection_data_cb, NULL, 1); + future = efl_ui_selection_get(obj, type, 0, eina_array_iterator_new(types)); + + efl_future_then(obj, future, _selection_data_cb); efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_PASTE, NULL); + eina_array_free(types); } EOLIAN static void -_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd EINA_UNUSED) +_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd) { - _efl_ui_textbox_selection_paste_type(obj, EFL_UI_SELECTION_TYPE_CLIPBOARD); + _efl_ui_textbox_selection_paste_type(obj, sd, EFL_UI_CNP_BUFFER_COPY_AND_PASTE); } EOLIAN static void @@ -2028,44 +1985,15 @@ _efl_ui_textbox_context_menu_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textb } EOLIAN static void -_efl_ui_textbox_cnp_mode_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Selection_Format cnp_mode) +_efl_ui_textbox_cnp_dnd_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Efl_Ui_Textbox_Cnp_Content content) { - Elm_Sel_Format dnd_format = EFL_UI_SELECTION_FORMAT_MARKUP; - - if (cnp_mode != EFL_UI_SELECTION_FORMAT_TARGETS) - { - if (cnp_mode & EFL_UI_SELECTION_FORMAT_VCARD) - ERR("VCARD format not supported for copy & paste!"); - else if (cnp_mode & EFL_UI_SELECTION_FORMAT_HTML) - ERR("HTML format not supported for copy & paste!"); - cnp_mode &= ~EFL_UI_SELECTION_FORMAT_VCARD; - cnp_mode &= ~EFL_UI_SELECTION_FORMAT_HTML; - } - - if (sd->cnp_mode == cnp_mode) return; - sd->cnp_mode = cnp_mode; - if (sd->cnp_mode == EFL_UI_SELECTION_FORMAT_TEXT) - dnd_format = EFL_UI_SELECTION_FORMAT_TEXT; - else if (cnp_mode == EFL_UI_SELECTION_FORMAT_IMAGE) - dnd_format |= EFL_UI_SELECTION_FORMAT_IMAGE; - - elm_drop_target_del(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); - sd->drop_format = dnd_format; - elm_drop_target_add(obj, sd->drop_format, - _dnd_enter_cb, NULL, - _dnd_leave_cb, NULL, - _dnd_pos_cb, NULL, - _dnd_drop_cb, NULL); + sd->content = content; } -EOLIAN static Efl_Ui_Selection_Format -_efl_ui_textbox_cnp_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) +EOLIAN static Efl_Ui_Textbox_Cnp_Content +_efl_ui_textbox_cnp_dnd_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd) { - return sd->cnp_mode; + return sd->content; } EOLIAN static void @@ -3279,7 +3207,7 @@ _efl_ui_textbox_selection_changed_cb(void *data, const Efl_Event *event EINA_UNU Eo *obj = data; EFL_UI_TEXT_DATA_GET(obj, sd); _edje_signal_emit(sd, "selection,changed", "efl.text"); - _selection_store(EFL_UI_SELECTION_TYPE_PRIMARY, obj); + _selection_store(EFL_UI_CNP_BUFFER_SELECTION, obj); _selection_defer(obj, sd); } diff --git a/src/lib/elementary/efl_ui_textbox.eo b/src/lib/elementary/efl_ui_textbox.eo index 2b7ccf9472..2605c477a3 100644 --- a/src/lib/elementary/efl_ui_textbox.eo +++ b/src/lib/elementary/efl_ui_textbox.eo @@ -1,3 +1,15 @@ +enum @beta Efl.Ui.Textbox_Cnp_Content { + [[What kind of content can be pasted into this widget using Copy & Paste or Drag & Drop functionality. + + Multiple options can be OR-ed together. + ]] + Nothing = 0, [[Nothing can be pasted or dropped into this widget.]] + Text = 1, [[Plain text can be pasted or dropped into this widget.]] + Markup = 3, [[Markup text can be pasted or dropped into this widget + (This includes Plain text).]] + Image = 4, [[Images can be pasted or dropped into this widget.]] +} + class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Clickable, Efl.Access.Text, Efl.Access.Editable.Text composites @@ -31,20 +43,17 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click enabled: bool; [[$true to enable the contextual menu.]] } } - @property cnp_mode @beta { - /* FIXME: Efl.Ui.Selection_Format does not allow markup without images! */ - [[Control pasting of text and images for the widget. + @property cnp_dnd_mode @beta { + [[Controls the type of content which can be pasted into the widget. - Normally the entry allows both text and images to be pasted. - - Note: This only changes the behaviour of text. + By default, both text and images are allowed.. ]] set { } get { } values { - format: Efl.Ui.Selection_Format; [[Format for copy & paste.]] + allowed_formats : Efl.Ui.Textbox_Cnp_Content; [[Allowed content types.]] } } @property selection_handles_enabled { diff --git a/src/lib/elementary/efl_ui_win.c b/src/lib/elementary/efl_ui_win.c index c0450eea9c..69f2e7b6d0 100644 --- a/src/lib/elementary/efl_ui_win.c +++ b/src/lib/elementary/efl_ui_win.c @@ -213,6 +213,9 @@ struct _Efl_Ui_Win_Data int ignore_frame_resize; Eina_Bool req_wh : 1; Eina_Bool req_xy : 1; + Eina_Array *selection_changed; + Eina_Array *planned_changes; + Eina_Inarray *drop_target; struct { short pointer_move; @@ -382,6 +385,8 @@ static void _elm_win_frame_style_update(Efl_Ui_Win_Data *sd, Eina_Bool force_emi static inline void _elm_win_need_frame_adjust(Efl_Ui_Win_Data *sd, const char *engine); static void _elm_win_resize_objects_eval(Evas_Object *obj, Eina_Bool force_resize); static void _elm_win_frame_obj_update(Efl_Ui_Win_Data *sd, Eina_Bool force); +static void _ee_backbone_init(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd); +static void _ee_backbone_shutdown(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd); static inline Efl_Ui_Win_Type _elm_win_type_to_efl_ui_win_type(Elm_Win_Type type) @@ -5933,6 +5938,7 @@ _efl_ui_win_efl_object_finalize(Eo *obj, Efl_Ui_Win_Data *sd) efl_file_mmap_get(efl_super(efl_part(obj, "background"), EFL_UI_WIN_PART_CLASS))) efl_file_load(efl_part(obj, "background")); } + _ee_backbone_init(obj, sd); return obj; } @@ -5968,6 +5974,8 @@ _efl_ui_win_efl_object_destructor(Eo *obj, Efl_Ui_Win_Data *pd EINA_UNUSED) if (pd->finalize_future) eina_future_cancel(pd->finalize_future); + _ee_backbone_shutdown(obj, pd); + efl_destructor(efl_super(obj, MY_CLASS)); efl_unref(pd->provider); @@ -5984,6 +5992,7 @@ _efl_ui_win_efl_object_constructor(Eo *obj, Efl_Ui_Win_Data *pd) pd->provider = efl_add_ref(EFL_UI_FOCUS_PARENT_PROVIDER_STANDARD_CLASS, NULL); pd->profile.available = eina_array_new(4); pd->max_w = pd->max_h = -1; + pd->planned_changes = eina_array_new(10); // For bindings: if no parent, allow simple unref if (!efl_parent_get(obj)) @@ -9187,6 +9196,249 @@ elm_win_teamwork_uri_open(Efl_Ui_Win *obj EINA_UNUSED, const char *uri EINA_UNUS ERR("Calling deprecrated function '%s'", __FUNCTION__); } +/* What here follows is code that implements the glue between ecore evas and efl_ui* side */ +typedef struct { + Eo *obj; + Eina_Bool currently_inside; +} Ui_Dnd_Target; + +static inline Efl_Ui_Cnp_Buffer +_ui_buffer_get(Ecore_Evas_Selection_Buffer buffer) +{ + if (buffer == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + return EFL_UI_CNP_BUFFER_SELECTION; + else if (buffer == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return EFL_UI_CNP_BUFFER_COPY_AND_PASTE; + + return -1; +} + +void +_register_selection_changed(Efl_Ui_Selection *selection) +{ + ELM_WIN_DATA_GET(efl_provider_find(selection, EFL_UI_WIN_CLASS), pd); + + eina_array_push(pd->planned_changes, selection); +} + +static Eina_Bool +_remove_object(void *data, void *gdata) +{ + if (data == gdata) + return EINA_FALSE; + return EINA_TRUE; +} + +static void +_selection_changed_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + Efl_Ui_Wm_Selection_Changed changed = { + .seat = seat, + .buffer = _ui_buffer_get(selection), + .caused_by = eina_array_count(pd->planned_changes) > 0 ? eina_array_data_get(pd->planned_changes, 0) : NULL, + }; + + for (unsigned int i = 0; i < eina_array_count(pd->selection_changed); ++i) + { + Eo *obj = eina_array_data_get(pd->selection_changed, i); + + efl_event_callback_call(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &changed); + } + + if (changed.caused_by) + eina_array_remove(pd->planned_changes, _remove_object, changed.caused_by); +} + +static void +_motion_cb(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + Efl_Ui_Drop_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)}; + + if (target->currently_inside && !inside) + { + target->currently_inside = EINA_FALSE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEFT, &ev); + } + else if (!target->currently_inside && inside) + { + target->currently_inside = EINA_TRUE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTERED, &ev); + } + else if (target->currently_inside && inside) + { + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, &ev); + } + eina_accessor_free(ev.available_types); + } +} + +static void +_enter_state_change_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, Eina_Bool move_inside) +{ + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + Efl_Ui_Drop_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)}; + + if (inside && move_inside) + { + target->currently_inside = EINA_TRUE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTERED, &ev); + } + else if (!move_inside && !target->currently_inside) + { + target->currently_inside = EINA_FALSE; + efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEFT, &ev); + } + } +} + +static void +_drop_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, const char *action) +{ + Eina_List *itr, *top_objects_list = NULL; + Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee); + Eina_Array *tmp = eina_array_new(10); + Eo *top_obj; + + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj); + Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y); + + if (inside) + { + EINA_SAFETY_ON_FALSE_GOTO(target->currently_inside, end); + eina_array_push(tmp, target->obj); + } + } + + /* We retrieve the (non-smart) objects pointed by (px, py) */ + top_objects_list = evas_tree_objects_at_xy_get(ecore_evas_get(ee), NULL, p.x, p.y); + /* We walk on this list from the last because if the list contains more than one + * element, all but the last will repeat events. The last one can repeat events + * or not. Anyway, this last one is the first that has to be taken into account + * for the determination of the drop target. + */ + EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj) + { + Evas_Object *object = top_obj; + /* We search for the dropable data into the object. If not found, we search into its parent. + * For example, if a button is a drop target, the first object will be an (internal) image. + * The drop target is attached to the button, i.e to image's parent. That's why we need to + * walk on the parents until NULL. + * If we find this dropable data, we found our drop target. + */ + while (object) + { + unsigned int out_idx; + if (!eina_array_find(tmp, object, &out_idx)) + { + object = evas_object_smart_parent_get(object); + } + else + { + Efl_Ui_Drop_Dropped_Event ev = {{p, seat, ecore_evas_drop_available_types_get(ee, seat)}, action}; + efl_event_callback_call(object, EFL_UI_DND_EVENT_DROP_DROPPED, &ev); + goto end; + } + } + } +end: + eina_list_free(top_objects_list); + eina_array_free(tmp); +} + +static void +_ee_backbone_init(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd) +{ + pd->selection_changed = eina_array_new(1); + pd->drop_target = eina_inarray_new(sizeof(Ui_Dnd_Target), 1); + + ecore_evas_callback_selection_changed_set(pd->ee, _selection_changed_cb); + ecore_evas_callback_drop_drop_set(pd->ee, _drop_cb); + ecore_evas_callback_drop_motion_set(pd->ee, _motion_cb); + ecore_evas_callback_drop_state_changed_set(pd->ee, _enter_state_change_cb); +} + +static void +_ee_backbone_shutdown(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd) +{ + ecore_evas_callback_selection_changed_set(pd->ee, NULL); + ecore_evas_callback_drop_drop_set(pd->ee, NULL); + ecore_evas_callback_drop_motion_set(pd->ee, NULL); + ecore_evas_callback_drop_state_changed_set(pd->ee, NULL); + + eina_array_free(pd->selection_changed); + pd->selection_changed = NULL; + eina_inarray_free(pd->drop_target); + pd->drop_target = NULL; + +} + +static Eina_Bool +_remove(void *data, void *gdata) +{ + if (data == gdata) + return EINA_FALSE; + return EINA_TRUE; +} + +void +_drop_event_register(Eo *obj) +{ + Ui_Dnd_Target target = {obj, EINA_FALSE}; + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + EINA_SAFETY_ON_NULL_RETURN(pd); + + eina_inarray_push(pd->drop_target, &target); +} + +void +_drop_event_unregister(Eo *obj) +{ + int idx = -1; + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i) + { + Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i); + if (target->obj == obj) + { + //FIXME emit drop + target->currently_inside = EINA_FALSE; + idx = i; + } + } + if (idx != -1) + eina_inarray_remove_at(pd->drop_target, idx); +} + +void +_selection_changed_event_register(Eo *obj) +{ + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + eina_array_push(pd->selection_changed, obj); +} +void +_selection_changed_event_unregister(Eo *obj) +{ + Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS); + + eina_array_remove(pd->selection_changed, _remove, obj); +} /* Internal EO APIs and hidden overrides */ ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_win, Efl_Ui_Win_Data) diff --git a/src/lib/elementary/elm_cnp.c b/src/lib/elementary/elm_cnp.c new file mode 100644 index 0000000000..cf1f0eedc0 --- /dev/null +++ b/src/lib/elementary/elm_cnp.c @@ -0,0 +1,244 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include + +#include "elm_priv.h" +#include "elm_entry_eo.h" + +static inline Ecore_Evas_Selection_Buffer +_elm_sel_type_to_ee_type(Elm_Sel_Type type) +{ + if (type == ELM_SEL_TYPE_PRIMARY) + return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER; + if (type == ELM_SEL_TYPE_XDND) + return ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER; + if (type == ELM_SEL_TYPE_CLIPBOARD) + return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; + return ECORE_EVAS_SELECTION_BUFFER_LAST; +} + +static inline Eina_Array* +_elm_sel_format_to_mime_type(Elm_Sel_Format format) +{ + Eina_Array *ret = eina_array_new(10); + if (format & ELM_SEL_FORMAT_TEXT) + eina_array_push(ret, "text/plain;charset=utf-8"); + if (format & ELM_SEL_FORMAT_MARKUP) + eina_array_push(ret, "application/x-elementary-markup"); + if (format & ELM_SEL_FORMAT_IMAGE) + { + eina_array_push(ret, "image/png"); + eina_array_push(ret, "image/jpeg"); + eina_array_push(ret, "image/x-ms-bmp"); + eina_array_push(ret, "image/gif"); + eina_array_push(ret, "image/tiff"); + eina_array_push(ret, "image/svg+xml"); + eina_array_push(ret, "image/x-xpixmap"); + eina_array_push(ret, "image/x-tga"); + eina_array_push(ret, "image/x-portable-pixmap"); + } + if (format & ELM_SEL_FORMAT_VCARD) + eina_array_push(ret, "text/vcard"); + if (format & ELM_SEL_FORMAT_HTML) + eina_array_push(ret, "application/xhtml+xml"); + + if (eina_array_count(ret) == 0) + ERR("Specified mime type is not available"); + + return ret; +} + +static inline const Elm_Sel_Format +_mime_type_to_elm_sel_format(const char *mime_type) +{ + if (eina_streq(mime_type, "text/vcard")) + return ELM_SEL_FORMAT_VCARD; + else if (eina_streq(mime_type, "application/x-elementary-markup")) + return ELM_SEL_FORMAT_MARKUP; + else if (eina_streq(mime_type, "application/xhtml+xml")) + return ELM_SEL_FORMAT_HTML; + else if (!strncmp(mime_type, "text/", strlen("text/"))) + return ELM_SEL_FORMAT_TEXT; + else if (!strncmp(mime_type, "image/", strlen("image/"))) + return ELM_SEL_FORMAT_IMAGE; + + return ELM_SEL_FORMAT_NONE; +} + +static int +_default_seat(const Eo *obj) +{ + return evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT)); +} + +EAPI Eina_Bool +elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, + Elm_Sel_Format format, + const void *buf, size_t buflen) +{ + Eina_Content *content; + Ecore_Evas *ee; + const char *mime_type; + Eina_Slice data; + Eina_Array *tmp; + + if (format == ELM_SEL_FORMAT_TEXT && ((char*)buf)[buflen - 1] != '\0') + { + data.mem = eina_memdup((unsigned char *)buf, buflen, EINA_TRUE); + data.len = buflen + 1; + } + else + { + data.mem = buf; + data.len = buflen; + } + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + + tmp = _elm_sel_format_to_mime_type(format); + if (eina_array_count(tmp) != 1) + { + ERR("You cannot specify more than one format when setting selection"); + } + mime_type = eina_array_data_get(tmp, 0); + content = eina_content_new(data, mime_type); + _register_selection_changed(obj); + + return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), content); +} + +EAPI Eina_Bool +elm_object_cnp_selection_clear(Evas_Object *obj, + Elm_Sel_Type selection) +{ + Ecore_Evas *ee; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), NULL); +} + +EAPI Eina_Bool +elm_cnp_clipboard_selection_has_owner(Evas_Object *obj) +{ + Ecore_Evas *ee; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + return ecore_evas_selection_exists(ee, _default_seat(obj), ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); + +} + +typedef struct _Sel_Lost_Data Sel_Lost_Data; +struct _Sel_Lost_Data +{ + const Evas_Object *obj; + Elm_Sel_Type type; + void *udata; + Elm_Selection_Loss_Cb loss_cb; +}; + +static void +_selection_changed_cb(void *data, const Efl_Event *ev) +{ + Sel_Lost_Data *ldata = data; + Efl_Ui_Wm_Selection_Changed *changed = ev->info; + + if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && ldata->type != ELM_SEL_TYPE_PRIMARY) + return; + + if (changed->buffer == EFL_UI_CNP_BUFFER_COPY_AND_PASTE && ldata->type != ELM_SEL_TYPE_CLIPBOARD) + return; + + if (ldata->obj == changed->caused_by) + return; + + ldata->loss_cb(ldata->udata, ldata->type); + free(data); + efl_event_callback_del(ev->object, ev->desc, _selection_changed_cb, data); +} + +EAPI void +elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, Elm_Selection_Loss_Cb func, const void *data) +{ + Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data)); + + if (!ldata) return; + ldata->obj = obj; + ldata->type = type; + ldata->udata = (void *)data; + ldata->loss_cb = func; + efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_changed_cb, ldata); +} + +typedef struct { + Elm_Drop_Cb data_cb; + void *data; + Elm_Sel_Format format; +} Callback_Storage; + +static Eina_Value +_callback_storage_deliver(Eo *obj, void *data, const Eina_Value value) +{ + Callback_Storage *cb_storage = data; + Eina_Content *content = eina_value_to_content(&value); + Elm_Sel_Format format = _mime_type_to_elm_sel_format(eina_content_type_get(content)); + Eina_Slice cdata; + + cdata = eina_content_data_get(content); + Elm_Selection_Data d = { 0 }; + d.data = eina_memdup((unsigned char*)cdata.bytes, cdata.len, EINA_FALSE); + d.len = cdata.len; + d.format = _mime_type_to_elm_sel_format(eina_content_type_get(content)); + + if (cb_storage->data_cb) + { + cb_storage->data_cb(cb_storage->data, obj, &d); + } + else + { + EINA_SAFETY_ON_FALSE_RETURN_VAL(format == ELM_SEL_FORMAT_TEXT || format == ELM_SEL_FORMAT_MARKUP || format == ELM_SEL_FORMAT_HTML, EINA_VALUE_EMPTY); + + _elm_entry_entry_paste(obj, (const char *) d.data); + } + free(d.data); + + return EINA_VALUE_EMPTY; +} + +static Eina_Value +_callback_storage_error(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, Eina_Error error) +{ + ERR("Content cound not be received because of %s.", eina_error_msg_get(error)); + return EINA_VALUE_EMPTY; +} + +static void +_callback_storage_free(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED) +{ + free(data); +} + +EAPI Eina_Bool +elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type selection, + Elm_Sel_Format format, + Elm_Drop_Cb data_cb, void *udata) +{ + Ecore_Evas *ee; + Eina_Array *mime_types; + Eina_Future *future; + Callback_Storage *storage; + + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + mime_types = _elm_sel_format_to_mime_type(format); + future = ecore_evas_selection_get(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), eina_array_iterator_new(mime_types)); + storage = calloc(1,sizeof(Callback_Storage)); + storage->data_cb = data_cb; + storage->data = udata; + storage->format = format; + + efl_future_then(obj, future, _callback_storage_deliver, _callback_storage_error, _callback_storage_free, EINA_VALUE_TYPE_CONTENT, storage); + + return EINA_TRUE; +} diff --git a/src/lib/elementary/elm_cnp.h b/src/lib/elementary/elm_cnp.h index 5feda3acc0..06346e40a5 100644 --- a/src/lib/elementary/elm_cnp.h +++ b/src/lib/elementary/elm_cnp.h @@ -43,8 +43,6 @@ * @{ */ -# include - /** * Event notifying that the selection has changed * @see Elm_Cnp_Event_Selection_Changed diff --git a/src/lib/elementary/elm_dnd.c b/src/lib/elementary/elm_dnd.c new file mode 100644 index 0000000000..699414bb4a --- /dev/null +++ b/src/lib/elementary/elm_dnd.c @@ -0,0 +1,812 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + + +#include +#include "elm_priv.h" + +int ELM_CNP_EVENT_SELECTION_CHANGED; + +typedef struct { + void *enter_data, *leave_data, *pos_data, *drop_data; + Elm_Drag_State enter_cb; + Elm_Drag_State leave_cb; + Elm_Drag_Pos pos_cb; + Elm_Drop_Cb drop_cb; + Eina_Array *mime_types; + Elm_Sel_Format format; + Elm_Xdnd_Action action; +} Elm_Drop_Target; + +static int +_default_seat(const Eo *obj) +{ + return evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT)); +} + +static const char* +_action_to_string(Elm_Xdnd_Action action) +{ + if (action == ELM_XDND_ACTION_COPY) return "copy"; + if (action == ELM_XDND_ACTION_MOVE) return "move"; + if (action == ELM_XDND_ACTION_PRIVATE) return "private"; + if (action == ELM_XDND_ACTION_ASK) return "ask"; + if (action == ELM_XDND_ACTION_LIST) return "list"; + if (action == ELM_XDND_ACTION_LINK) return "link"; + if (action == ELM_XDND_ACTION_DESCRIPTION) return "description"; + return "unknown"; +} + +static Elm_Xdnd_Action +_string_to_action(const char* action) +{ + if (eina_streq(action, "copy")) return ELM_XDND_ACTION_COPY; + else if (eina_streq(action, "move")) return ELM_XDND_ACTION_MOVE; + else if (eina_streq(action, "private")) return ELM_XDND_ACTION_PRIVATE; + else if (eina_streq(action, "ask")) return ELM_XDND_ACTION_ASK; + else if (eina_streq(action, "list")) return ELM_XDND_ACTION_LIST; + else if (eina_streq(action, "link")) return ELM_XDND_ACTION_LINK; + else if (eina_streq(action, "description")) return ELM_XDND_ACTION_DESCRIPTION; + return ELM_XDND_ACTION_UNKNOWN; +} + +static void +_enter_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + + if (target->enter_cb) + target->enter_cb(target->enter_data, ev->object); +} + +static void +_leave_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + + if (target->leave_cb) + target->leave_cb(target->leave_data, ev->object); +} + +static void +_pos_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + Efl_Ui_Drop_Event *event = ev->info; + + if (target->pos_cb) + target->pos_cb(target->pos_data, ev->object, event->position.x, event->position.y, target->action); //FIXME action +} + +static Eina_Value +_deliver_content(Eo *obj, void *data, const Eina_Value value) +{ + Elm_Drop_Target *target = data; + Elm_Selection_Data sel_data; + Eina_Content *content = eina_value_to_content(&value); + + sel_data.data = (void*)eina_content_data_get(content).mem; + sel_data.len = eina_content_data_get(content).len; + sel_data.action = target->action; + sel_data.format = target->format; + + if (target->drop_cb) + target->drop_cb(target->drop_data, obj, &sel_data); + + return EINA_VALUE_EMPTY; +} + +static void +_drop_cb(void *data, const Efl_Event *ev) +{ + Efl_Ui_Drop_Dropped_Event *event = ev->info; + Elm_Drop_Target *target = data; + target->action = _string_to_action(event->action); + efl_future_then(ev->object, efl_ui_dnd_drop_data_get(ev->object, _default_seat(ev->object), eina_array_iterator_new(target->mime_types)), + .success = _deliver_content, + .data = target + ); +} + +static void +_inv_cb(void *data, const Efl_Event *ev) +{ + Elm_Drop_Target *target = data; + elm_drop_target_del(ev->object, target->format, target->enter_cb, target->enter_data, target->leave_cb, + target->leave_data, target->pos_cb, target->pos_data, target->drop_cb, target->drop_data); +} + +EFL_CALLBACKS_ARRAY_DEFINE(drop_target_cb, + {EFL_UI_DND_EVENT_DROP_ENTERED, _enter_cb}, + {EFL_UI_DND_EVENT_DROP_LEFT, _leave_cb}, + {EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, _pos_cb}, + {EFL_UI_DND_EVENT_DROP_DROPPED, _drop_cb}, + {EFL_EVENT_INVALIDATE, _inv_cb} +) + +static Eina_Hash *target_register = NULL; + +static Eina_Array* +_format_to_mime_array(Elm_Sel_Format format) +{ + Eina_Array *ret = eina_array_new(10); + + if (format & ELM_SEL_FORMAT_TEXT) + eina_array_push(ret, "text/plain;charset=utf-8"); + if (format & ELM_SEL_FORMAT_MARKUP) + eina_array_push(ret, "application/x-elementary-markup"); + if (format & ELM_SEL_FORMAT_IMAGE) + { + eina_array_push(ret, "image/png"); + eina_array_push(ret, "image/jpeg"); + eina_array_push(ret, "image/x-ms-bmp"); + eina_array_push(ret, "image/gif"); + eina_array_push(ret, "image/tiff"); + eina_array_push(ret, "image/svg+xml"); + eina_array_push(ret, "image/x-xpixmap"); + eina_array_push(ret, "image/x-tga"); + eina_array_push(ret, "image/x-portable-pixmap"); + } + if (format & ELM_SEL_FORMAT_VCARD) + eina_array_push(ret, "text/vcard"); + if (format & ELM_SEL_FORMAT_HTML) + eina_array_push(ret, "text/html"); + + return ret; +} + +EAPI Eina_Bool +elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, + Elm_Drag_State enter_cb, void *enter_data, + Elm_Drag_State leave_cb, void *leave_data, + Elm_Drag_Pos pos_cb, void *pos_data, + Elm_Drop_Cb drop_cb, void *drop_data) +{ + + Elm_Drop_Target *target = calloc(1, sizeof(Elm_Drop_Target)); + target->enter_cb = enter_cb; + target->enter_data = enter_data; + target->leave_cb = leave_cb; + target->leave_data = leave_data; + target->pos_cb = pos_cb; + target->pos_data = pos_data; + target->drop_cb = drop_cb; + target->drop_data = drop_data; + target->mime_types = _format_to_mime_array(format); + target->format = format; + + efl_event_callback_array_add(obj, drop_target_cb(), target); + + if (!target_register) + target_register = eina_hash_pointer_new(NULL); + eina_hash_list_append(target_register, &obj, target); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, + Elm_Drag_State enter_cb, void *enter_data, + Elm_Drag_State leave_cb, void *leave_data, + Elm_Drag_Pos pos_cb, void *pos_data, + Elm_Drop_Cb drop_cb, void *drop_data) +{ + Elm_Drop_Target *target; + Eina_List *n, *found = NULL; + + if (!target_register) + return EINA_TRUE; + Eina_List *targets = eina_hash_find(target_register, &obj); + + if (!targets) + return EINA_TRUE; + + EINA_LIST_FOREACH(targets, n, target) + { + if (target->enter_cb == enter_cb && target->enter_data == enter_data && + target->leave_cb == leave_cb && target->leave_data == leave_data && + target->pos_cb == pos_cb && target->pos_data == pos_data && + target->drop_cb == drop_cb && target->drop_data == drop_data && + target->format == format) + { + + found = n; + break; + } + } + if (found) + { + efl_event_callback_array_del(obj, drop_target_cb(), eina_list_data_get(found)); + eina_hash_list_remove(target_register, &obj, target); + eina_array_free(target->mime_types); + free(target); + } + + return EINA_TRUE; +} + +struct _Item_Container_Drag_Info +{ /* Info kept for containers to support drag */ + Evas_Object *obj; + Ecore_Timer *tm; /* When this expires, start drag */ + double anim_tm; /* Time period to set tm */ + double tm_to_drag; /* Time period to set tm */ + Elm_Xy_Item_Get_Cb itemgetcb; + Elm_Item_Container_Data_Get_Cb data_get; + + Evas_Coord x_down; /* Mouse down x cord when drag starts */ + Evas_Coord y_down; /* Mouse down y cord when drag starts */ + + /* Some extra information needed to impl default anim */ + Evas *e; + Eina_List *icons; /* List of icons to animate (Anim_Icon) */ + int final_icon_w; /* We need the w and h of the final icon for the animation */ + int final_icon_h; + Ecore_Animator *ea; + + Elm_Drag_User_Info user_info; +}; +typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info; + +struct _Anim_Icon +{ + int start_x; + int start_y; + int start_w; + int start_h; + Evas_Object *o; +}; +typedef struct _Anim_Icon Anim_Icon; +static Eina_List *cont_drag_tg = NULL; /* List of Item_Container_Drag_Info */ + +static Eina_Bool elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full); +static void _cont_obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); +static void _cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); +static void _cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info); + +static void +_cont_drag_done_cb(void *data, Evas_Object *obj EINA_UNUSED) +{ + Item_Container_Drag_Info *st = data; + elm_widget_scroll_freeze_pop(st->obj); + if (st->user_info.dragdone) + st->user_info.dragdone(st->user_info.donecbdata, NULL, EINA_FALSE); /*FIXME*/ +} + +static Eina_Bool +_cont_obj_drag_start(void *data) +{ /* Start a drag-action when timer expires */ + Item_Container_Drag_Info *st = data; + st->tm = NULL; + Elm_Drag_User_Info *info = &st->user_info; + if (info->dragstart) info->dragstart(info->startcbdata, st->obj); + elm_widget_scroll_freeze_push(st->obj); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + elm_drag_start( /* Commit the start only if data_get successful */ + st->obj, info->format, + info->data, info->action, + info->createicon, info->createdata, + info->dragpos, info->dragdata, + info->acceptcb, info->acceptdata, + _cont_drag_done_cb, st); + ELM_SAFE_FREE(info->data, free); + + return ECORE_CALLBACK_CANCEL; +} + +static inline Eina_List * +_anim_icons_make(Eina_List *icons) +{ /* Make local copies of all icons, add them to list */ + Eina_List *list = NULL, *itr; + Evas_Object *o; + + EINA_LIST_FOREACH(icons, itr, o) + { /* Now add icons to animation window */ + Anim_Icon *st = calloc(1, sizeof(*st)); + + if (!st) + { + ERR("Failed to allocate memory for icon!"); + continue; + } + + evas_object_geometry_get(o, &st->start_x, &st->start_y, &st->start_w, &st->start_h); + evas_object_show(o); + st->o = o; + list = eina_list_append(list, st); + } + + return list; +} + +static Eina_Bool +_drag_anim_play(void *data, double pos) +{ /* Impl of the animation of icons, called on frame time */ + Item_Container_Drag_Info *st = data; + Eina_List *l; + Anim_Icon *sti; + + if (st->ea) + { + if (pos > 0.99) + { + st->ea = NULL; /* Avoid deleting on mouse up */ + EINA_LIST_FOREACH(st->icons, l, sti) + evas_object_hide(sti->o); + + _cont_obj_drag_start(st); /* Start dragging */ + return ECORE_CALLBACK_CANCEL; + } + + Evas_Coord xm, ym; + evas_pointer_canvas_xy_get(st->e, &xm, &ym); + EINA_LIST_FOREACH(st->icons, l, sti) + { + int x, y, h, w; + w = sti->start_w + ((st->final_icon_w - sti->start_w) * pos); + h = sti->start_h + ((st->final_icon_h - sti->start_h) * pos); + x = sti->start_x - (pos * ((sti->start_x + (w/2) - xm))); + y = sti->start_y - (pos * ((sti->start_y + (h/2) - ym))); + evas_object_move(sti->o, x, y); + evas_object_resize(sti->o, w, h); + } + + return ECORE_CALLBACK_RENEW; + } + + return ECORE_CALLBACK_CANCEL; +} + +static inline Eina_Bool +_drag_anim_start(void *data) +{ /* Start default animation */ + Item_Container_Drag_Info *st = data; + + st->tm = NULL; + /* Now we need to build an (Anim_Icon *) list */ + st->icons = _anim_icons_make(st->user_info.icons); + if (st->user_info.createicon) + { + Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_DND); + Evas_Object *final_icon = st->user_info.createicon(st->user_info.createdata, temp_win, NULL, NULL); + evas_object_geometry_get(final_icon, NULL, NULL, &st->final_icon_w, &st->final_icon_h); + evas_object_del(final_icon); + evas_object_del(temp_win); + } + st->ea = ecore_animator_timeline_add(st->anim_tm, _drag_anim_play, st); + + return EINA_FALSE; +} + +static Eina_Bool +_cont_obj_anim_start(void *data) +{ /* Start a drag-action when timer expires */ + Item_Container_Drag_Info *st = data; + int xposret, yposret; /* Unused */ + Elm_Object_Item *it = (st->itemgetcb) ? + (st->itemgetcb(st->obj, st->x_down, st->y_down, &xposret, &yposret)) + : NULL; + + st->tm = NULL; + st->user_info.format = ELM_SEL_FORMAT_TARGETS; /* Default */ + st->icons = NULL; + st->user_info.data = NULL; + st->user_info.action = ELM_XDND_ACTION_COPY; /* Default */ + + if (!it) /* Failed to get mouse-down item, abort drag */ + return ECORE_CALLBACK_CANCEL; + + if (st->data_get) + { /* collect info then start animation or start dragging */ + if (st->data_get( /* Collect drag info */ + st->obj, /* The container object */ + it, /* Drag started on this item */ + &st->user_info)) + { + if (st->user_info.icons) + _drag_anim_start(st); + else + { + if (st->anim_tm) + { + // even if we don't manage the icons animation, we have + // to wait until it is finished before beginning drag. + st->tm = ecore_timer_add(st->anim_tm, _cont_obj_drag_start, st); + } + else + _cont_obj_drag_start(st); /* Start dragging, no anim */ + } + } + } + + return ECORE_CALLBACK_CANCEL; +} + +static int +_drag_item_container_cmp(const void *d1, + const void *d2) +{ + const Item_Container_Drag_Info *st = d1; + return (((uintptr_t) (st->obj)) - ((uintptr_t) d2)); +} + +void +_anim_st_free(Item_Container_Drag_Info *st) +{ /* Stops and free mem of ongoing animation */ + if (st) + { + ELM_SAFE_FREE(st->ea, ecore_animator_del); + Anim_Icon *sti; + + EINA_LIST_FREE(st->icons, sti) + { + evas_object_del(sti->o); + free(sti); + } + + st->icons = NULL; + } +} + +static void +_cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Cancel any drag waiting to start on timeout */ + Item_Container_Drag_Info *st = data; + + if (((Evas_Event_Mouse_Up *)event_info)->button != 1) + return; /* We only process left-click at the moment */ + + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st); + + ELM_SAFE_FREE(st->tm, ecore_timer_del); + + _anim_st_free(st); +} + +static void +_cont_obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Cancel any drag waiting to start on timeout */ + if (((Evas_Event_Mouse_Move *)event_info)->event_flags & EVAS_EVENT_FLAG_ON_HOLD) + { + Item_Container_Drag_Info *st = data; + + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st); + evas_object_event_callback_del_full + (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st); + elm_drag_item_container_del_internal(obj, EINA_FALSE); + + ELM_SAFE_FREE(st->tm, ecore_timer_del); + + _anim_st_free(st); + } +} + +static Eina_Bool +elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full) +{ + Item_Container_Drag_Info *st = + eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj); + + if (st) + { + ELM_SAFE_FREE(st->tm, ecore_timer_del); /* Cancel drag-start timer */ + + if (st->ea) /* Cancel ongoing default animation */ + _anim_st_free(st); + + if (full) + { + st->itemgetcb = NULL; + st->data_get = NULL; + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_MOUSE_DOWN, _cont_obj_mouse_down, st); + + cont_drag_tg = eina_list_remove(cont_drag_tg, st); + ELM_SAFE_FREE(st->user_info.data, free); + free(st); + } + + return EINA_TRUE; + } + return EINA_FALSE; +} + +static void +_cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info) +{ /* Launch a timer to start dragging */ + Evas_Event_Mouse_Down *ev = event_info; + if (ev->button != 1) + return; /* We only process left-click at the moment */ + + Item_Container_Drag_Info *st = data; + evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_MOVE, + _cont_obj_mouse_move, st); + + evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_UP, + _cont_obj_mouse_up, st); + + ecore_timer_del(st->tm); + + st->e = e; + st->x_down = ev->canvas.x; + st->y_down = ev->canvas.y; + st->tm = ecore_timer_add(st->tm_to_drag, _cont_obj_anim_start, st); +} +EAPI Eina_Bool +elm_drag_item_container_del(Evas_Object *obj) +{ + return elm_drag_item_container_del_internal(obj, EINA_TRUE); +} + +EAPI Eina_Bool +elm_drag_item_container_add(Evas_Object *obj, + double anim_tm, + double tm_to_drag, + Elm_Xy_Item_Get_Cb itemgetcb, + Elm_Item_Container_Data_Get_Cb data_get) +{ + Item_Container_Drag_Info *st; + + if (elm_drag_item_container_del_internal(obj, EINA_FALSE)) + { /* Updating info of existing obj */ + st = eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj); + if (!st) return EINA_FALSE; + } + else + { + st = calloc(1, sizeof(*st)); + if (!st) return EINA_FALSE; + + st->obj = obj; + cont_drag_tg = eina_list_append(cont_drag_tg, st); + + /* Register for mouse callback for container to start/abort drag */ + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + _cont_obj_mouse_down, st); + } + + st->tm = NULL; + st->anim_tm = anim_tm; + st->tm_to_drag = tm_to_drag; + st->itemgetcb = itemgetcb; + st->data_get = data_get; + return EINA_TRUE; +} + +static Eina_List *cont_drop_tg = NULL; /* List of Item_Container_Drop_Info */ + +struct _Item_Container_Drop_Info +{ /* Info kept for containers to support drop */ + Evas_Object *obj; + Elm_Xy_Item_Get_Cb itemgetcb; + Elm_Drop_Item_Container_Cb dropcb; + Elm_Drag_Item_Container_Pos poscb; +}; +typedef struct _Item_Container_Drop_Info Item_Container_Drop_Info; + + +typedef struct +{ + Evas_Object *obj; + /* FIXME: Cache window */ + Eina_Inlist *cbs_list; /* List of Dropable_Cbs * */ + struct { + Evas_Coord x, y; + Eina_Bool in : 1; + const char *type; + Elm_Sel_Format format; + } last; +} Dropable; + +static int +_drop_item_container_cmp(const void *d1, + const void *d2) +{ + const Item_Container_Drop_Info *st = d1; + return (((uintptr_t) (st->obj)) - ((uintptr_t) d2)); +} + +static void +_elm_item_container_pos_cb(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action) +{ /* obj is the container pointer */ + Elm_Object_Item *it = NULL; + int xposret = 0; + int yposret = 0; + + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st && st->poscb) + { /* Call container drop func with specific item pointer */ + int xo = 0; + int yo = 0; + + evas_object_geometry_get(obj, &xo, &yo, NULL, NULL); + if (st->itemgetcb) + it = st->itemgetcb(obj, x+xo, y+yo, &xposret, &yposret); + + st->poscb(data, obj, it, x, y, xposret, yposret, action); + } +} + +static Eina_Bool +_elm_item_container_drop_cb(void *data, Evas_Object *obj , Elm_Selection_Data *ev) +{ /* obj is the container pointer */ + Elm_Object_Item *it = NULL; + int xposret = 0; + int yposret = 0; + + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st && st->dropcb) + { /* Call container drop func with specific item pointer */ + int xo = 0; + int yo = 0; + + evas_object_geometry_get(obj, &xo, &yo, NULL, NULL); + if (st->itemgetcb) + it = st->itemgetcb(obj, ev->x+xo, ev->y+yo, &xposret, &yposret); + + return st->dropcb(data, obj, it, ev, xposret, yposret); + } + + return EINA_FALSE; +} + +static Eina_Bool +elm_drop_item_container_del_internal(Evas_Object *obj, Eina_Bool full) +{ + Item_Container_Drop_Info *st = + eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + + if (st) + { + // temp until st is stored inside data of obj. + //FIXME delete this drop container + st->itemgetcb= NULL; + st->poscb = NULL; + st->dropcb = NULL; + + if (full) + { + cont_drop_tg = eina_list_remove(cont_drop_tg, st); + free(st); + } + + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EAPI Eina_Bool +elm_drop_item_container_add(Evas_Object *obj, + Elm_Sel_Format format, + Elm_Xy_Item_Get_Cb itemgetcb, + Elm_Drag_State entercb, void *enterdata, + Elm_Drag_State leavecb, void *leavedata, + Elm_Drag_Item_Container_Pos poscb, void *posdata, + Elm_Drop_Item_Container_Cb dropcb, void *dropdata) +{ + Item_Container_Drop_Info *st; + + if (elm_drop_item_container_del_internal(obj, EINA_FALSE)) + { /* Updating info of existing obj */ + st = eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj); + if (!st) return EINA_FALSE; + } + else + { + st = calloc(1, sizeof(*st)); + if (!st) return EINA_FALSE; + + st->obj = obj; + cont_drop_tg = eina_list_append(cont_drop_tg, st); + } + + st->itemgetcb = itemgetcb; + st->poscb = poscb; + st->dropcb = dropcb; + elm_drop_target_add(obj, format, + entercb, enterdata, + leavecb, leavedata, + _elm_item_container_pos_cb, posdata, + _elm_item_container_drop_cb, dropdata); + return EINA_TRUE; +} + + +EAPI Eina_Bool +elm_drop_item_container_del(Evas_Object *obj) +{ + return elm_drop_item_container_del_internal(obj, EINA_TRUE); +} + +typedef struct { + void *dragdata, *acceptdata, *donecbdata; + Elm_Drag_Pos dragposcb; + Elm_Drag_Accept acceptcb; + Elm_Drag_State dragdonecb; +} Elm_Drag_Data; + +static void +_drag_finished_cb(void *data, const Efl_Event *ev) +{ + Elm_Drag_Data *dd = data; + Eina_Bool *accepted = ev->info; + + if (dd->acceptcb) + dd->acceptcb(dd->acceptdata, ev->object, *accepted); + + if (dd->dragdonecb) + dd->dragdonecb(dd->donecbdata, ev->object); + + efl_event_callback_del(ev->object, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd); + free(dd); +} + +EAPI Eina_Bool +elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, + const char *data, Elm_Xdnd_Action action, + Elm_Drag_Icon_Create_Cb createicon, + void *createdata, + Elm_Drag_Pos dragpos, void *dragdata, + Elm_Drag_Accept acceptcb, void *acceptdata, + Elm_Drag_State dragdone, void *donecbdata) +{ + Eina_Array *mime_types; + Eina_Content *content; + Efl_Content *ui; + int x, y, w, h; + Efl_Ui_Widget *widget; + Elm_Drag_Data *dd; + const char *str_action; + + str_action = _action_to_string(action); + dd = calloc(1, sizeof(Elm_Drag_Data)); + dd->dragposcb = dragpos; + dd->dragdata = dragdata; + dd->acceptcb = acceptcb; + dd->acceptdata = acceptdata; + dd->dragdonecb = dragdone; + dd->donecbdata = donecbdata; + mime_types = _format_to_mime_array(format); + if (eina_array_count(mime_types) != 1) + { + WRN("You passed more than one format, this is not going to work well"); + } + content = eina_content_new((Eina_Slice) EINA_SLICE_STR_FULL(data), eina_array_data_get(mime_types, 0)); + ui = efl_ui_dnd_drag_start(obj, content, str_action, _default_seat(obj)); + widget = createicon(createdata, ui, &x, &y); + evas_object_geometry_get(widget, NULL, NULL, &w, &h); + evas_object_show(widget); + efl_content_set(ui, widget); + efl_gfx_entity_size_set(ui, EINA_SIZE2D(w, h)); + eina_array_free(mime_types); + + efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drag_cancel(Evas_Object *obj) +{ + efl_ui_dnd_drag_cancel(obj, _default_seat(obj)); + + return EINA_TRUE; +} + +EAPI Eina_Bool +elm_drag_action_set(Evas_Object *obj EINA_UNUSED, Elm_Xdnd_Action action EINA_UNUSED) +{ + ERR("This operation is not supported anymore."); + return EINA_FALSE; +} diff --git a/src/lib/elementary/elm_entry.c b/src/lib/elementary/elm_entry.c index ab1f11544b..e3a81dea76 100644 --- a/src/lib/elementary/elm_entry.c +++ b/src/lib/elementary/elm_entry.c @@ -708,7 +708,7 @@ _selection_data_cb(void *data EINA_UNUSED, char *entry_tag; int len; static const char *tag_string = - ""; + ""; len = strlen(tag_string) + strlen(buf); entry_tag = alloca(len + 1); @@ -1628,7 +1628,7 @@ _selection_store(Elm_Sel_Type seltype, if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */ elm_cnp_selection_set - (obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel)); + (obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel) + 1); elm_cnp_selection_loss_callback_set(obj, seltype, _selection_clear, obj); if (seltype == ELM_SEL_TYPE_CLIPBOARD) eina_stringshare_replace(&sd->cut_sel, sel); @@ -1731,7 +1731,7 @@ _menu_call(Evas_Object *obj) const char *context_menu_orientation; Eina_Bool ownersel; - ownersel = elm_selection_selection_has_owner(obj); + ownersel = elm_cnp_clipboard_selection_has_owner(obj); if (!sd->items) { /* prevent stupid blank hoversel */ diff --git a/src/lib/elementary/elm_main.c b/src/lib/elementary/elm_main.c index d1d0c4a183..4bf652077b 100644 --- a/src/lib/elementary/elm_main.c +++ b/src/lib/elementary/elm_main.c @@ -910,7 +910,6 @@ elm_quicklaunch_sub_shutdown(void) _elm_module_shutdown(); if (_elm_prefs_initted) _elm_prefs_shutdown(); - _efl_ui_dnd_shutdown(); elm_color_class_shutdown(); } diff --git a/src/lib/elementary/elm_priv.h b/src/lib/elementary/elm_priv.h index 90b90fc40d..8cfc7c952a 100644 --- a/src/lib/elementary/elm_priv.h +++ b/src/lib/elementary/elm_priv.h @@ -165,7 +165,6 @@ # include "efl_ui_focus_parent_provider.eo.h" # include "efl_ui_focus_parent_provider_standard.eo.h" -# include "efl_ui_selection_manager.eo.h" # include "efl_datetime_manager.eo.h" extern const char *_efl_model_property_itemw; @@ -668,9 +667,6 @@ void _elm_prefs_data_init(void); void _elm_prefs_data_shutdown(void); /* init functions for dnd and cnp */ -Eo* _efl_ui_selection_manager_get(Eo *obj); -void _efl_ui_dnd_shutdown(void); - int _elm_ews_wm_init(void); void _elm_ews_wm_shutdown(void); void _elm_ews_wm_rescale(Elm_Theme *th, @@ -1060,4 +1056,10 @@ typedef struct Efl_Ui_Shared_Win_Data* efl_ui_win_shared_data_get(Efl_Ui_Win *win); +void _selection_changed_event_register(Eo *obj); +void _selection_changed_event_unregister(Eo *obj); +void _drop_event_register(Eo *obj); +void _drop_event_unregister(Eo *obj); +void _register_selection_changed(Efl_Ui_Selection *selection); + #endif diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index d4a34da04f..42a3557fe6 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -143,7 +143,6 @@ pub_eo_files = [ 'elm_code_widget.eo', 'efl_ui_selection.eo', 'efl_ui_dnd.eo', - 'efl_ui_dnd_container.eo', 'efl_ui_focus_manager_window_root.eo', 'efl_ui_spotlight_container.eo', 'efl_ui_spotlight_manager.eo', @@ -211,8 +210,6 @@ endforeach pub_eo_types_files = [ 'elm_general.eot', 'efl_ui.eot', - 'efl_ui_selection_types.eot', - 'efl_ui_dnd_types.eot' ] foreach eo_file : pub_eo_types_files @@ -236,7 +233,6 @@ priv_eo_files = [ 'efl_ui_focus_parent_provider.eo', 'efl_ui_focus_parent_provider_standard.eo', 'efl_ui_state_model.eo', - 'efl_ui_selection_manager.eo', 'efl_datetime_manager.eo', 'efl_ui_size_model.eo', 'efl_ui_homogeneous_model.eo', @@ -786,6 +782,8 @@ elementary_src = [ 'elm_icon.c', 'efl_ui_image.c', 'elm_index.c', + 'elm_cnp.c', + 'elm_dnd.c', 'efl_access_object.c', 'efl_access_action.c', 'efl_access_component.c', @@ -908,7 +906,6 @@ elementary_src = [ 'efl_ui_scroller.c', 'efl_ui_scroll_manager.c', 'efl_ui_pan.c', - 'efl_ui_selection_manager.c', 'efl_ui_selection_manager_private.h', 'efl_ui_selection.c', 'efl_datetime_manager.c', @@ -948,7 +945,7 @@ elementary_src = [ 'efl_ui_collection_view.c', 'efl_ui_pager.c', 'efl_ui_stack.c', - 'efl_ui_separator.c' + 'efl_ui_separator.c', ] elementary_deps = [emile, eo, efl, edje, ethumb, ethumb_client, emotion, ecore_imf, ecore_con, eldbus, efreet, efreet_mime, efreet_trash, eio, atspi, dl, intl] diff --git a/src/lib/eo/eina_types.eot b/src/lib/eo/eina_types.eot index bff83968c1..000a2567d9 100644 --- a/src/lib/eo/eina_types.eot +++ b/src/lib/eo/eina_types.eot @@ -60,6 +60,17 @@ struct @extern Eina.Matrix3 { zz: double; [[ZZ value.]] } +struct @extern Eina.Content; [[ + Container for any type of content. + + Each @Eina.Content is made of an @Eina.Slice of memory and an IANA MIME type: + https://www.iana.org/assignments/media-types/media-types.xhtml + + If the type is a text-style type, the last byte of the slice must be \0. + + @since 1.24 +]] + struct @extern Eina.Matrix4 { [[A bidimensional array of floating point values with 4 rows and 4 columns. diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c index 95d0f36bd0..9aa455553d 100644 --- a/src/lib/evas/canvas/evas_main.c +++ b/src/lib/evas/canvas/evas_main.c @@ -120,6 +120,21 @@ _efl_gfx_image_load_error_to_evas_load_error(Eina_Error err) return EVAS_LOAD_ERROR_GENERIC; } +static Eina_Content* +_markup_to_utf8(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + char *utf8 = evas_textblock_text_markup_to_utf8(NULL, slice.mem); + return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(utf8), to_type); +} + +static Eina_Content* +_utf8_to_markup(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + char *markup = evas_textblock_text_utf8_to_markup(NULL, slice.mem); + return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(markup), to_type); +} EAPI int evas_init(void) @@ -179,6 +194,9 @@ evas_init(void) _efl_gfx_image_load_error_init(); + eina_content_converter_conversion_register("application/x-elementary-markup", "text/plain;charset=utf-8", _markup_to_utf8); + eina_content_converter_conversion_register("text/plain;charset=utf-8", "application/x-elementary-markup", _utf8_to_markup); + return _evas_init_count; shutdown_filter: diff --git a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c index e1c5a66670..c8e2895358 100644 --- a/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c +++ b/src/modules/ecore_evas/engines/cocoa/ecore_evas_cocoa.c @@ -34,6 +34,11 @@ static Ecore_Event_Handler *ecore_evas_event_handlers[4]; static const char *_iface_name = "opengl_cocoa"; static const int _iface_version = 1; +typedef struct { + Ecore_Evas_Selection_Callbacks clipboard; + Eina_Future *delivery; +} Ecore_Evas_Cocoa_Engine_Data; + static inline Ecore_Evas * _ecore_evas_cocoa_match(Ecore_Cocoa_Object *cocoa_win) { @@ -422,6 +427,125 @@ _ecore_evas_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func ee->func.fn_delete_request = func; } +static Eina_Value +_delivery(void *data, const Eina_Value value EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Cocoa_Engine_Data *edata = ee->engine.data; + Eina_Rw_Slice slice; + const char *mime_type = NULL; + + EINA_SAFETY_ON_NULL_GOTO(edata->delivery, end); + + for (unsigned int i = 0; i < eina_array_count(edata->clipboard.available_types); ++i) + { + mime_type = eina_array_data_get(edata->clipboard.available_types, i); + if (!strncmp("text/", mime_type, strlen("text/"))) + break; + } + if (mime_type) + { + edata->clipboard.delivery(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER, mime_type, &slice); + EINA_SAFETY_ON_FALSE_GOTO(ecore_cocoa_clipboard_set(slice.mem, slice.len, mime_type), end); + } + else + { + ERR("No compatible mime type found"); + } + +end: + return EINA_VALUE_EMPTY; +} + +static Eina_Bool +_ecore_evas_cocoa_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) +{ + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return EINA_FALSE; + + if (!delivery && !cancel) + { + ecore_cocoa_clipboard_clear(); + return EINA_TRUE; + } + else + { + Ecore_Evas_Cocoa_Engine_Data *edata = ee->engine.data; + + if (edata->clipboard.cancel) + { + edata->clipboard.cancel(ee, seat, selection); + eina_array_free(edata->clipboard.available_types); + } + + edata->delivery = efl_loop_job(efl_main_loop_get()); + eina_future_then(edata->delivery, _delivery, ee); + edata->clipboard.delivery = delivery; + edata->clipboard.cancel = cancel; + edata->clipboard.available_types = available_types; + return EINA_TRUE; + } +} + +Eina_Future* +_ecore_evas_cocoa_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Eina_Future *future; + Eina_Promise *promise; + const char *mime_type; + + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return eina_future_rejected(efl_loop_future_scheduler_get(efl_main_loop_get()), ecore_evas_no_selection); + + promise = efl_loop_promise_new(efl_main_loop_get()); + future = eina_future_new(promise); + + for (unsigned int i = 0; i < eina_array_count(acceptable_type); ++i) + { + mime_type = eina_array_data_get(acceptable_type, i); + if (!strncmp("text/", mime_type, strlen("text/"))) + break; + } + if (!mime_type) + { + eina_promise_reject(promise, ecore_evas_no_matching_type); + } + else + { + int size; + void *data; + Eina_Content *content; + Eina_Rw_Slice slice; + + data = ecore_cocoa_clipboard_get(&size, mime_type); + if (!strncmp(mime_type, "text", strlen("text"))) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + slice.len = size + 1; + slice.mem = eina_memdup(data, size, EINA_TRUE); + } + else + { + slice.len = size; + slice.mem = data; + } + content = eina_content_new(eina_rw_slice_slice_get(slice), mime_type); + if (!content) // construction can fail because of some validation reasons + eina_promise_reject(promise, ecore_evas_no_matching_type); + else + eina_promise_resolve(promise, eina_value_content_init(content)); + } + return future; +} + +static Eina_Bool +_ecore_evas_cocoa_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection EINA_UNUSED) +{ + if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return ecore_cocoa_clipboard_exists(); + return EINA_FALSE; +} + static Ecore_Evas_Engine_Func _ecore_cocoa_engine_func = { _ecore_evas_cocoa_free, @@ -508,6 +632,11 @@ static Ecore_Evas_Engine_Func _ecore_cocoa_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get + _ecore_evas_cocoa_selection_claim, //fn_selection_claim + _ecore_evas_cocoa_selection_has_owner, //fn_selection_has_owner + _ecore_evas_cocoa_selection_request, //fn_selection_request + NULL, //fn_dnd_start + NULL, //fn_dnd_stop }; static Ecore_Cocoa_Window * @@ -517,11 +646,11 @@ _ecore_evas_cocoa_window_get(const Ecore_Evas *ee) return (Ecore_Cocoa_Window *)(ee->prop.window); } - EAPI Ecore_Evas * ecore_evas_cocoa_new_internal(Ecore_Cocoa_Window *parent EINA_UNUSED, int x, int y, int w, int h) { Ecore_Evas *ee; + Ecore_Evas_Cocoa_Engine_Data *edata; Ecore_Evas_Interface_Cocoa *iface; if (!ecore_cocoa_init()) @@ -532,6 +661,10 @@ ecore_evas_cocoa_new_internal(Ecore_Cocoa_Window *parent EINA_UNUSED, int x, int ee = calloc(1, sizeof(Ecore_Evas)); if (!ee) goto shutdown_ecore_cocoa; + edata = calloc(1, sizeof(Ecore_Evas_Cocoa_Engine_Data)); + if (!edata) + goto shutdown_ecore_cocoa_engine_data; + ee->engine.data = edata; ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); @@ -606,6 +739,8 @@ ecore_evas_cocoa_new_internal(Ecore_Cocoa_Window *parent EINA_UNUSED, int x, int free(ee->name); //free_ee: _ecore_evas_cocoa_shutdown(); + free(edata); + shutdown_ecore_cocoa_engine_data: free(ee); shutdown_ecore_cocoa: ecore_cocoa_shutdown(); diff --git a/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c b/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c index 8abc7401b6..ef4ba057b9 100644 --- a/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c +++ b/src/modules/ecore_evas/engines/sdl/ecore_evas_sdl.c @@ -455,6 +455,9 @@ static Ecore_Evas_Engine_Func _ecore_sdl_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get + NULL, //fn_selection_claim + NULL, //fn_selection_has_owner + NULL, //fn_selection_request }; static Ecore_Evas* diff --git a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c index c14bdbcd33..b2bf7c75ec 100644 --- a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c +++ b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c @@ -4,6 +4,7 @@ #include "ecore_evas_wayland_private.h" #include +#include "ecore_wl2_internal.h" extern EAPI Eina_List *_evas_canvas_image_data_unset(Evas *eo_e); extern EAPI void _evas_canvas_image_data_regenerate(Eina_List *list); @@ -32,6 +33,7 @@ static Eina_Array *_ecore_evas_wl_event_hdls; static void _ecore_evas_wayland_resize(Ecore_Evas *ee, int location); static void _ecore_evas_wl_common_rotation_set(Ecore_Evas *ee, int rotation, int resize); +static void _ecore_evas_wl_selection_init(Ecore_Evas *ee); /* local functions */ static void @@ -881,14 +883,14 @@ _rotation_do(Ecore_Evas *ee, int rotation, int resize) { /* resize the canvas */ evas_output_size_set(ee->evas, ee->req.w, ee->req.h); - evas_output_viewport_set(ee->evas, 0, 0, + evas_output_viewport_set(ee->evas, 0, 0, ee->req.w, ee->req.h); } else { /* resize the canvas */ evas_output_size_set(ee->evas, ee->req.h, ee->req.w); - evas_output_viewport_set(ee->evas, 0, 0, + evas_output_viewport_set(ee->evas, 0, 0, ee->req.h, ee->req.w); } } @@ -1440,6 +1442,15 @@ _ecore_evas_wl_common_free(Ecore_Evas *ee) if (wdata->frame) ecore_wl2_window_frame_callback_del(wdata->frame); wdata->frame = NULL; ecore_event_handler_del(wdata->sync_handler); + ecore_event_handler_del(wdata->changed_handler); + ecore_event_handler_del(wdata->send_handler); + ecore_event_handler_del(wdata->offer_handler); + ecore_event_handler_del(wdata->dnd_leave_handler); + ecore_event_handler_del(wdata->dnd_enter_handler); + ecore_event_handler_del(wdata->dnd_motion_handler); + ecore_event_handler_del(wdata->dnd_drop_handler); + ecore_event_handler_del(wdata->dnd_end_handler); + if (wdata->win) { ecore_wl2_window_close_callback_set(wdata->win, NULL, NULL); @@ -2389,6 +2400,457 @@ _ecore_wl2_devices_setup(Ecore_Evas *ee, Ecore_Wl2_Display *display) return r; } +static void +_reeval_seat(unsigned int *seat, Ecore_Evas *ee) +{ + if (*seat == 0) + *seat = evas_device_seat_id_get(evas_default_device_get(ee->evas, EFL_INPUT_DEVICE_TYPE_SEAT)); +} + +static inline void +_clear_selection(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection) +{ + Ecore_Evas_Engine_Wl_Data *edata = ee->engine.data; + Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks; + + EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel); + + cbs->cancel(ee, seat, selection); + eina_array_free(cbs->available_types); + memset(cbs, 0, sizeof(Ecore_Evas_Selection_Callbacks)); +} + +static void +_store_selection_cbs(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) +{ + Ecore_Evas_Wl_Selection_Data *sdata; + Ecore_Evas_Engine_Wl_Data *edata; + Ecore_Evas_Selection_Callbacks *cbs; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + cbs = &sdata->callbacks; + + if (cbs->cancel) + { + _clear_selection(ee, seat, selection); + } + + cbs->delivery = delivery; + cbs->cancel = cancel; + cbs->available_types = available_types; +} + +static inline Ecore_Wl2_Input* +_fetch_input(Ecore_Evas *ee, unsigned int seat) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + return ecore_wl2_display_input_find(ecore_wl2_window_display_get(wdata->win), seat); +} + +static Eina_Bool +_ecore_evas_wl_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection]; + char *tmp_array[eina_array_count(available_types) + 1]; + + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + { + _store_selection_cbs(ee, seat, selection, available_types, delivery, cancel); + return EINA_TRUE; + } + + _reeval_seat(&seat, ee); + _store_selection_cbs(ee, seat, selection, available_types, delivery, cancel); + + for (unsigned int i = 0; i < eina_array_count(available_types); ++i) + { + tmp_array[i] = eina_array_data_get(available_types, i); + } + tmp_array[eina_array_count(available_types)] = NULL; + + data->sent_serial = ecore_wl2_dnd_selection_set(_fetch_input(ee, seat), (const char**)tmp_array); + return EINA_TRUE; +} + + +static Eina_Future* +_ecore_evas_wl_selection_request(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_types) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection]; + Ecore_Wl2_Input *input; + Ecore_Wl2_Offer *offer = NULL; + Eina_Future *future; + + _reeval_seat(&seat, ee); + input = _fetch_input(ee, seat); + + if (data->delivery) + { + eina_promise_reject(data->delivery, ecore_evas_request_replaced); + data->delivery = NULL; + } + data->delivery = efl_loop_promise_new(efl_main_loop_get()); + future = eina_future_new(data->delivery); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + offer = data->offer = wdata->external_offer; + } + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + { + offer = data->offer = ecore_wl2_dnd_selection_get(input); + } + + if (!offer) + { + eina_promise_reject(data->delivery, ecore_evas_no_selection); + data->delivery = NULL; + } + else + { + Eina_Array *available_types = ecore_wl2_offer_mimes_get(offer); + char *selected_type = NULL; + + for (unsigned int i = 0; i < eina_array_count(available_types) && !selected_type; ++i) + { + char *available_type = eina_array_data_get(available_types, i); + for (unsigned int j = 0; j < eina_array_count(acceptable_types) && !selected_type; ++j) + { + char *acceptable_type = eina_array_data_get(acceptable_types, j); + if (eina_streq(acceptable_type, available_type)) + { + selected_type = available_type; + data->later_convert = NULL; + break; + } + + const char *convert_available_type; + Eina_Iterator *convertions = eina_content_converter_possible_conversions(available_type); + EINA_ITERATOR_FOREACH(convertions, convert_available_type) + { + if (eina_streq(convert_available_type, acceptable_type)) + { + selected_type = available_type; + data->later_convert = acceptable_type; + } + } + eina_iterator_free(convertions); + } + + } + if (selected_type) + { + ecore_wl2_offer_receive(offer, selected_type); + ecore_wl2_display_flush(ecore_wl2_input_display_get(input)); + } + else + { + eina_promise_reject(data->delivery, ecore_evas_no_matching_type); + data->delivery = NULL; + } + } + + return future; +} + +static Eina_Bool +_ecore_evas_wl_selection_has_owner(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection EINA_UNUSED) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Wl2_Input *input; + + _reeval_seat(&seat, ee); + input = _fetch_input(ee, seat); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER ) + return !!ecore_wl2_dnd_selection_get(input); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection]; + return !!data->offer; + } + + return EINA_FALSE; //the selection buffer is not supportet in wayland +} + +static Eina_Bool +_wl_selection_changed(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + Ecore_Wl2_Event_Seat_Selection *sel = event; + Ecore_Evas *ee = data; + Ecore_Wl2_Input *input; + unsigned int seat = sel->seat; + + _reeval_seat(&seat, ee); + input = _fetch_input(ee, seat); + if (!ecore_wl2_dnd_selection_get(input)) + return ECORE_CALLBACK_PASS_ON; + + if (ee->func.fn_selection_changed) + ee->func.fn_selection_changed(ee, 0, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); + + return ECORE_CALLBACK_PASS_ON; +} + +typedef struct { + Eina_Rw_Slice slice; + unsigned int written_bytes; +} Delayed_Writing; + +static Eina_Bool +_write_to_fd(void *data, Ecore_Fd_Handler *fd_handler) +{ + int fd = ecore_main_fd_handler_fd_get(fd_handler); + Delayed_Writing *slice = data; + + size_t len = write(fd, slice->slice.mem + slice->written_bytes, slice->slice.len - slice->written_bytes); + + slice->written_bytes += len; + if (slice->written_bytes != slice->slice.len) + { + return EINA_TRUE; + } + else + { + ecore_main_fd_handler_del(fd_handler); + free(slice->slice.mem); + free(slice); + close(fd); + return EINA_FALSE; + } + +} + +static Eina_Bool +_wl_interaction_send(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Wl2_Event_Data_Source_Send *ev = event; + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Evas_Wl_Selection_Data *selection = NULL; + Delayed_Writing *forign_slice = calloc(1, sizeof(Delayed_Writing)); + Ecore_Evas_Selection_Buffer buffer = ECORE_EVAS_SELECTION_BUFFER_LAST; + + if (ev->serial == wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER].sent_serial) + buffer = ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER; + else if (ev->serial == wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].sent_serial) + { + buffer = ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER; + ee->drag.accepted = EINA_TRUE; + } + + if (buffer == ECORE_EVAS_SELECTION_BUFFER_LAST) + { + //silent return, this send request was *not* for this window + return ECORE_CALLBACK_PASS_ON; + } + + selection = &wdata->selection_data[buffer]; + EINA_SAFETY_ON_NULL_GOTO(selection, end); + EINA_SAFETY_ON_NULL_GOTO(selection->callbacks.delivery, end); + EINA_SAFETY_ON_FALSE_GOTO(selection->callbacks.delivery(ee, ev->seat, buffer, ev->type, &forign_slice->slice), end); + ecore_main_fd_handler_add(ev->fd, ECORE_FD_WRITE, _write_to_fd, forign_slice, NULL, NULL); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_receive(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Ecore_Wl2_Event_Offer_Data_Ready *ready = event; + Ecore_Evas_Selection_Buffer selection = ECORE_EVAS_SELECTION_BUFFER_LAST; + + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (wdata->selection_data[i].offer == ready->offer) + { + selection = i; + break; + } + } + + if (selection == ECORE_EVAS_SELECTION_BUFFER_LAST) + return ECORE_CALLBACK_PASS_ON; + + //Now deliver the content + Eina_Slice slice; + + if (!strncmp(ready->mimetype, "text", strlen("text"))) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + slice.len = ready->len + 1; + slice.mem = eina_memdup((unsigned char*)ready->data, ready->len, EINA_TRUE); + } + else + { + slice.len = ready->len; + slice.mem = ready->data; + } + + Eina_Content *content = eina_content_new(slice, ready->mimetype); + + if (wdata->selection_data[selection].later_convert) + { + Eina_Content *tmp = eina_content_convert(content, wdata->selection_data[selection].later_convert); + wdata->selection_data[selection].later_convert = NULL; + eina_content_free(content); + content = tmp; + } + + eina_promise_resolve(wdata->selection_data[selection].delivery, eina_value_content_init(content)); + wdata->selection_data[selection].delivery = NULL; + eina_content_free(content); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_dnd_leave(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Eina_Position2D cpos; + Eina_Position2D fpos = EINA_POSITION2D(0, 0); + Ecore_Wl2_Event_Dnd_Leave *ev = event; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + //evas_output_framespace_get(ee->evas, &fpos.x, &fpos.y, NULL, NULL); + ecore_wl2_input_pointer_xy_get(ecore_wl2_display_input_find(ev->display, ev->seat), &cpos.x, &cpos.y); + ecore_evas_dnd_leave(data, ev->seat, EINA_POSITION2D(cpos.x - fpos.x, cpos.y - fpos.y)); + wdata->external_offer = NULL; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_dnd_motion(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_Motion *ev = event; + Eina_Position2D fpos = EINA_POSITION2D(0, 0); + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + evas_output_framespace_get(ee->evas, &fpos.x, &fpos.y, NULL, NULL); + ecore_evas_dnd_position_set(data, ev->seat, EINA_POSITION2D(ev->x - fpos.x, ev->y - fpos.y)); + return ECORE_CALLBACK_PASS_ON; +} +static Eina_Bool +_wl_selection_dnd_enter(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_Enter *ev = event; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + Eina_Position2D fpos = EINA_POSITION2D(0, 0); + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + evas_output_framespace_get(ee->evas, &fpos.x, &fpos.y, NULL, NULL); + ecore_evas_dnd_enter(data, ev->seat, eina_array_iterator_new(ecore_wl2_offer_mimes_get(ev->offer)), EINA_POSITION2D(ev->x - fpos.x, ev->y - fpos.y)); + ecore_wl2_offer_mimes_set(ev->offer, ecore_wl2_offer_mimes_get(ev->offer)); + wdata->external_offer = ev->offer; + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_wl_selection_dnd_drop(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_Drop *ev = event; + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + wdata = ee->engine.data; + + if (ee->func.fn_dnd_drop) + ee->func.fn_dnd_drop(ee, ev->seat, ecore_evas_dnd_pos_get(ee, ev->seat), "ask"); + + ecore_wl2_dnd_drag_end(_fetch_input(ee, ev->seat)); + wdata->external_offer = NULL; + + return ECORE_CALLBACK_PASS_ON; +} +static Eina_Bool +_wl_selection_dnd_end(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Evas *ee = data; + Ecore_Wl2_Event_Dnd_End *ev = event; + + if (ee->prop.window != (Ecore_Window)ev->win) return ECORE_CALLBACK_PASS_ON; + + + if (ee->drag.free) + ee->drag.free(ee, ev->seat, ee->drag.data, ee->drag.accepted); + ee->drag.free = NULL; + //we got dropped, we should call + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_ecore_evas_wl_selection_init(Ecore_Evas *ee) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + + wdata->changed_handler = ecore_event_handler_add(ECORE_WL2_EVENT_SEAT_SELECTION, + _wl_selection_changed, ee); + wdata->send_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, + _wl_interaction_send, ee); + wdata->offer_handler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, + _wl_selection_receive, ee); + wdata->dnd_leave_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_LEAVE, + _wl_selection_dnd_leave, ee); + wdata->dnd_motion_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, + _wl_selection_dnd_motion, ee); + wdata->dnd_enter_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_ENTER, + _wl_selection_dnd_enter, ee); + wdata->dnd_drop_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, + _wl_selection_dnd_drop, ee); + wdata->dnd_end_handler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_DROP, + _wl_selection_dnd_end, ee); + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + wdata->selection_data[i].callbacks.available_types = NULL; + wdata->selection_data[i].callbacks.delivery = NULL; + wdata->selection_data[i].callbacks.cancel = NULL; + } +} + +static Eina_Bool +_ecore_evas_wl_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *available_types, Ecore_Evas *drag_rep, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel, const char *action EINA_UNUSED) +{ + Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data; + const char *tmp_array[eina_array_count(available_types) + 1]; + + _reeval_seat(&seat, ee); + _store_selection_cbs(ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, available_types, delivery, cancel); + + for (unsigned int i = 0; i < eina_array_count(available_types); ++i) + { + tmp_array[i] = eina_array_data_get(available_types, i); + } + tmp_array[eina_array_count(available_types)] = NULL; + + ecore_wl2_dnd_drag_types_set(_fetch_input(ee, seat), (const char**)tmp_array); + wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].sent_serial = + ecore_wl2_dnd_drag_start(_fetch_input(ee, seat), _ecore_evas_wayland_window_get(ee), _ecore_evas_wayland_window_get(drag_rep)); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_wl_dnd_stop(Ecore_Evas *ee, unsigned int seat) +{ + _clear_selection(ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); + _reeval_seat(&seat, ee); + ecore_wl2_dnd_drag_end(_fetch_input(ee, seat)); + return EINA_TRUE; +} + static Ecore_Evas_Engine_Func _ecore_wl_engine_func = { _ecore_evas_wl_common_free, @@ -2474,6 +2936,11 @@ static Ecore_Evas_Engine_Func _ecore_wl_engine_func = _ecore_evas_wl_common_pointer_device_xy_get, _ecore_evas_wl_common_prepare, NULL, //fn_last_tick_get + _ecore_evas_wl_selection_claim, //fn_selection_claim + _ecore_evas_wl_selection_has_owner, //fn_selection_has_owner + _ecore_evas_wl_selection_request, //fn_selection_request + _ecore_evas_wl_dnd_start, //fn_dnd_start + _ecore_evas_wl_dnd_stop, //fn_dnd_stop }; static void @@ -2650,6 +3117,7 @@ _ecore_evas_wl_common_new_internal(const char *disp_name, Ecore_Window parent, i } _ecore_evas_wl_common_wm_rotation_protocol_set(ee); + _ecore_evas_wl_selection_init(ee); ecore_evas_done(ee, EINA_FALSE); diff --git a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h index e69970f262..d042719d93 100644 --- a/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h +++ b/src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h @@ -34,12 +34,23 @@ typedef struct _Ecore_Evas_Engine_Wl_Data Ecore_Evas_Engine_Wl_Data; +typedef struct _Ecore_Evas_Wl_Selection_Data Ecore_Evas_Wl_Selection_Data; + +struct _Ecore_Evas_Wl_Selection_Data +{ + Ecore_Evas_Selection_Callbacks callbacks; + Eina_Promise *delivery; + Ecore_Wl2_Offer *offer; + const char *later_convert; + uint32_t sent_serial; //The serial of the last sent selection op +}; + struct _Ecore_Evas_Engine_Wl_Data { Ecore_Wl2_Display *display; Eina_List *regen_objs; Ecore_Wl2_Window *parent, *win; - Ecore_Event_Handler *sync_handler; + Ecore_Event_Handler *sync_handler, *changed_handler, *end_handler, *send_handler, *offer_handler, *dnd_leave_handler, *dnd_motion_handler, *dnd_enter_handler, *dnd_drop_handler, *dnd_end_handler; int fx, fy, fw, fh; Ecore_Wl2_Frame_Cb_Handle *frame; int x_rel; @@ -47,7 +58,8 @@ struct _Ecore_Evas_Engine_Wl_Data uint32_t timestamp; Eina_List *devices_list; int cw, ch; - + Ecore_Evas_Wl_Selection_Data selection_data[ECORE_EVAS_SELECTION_BUFFER_LAST]; + Ecore_Wl2_Offer *external_offer; struct { Eina_Bool supported : 1; diff --git a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c index 39def9d49f..7f6eb98e48 100644 --- a/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c +++ b/src/modules/ecore_evas/engines/win32/ecore_evas_win32.c @@ -62,11 +62,15 @@ static const int interface_win32_version = 1; typedef struct _Ecore_Evas_Engine_Data_Win32 Ecore_Evas_Engine_Data_Win32; -struct _Ecore_Evas_Engine_Data_Win32 { +struct _Ecore_Evas_Engine_Data_Win32 +{ Ecore_Win32_Window *parent; - struct { - unsigned char region : 1; - unsigned char fullscreen : 1; + Ecore_Evas_Selection_Callbacks clipboard; + Eina_Future *delivery; + struct + { + unsigned char region : 1; + unsigned char fullscreen : 1; } state; }; @@ -1197,93 +1201,215 @@ _ecore_evas_win32_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) *ydpi = y_dpi; } +static Eina_Value +_delivery(void *data, const Eina_Value value EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Data_Win32 *edata = ee->engine.data; + Eina_Rw_Slice slice; + const char *mime_type = NULL; + + EINA_SAFETY_ON_NULL_GOTO(edata->delivery, end); + + for (unsigned int i = 0; i < eina_array_count(edata->clipboard.available_types); ++i) + { + mime_type = eina_array_data_get(edata->clipboard.available_types, i); + if (eina_str_has_prefix(mime_type, "text/")) + break; + } + if (mime_type) + { + edata->clipboard.delivery(ee, 0, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER, mime_type, &slice); + EINA_SAFETY_ON_FALSE_GOTO(ecore_win32_clipboard_set((Ecore_Win32_Window *)ee->prop.window, slice.mem, slice.len, mime_type), end); + } + else + { + ERR("No compatible mime type found"); + } + +end: + return EINA_VALUE_EMPTY; +} + +static Eina_Bool +_ecore_evas_win32_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) +{ + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return EINA_FALSE; + + if (!delivery && !cancel) + { + ecore_win32_clipboard_clear((Ecore_Win32_Window *)ee->prop.window); + return EINA_TRUE; + } + else + { + Ecore_Evas_Engine_Data_Win32 *edata = ee->engine.data; + + if (edata->clipboard.cancel) + { + edata->clipboard.cancel(ee, seat, selection); + eina_array_free(edata->clipboard.available_types); + } + + edata->delivery = efl_loop_job(efl_main_loop_get()); + eina_future_then(edata->delivery, _delivery, ee); + edata->clipboard.delivery = delivery; + edata->clipboard.cancel = cancel; + edata->clipboard.available_types = available_types; + return EINA_TRUE; + } +} + +Eina_Future* +_ecore_evas_win32_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Eina_Future *future; + Eina_Promise *promise; + const char *mime_type = NULL; + + if (selection != ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + return eina_future_rejected(efl_loop_future_scheduler_get(efl_main_loop_get()), ecore_evas_no_selection); + + promise = efl_loop_promise_new(efl_main_loop_get()); + future = eina_future_new(promise); + + for (unsigned int i = 0; i < eina_array_count(acceptable_type); ++i) + { + mime_type = eina_array_data_get(acceptable_type, i); + if (eina_str_has_prefix(mime_type, "text/")) + break; + } + if (!mime_type) + { + eina_promise_reject(promise, ecore_evas_no_matching_type); + } + else + { + size_t size; + void *data; + Eina_Content *content; + Eina_Rw_Slice slice; + + data = ecore_win32_clipboard_get((Ecore_Win32_Window *)ee->prop.window, &size, mime_type); + if (eina_str_has_prefix(mime_type, "text/")) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + slice.len = size + 1; + slice.mem = eina_memdup(data, size, EINA_TRUE); + } + else + { + slice.len = size; + slice.mem = data; + } + content = eina_content_new(eina_rw_slice_slice_get(slice), mime_type); + if (!content) // construction can fail because of some validation reasons + eina_promise_reject(promise, ecore_evas_no_matching_type); + else + eina_promise_resolve(promise, eina_value_content_init(content)); + } + return future; +} + +static Eina_Bool +_ecore_evas_win32_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + return (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); +} + static Ecore_Evas_Engine_Func _ecore_win32_engine_func = { _ecore_evas_win32_free, - NULL, - NULL, - NULL, - NULL, - _ecore_evas_win32_callback_delete_request_set, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - _ecore_evas_win32_move, - NULL, - _ecore_evas_win32_resize, - _ecore_evas_win32_move_resize, - _ecore_evas_win32_rotation_set, - _ecore_evas_win32_shaped_set, - _ecore_evas_win32_show, - _ecore_evas_win32_hide, - _ecore_evas_win32_raise, - _ecore_evas_win32_lower, - _ecore_evas_win32_activate, - _ecore_evas_win32_title_set, - NULL, /* _ecore_evas_x_name_class_set */ - _ecore_evas_win32_size_min_set, - _ecore_evas_win32_size_max_set, - _ecore_evas_win32_size_base_set, - _ecore_evas_win32_size_step_set, - _ecore_evas_win32_object_cursor_set, - _ecore_evas_win32_object_cursor_unset, - NULL, /* _ecore_evas_x_layer_set */ - _ecore_evas_win32_focus_set, - _ecore_evas_win32_iconified_set, - _ecore_evas_win32_borderless_set, - _ecore_evas_win32_override_set, - NULL, - _ecore_evas_win32_fullscreen_set, - NULL, /* _ecore_evas_x_avoid_damage_set */ - NULL, /* _ecore_evas_x_withdrawn_set */ - NULL, /* _ecore_evas_x_sticky_set */ - NULL, /* _ecore_evas_x_ignore_events_set */ - _ecore_evas_win32_alpha_set, - NULL, //transparent - NULL, // profiles_set - NULL, // profile_set + NULL, + NULL, + NULL, + NULL, + _ecore_evas_win32_callback_delete_request_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_win32_move, + NULL, + _ecore_evas_win32_resize, + _ecore_evas_win32_move_resize, + _ecore_evas_win32_rotation_set, + _ecore_evas_win32_shaped_set, + _ecore_evas_win32_show, + _ecore_evas_win32_hide, + _ecore_evas_win32_raise, + _ecore_evas_win32_lower, + _ecore_evas_win32_activate, + _ecore_evas_win32_title_set, + NULL, /* _ecore_evas_x_name_class_set */ + _ecore_evas_win32_size_min_set, + _ecore_evas_win32_size_max_set, + _ecore_evas_win32_size_base_set, + _ecore_evas_win32_size_step_set, + _ecore_evas_win32_object_cursor_set, + _ecore_evas_win32_object_cursor_unset, + NULL, /* _ecore_evas_x_layer_set */ + _ecore_evas_win32_focus_set, + _ecore_evas_win32_iconified_set, + _ecore_evas_win32_borderless_set, + _ecore_evas_win32_override_set, + NULL, + _ecore_evas_win32_fullscreen_set, + NULL, /* _ecore_evas_x_avoid_damage_set */ + NULL, /* _ecore_evas_x_withdrawn_set */ + NULL, /* _ecore_evas_x_sticky_set */ + NULL, /* _ecore_evas_x_ignore_events_set */ + _ecore_evas_win32_alpha_set, + NULL, //transparent + NULL, // profiles_set + NULL, // profile_set - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, - NULL, // render - _ecore_evas_win32_screen_geometry_get, - _ecore_evas_win32_screen_dpi_get, - NULL, - NULL, // msg_send + NULL, // render + _ecore_evas_win32_screen_geometry_get, + _ecore_evas_win32_screen_dpi_get, + NULL, + NULL, // msg_send - NULL, // pointer_xy_get - NULL, // pointer_warp + NULL, // pointer_xy_get + NULL, // pointer_warp - NULL, // wm_rot_preferred_rotation_set - NULL, // wm_rot_available_rotations_set - NULL, // wm_rot_manual_rotation_done_set - NULL, // wm_rot_manual_rotation_done + NULL, // wm_rot_preferred_rotation_set + NULL, // wm_rot_available_rotations_set + NULL, // wm_rot_manual_rotation_done_set + NULL, // wm_rot_manual_rotation_done - NULL, // aux_hints_set + NULL, // aux_hints_set - NULL, // fn_animator_register - NULL, // fn_animator_unregister + NULL, // fn_animator_register + NULL, // fn_animator_unregister - NULL, // fn_evas_changed - NULL, //fn_focus_device_set - NULL, //fn_callback_focus_device_in_set - NULL, //fn_callback_focus_device_out_set - NULL, //fn_callback_device_mouse_in_set - NULL, //fn_callback_device_mouse_out_set - NULL, //fn_pointer_device_xy_get - NULL, //fn_prepare - NULL, //fn_last_tick_get + NULL, // fn_evas_changed + NULL, //fn_focus_device_set + NULL, //fn_callback_focus_device_in_set + NULL, //fn_callback_focus_device_out_set + NULL, //fn_callback_device_mouse_in_set + NULL, //fn_callback_device_mouse_out_set + NULL, //fn_pointer_device_xy_get + NULL, //fn_prepare + NULL, //fn_last_tick_get + _ecore_evas_win32_selection_claim, //fn_selection_claim + _ecore_evas_win32_selection_has_owner, //fn_selection_has_owner + _ecore_evas_win32_selection_request, //fn_selection_request + NULL, //fn_dnd_start + NULL, //fn_dnd_stop }; #endif /* BUILD_ECORE_EVAS_WIN32 */ diff --git a/src/modules/ecore_evas/engines/x/ecore_evas_x.c b/src/modules/ecore_evas/engines/x/ecore_evas_x.c index abea314d33..e6463fd6a9 100644 --- a/src/modules/ecore_evas/engines/x/ecore_evas_x.c +++ b/src/modules/ecore_evas/engines/x/ecore_evas_x.c @@ -73,6 +73,16 @@ static Eina_Bool wm_exists; typedef struct _Ecore_Evas_Engine_Data_X11 Ecore_Evas_Engine_Data_X11; +typedef struct { + Ecore_Evas_Selection_Callbacks callbacks; + Ecore_Evas_Selection_Buffer buffer; + Ecore_Evas *ee; + Eina_Promise *delivery; + Eina_Array *acceptable_type; + Eina_Stringshare *requested_type; + Eina_Stringshare *later_conversion; +} Ecore_Evas_X11_Selection_Data; + struct _Ecore_Evas_Engine_Data_X11 { Ecore_X_Window win_root; Eina_List *win_extra; @@ -128,6 +138,11 @@ struct _Ecore_Evas_Engine_Data_X11 { void *visual; // store visual used to create pixmap unsigned long colormap; // store colormap used to create pixmap } pixmap; + Ecore_Evas_X11_Selection_Data selection_data[ECORE_EVAS_SELECTION_BUFFER_LAST]; + Eina_Array *xserver_atom_name_during_dnd; + Ecore_Event_Handler *mouse_up_handler; + Ecore_Job *init_job; + int skip_clean_event; Eina_Bool destroyed : 1; // X window has been deleted and cannot be used Eina_Bool fully_obscured : 1; // X window is fully obscured Eina_Bool configured : 1; // X window has been configured @@ -151,6 +166,8 @@ static void _alpha_do(Ecore_Evas *, int); static void _transparent_do(Ecore_Evas *, int); static void _avoid_damage_do(Ecore_Evas *, int); static void _rotation_do(Ecore_Evas *, int, int); +static void _ecore_evas_x_selection_init(void); +static void _ecore_evas_x_selection_window_init(Ecore_Evas *ee); #define SWAP_INT(a, b) do { a ^= b; b ^= a; a ^= b; } while (0) @@ -361,7 +378,7 @@ _ecore_evas_x_aux_hints_supported_update(Ecore_Evas *ee) for (i = 0; i < num; i++) { hint = eina_stringshare_add(str[i]); - ee->prop.aux_hint.supported_list = + ee->prop.aux_hint.supported_list = eina_list_append(ee->prop.aux_hint.supported_list, hint); } @@ -414,7 +431,7 @@ _ecore_evas_x_gl_window_new(Ecore_Evas *ee, Ecore_X_Window parent, int x, int y, op++; einfo->vsync = opt[op]; } -#ifdef EVAS_ENGINE_GL_X11_SWAP_MODE_EXISTS +#ifdef EVAS_ENGINE_GL_X11_SWAP_MODE_EXISTS else if (opt[op] == ECORE_EVAS_GL_X11_OPT_SWAP_MODE) { op++; @@ -845,7 +862,7 @@ _ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED Eina_Bool focus_skip : 1; } prop; } prev; - + prev.x.modal = edata->state.modal; prev.x.sticky = edata->state.sticky; prev.x.maximized_v = edata->state.maximized_v; @@ -856,7 +873,7 @@ _ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED prev.x.fullscreen = edata->state.fullscreen; prev.x.above = edata->state.above; prev.x.below = edata->state.below; - + prev.prop.modal = ee->prop.modal; prev.prop.maximized = ee->prop.maximized; prev.prop.sticky = ee->prop.sticky; @@ -879,7 +896,7 @@ _ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED ee->prop.sticky = EINA_FALSE; ee->prop.fullscreen = EINA_FALSE; // ee->prop.focus_skip = EINA_FALSE; - + ecore_x_netwm_window_state_get(e->win, &state, &num); if (state) { @@ -1253,7 +1270,7 @@ _ecore_evas_x_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; edata = ee->engine.data; -/* +/* { time_t t; char *ct; @@ -1304,7 +1321,7 @@ _ecore_evas_x_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void edata->outdelay = NULL; _fake_out(ee); } - + /* if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; */ if (!_ecore_evas_mouse_in_check(ee, NULL)) { @@ -1388,7 +1405,7 @@ _ecore_evas_x_event_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void ecore_timer_del(edata->outdelay); edata->outdelay = NULL; } - + // if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; // printf("OUT: ee->in=%i, e->mode=%i, e->detail=%i, dount_count=%i\n", // ee->in, e->mode, e->detail, evas_event_down_count_get(ee->evas)); @@ -1417,7 +1434,7 @@ _ecore_evas_x_event_window_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED ee = ecore_event_window_match(e->win); if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; -//xx// filtering with these doesnt help +//xx// filtering with these doesnt help //xx// if (e->mode == ECORE_X_EVENT_MODE_UNGRAB) return ECORE_CALLBACK_PASS_ON; _ecore_evas_focus_device_set(ee, NULL, EINA_TRUE); return ECORE_CALLBACK_PASS_ON; @@ -1433,7 +1450,7 @@ _ecore_evas_x_event_window_focus_out(void *data EINA_UNUSED, int type EINA_UNUSE ee = ecore_event_window_match(e->win); if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; -//xx// filtering with these doesnt help +//xx// filtering with these doesnt help //xx// if (e->mode == ECORE_X_EVENT_MODE_GRAB) return ECORE_CALLBACK_PASS_ON; // if (ee->prop.fullscreen) @@ -1970,6 +1987,7 @@ _ecore_evas_x_init(void) ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE, _ecore_evas_x_event_window_create, NULL); ecore_event_evas_init(); + _ecore_evas_x_selection_init(); return _ecore_evas_init_count; } @@ -1997,6 +2015,7 @@ _ecore_evas_x_free(Ecore_Evas *ee) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + ecore_job_del(edata->init_job); if (edata->pixmap.back) ecore_x_pixmap_free(edata->pixmap.back); if (edata->pixmap.front) @@ -2145,7 +2164,7 @@ _ecore_evas_x_resize(Ecore_Evas *ee, int w, int h) } /* check for valid property window - * + * * NB: If we do not have one, check for valid pixmap rendering */ if (!ee->prop.window) { @@ -2153,7 +2172,7 @@ _ecore_evas_x_resize(Ecore_Evas *ee, int w, int h) if ((edata->pixmap.w != vw) || (edata->pixmap.h != vh)) { /* free the backing pixmap */ - if (edata->pixmap.back) + if (edata->pixmap.back) ecore_x_pixmap_free(edata->pixmap.back); } } @@ -2696,6 +2715,7 @@ _alpha_do(Ecore_Evas *ee, int alpha) _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); _ecore_evas_x_size_pos_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); #endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ if ((id = getenv("DESKTOP_STARTUP_ID"))) { @@ -2850,6 +2870,7 @@ _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha) _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); _ecore_evas_x_size_pos_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); #endif /* BUILD_ECORE_EVAS_OPENGL_X11 */ if ((id = getenv("DESKTOP_STARTUP_ID"))) { @@ -2918,7 +2939,7 @@ _ecore_evas_x_aspect_set(Ecore_Evas *ee, double aspect) ee->prop.aspect = aspect; _ecore_evas_x_size_pos_hints_update(ee); -// netwm state +// netwm state // if (ee->should_be_visible) // ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, // ECORE_X_WINDOW_STATE_STICKY, -1, sticky); @@ -3545,14 +3566,14 @@ norandr: if (!found) goto norandr; } -static void +static void _ecore_evas_x_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) { if (ee->prop.window) ecore_x_pointer_xy_get(ee->prop.window, x, y); } -static Eina_Bool +static Eina_Bool _ecore_evas_x_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) { return ecore_x_pointer_warp(ee->prop.window, x, y); @@ -3667,6 +3688,733 @@ _ecore_evas_x_aux_hints_set(Ecore_Evas *ee, const char *hints) (ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT); } +static Ecore_X_Atom ecore_evas_selection_to_atom[] = {0, 0, 0, 0}; +static Ecore_Event_Handler *ecore_evas_selection_handlers[8]; + +static inline Ecore_Evas_Selection_Buffer +_atom_to_selection(Ecore_X_Atom atom) +{ + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (ecore_evas_selection_to_atom[i] == atom) + return i; + } + return ECORE_EVAS_SELECTION_BUFFER_LAST; +} + +static Eina_Stringshare* +_decrypt_type(const char *target) +{ + // reference https://tronche.com/gui/x/icccm/sec-2.html + if (eina_streq(target, "TEXT")) return eina_stringshare_add("text/plain"); + //FIXME no support in eina_content for that so far + if (eina_streq(target, "COMPOUND_TEXT")) return eina_stringshare_add("text/plain"); + // reference https://tronche.com/gui/x/icccm/sec-2.html + if (eina_streq(target, "STRING")) return eina_stringshare_add("text/plain;charset=iso-8859-1"); + if (eina_streq(target, "UTF8_STRING")) return eina_stringshare_add("text/plain;charset=utf-8"); + + return eina_stringshare_add(target); +} + +static Eina_Stringshare* +_mime_to_xserver_type(const char *target) +{ + // FIXME // reference https://tronche.com/gui/x/icccm/sec-2.html says it is in the owners choice of encoding, not sure what this means directly here + if (eina_streq(target, "text/plain")) return eina_stringshare_add("TEXT"); + // reference https://tronche.com/gui/x/icccm/sec-2.html + if (eina_streq(target, "text/plain;charset=iso-8859-1")) return eina_stringshare_add("STRING"); + if (eina_streq(target, "text/plain;charset=utf-8")) return eina_stringshare_add("UTF8_STRING"); + + return eina_stringshare_add(target); +} + +static inline void +_clear_selection(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection) +{ + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks; + + EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel); + + cbs->cancel(ee, 1, selection); + eina_array_free(cbs->available_types); + + cbs->delivery = NULL; + cbs->cancel = NULL; + cbs->available_types = NULL; +} + +static void +_clear_selection_delivery(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection) +{ + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + eina_stringshare_replace(&edata->selection_data[selection].requested_type, NULL); + eina_stringshare_replace(&edata->selection_data[selection].later_conversion, NULL); + edata->selection_data[selection].delivery = NULL; + eina_array_free(edata->selection_data[selection].acceptable_type); + edata->selection_data[selection].acceptable_type = NULL; +} + +static void +_ecore_x_selection_request(Ecore_X_Window win, Ecore_Evas_Selection_Buffer selection, const char *type) +{ + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + ecore_x_selection_primary_request(win, type); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + ecore_x_selection_clipboard_request(win, type); + else + ecore_x_selection_xdnd_request(win, type); +} + +static void +_search_fitting_type(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Eina_Array *arr) +{ + Eina_Stringshare *mime_type; + Eina_Bool found_conversion = EINA_FALSE; + +#define HANDLE_TYPE() \ + { \ + edata->selection_data[selection].requested_type = eina_stringshare_add(x11_name); \ + edata->selection_data[selection].later_conversion = eina_stringshare_add(acceptable_type);\ + found_conversion = EINA_TRUE; \ + break; \ + } + + EINA_SAFETY_ON_NULL_RETURN(edata->selection_data[selection].acceptable_type); + + for (unsigned int i = 0; i < eina_array_count(arr) && !found_conversion; ++i) + { + const char *x11_name = eina_array_data_get(arr, i); + mime_type = _decrypt_type(x11_name); + + for (unsigned int j = 0; j < eina_array_count(edata->selection_data[selection].acceptable_type) && !found_conversion; ++j) + { + const char *acceptable_type = (const char*) eina_array_data_get(edata->selection_data[selection].acceptable_type, j); + + if (mime_type == acceptable_type) + HANDLE_TYPE() + + //if there is no available type yet, check if we can convert to the desired type via this type + if (!found_conversion) + { + const char *convertion_type = NULL; + Eina_Iterator *iter = eina_content_converter_possible_conversions(mime_type); + EINA_ITERATOR_FOREACH(iter, convertion_type) + { + if (convertion_type == acceptable_type) + HANDLE_TYPE() + } + eina_iterator_free(iter); + } + } + eina_stringshare_del(mime_type); + } + if (found_conversion) + { + _ecore_x_selection_request(ee->prop.window, selection, edata->selection_data[selection].requested_type); + } + else + { + eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_error_init(ecore_evas_no_matching_type)); + _clear_selection_delivery(ee, selection); + } + +#undef HANDLE_TYPE +} + +static void +_search_fitting_type_from_event(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev) +{ + Ecore_X_Atom *available_atoms; + Ecore_X_Selection_Data_Targets *targets; + Eina_Array *tmp = eina_array_new(10); + + targets = ev->data; + available_atoms = (Ecore_X_Atom *)targets->data.data; + for (int i = 0; i < targets->data.length; ++i) + { + Ecore_X_Atom atom = available_atoms[i]; + eina_array_push(tmp, ecore_x_atom_name_get(atom)); + } + _search_fitting_type(ee, edata, selection, tmp); + eina_array_free(tmp); +} + +static void +_deliver_content(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev) +{ + Ecore_X_Selection_Data *x11_data = ev->data; + Eina_Rw_Slice data; + Eina_Content *result; + Eina_Stringshare *mime_type = _decrypt_type(edata->selection_data[selection].requested_type); + + if (!strncmp(mime_type, "text", strlen("text"))) + { + //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. + data.len = x11_data->length + 1; + data.mem = eina_memdup(x11_data->data, x11_data->length, EINA_TRUE); + } + else + { + data.len = x11_data->length; + data.mem = x11_data->data; + } + + result = eina_content_new(eina_rw_slice_slice_get(data), mime_type); + + //ensure that we deliver the correct type, we might have choosen a convertion before + if (edata->selection_data[selection].later_conversion != mime_type) + { + Eina_Content *tmp = eina_content_convert(result, edata->selection_data[selection].later_conversion); + eina_content_free(result); + result = tmp; + } + + eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_content_init(result)); + eina_content_free(result); + _clear_selection_delivery(ee, selection); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + ecore_x_dnd_send_finished(); +} + +static Eina_Bool +_ecore_evas_x_selection_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Selection_Notify *ev = event; + Ecore_Evas_Selection_Buffer selection; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + ee = ecore_event_window_match(ev->win); + selection = _atom_to_selection(ev->atom); + EINA_SAFETY_ON_FALSE_GOTO(!!ee, end); + EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); + edata = ee->engine.data; + + //if dnd drops above us, and even if we did not request anything, we are getting notified, refuse to do anything + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER && + !edata->selection_data[selection].later_conversion) + { + ecore_x_dnd_send_finished(); + } + else + { + if (eina_streq(ev->target, "TARGETS") || eina_streq(ev->target, "ATOMS")) + { + //This will decide for a type, and will sent that via _ecore_x_selection_request + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, EINA_FALSE); + _search_fitting_type_from_event(ee, edata, selection, ev); + } + else + { + //This will read the data, fill it into a Eina_Content apply all conversions required. + EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].later_conversion, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].requested_type, EINA_FALSE); + _deliver_content(ee, edata, selection, ev); + } + } +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_selection_clear(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Selection_Clear *ev = event; + Ecore_Evas_Selection_Callbacks *cbs; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas_Selection_Buffer selection; + Ecore_Evas *ee; + + ee = ecore_event_window_match(ev->win); + selection = _atom_to_selection(ev->atom); + EINA_SAFETY_ON_FALSE_GOTO(ee, end); + EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); + edata = ee->engine.data; + cbs = &edata->selection_data[selection].callbacks; + + //skip clean event + if (edata->skip_clean_event) + { + edata->skip_clean_event --; + goto end; + } + + if (cbs->cancel) + _clear_selection(ee, selection); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_force_stop_self_dnd(Ecore_Evas *ee) +{ + Ecore_Evas_Engine_Data_X11 *edata; + + EINA_SAFETY_ON_NULL_RETURN(ee); + edata = ee->engine.data; + EINA_SAFETY_ON_NULL_RETURN(edata); + + //Never clear the buffer for selection here. + //Selection buffer is freed as a response to the FINISHED event. + ecore_x_pointer_ungrab(); + ecore_x_dnd_self_drop(); + ecore_x_dnd_aware_set(ee->prop.window, EINA_FALSE); + ecore_event_handler_del(edata->mouse_up_handler); + edata->mouse_up_handler = NULL; + + if (ee->drag.free) + ee->drag.free(ee, 1, ee->drag.data, ee->drag.accepted); + ee->drag.free = NULL; +} + +static Eina_Bool +_ecore_evas_x_selection_fixes_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Fixes_Selection_Notify *ev = event; + Ecore_Evas *ee; + Ecore_Evas_Selection_Buffer selection; + + ee = ecore_event_window_match(ev->win); + selection = _atom_to_selection(ev->atom); + EINA_SAFETY_ON_FALSE_GOTO(!!ee, end); + EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); + + //notify that the selection has changed on this ecore evas + if (ee->func.fn_selection_changed) + ee->func.fn_selection_changed(ee, 0, selection); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_eina_content_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize) +{ + Ecore_Evas_X11_Selection_Data *sdata = data; + Eina_Bool ret = EINA_FALSE;; + if (eina_streq(target, "TARGETS") || eina_streq(target, "ATOM")) + { + //list all available types that we have currently + Ecore_X_Atom *result = calloc(eina_array_count(sdata->callbacks.available_types), sizeof(Ecore_X_Atom)); + for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i) + { + result[i] = ecore_x_atom_get(eina_array_data_get(sdata->callbacks.available_types, i)); + } + *size_ret = eina_array_count(sdata->callbacks.available_types); + *data_ret = result; + *ttype = ECORE_X_ATOM_ATOM; + *typesize = 32; /* urk */ + ret = EINA_TRUE; + } + else + { + const char *mime_type = _decrypt_type(target); + for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i) + { + if (mime_type == eina_array_data_get(sdata->callbacks.available_types, i)) + { + Eina_Rw_Slice slice; + sdata->callbacks.delivery(sdata->ee, 1, sdata->buffer, mime_type, &slice); + *size_ret = slice.len; + *data_ret = slice.mem; + *ttype = ecore_x_atom_get(target); //use here target in order to get the correct atom + //FIXME in selection manager we never set here the typesize, isn't that weird ? + ret = EINA_TRUE; + break; + } + } + eina_stringshare_del(mime_type); + } + + return ret; +} + +static Eina_Bool +_ecore_evas_x_dnd_enter(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Enter *enter = event; + Eina_Array *mime_tmp; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + mime_tmp = eina_array_new(10); + ee = ecore_event_window_match(enter->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + edata = ee->engine.data; + edata->xserver_atom_name_during_dnd = eina_array_new(10); + for (int i = 0; i < enter->num_types; ++i) + { + const char *mime_type = _decrypt_type(enter->types[i]); + eina_array_push(mime_tmp, mime_type); + eina_array_push(edata->xserver_atom_name_during_dnd, eina_stringshare_add(enter->types[i])); + } + ecore_evas_dnd_enter(ee, 1, eina_array_iterator_new(mime_tmp), EINA_POSITION2D(0,0)); //FIXME + eina_array_free(mime_tmp); + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_dnd_leave(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Leave *leave = event; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + ee = ecore_event_window_match(leave->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + edata = ee->engine.data; + ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(0,0)); + for (unsigned int i = 0; i < eina_array_count(edata->xserver_atom_name_during_dnd); ++i) + { + eina_stringshare_del(eina_array_data_get(edata->xserver_atom_name_during_dnd, i)); + } + eina_array_free(edata->xserver_atom_name_during_dnd); + edata->xserver_atom_name_during_dnd = NULL; +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Ecore_X_Atom +_x11_dnd_action_rev_map(const char* action) +{ + if (eina_streq(action, "copy")) return ECORE_X_ATOM_XDND_ACTION_COPY; + if (eina_streq(action, "move")) return ECORE_X_ATOM_XDND_ACTION_MOVE; + else if (eina_streq(action, "privat")) return ECORE_X_ATOM_XDND_ACTION_PRIVATE; + else if (eina_streq(action, "ask")) return ECORE_X_ATOM_XDND_ACTION_ASK; + else if (eina_streq(action, "list")) return ECORE_X_ATOM_XDND_ACTION_LIST; + else if (eina_streq(action, "link")) return ECORE_X_ATOM_XDND_ACTION_LINK; + else if (eina_streq(action, "description")) return ECORE_X_ATOM_XDND_ACTION_DESCRIPTION; + return 0; +} + +static const char* +_x11_dnd_action_map(Ecore_X_Atom action) +{ + if (action == ECORE_X_DND_ACTION_COPY) return "copy"; + if (action == ECORE_X_ATOM_XDND_ACTION_MOVE) return "move"; + if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE) return "privat"; + if (action == ECORE_X_ATOM_XDND_ACTION_ASK) return "ask"; + if (action == ECORE_X_ATOM_XDND_ACTION_LIST) return "list"; + if (action == ECORE_X_ATOM_XDND_ACTION_LINK) return "link"; + if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION) return "description"; + + return "unknown"; +} + +static Eina_Bool +_ecore_evas_x_dnd_position(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Position *pos = event; + int x, y, w, h; + Ecore_Evas *ee; + + ee = ecore_event_window_match(pos->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + ecore_evas_geometry_get(ee, &x, &y, &w, &h); + ecore_evas_dnd_position_set(ee, 1, EINA_POSITION2D(pos->position.x - x, pos->position.y - y)); + ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, (Ecore_X_Rectangle){x,y,w,h}, pos->action); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_dnd_drop(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Drop *drop = event; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas *ee; + + ee = ecore_event_window_match(drop->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + edata = ee->engine.data; + if (ee->func.fn_dnd_drop) + ee->func.fn_dnd_drop(ee, 1, ecore_evas_dnd_pos_get(ee, 1), _x11_dnd_action_map(drop->action)); + if (edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].delivery && + !edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].requested_type) + { + //only abort dnd if we have something to deliver here, otherwise some other dnd implementation in our own window is handling that + ecore_x_dnd_send_finished(); + } + ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(drop->position.x ,drop->position.y)); + eina_array_free(edata->xserver_atom_name_during_dnd); + edata->xserver_atom_name_during_dnd = NULL; +end: + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_finished(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Ecore_X_Event_Xdnd_Finished *finished = event; + Ecore_Evas *ee; + + ee = ecore_event_window_match(finished->win); + EINA_SAFETY_ON_NULL_GOTO(ee, end); + + _clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_ecore_evas_x_selection_init(void) +{ + Ecore_X_Atom _ecore_evas_selection_to_atom[] = {ECORE_X_ATOM_SELECTION_PRIMARY, ECORE_X_ATOM_SELECTION_CLIPBOARD, ECORE_X_ATOM_SELECTION_XDND}; + + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + ecore_evas_selection_to_atom[i] = _ecore_evas_selection_to_atom[i]; + } + + ecore_evas_selection_handlers[0] = + ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, + _ecore_evas_x_selection_notify, NULL); + ecore_evas_selection_handlers[1] = + ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, + _ecore_evas_x_selection_clear, NULL); + if (ECORE_X_EVENT_FIXES_SELECTION_NOTIFY) + ecore_evas_selection_handlers[2] = + ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, + _ecore_evas_x_selection_fixes_notify, NULL); + + ecore_evas_selection_handlers[3] = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER, + _ecore_evas_x_dnd_enter, NULL); + ecore_evas_selection_handlers[4] = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE, + _ecore_evas_x_dnd_leave, NULL); + ecore_evas_selection_handlers[5] = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION, + _ecore_evas_x_dnd_position, NULL); + ecore_evas_selection_handlers[6] = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP, + _ecore_evas_x_dnd_drop, NULL); + ecore_evas_selection_handlers[7] = ecore_event_handler_add(ECORE_X_EVENT_XDND_FINISHED, + _ecore_evas_x_finished, NULL); + /* for us known type */ + char *supported_types[] = { + "text/plain", + "text/plain;charset=utf-8", + "image/png", + "image/jpeg", + "image/x-ms-bmp", + "image/gif", + "image/tiff", + "image/svg+xml", + "image/x-xpixmap", + "image/x-tga", + "image/x-portable-pixmap", + "TEXT", + "COMPOUND_TEXT", + "STRING", + "UTF8_STRING", + "text/x-vcard", + "text/uri-list", + "application/x-elementary-markup", + "ATOM", + "TARGETS", + NULL + }; + for (int i = 0; supported_types[i]; ++i) + { + ecore_x_selection_converter_add(supported_types[i], _eina_content_converter); + } +} + +static Eina_Bool +_ecore_evas_x_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + return !!ecore_x_selection_owner_get(ecore_evas_selection_to_atom[selection]); +} + +static void +_deliver_selection_changed(void *data) +{ + Ecore_Evas *ee = data; + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + + if (!ee->func.fn_selection_changed) + goto end; + + if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)) + ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER); + if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)) + ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER); + if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)) + ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); +end: + edata->init_job = NULL; +} + +static void +_ecore_evas_x_selection_window_init(Ecore_Evas *ee) +{ + Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + ecore_x_fixes_window_selection_notification_request(ee->prop.window, ecore_evas_selection_to_atom[i]); + edata->selection_data[i].ee = ee; + edata->selection_data[i].buffer = i; + } + ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE); + edata->init_job = ecore_job_add(_deliver_selection_changed, ee); +} + +static void +_store_selection_cbs(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer)) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_Evas_Selection_Callbacks *cbs; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + cbs = &sdata->callbacks; + + if (cbs->cancel) + { + _clear_selection(ee, selection); + edata->skip_clean_event ++; //we are going to overwrite our own selection, this will emit a clean event, but we already freed it. + } + + cbs->delivery = delivery; + cbs->cancel = cancel; + cbs->available_types = available_types; +} + +static Eina_Bool +_ecore_evas_x_selection_claim(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + + _store_selection_cbs(ee, selection, available_types, delivery, cancel); + + if (eina_array_count(available_types) > 0) + { + //the commands below will *copy* the content of sdata, this you have to ensure that clear is called when sdata is changed. + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + ecore_x_selection_primary_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data)); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + ecore_x_selection_clipboard_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data)); + } + else + { + if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) + ecore_x_selection_primary_clear(); + else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) + ecore_x_selection_clipboard_clear(); + } + + //for drag and drop, we are not calling anything in here + + return EINA_TRUE; +} + +Eina_Future* +_ecore_evas_x_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + Eina_Future *future; + + edata = ee->engine.data; + sdata = &edata->selection_data[selection]; + + if (sdata->delivery) + { + eina_promise_reject(sdata->delivery, ecore_evas_request_replaced); + _clear_selection_delivery(ee, selection); + } + sdata->delivery = efl_loop_promise_new(efl_main_loop_get()); + sdata->acceptable_type = acceptable_type; + future = eina_future_new(sdata->delivery); + + if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) + { + //when in dnd - we are requesting out of the set that we know from the enter event + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, NULL); + EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, NULL); + _search_fitting_type(ee, edata, selection, edata->xserver_atom_name_during_dnd); + } + else + { + //when not dnd - we are first wanting to know what is available + _ecore_x_selection_request(ee->prop.window, selection, ECORE_X_SELECTION_TARGET_TARGETS); + } + + return future; +} + +static void +_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos) +{ + Ecore_Evas *ee = data; + Eina_Rect rect; + + ecore_evas_geometry_get(ee->drag.rep, &rect.x, &rect.y, &rect.w, &rect.h); + + ecore_evas_move(ee->drag.rep, pos->position.x - rect.w / 2, pos->position.y - rect.h/2); +} + +static Eina_Bool +_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event EINA_UNUSED) +{ + Ecore_Evas *ee = data; + + _force_stop_self_dnd(ee); + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_x_dnd_start(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Array *available_types, Ecore_Evas *drag_rep, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer), const char* action) +{ + Ecore_Evas_X11_Selection_Data *sdata; + Ecore_Evas_Engine_Data_X11 *edata; + Ecore_X_Atom actx; + + edata = ee->engine.data; + sdata = &edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER]; + _store_selection_cbs(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, available_types, delivery, cancel); + + //first set all types we have + ecore_x_dnd_types_set(ee->prop.window, NULL, 0); + for (unsigned int i = 0; i < eina_array_count(available_types); ++i) + { + const char *xserver_mime_type = _mime_to_xserver_type(eina_array_data_get(available_types, i)); + ecore_x_dnd_type_set(ee->prop.window, xserver_mime_type, EINA_TRUE); + eina_stringshare_del(xserver_mime_type); + } + ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE); + ecore_x_dnd_callback_pos_update_set(_x11_drag_move, ee); + ecore_x_dnd_self_begin(ee->prop.window, (unsigned char*)sdata, sizeof(Ecore_Evas_X11_Selection_Data)); + actx = _x11_dnd_action_rev_map(action); + ecore_x_dnd_source_action_set(actx); + ecore_x_pointer_grab(ee->prop.window); + + ecore_x_window_ignore_set(drag_rep->prop.window, EINA_TRUE); + + if (edata->mouse_up_handler) + ecore_event_handler_del(edata->mouse_up_handler); + edata->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, + _x11_drag_mouse_up, ee); + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_x_dnd_stop(Ecore_Evas *ee, unsigned int seat EINA_UNUSED) +{ + _force_stop_self_dnd(ee); + _clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER); + ecore_x_selection_xdnd_clear(); //This is needed otherwise a outdated sdata struct will be accessed + return EINA_TRUE; +} + static Ecore_Evas_Engine_Func _ecore_x_engine_func = { _ecore_evas_x_free, @@ -3754,6 +4502,11 @@ static Ecore_Evas_Engine_Func _ecore_x_engine_func = NULL, //fn_pointer_device_xy_get NULL, //fn_prepare NULL, //fn_last_tick_get + _ecore_evas_x_selection_claim, //fn_selection_claim + _ecore_evas_x_selection_has_owner, //fn_selection_has_owner + _ecore_evas_x_selection_request, //fn_selection_request + _ecore_evas_x_dnd_start, //fn_dnd_start + _ecore_evas_x_dnd_stop, //fn_dnd_stop }; /* @@ -3772,19 +4525,19 @@ _ecore_evas_x_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ /* printf("\tPixman Size: %d %d\n", edata->pixmap.w, edata->pixmap.h); */ /* printf("\tEE Size: %d %d\n", ee->w, ee->h); */ - /* before rendering to the back buffer pixmap, we should check the - * size. If the back buffer is not the proper size, destroy it and + /* before rendering to the back buffer pixmap, we should check the + * size. If the back buffer is not the proper size, destroy it and * create a new one at the proper size */ if ((edata->pixmap.w != ee->w) || (edata->pixmap.h != ee->h)) { int fw = 0, fh = 0; /* free the backing pixmap */ - if (edata->pixmap.back) + if (edata->pixmap.back) ecore_x_pixmap_free(edata->pixmap.back); - edata->pixmap.back = - ecore_x_pixmap_new(edata->win_root, ee->w, ee->h, + edata->pixmap.back = + ecore_x_pixmap_new(edata->win_root, ee->w, ee->h, edata->pixmap.depth); evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh); @@ -3803,7 +4556,7 @@ _ecore_evas_x_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -3821,7 +4574,7 @@ _ecore_evas_x_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -3844,8 +4597,8 @@ _ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ /* printf("\tBack Pixmap: %d\n", edata->pixmap.back); */ /* printf("\tFront Pixmap: %d\n", edata->pixmap.front); */ - /* done drawing to the back buffer. flip it to the front so that - * any calls to "fetch pixmap" will return the front buffer already + /* done drawing to the back buffer. flip it to the front so that + * any calls to "fetch pixmap" will return the front buffer already * pre-rendered */ /* record the current front buffer */ @@ -3870,7 +4623,7 @@ _ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -3888,7 +4641,7 @@ _ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { - ERR("evas_engine_info_set() init engine '%s' failed.", + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); } } @@ -4117,6 +4870,7 @@ ecore_evas_software_x11_new_internal(const char *disp_name, Ecore_X_Window paren _ecore_evas_x_wm_rotation_protocol_set(ee); _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); ee->engine.func->fn_render = _ecore_evas_x_render; ee->draw_block = EINA_TRUE; @@ -4307,9 +5061,9 @@ ecore_evas_software_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Windo edata->pixmap.colormap = einfo->info.colormap; /* create front and back pixmaps for double-buffer rendering */ - edata->pixmap.front = + edata->pixmap.front = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); - edata->pixmap.back = + edata->pixmap.back = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); einfo->info.drawable = edata->pixmap.back; @@ -4322,7 +5076,7 @@ ecore_evas_software_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Windo } } - /* FIXME: Allow of these set properties or do something with the + /* FIXME: Allow of these set properties or do something with the * ee->prop.window (x window), which we do not have in pixmap case */ /* _ecore_evas_x_hints_update(ee); */ @@ -4370,7 +5124,7 @@ _ecore_evas_software_x11_pixmap_visual_get(const Ecore_Evas *ee) return edata->pixmap.visual; } -static unsigned long +static unsigned long _ecore_evas_software_x11_pixmap_colormap_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "software_x11"))) return 0; @@ -4378,7 +5132,7 @@ _ecore_evas_software_x11_pixmap_colormap_get(const Ecore_Evas *ee) return edata->pixmap.colormap; } -static int +static int _ecore_evas_software_x11_pixmap_depth_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "software_x11"))) return 0; @@ -4553,6 +5307,7 @@ ecore_evas_gl_x11_options_new_internal(const char *disp_name, Ecore_X_Window par _ecore_evas_x_wm_rotation_protocol_set(ee); _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); + _ecore_evas_x_selection_window_init(ee); ee->draw_block = 1; if (!wm_exists) edata->configured = 1; @@ -4719,9 +5474,9 @@ ecore_evas_gl_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Window pare edata->pixmap.colormap = einfo->info.colormap; /* create front and back pixmaps for double-buffer rendering */ - edata->pixmap.front = + edata->pixmap.front = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); - edata->pixmap.back = + edata->pixmap.back = ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth); einfo->info.drawable = edata->pixmap.back; @@ -4779,7 +5534,7 @@ _ecore_evas_gl_x11_pixmap_visual_get(const Ecore_Evas *ee) return edata->pixmap.visual; } -static unsigned long +static unsigned long _ecore_evas_gl_x11_pixmap_colormap_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "opengl_x11"))) return 0; @@ -4787,7 +5542,7 @@ _ecore_evas_gl_x11_pixmap_colormap_get(const Ecore_Evas *ee) return edata->pixmap.colormap; } -static int +static int _ecore_evas_gl_x11_pixmap_depth_get(const Ecore_Evas *ee) { if (!(!strcmp(ee->driver, "opengl_x11"))) return 0; diff --git a/src/modules/emotion/generic/Emotion_Generic_Plugin.h b/src/modules/emotion/generic/Emotion_Generic_Plugin.h deleted file mode 100644 index 96b69f6421..0000000000 --- a/src/modules/emotion/generic/Emotion_Generic_Plugin.h +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef EMOTION_GENERIC_PLUGIN_H -#define EMOTION_GENERIC_PLUGIN_H - -#include -#include -#include -#include -#include - -#include - -#define DEFAULTWIDTH 320 -#define DEFAULTHEIGHT 240 -#define DEFAULTPITCH 4 - -typedef enum _Emotion_Generic_Cmd Emotion_Generic_Cmd; -typedef enum _Emotion_Generic_Result Emotion_Generic_Result; -typedef struct _Emotion_Generic_Video_Frame Emotion_Generic_Video_Frame; -typedef struct _Emotion_Generic_Video_Shared Emotion_Generic_Video_Shared; - -enum _Emotion_Generic_Cmd -{ - EM_CMD_INIT = 0, // 0 param: shared memory identifier (string) - EM_CMD_PLAY, // 1 param: position (float) - EM_CMD_STOP, // 2 param: none - EM_CMD_FILE_SET, // 3 param: filename (string) - EM_CMD_FILE_SET_DONE, // 4 param: none - EM_CMD_FILE_CLOSE, // 5 param: none - EM_CMD_POSITION_SET, // 6 param: position (float) - EM_CMD_SPEED_SET, // 7 param: speed (float) - EM_CMD_AUDIO_MUTE_SET, // 8 param: muted (int) - EM_CMD_VIDEO_MUTE_SET, // 9 param: muted (int) - EM_CMD_SPU_MUTE_SET, // 10 param: muted (int) - EM_CMD_VOLUME_SET, // 11 param: volume (float) - EM_CMD_AUDIO_TRACK_SET, // 12 param: track id (int) - EM_CMD_VIDEO_TRACK_SET, // 13 param: track id (int) - EM_CMD_SPU_TRACK_SET, // 14 param: track id (int) - EM_CMD_SUBTITLE_SET, // 15 param: subtitle filename (string) - EM_CMD_LAST -}; - -enum _Emotion_Generic_Result -{ - EM_RESULT_INIT = 0, // param: none - EM_RESULT_FILE_SET, // param: none - EM_RESULT_FILE_SET_DONE, // param: success (int) - EM_RESULT_PLAYBACK_STARTED, // param: none - EM_RESULT_PLAYBACK_STOPPED, // param: none - EM_RESULT_FILE_CLOSE, // param: none - EM_RESULT_FRAME_NEW, // param: none - EM_RESULT_FRAME_SIZE, // param: int, int (width, height) - EM_RESULT_LENGTH_CHANGED, // param: float - EM_RESULT_POSITION_CHANGED, // param: float - EM_RESULT_SEEKABLE_CHANGED, // param: int - EM_RESULT_AUDIO_TRACK_INFO, // param: current track, track count, track_id, track_name, track_id2, track_name2, ... - EM_RESULT_VIDEO_TRACK_INFO, // param: current track, track count, track_id, track_name, track_id2, track_name2, ... - EM_RESULT_SPU_TRACK_INFO, // param: current spu, spu count, spu_id, spu_name, spu_id2, spu_name2, ... - // (int, int, int, string, int, string, ...) - EM_RESULT_META_INFO, // param: title, artist, album, year, genre, comments, disc id, count (all int) - EM_RESULT_LAST -}; - -/* structure for frames 2 buffers to keep integrity */ -struct _Emotion_Generic_Video_Frame -{ - unsigned char *frames[3]; -}; - -/* structure for frames 2 buffers to keep integrity */ -struct _Emotion_Generic_Video_Shared -{ - int size; - int width; - int height; - int pitch; - /** - * - "emotion" is the frame from where the Emotion process is reading pixels. - * The player shouldn't touch this frame. - * - "player" is the frame where the slave process is writing pixels. - * The emotion process shouldn't touch this frame. - * - "last" is the last frame that was rendered by the player. Emotion will - * use this frame the next time it will fetch pixels to Evas. - * - "next" is the unused frame. The player currently using the "player" - * should, after finishing this frame, set "last" to "player", and "player" - * to "next", and finally "next" to "last" so this operation can be done - * many times in case that Emotion does not request pixels fast enough. - */ - struct { - int emotion; - int player; - int last; - int next; - } frame; - Eina_Semaphore lock; - int frame_drop; -}; - -static inline int -emotion_generic_shm_get(const char *shmname, Emotion_Generic_Video_Shared **vs, Emotion_Generic_Video_Frame *vf) -{ - int shmfd = -1; - int size; - Emotion_Generic_Video_Shared *t_vs; - - shmfd = shm_open(shmname, O_RDWR, 0700); - if (shmfd == -1) - { - fprintf(stderr, "player: could not open shm: %s: %s\n", - shmname, strerror(errno)); - return 0; - } - - t_vs = mmap(NULL, sizeof(*t_vs), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0); - if (t_vs == MAP_FAILED) - { - fprintf(stderr, "player: could not map shared memory: %s\n", - strerror(errno)); - close(shmfd); - return 0; - } - size = t_vs->size; - munmap(t_vs, sizeof(*t_vs)); - t_vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0); - if (t_vs == MAP_FAILED) - { - fprintf(stderr, "player: could not map shared memory: %s\n", - strerror(errno)); - close(shmfd); - return 0; - } - close(shmfd); - - vf->frames[0] = (unsigned char *)t_vs + sizeof(*t_vs); - vf->frames[1] = (unsigned char *)t_vs + sizeof(*t_vs) + t_vs->height * t_vs->width * t_vs->pitch; - vf->frames[2] = (unsigned char *)t_vs + sizeof(*t_vs) + 2 * t_vs->height * t_vs->width * t_vs->pitch; - - *vs = t_vs; - - return 1; -} - -static inline void -emotion_generic_shm_free(Emotion_Generic_Video_Shared *vs) -{ - munmap(vs, vs->size); -} - -#endif // EMOTION_GENERIC_PLUGIN_H diff --git a/src/modules/emotion/generic/README b/src/modules/emotion/generic/README deleted file mode 100644 index c2a028de5d..0000000000 --- a/src/modules/emotion/generic/README +++ /dev/null @@ -1,79 +0,0 @@ -Generic - emotion backend -========================= - -This generic player backend executes a separate player in another -process. It receives the bytes to be drawn on the emotion object through -a shared memory, and communicates with the player through a pipe, using -the player standard input/output. - -The player must communicate with emotion using the defined commands -specified in the Emotion_Generic_Plugin.h. It doesn't need to link -against emotion, just include this file for easier implementation. - - -How does it work? -================= - -When the module is initialized for an emotion object, it starts another process -that runs the specified player. The player command line is specified using: - - emotion_object_module_option_set(object, "player", ); - -A player using libvlc is being provided now, and the generic module internally -checks if the command given was "vlc", in which case it will use this provided -vlc player. - -When a file is set to this object, it will send the file name to the player, and -expect an answer that will tell that the player already decoded a bit of the -file, and the video size is already set on the module, so it can allocate a -shared memory with correct size. - -The module then allocates the memory, sends a message to the player and expect -an answer. After this last answer, the "open_done" signal is sent and the module -knows that it is ready for playing. Commands sent before the module being ready -are now applied (and play is resumed if necessary). - -During this setup stage, info about the file set will be stored in the module, -so commands like meta data get, length get and so will be available to sync -calls like emotion_object_play_length_get(); - -If the player dies for any reason, a "decode_stop" signal is sent (should change -to something more like an error signal), and if play is called again, it will be -restarted. The playback should start from the same point it was before the -player crashed, if the player supports seek on the current media format). - -TODO -==== - - - Provide better description for commands; - - Explain in details the communication emotion <-> player; - - Make more common functions for players; - - (maybe) add support for named pipes, so we don't rely on standard in/out - for communication; - - Add a detection on the player to know that the emotion process died (so it - can just exit); - - shmname should contain the child pid too; - - better names for commands, maybe add namespace everywhere; - - -questions -========= - - - Using semaphores to lock the critical region between process, and pthread - mutexes for the threads inside the player. Should move to only one type - (semphores or mutexes)? - - There are 2 inline functions insde Emotion_Generic_Plugin.h to make it easier - for the player to get the shared memory correctly. Any problem with this? - Would be good to add more functions/macros to make common tasks like - parsing commands there too? - - Should move players to another project (outside of emotion)? - - -problems -======== - - file_set has some critical time when file is not set yet when we can't call - some functions (I think only another file_set now); - - communication player -> emotion depends on '\n' to delimitate commands, will - remove this soon (fix this urgently!); - - need to implement missing APIs; - diff --git a/src/modules/emotion/generic/emotion_generic.c b/src/modules/emotion/generic/emotion_generic.c deleted file mode 100644 index 601e9e2d92..0000000000 --- a/src/modules/emotion/generic/emotion_generic.c +++ /dev/null @@ -1,1908 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "emotion_modules.h" -#include "emotion_generic.h" - -static Eina_Prefix *pfx = NULL; -static Eina_List *_generic_players = NULL; -static int _emotion_init_count = 0; - -static int _emotion_generic_log_domain = -1; -#ifdef DBG -#undef DBG -#endif -#define DBG(...) EINA_LOG_DOM_DBG(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef INF -#undef INF -#endif -#define INF(...) EINA_LOG_DOM_INFO(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef WRN -#undef WRN -#endif -#define WRN(...) EINA_LOG_DOM_WARN(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef ERR -#undef ERR -#endif -#define ERR(...) EINA_LOG_DOM_ERR(_emotion_generic_log_domain, __VA_ARGS__) - -#ifdef CRI -#undef CRI -#endif -#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_generic_log_domain, __VA_ARGS__) - - -static Eina_Bool _fork_and_exec(Emotion_Generic_Video *ev); -static void em_partial_shutdown(Emotion_Generic_Video *ev); - - -static void -_player_send_cmd(Emotion_Generic_Video *ev, int cmd) -{ - if (cmd >= EM_CMD_LAST) - { - ERR("invalid command to player."); - return; - } - if (!ev->fd_write) - { - ERR("you should wait for emotion to be ready to take action."); - return; - } - ecore_pipe_write(ev->fd_write, &cmd, sizeof(cmd)); -} - -static void -_player_send_int(Emotion_Generic_Video *ev, int number) -{ - if (!ev->fd_write) - { - ERR("you should wait for emotion to be ready to take action."); - return; - } - ecore_pipe_write(ev->fd_write, &number, sizeof(number)); -} - -static void -_player_send_float(Emotion_Generic_Video *ev, float number) -{ - if (!ev->fd_write) - { - ERR("you should wait for emotion to be ready to take action."); - return; - } - ecore_pipe_write(ev->fd_write, &number, sizeof(number)); -} - -static void -_player_send_str(Emotion_Generic_Video *ev, const char *str, Eina_Bool stringshared) -{ - int len; - - if (stringshared) - len = str ? eina_stringshare_strlen(str) + 1 : 0; - else - len = str ? strlen(str) + 1 : 0; - - if (str) - ecore_pipe_write(ev->fd_write, str, len); -} - -static Eina_Bool -_create_shm_data(Emotion_Generic_Video *ev, const char *shmname) -{ - int shmfd; - int npages; - size_t size; - Emotion_Generic_Video_Shared *vs; - - shmfd = shm_open(shmname, O_CREAT | O_RDWR | O_TRUNC, 0700); - if (shmfd == -1) - { - ERR("player: could not create shm %s: %s", shmname, strerror(errno)); - return 0; - } - size = 3 * (ev->w * ev->h * DEFAULTPITCH) + sizeof(*vs); - - npages = (int)(size / getpagesize()) + 1; - size = npages * getpagesize(); - - if (ftruncate(shmfd, size)) - { - ERR("error when allocating shared memory (size = %zd): " - "%s", size, strerror(errno)); - close(shmfd); - shm_unlink(shmname); - return EINA_FALSE; - } - vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0); - if (vs == MAP_FAILED) - { - ERR("error when mapping shared memory: %s", strerror(errno)); - close(shmfd); - shm_unlink(shmname); - return EINA_FALSE; - } - close(shmfd); - - vs->size = size; - vs->width = ev->w; - vs->height = ev->h; - vs->pitch = DEFAULTPITCH; - vs->frame.emotion = 0; - vs->frame.player = 1; - vs->frame.last = 2; - vs->frame.next = 2; - vs->frame_drop = 0; - if (!eina_semaphore_new(&vs->lock, 1)) - { - ERR("can not create semaphore"); - munmap(vs, size); - shm_unlink(shmname); - return EINA_FALSE; - } - ev->frame.frames[0] = (unsigned char *)vs + sizeof(*vs); - ev->frame.frames[1] = (unsigned char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch; - ev->frame.frames[2] = (unsigned char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch; - - if (ev->shared) - munmap(ev->shared, ev->shared->size); - ev->shared = vs; - - return EINA_TRUE; -} - -static void -_player_new_frame(Emotion_Generic_Video *ev) -{ - if (!ev->file_ready) - return; - _emotion_frame_new(ev->obj); -} - -static void -_file_open(Emotion_Generic_Video *ev) -{ - INF("Opening file: %s", ev->filename); - ev->drop = 0; - - if (!ev->ready || !ev->filename) - return; - _player_send_cmd(ev, EM_CMD_FILE_SET); - _player_send_str(ev, ev->filename, EINA_TRUE); -} - -static void -_player_file_set_done(Emotion_Generic_Video *ev) -{ - if (ev->file_changed) - { - _file_open(ev); - ev->file_changed = EINA_FALSE; - return; - } - - if (!_create_shm_data(ev, ev->shmname)) - { - ERR("could not create shared memory."); - return; - } - _player_send_cmd(ev, EM_CMD_FILE_SET_DONE); -} - -static void -_player_ready(Emotion_Generic_Video *ev) -{ - INF("received: player ready."); - - ev->initializing = EINA_FALSE; - ev->ready = EINA_TRUE; - - if (!ev->filename) - return; - - _file_open(ev); -} - -static Eina_Bool -_player_cmd_param_read(Emotion_Generic_Video *ev, void *param, size_t size) -{ - ssize_t done, todo, i; - - /* When a parameter must be read, we cannot make sure it will be entirely - * available. Thus we store the bytes that could be read in a temp buffer, - * and when more data is read we try to complete the buffer and finally use - * the read value. - */ - if (!ev->cmd.tmp) - { - ev->cmd.tmp = malloc(size); - ev->cmd.i = 0; - ev->cmd.total = size; - } - - todo = ev->cmd.total - ev->cmd.i; - i = ev->cmd.i; - - done = (ev->offset + todo > ev->length) ? ev->length - ev->offset : todo; - memcpy(&ev->cmd.tmp[i], &ev->buffer[ev->offset], done); - ev->offset += done; - - if (done == todo) - { - memcpy(param, ev->cmd.tmp, size); - free(ev->cmd.tmp); - ev->cmd.tmp = NULL; - return EINA_TRUE; - } - - if (done > 0) - ev->cmd.i += done; - - return EINA_FALSE; -} - -static void -_player_frame_resize(Emotion_Generic_Video *ev) -{ - int w, h; - - w = ev->cmd.param.size.width; - h = ev->cmd.param.size.height; - - INF("received frame resize: %dx%d", w, h); - ev->w = w; - ev->h = h; - ev->ratio = (float)w / h; - - _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio); -} - -static void -_player_length_changed(Emotion_Generic_Video *ev) -{ - float length = ev->cmd.param.f_num; - - INF("received length changed: %0.3f", length); - - ev->len = length; - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); -} - -static void -_player_position_changed(Emotion_Generic_Video *ev) -{ - float position = ev->cmd.param.f_num; - - // INF("received position changed: %0.3f", position); - - ev->pos = position; - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); -/* hmmm. no _emotion_progress_set() is for "buffering" progress. - if (ev->len == 0) - return; - - float progress = ev->pos / ev->len; - char buf[16]; - snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100); - - _emotion_progress_set(ev->obj, buf, progress); - */ -} - -static void -_player_seekable_changed(Emotion_Generic_Video *ev) -{ - int seekable = ev->cmd.param.i_num; - - INF("received seekable changed: %d", seekable); - - seekable = !!seekable; - - ev->seekable = seekable; -} - -static void -_audio_channels_free(Emotion_Generic_Video *ev) -{ - int i; - for (i = 0; i < ev->audio_channels_count; i++) - eina_stringshare_del(ev->audio_channels[i].name); - free(ev->audio_channels); - ev->audio_channels = NULL; - ev->audio_channels_count = 0; -} - -static void -_video_channels_free(Emotion_Generic_Video *ev) -{ - int i; - for (i = 0; i < ev->video_channels_count; i++) - eina_stringshare_del(ev->video_channels[i].name); - free(ev->video_channels); - ev->video_channels = NULL; - ev->video_channels_count = 0; -} - -static void -_spu_channels_free(Emotion_Generic_Video *ev) -{ - int i; - for (i = 0; i < ev->spu_channels_count; i++) - eina_stringshare_del(ev->spu_channels[i].name); - free(ev->spu_channels); - ev->spu_channels = NULL; - ev->spu_channels_count = 0; -} - -static void -_player_tracks_info(Emotion_Generic_Video *ev, Emotion_Generic_Channel **channels, int *count, int *current) -{ - Emotion_Generic_Channel *pchannels; - int i; - - *count = ev->cmd.param.track.total; - *current = ev->cmd.param.track.current; - pchannels = ev->cmd.param.track.channels; - - INF("number of tracks: %d (current = %d):", *count, *current); - for (i = 0; i < *count; i++) - { - INF("\tchannel %d: %s", pchannels[i].id, pchannels[i].name); - } - - *channels = pchannels; -} - -static void -_player_audio_tracks_info(Emotion_Generic_Video *ev) -{ - INF("Receiving audio channels:"); - if (ev->audio_channels_count) - _audio_channels_free(ev); - - _player_tracks_info(ev, &ev->audio_channels, &ev->audio_channels_count, - &ev->audio_channel_current); -} - -static void -_player_video_tracks_info(Emotion_Generic_Video *ev) -{ - INF("Receiving video channels:"); - if (ev->video_channels_count) - _video_channels_free(ev); - - _player_tracks_info(ev, &ev->video_channels, &ev->video_channels_count, - &ev->video_channel_current); -} - -static void -_player_spu_tracks_info(Emotion_Generic_Video *ev) -{ - INF("Receiving spu channels:"); - if (ev->spu_channels_count) - _spu_channels_free(ev); - - _player_tracks_info(ev, &ev->spu_channels, &ev->spu_channels_count, - &ev->spu_channel_current); -} - -static void -_player_meta_info_free(Emotion_Generic_Video *ev) -{ - eina_stringshare_replace(&ev->meta.title, NULL); - eina_stringshare_replace(&ev->meta.artist, NULL); - eina_stringshare_replace(&ev->meta.album, NULL); - eina_stringshare_replace(&ev->meta.year, NULL); - eina_stringshare_replace(&ev->meta.genre, NULL); - eina_stringshare_replace(&ev->meta.comment, NULL); - eina_stringshare_replace(&ev->meta.disc_id, NULL); - eina_stringshare_replace(&ev->meta.count, NULL); -} - -static void -_player_meta_info_read(Emotion_Generic_Video *ev) -{ - INF("Receiving meta info:"); - _player_meta_info_free(ev); - ev->meta.title = ev->cmd.param.meta.title; - ev->meta.artist = ev->cmd.param.meta.artist; - ev->meta.album = ev->cmd.param.meta.album; - ev->meta.year = ev->cmd.param.meta.year; - ev->meta.genre = ev->cmd.param.meta.genre; - ev->meta.comment = ev->cmd.param.meta.comment; - ev->meta.disc_id = ev->cmd.param.meta.disc_id; - ev->meta.count = ev->cmd.param.meta.count; - INF("title: '%s'", ev->meta.title); - INF("artist: '%s'", ev->meta.artist); - INF("album: '%s'", ev->meta.album); - INF("year: '%s'", ev->meta.year); - INF("genre: '%s'", ev->meta.genre); - INF("comment: '%s'", ev->meta.comment); - INF("disc_id: '%s'", ev->meta.disc_id); - INF("count: '%s'", ev->meta.count); -} - -static void -_player_file_closed(Emotion_Generic_Video *ev) -{ - INF("Closed previous file."); - eina_semaphore_free(&ev->shared->lock); - ev->closing = EINA_FALSE; - - if (ev->opening) - _file_open(ev); -} - -static void -_player_open_done(Emotion_Generic_Video *ev) -{ - int success; - - success = ev->cmd.param.i_num; - shm_unlink(ev->shmname); - - if (ev->file_changed) - { - _file_open(ev); - ev->file_changed = EINA_FALSE; - return; - } - - ev->opening = EINA_FALSE; - if (!success) - { - ERR("Could not open file."); - return; - } - - ev->file_ready = EINA_TRUE; - - _emotion_open_done(ev->obj); - - _player_send_cmd(ev, EM_CMD_VOLUME_SET); - _player_send_float(ev, ev->volume); - - _player_send_cmd(ev, EM_CMD_SPEED_SET); - _player_send_float(ev, ev->speed); - - int mute = ev->audio_mute; - _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET); - _player_send_int(ev, mute); - - mute = ev->video_mute; - _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET); - _player_send_int(ev, mute); - - mute = ev->spu_mute; - _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET); - _player_send_int(ev, mute); - - if (ev->play) - { - _player_send_cmd(ev, EM_CMD_PLAY); - _player_send_float(ev, ev->pos); - } - - INF("Open done"); -} - -static void -_player_cmd_process(Emotion_Generic_Video *ev) -{ - switch (ev->cmd.type) { - case EM_RESULT_INIT: - _player_ready(ev); - break; - case EM_RESULT_FRAME_NEW: - _player_new_frame(ev); - break; - case EM_RESULT_FILE_SET: - _player_file_set_done(ev); - break; - case EM_RESULT_FILE_SET_DONE: - _player_open_done(ev); - break; - case EM_RESULT_FILE_CLOSE: - _player_file_closed(ev); - break; - case EM_RESULT_PLAYBACK_STARTED: - _emotion_playback_started(ev->obj); - break; - case EM_RESULT_PLAYBACK_STOPPED: - ev->play = 0; - _emotion_playback_finished(ev->obj); - _emotion_decode_stop(ev->obj); - break; - case EM_RESULT_FRAME_SIZE: - _player_frame_resize(ev); - break; - case EM_RESULT_LENGTH_CHANGED: - _player_length_changed(ev); - break; - case EM_RESULT_POSITION_CHANGED: - _player_position_changed(ev); - break; - case EM_RESULT_SEEKABLE_CHANGED: - _player_seekable_changed(ev); - break; - case EM_RESULT_AUDIO_TRACK_INFO: - _player_audio_tracks_info(ev); - break; - case EM_RESULT_VIDEO_TRACK_INFO: - _player_video_tracks_info(ev); - break; - case EM_RESULT_SPU_TRACK_INFO: - _player_spu_tracks_info(ev); - break; - case EM_RESULT_META_INFO: - _player_meta_info_read(ev); - break; - default: - WRN("received wrong command: %d", ev->cmd.type); - } - - ev->cmd.type = -1; -} - -static void -_player_cmd_single_int_process(Emotion_Generic_Video *ev) -{ - if (!_player_cmd_param_read(ev, &ev->cmd.param.i_num, sizeof(ev->cmd.param.i_num))) - return; - - _player_cmd_process(ev); -} - -static void -_player_cmd_single_float_process(Emotion_Generic_Video *ev) -{ - if (!_player_cmd_param_read(ev, &ev->cmd.param.f_num, sizeof(ev->cmd.param.f_num))) - return; - - _player_cmd_process(ev); -} - -static void -_player_cmd_double_int_process(Emotion_Generic_Video *ev) -{ - int param; - - if (ev->cmd.num_params == 0) - { - ev->cmd.num_params = 2; - ev->cmd.cur_param = 0; - ev->cmd.param.size.width = 0; - ev->cmd.param.size.height = 0; - } - - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - - if (ev->cmd.cur_param == 0) - ev->cmd.param.size.width = param; - else - ev->cmd.param.size.height = param; - - ev->cmd.cur_param++; - if (ev->cmd.cur_param == ev->cmd.num_params) - _player_cmd_process(ev); -} - -static void -_player_cmd_track_info(Emotion_Generic_Video *ev) -{ - int param; - int i; - - if (ev->cmd.num_params == 0) - { - ev->cmd.cur_param = 0; - ev->cmd.num_params = 2; - ev->cmd.param.track.channels = NULL; - ev->cmd.s_len = -1; - } - - while (ev->cmd.cur_param < 2) - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - - if (ev->cmd.cur_param == 0) - ev->cmd.param.track.current = param; - else - { - ev->cmd.param.track.total = param; - ev->cmd.num_params += param * 2; - ev->cmd.param.track.channels = - calloc(param, sizeof(*ev->cmd.param.track.channels)); - } - ev->cmd.cur_param++; - } - - if (ev->cmd.cur_param == ev->cmd.num_params) - { - _player_cmd_process(ev); - return; - } - - i = (ev->cmd.cur_param - 2) / 2; - if ((ev->cmd.cur_param % 2) == 0) // reading track id - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - ev->cmd.param.track.channels[i].id = param; - ev->cmd.cur_param++; - } - else // reading track name - { - char buf[PATH_MAX]; - - if (ev->cmd.s_len == -1) - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - ev->cmd.s_len = param; - } - - if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len)) - return; - ev->cmd.param.track.channels[i].name = - eina_stringshare_add_length(buf, ev->cmd.s_len); - ev->cmd.cur_param++; - ev->cmd.s_len = -1; - } - - if (ev->cmd.cur_param == ev->cmd.num_params) - _player_cmd_process(ev); -} - -static void -_player_cmd_meta_info(Emotion_Generic_Video *ev) -{ - int param; - const char *info; - char buf[PATH_MAX]; - - if (ev->cmd.num_params == 0) - { - ev->cmd.cur_param = 0; - ev->cmd.num_params = 8; - ev->cmd.param.meta.title = NULL; - ev->cmd.param.meta.artist = NULL; - ev->cmd.param.meta.album = NULL; - ev->cmd.param.meta.year = NULL; - ev->cmd.param.meta.genre = NULL; - ev->cmd.param.meta.comment = NULL; - ev->cmd.param.meta.disc_id = NULL; - ev->cmd.param.meta.count = NULL; - ev->cmd.s_len = -1; - } - - if (ev->cmd.s_len == -1) - { - if (!_player_cmd_param_read(ev, ¶m, sizeof(param))) - return; - ev->cmd.s_len = param; - } - - if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len)) - return; - - info = eina_stringshare_add_length(buf, ev->cmd.s_len); - ev->cmd.s_len = -1; - - if (ev->cmd.cur_param == 0) - ev->cmd.param.meta.title = info; - else if (ev->cmd.cur_param == 1) - ev->cmd.param.meta.artist = info; - else if (ev->cmd.cur_param == 2) - ev->cmd.param.meta.album = info; - else if (ev->cmd.cur_param == 3) - ev->cmd.param.meta.year = info; - else if (ev->cmd.cur_param == 4) - ev->cmd.param.meta.genre = info; - else if (ev->cmd.cur_param == 5) - ev->cmd.param.meta.comment = info; - else if (ev->cmd.cur_param == 6) - ev->cmd.param.meta.disc_id = info; - else if (ev->cmd.cur_param == 7) - ev->cmd.param.meta.count = info; - - ev->cmd.cur_param++; - - if (ev->cmd.cur_param == 8) - _player_cmd_process(ev); -} - -static void -_player_cmd_read(Emotion_Generic_Video *ev) -{ - if (ev->cmd.type < 0) - { - if (!_player_cmd_param_read(ev, &ev->cmd.type, sizeof(ev->cmd.type))) - return; - ev->cmd.num_params = 0; - } - - switch (ev->cmd.type) { - case EM_RESULT_INIT: - case EM_RESULT_FILE_SET: - case EM_RESULT_PLAYBACK_STARTED: - case EM_RESULT_PLAYBACK_STOPPED: - case EM_RESULT_FILE_CLOSE: - case EM_RESULT_FRAME_NEW: - _player_cmd_process(ev); - break; - case EM_RESULT_FILE_SET_DONE: - case EM_RESULT_SEEKABLE_CHANGED: - _player_cmd_single_int_process(ev); - break; - case EM_RESULT_LENGTH_CHANGED: - case EM_RESULT_POSITION_CHANGED: - _player_cmd_single_float_process(ev); - break; - case EM_RESULT_FRAME_SIZE: - _player_cmd_double_int_process(ev); - break; - case EM_RESULT_AUDIO_TRACK_INFO: - case EM_RESULT_VIDEO_TRACK_INFO: - case EM_RESULT_SPU_TRACK_INFO: - _player_cmd_track_info(ev); - break; - case EM_RESULT_META_INFO: - _player_cmd_meta_info(ev); - break; - - default: - WRN("received wrong command: %d", ev->cmd.type); - ev->cmd.type = -1; - } -} - -static void -_player_cmd_handler_cb(void *data, void *buffer, unsigned int nbyte) -{ - Emotion_Generic_Video *ev = data; - - ev->buffer = buffer; - ev->length = nbyte; - ev->offset = 0; - - _player_cmd_read(ev); - - ev->buffer = NULL; - ev->length = 0; -} - -static Eina_Bool -_player_data_cb(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Exe_Event_Data *ev = event; - Emotion_Generic_Video *evideo = data; - int i; - - if (ev->exe != evideo->player.exe) - { - INF("slave != ev->exe"); - return ECORE_CALLBACK_PASS_ON; - } - - for (i = 0; ev->lines[i].line; i++) - INF("received input from player: \"%s\"", ev->lines[i].line); - - return ECORE_CALLBACK_DONE; -} - -static Eina_Bool -_player_add_cb(void *data, int type EINA_UNUSED, void *event) -{ - Ecore_Exe_Event_Add *event_add = event; - Ecore_Exe *player = event_add->exe; - Emotion_Generic_Video *ev = data; - - if (ev->player.exe != player) - { - INF("ev->player != player."); - return ECORE_CALLBACK_PASS_ON; - } - - _player_send_cmd(ev, EM_CMD_INIT); - _player_send_str(ev, ev->shmname, EINA_TRUE); - - return ECORE_CALLBACK_DONE; -} - -static Eina_Bool -_player_del_cb(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) -{ - Ecore_Exe_Event_Del *event_del = event; - Ecore_Exe *player = event_del->exe; - Emotion_Generic_Video *ev = data; - - if (ev->player.exe != player) - { - INF("ev->player != player."); - return ECORE_CALLBACK_PASS_ON; - } - - ERR("player died."); - - ev->player.exe = NULL; - ev->ready = EINA_FALSE; - ev->file_ready = EINA_FALSE; - ecore_pipe_del(ev->fd_read); - ecore_pipe_del(ev->fd_write); - ev->fd_read = NULL; - ev->fd_write = NULL; - _emotion_decode_stop(ev->obj); - - return ECORE_CALLBACK_DONE; -} - -static void -_player_dummy(void *data EINA_UNUSED, - void *buffer EINA_UNUSED, - unsigned int nbyte EINA_UNUSED) -{ -} - -static Eina_Bool -_player_exec(Emotion_Generic_Video *ev) -{ - Ecore_Pipe *in; - Ecore_Pipe *out; - char buf[PATH_MAX]; - - out = ecore_pipe_full_add(_player_dummy, NULL, -1, -1, EINA_TRUE, EINA_FALSE); - if (!out) - { - ERR("could not create pipe for communication emotion -> player: %s", strerror(errno)); - return EINA_FALSE; - } - - in = ecore_pipe_full_add(_player_cmd_handler_cb, ev, -1, -1, EINA_FALSE, EINA_TRUE); - if (!in) - { - ERR("could not create pipe for communication player -> emotion: %s", strerror(errno)); - ecore_pipe_del(in); - ecore_pipe_del(out); - return EINA_FALSE; - } - - snprintf(buf, sizeof(buf), "%s %d %d", ev->engine->path, - ecore_pipe_read_fd(out), - ecore_pipe_write_fd(in)); - - ev->player.exe = ecore_exe_pipe_run( - buf, ECORE_EXE_NOT_LEADER | ECORE_EXE_TERM_WITH_PARENT, ev); - - INF("created pipe emotion -> player: %d -> %d", - ecore_pipe_write_fd(out), ecore_pipe_read_fd(out)); - INF("created pipe player -> emotion: %d -> %d", - ecore_pipe_write_fd(in), ecore_pipe_read_fd(in)); - - ecore_pipe_write_close(in); - ecore_pipe_read_close(out); - - if (!ev->player.exe) - { - ecore_pipe_del(in); - ecore_pipe_del(out); - return EINA_FALSE; - } - - ev->fd_read = in; - ev->fd_write = out; - - return EINA_TRUE; -} - -static Eina_Bool -_fork_and_exec(Emotion_Generic_Video *ev) -{ - char shmname[256]; - - snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%p_%f", - getpid(), ev->obj, ecore_time_get()); - - ev->shmname = eina_stringshare_add(shmname); - - ev->player_add = ecore_event_handler_add(ECORE_EXE_EVENT_ADD, - _player_add_cb, ev); - ev->player_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, - _player_del_cb, ev); - ev->player_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA, - _player_data_cb, ev); - - if (!_player_exec(ev)) - { - eina_stringshare_del(ev->shmname); - ecore_event_handler_del(ev->player_add); - ecore_event_handler_del(ev->player_del); - ecore_event_handler_del(ev->player_data); - ERR("could not start player."); - return EINA_FALSE; - } - - ev->initializing = EINA_TRUE; - - return EINA_TRUE; -} - -typedef struct _Delay_Munmap Delay_Munmap; -struct _Delay_Munmap -{ - void *map; - size_t size; -}; - -static void -_delayed_munmap(void *data, Evas *e, void *event_info EINA_UNUSED) -{ - Delay_Munmap *dm = data; - - evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_POST, _delayed_munmap, data); - fprintf(stderr, "munmapping !\n"); - munmap(dm->map, dm->size); - free(dm); -} - -static void -_delayed_next_frame(void *data, Evas *e, void *event_info EINA_UNUSED) -{ - evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, _delayed_munmap, data); - evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_PRE, _delayed_next_frame, data); -} - -static void -em_partial_shutdown(Emotion_Generic_Video *ev) -{ - if (ev->player.exe) - { - ecore_exe_terminate(ev->player.exe); - ecore_exe_free(ev->player.exe); - ev->player.exe = NULL; - } - - ev->file_ready = EINA_FALSE; - - if (ev->shared) - { - Evas_Object *o; - Delay_Munmap *dm; - - dm = malloc(sizeof (Delay_Munmap)); - if (dm) - { - dm->map = ev->shared; - dm->size = ev->shared->size; - evas_event_callback_add(evas_object_evas_get(ev->obj), - EVAS_CALLBACK_RENDER_PRE, - _delayed_next_frame, dm); - } - - o = emotion_object_image_get(ev->obj); - evas_object_image_data_set(o, NULL); - evas_object_image_size_set(o, 1, 1); - } - ev->shared = NULL; - - _emotion_image_reset(ev->obj); - - if (ev->fd_read) - ecore_pipe_del(ev->fd_read); - ev->fd_read = NULL; - if (ev->fd_write) - ecore_pipe_del(ev->fd_write); - ev->fd_write = NULL; - - if (ev->player_add) ecore_event_handler_del(ev->player_add); - ev->player_add = NULL; - if (ev->player_data) ecore_event_handler_del(ev->player_data); - ev->player_data = NULL; - if (ev->player_del) ecore_event_handler_del(ev->player_del); - ev->player_del = NULL; -} - - -/* Emotion interface */ -static void * -em_add(const Emotion_Engine *api, Evas_Object *obj, const Emotion_Module_Options *opt EINA_UNUSED) -{ - Emotion_Generic_Video *ev; - - ev = calloc(1, sizeof(*ev)); - EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); - - ev->fd_read = NULL; - ev->fd_write = NULL; - ev->speed = 1.0; - ev->volume = 0.8; - ev->audio_mute = EINA_FALSE; - ev->cmd.type = -1; - - ev->obj = obj; - ev->engine = (Emotion_Engine_Generic *)api; - - if (!_fork_and_exec(ev)) - { - free(ev); - return NULL; - } - - return ev; -} - -static void -em_del(void *data) -{ - Emotion_Generic_Video *ev = data; - - eina_stringshare_del(ev->shmname); - - em_partial_shutdown(ev); -} - -static unsigned char -em_file_open(void *data, const char *file) -{ - Emotion_Generic_Video *ev = data; - INF("file set: %s", file); - if (!ev) return 0; - - eina_stringshare_replace(&ev->filename, file); - - ev->pos = 0; - ev->w = 0; - ev->h = 0; - ev->ratio = 1; - ev->len = 0; - - if (ev->ready && ev->opening) - { - INF("file changed while opening."); - ev->file_changed = EINA_TRUE; - return 1; - } - - ev->opening = EINA_TRUE; - - if (!ev->closing) - _file_open(ev); - - return 1; -} - -static void -em_file_close(void *data) -{ - Emotion_Generic_Video *ev = data; - - if (!ev || !ev->filename) return; - - INF("file close: %s", ev->filename); - - eina_stringshare_replace(&ev->filename, NULL); - eina_stringshare_replace(&ev->subtitle_path, NULL); - - ev->file_ready = EINA_FALSE; - _audio_channels_free(ev); - _video_channels_free(ev); - _spu_channels_free(ev); - _player_meta_info_free(ev); - - if (ev->opening) - return; - - _player_send_cmd(ev, EM_CMD_FILE_CLOSE); - ev->closing = EINA_TRUE; -} - -static Emotion_Format -em_format_get(void *ef EINA_UNUSED) -{ - return EMOTION_FORMAT_BGRA; -} - -static void -em_video_data_size_get(void *data, int *w, int *h) -{ - Emotion_Generic_Video *ev = data; - - if (!ev) return; - if (w) *w = ev->w; - if (h) *h = ev->h; -} - -static void -em_play(void *data, double pos) -{ - Emotion_Generic_Video *ev = data; - - if (!ev) - return; - - ev->play = EINA_TRUE; - INF("play: %0.3f", pos); - - if (ev->initializing || ev->opening) - return; - - if (ev->ready) - { - if (ev->subtitle_path) - { - _player_send_cmd(ev, EM_CMD_SUBTITLE_SET); - _player_send_str(ev, ev->subtitle_path, EINA_TRUE); - } - - _player_send_cmd(ev, EM_CMD_PLAY); - _player_send_float(ev, ev->pos); - - return; - } - - if (!_player_exec(ev)) - ERR("could not start player."); -} - -static void -em_stop(void *data) -{ - Emotion_Generic_Video *ev = data; - - if (!ev) - return; - - ev->play = EINA_FALSE; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_STOP); - _emotion_decode_stop(ev->obj); -} - -static void -em_size_get(void *data, int *w, int *h) -{ - Emotion_Generic_Video *ev = data; - if (w) *w = ev->w; - if (h) *h = ev->h; -} - -static void -em_pos_set(void *data, double pos) -{ - Emotion_Generic_Video *ev = data; - float position = pos; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_POSITION_SET); - _player_send_float(ev, position); - _emotion_seek_done(ev->obj); -} - -static double -em_len_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->len; -} - -static double -em_buffer_size_get(void *data EINA_UNUSED) -{ - return 1.0; -} - -static int -em_fps_num_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return (int)(ev->fps * 1000.0); -} - -static int -em_fps_den_get(void *ef EINA_UNUSED) -{ - return 1000; -} - -static double -em_fps_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->fps; -} - -static double -em_pos_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->pos; -} - -static void -em_vis_set(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED) -{ -} - -static Emotion_Vis -em_vis_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->vis; -} - -static Eina_Bool -em_vis_supported(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED) -{ - return EINA_FALSE; -} - -static double -em_ratio_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->ratio; -} - -static int -em_video_handled(void *ef EINA_UNUSED) -{ - DBG("video handled!"); - return 1; -} - -static int -em_audio_handled(void *ef EINA_UNUSED) -{ - DBG("audio handled!"); - return 1; -} - -static int -em_seekable(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->seekable; -} - -static void -em_frame_done(void *ef EINA_UNUSED) -{ -} - -static int -em_yuv_rows_get(void *data EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, unsigned char **yrows EINA_UNUSED, unsigned char **urows EINA_UNUSED, unsigned char **vrows EINA_UNUSED) -{ - return 0; -} - -static int -em_bgra_data_get(void *data, unsigned char **bgra_data) -{ - Emotion_Generic_Video *ev = data; - - if (!ev || !ev->file_ready) - return 0; - - // lock frame here - if (!eina_semaphore_lock(&ev->shared->lock)) - return 0; - - // send current frame to emotion - if (ev->shared->frame.emotion != ev->shared->frame.last) - { - ev->shared->frame.next = ev->shared->frame.emotion; - ev->shared->frame.emotion = ev->shared->frame.last; - } - *bgra_data = ev->frame.frames[ev->shared->frame.emotion]; - - if (ev->shared->frame_drop > 1) - WRN("dropped frames: %d", ev->shared->frame_drop - 1); - ev->shared->frame_drop = 0; - - // unlock frame here - eina_semaphore_release(&ev->shared->lock, 1); - ev->drop = 0; - - return 1; -} - -static void -em_event_feed(void *ef EINA_UNUSED, int event EINA_UNUSED) -{ -} - -static void -em_event_mouse_button_feed(void *ef EINA_UNUSED, int button EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ -} - -static void -em_event_mouse_move_feed(void *ef EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ -} - -static int -em_video_channel_count(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->video_channels_count; -} - -static void -em_video_channel_set(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->video_channels_count) - { - WRN("video channel out of range."); - return; - } - - _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET); - _player_send_int(ev, ev->video_channels[channel].id); - ev->video_channel_current = channel; -} - -static int -em_video_channel_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->video_channel_current; -} - -static void -em_video_subtitle_file_set(void *data, const char *filepath) -{ - Emotion_Generic_Video *ev = data; - eina_stringshare_replace(&ev->subtitle_path, filepath); -} - -static const char * -em_video_subtitle_file_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->subtitle_path; -} - -static const char * -em_video_channel_name_get(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->video_channels_count) - { - WRN("video channel out of range."); - return NULL; - } - - return ev->video_channels[channel].name; -} - -static void -em_video_channel_mute_set(void *data, int mute) -{ - Emotion_Generic_Video *ev = data; - - ev->video_mute = !!mute; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET); - _player_send_int(ev, mute); -} - -static int -em_video_channel_mute_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->video_mute; -} - -static int -em_audio_channel_count(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->audio_channels_count; -} - -static void -em_audio_channel_set(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->audio_channels_count) - { - WRN("audio channel out of range."); - return; - } - - _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET); - _player_send_int(ev, ev->audio_channels[channel].id); - ev->audio_channel_current = channel; -} - -static int -em_audio_channel_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->audio_channel_current; -} - -static const char * -em_audio_channel_name_get(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->audio_channels_count) - { - WRN("audio channel out of range."); - return NULL; - } - - return ev->audio_channels[channel].name; -} - -static void -em_audio_channel_mute_set(void *data, int mute) -{ - Emotion_Generic_Video *ev = data; - - ev->audio_mute = !!mute; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET); - _player_send_int(ev, mute); -} - -static int -em_audio_channel_mute_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->audio_mute; -} - -static void -em_audio_channel_volume_set(void *data, double vol) -{ - Emotion_Generic_Video *ev = data; - - if (vol > 1.0) vol = 1.0; - if (vol < 0.0) vol = 0.0; - - ev->volume = vol; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_VOLUME_SET); - _player_send_float(ev, ev->volume); -} - -static double -em_audio_channel_volume_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->volume; -} - -static int -em_spu_channel_count(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->spu_channels_count; -} - -static void -em_spu_channel_set(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->spu_channels_count) - { - WRN("spu channel out of range."); - return; - } - - _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET); - _player_send_int(ev, ev->spu_channels[channel].id); - ev->spu_channel_current = channel; -} - -static int -em_spu_channel_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->spu_channel_current; -} - -static const char * -em_spu_channel_name_get(void *data, int channel) -{ - Emotion_Generic_Video *ev = data; - - if (channel < 0 || channel >= ev->spu_channels_count) - { - WRN("spu channel out of range."); - return NULL; - } - - return ev->spu_channels[channel].name; -} - -static void -em_spu_channel_mute_set(void *data, int mute) -{ - Emotion_Generic_Video *ev = data; - - ev->spu_mute = !!mute; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET); - _player_send_int(ev, mute); -} - -static int -em_spu_channel_mute_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return ev->spu_mute; -} - -static int -em_chapter_count(void *ef EINA_UNUSED) -{ - int num = 0; - return num; -} - -static void -em_chapter_set(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ -} - -static int -em_chapter_get(void *ef EINA_UNUSED) -{ - int num = 0; - return num; -} - -static const char * -em_chapter_name_get(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ - return NULL; -} - -static void -em_speed_set(void *data, double speed) -{ - Emotion_Generic_Video *ev = data; - float rate = speed; - ev->speed = rate; - - if (!ev->file_ready) - return; - - _player_send_cmd(ev, EM_CMD_SPEED_SET); - _player_send_float(ev, rate); -} - -static double -em_speed_get(void *data) -{ - Emotion_Generic_Video *ev = data; - return (double)ev->speed; -} - -static int -em_eject(void *ef EINA_UNUSED) -{ - return 1; -} - -static const char * -em_meta_get(void *data, int meta) -{ - Emotion_Generic_Video *ev = data; - - switch (meta) - { - case EMOTION_META_INFO_TRACK_TITLE: - return ev->meta.title; - case EMOTION_META_INFO_TRACK_ARTIST: - return ev->meta.artist; - case EMOTION_META_INFO_TRACK_ALBUM: - return ev->meta.album; - case EMOTION_META_INFO_TRACK_YEAR: - return ev->meta.year; - case EMOTION_META_INFO_TRACK_GENRE: - return ev->meta.genre; - case EMOTION_META_INFO_TRACK_COMMENT: - return ev->meta.comment; - case EMOTION_META_INFO_TRACK_DISC_ID: - return ev->meta.disc_id; - case EMOTION_META_INFO_TRACK_COUNT: - return ev->meta.count; - } - - return NULL; -} - - -/* Players/modules */ -static const Emotion_Engine em_template_engine = -{ - EMOTION_ENGINE_API_VERSION, - EMOTION_ENGINE_PRIORITY_DEFAULT, - "generic", - em_add, /* add */ - em_del, /* del */ - em_file_open, /* file_open */ - em_file_close, /* file_close */ - em_play, /* play */ - em_stop, /* stop */ - em_size_get, /* size_get */ - em_pos_set, /* pos_set */ - em_len_get, /* len_get */ - em_buffer_size_get, /* buffer_size_get */ - em_fps_num_get, /* fps_num_get */ - em_fps_den_get, /* fps_den_get */ - em_fps_get, /* fps_get */ - em_pos_get, /* pos_get */ - em_vis_set, /* vis_set */ - em_vis_get, /* vis_get */ - em_vis_supported, /* vis_supported */ - em_ratio_get, /* ratio_get */ - em_video_handled, /* video_handled */ - em_audio_handled, /* audio_handled */ - em_seekable, /* seekable */ - em_frame_done, /* frame_done */ - em_format_get, /* format_get */ - em_video_data_size_get, /* video_data_size_get */ - em_yuv_rows_get, /* yuv_rows_get */ - em_bgra_data_get, /* bgra_data_get */ - em_event_feed, /* event_feed */ - em_event_mouse_button_feed, /* event_mouse_button_feed */ - em_event_mouse_move_feed, /* event_mouse_move_feed */ - em_video_channel_count, /* video_channel_count */ - em_video_channel_set, /* video_channel_set */ - em_video_channel_get, /* video_channel_get */ - em_video_subtitle_file_set, /* video_subtitle_file_set */ - em_video_subtitle_file_get, /* video_subtitle_file_get */ - em_video_channel_name_get, /* video_channel_name_get */ - em_video_channel_mute_set, /* video_channel_mute_set */ - em_video_channel_mute_get, /* video_channel_mute_get */ - em_audio_channel_count, /* audio_channel_count */ - em_audio_channel_set, /* audio_channel_set */ - em_audio_channel_get, /* audio_channel_get */ - em_audio_channel_name_get, /* audio_channel_name_get */ - em_audio_channel_mute_set, /* audio_channel_mute_set */ - em_audio_channel_mute_get, /* audio_channel_mute_get */ - em_audio_channel_volume_set, /* audio_channel_volume_set */ - em_audio_channel_volume_get, /* audio_channel_volume_get */ - em_spu_channel_count, /* spu_channel_count */ - em_spu_channel_set, /* spu_channel_set */ - em_spu_channel_get, /* spu_channel_get */ - em_spu_channel_name_get, /* spu_channel_name_get */ - em_spu_channel_mute_set, /* spu_channel_mute_set */ - em_spu_channel_mute_get, /* spu_channel_mute_get */ - em_chapter_count, /* chapter_count */ - em_chapter_set, /* chapter_set */ - em_chapter_get, /* chapter_get */ - em_chapter_name_get, /* chapter_name_get */ - em_speed_set, /* speed_set */ - em_speed_get, /* speed_get */ - em_eject, /* eject */ - em_meta_get, /* meta_get */ - NULL, /* priority_set */ - NULL, /* priority_get */ - NULL /* em_meta_artwork_get */ -}; - -static void -_player_entry_add(const Eina_File_Direct_Info *info) -{ - Emotion_Engine_Generic *eg; - const char *name; - char *endptr; - int priority; - - name = info->path + info->name_start; - - priority = strtol(name, &endptr, 10); - if (endptr == name) - priority = EMOTION_ENGINE_PRIORITY_DEFAULT; - else - { - if ((*endptr == '-') || (*endptr == '_')) - endptr++; - name = endptr; - } - - if (*name == '\0') - { - ERR("Invalid generic player: %s", info->path); - return; - } - - eg = malloc(sizeof(Emotion_Engine_Generic)); - EINA_SAFETY_ON_NULL_RETURN(eg); - - /* inherit template */ - memcpy(&(eg->engine), &em_template_engine, sizeof(em_template_engine)); - - eg->path = strdup(info->path); - EINA_SAFETY_ON_NULL_GOTO(eg->path, error_path); - - eg->engine.name = strdup(name); - EINA_SAFETY_ON_NULL_GOTO(eg->engine.name, error_name); - - eg->engine.priority = priority; - - DBG("Add player name=%s, priority=%d, path=%s", - eg->engine.name, eg->engine.priority, eg->path); - _generic_players = eina_list_append(_generic_players, eg); - - return; - - error_name: - free(eg->path); - error_path: - free(eg); -} - -static void -_player_entry_free(Emotion_Engine_Generic *eg) -{ - free(eg->path); - free((void *)eg->engine.name); - free(eg); -} - -static void -_players_all_from(const char *path) -{ - const Eina_File_Direct_Info *info; - int count = 0; - Eina_Iterator *itr = eina_file_direct_ls(path); - if (!itr) goto end; - EINA_ITERATOR_FOREACH(itr, info) - { - if (access(info->path, R_OK | X_OK) == 0) - { - _player_entry_add(info); - count++; - } - } - eina_iterator_free(itr); - - end: - if (count == 0) - DBG("No generic players at %s", path); -} - -static void -_players_load(void) -{ - char buf[PATH_MAX]; - - eina_str_join(buf, sizeof(buf), '/', - eina_prefix_lib_get(pfx), - "emotion/generic_players/" MODULE_ARCH); - _players_all_from(buf); - - if (!_generic_players) - { - WRN("no generic players available"); - } - else - { - const Eina_List *n; - const Emotion_Engine_Generic *eg; - INF("Found %d generic players", eina_list_count(_generic_players)); - EINA_LIST_FOREACH(_generic_players, n, eg) - _emotion_module_register(&(eg->engine)); - } -} - -Eina_Bool -generic_module_init(void) -{ - if (_emotion_init_count > 0) - { - _emotion_init_count++; - return EINA_TRUE; - } - - _emotion_generic_log_domain = eina_log_domain_register("emotion_generic", - EINA_COLOR_LIGHTCYAN); - if (_emotion_generic_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion_generic'"); - return EINA_FALSE; - } - - pfx = eina_prefix_new(NULL, emotion_init, - "EMOTION", "emotion", "checkme", - PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, - PACKAGE_DATA_DIR, PACKAGE_DATA_DIR); - if (!pfx) - { - CRI("Could not get prefix for emotion"); - eina_log_domain_unregister(_emotion_generic_log_domain); - _emotion_generic_log_domain = -1; - return EINA_FALSE; - } - - _players_load(); - - _emotion_init_count = 1; - return EINA_TRUE; -} - -void -generic_module_shutdown(void) -{ - Emotion_Engine_Generic *eg; - - if (_emotion_init_count > 1) - { - _emotion_init_count--; - return; - } - else if (_emotion_init_count == 0) - { - EINA_LOG_ERR("too many generic_module_shutdown()"); - return; - } - _emotion_init_count = 0; - - EINA_LIST_FREE(_generic_players, eg) - { - _emotion_module_unregister(&(eg->engine)); - _player_entry_free(eg); - } - - eina_log_domain_unregister(_emotion_generic_log_domain); - _emotion_generic_log_domain = -1; - - eina_prefix_free(pfx); - pfx = NULL; -} - -#ifndef EMOTION_STATIC_BUILD_GENERIC - -EINA_MODULE_INIT(generic_module_init); -EINA_MODULE_SHUTDOWN(generic_module_shutdown); - -#endif diff --git a/src/modules/emotion/generic/emotion_generic.h b/src/modules/emotion/generic/emotion_generic.h deleted file mode 100644 index 2830d33d4a..0000000000 --- a/src/modules/emotion/generic/emotion_generic.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef EMOTION_GENERIC_H -#define EMOTION_GENERIC_H - -#include - -#include "Emotion_Generic_Plugin.h" - -/* default values */ - -typedef struct _Emotion_Generic_Video Emotion_Generic_Video; -typedef struct _Emotion_Generic_Player Emotion_Generic_Player; -typedef struct _Emotion_Generic_Cmd_Buffer Emotion_Generic_Cmd_Buffer; -typedef struct _Emotion_Generic_Channel Emotion_Generic_Channel; -typedef struct _Emotion_Generic_Meta Emotion_Generic_Meta; - -struct _Emotion_Generic_Player -{ - Ecore_Exe *exe; -}; - -struct _Emotion_Generic_Channel -{ - int id; - const char *name; -}; - -struct _Emotion_Generic_Meta -{ - const char *title; - const char *artist; - const char *album; - const char *year; - const char *genre; - const char *comment; - const char *disc_id; - const char *count; -}; - -struct _Emotion_Generic_Cmd_Buffer -{ - char *tmp; - int type; - ssize_t i, total; - int s_len; - int num_params, cur_param; - int padding; - union { - struct { - int width; - int height; - } size; - int i_num; - float f_num; - struct { - int total; - int current; - Emotion_Generic_Channel *channels; - } track; - Emotion_Generic_Meta meta; - } param; -}; - -typedef struct _Emotion_Engine_Generic -{ - Emotion_Engine engine; - char *path; -} Emotion_Engine_Generic; - -/* emotion/generic main structure */ -struct _Emotion_Generic_Video -{ - const Emotion_Engine_Generic *engine; - const char *shmname; - - Emotion_Generic_Player player; - Emotion_Generic_Cmd_Buffer cmd; - Ecore_Event_Handler *player_add, *player_del, *player_data; - int drop; - Ecore_Pipe *fd_read; - Ecore_Pipe *fd_write; - const unsigned char *buffer; - ssize_t length; - ssize_t offset; - - const char *filename; - volatile double len; - volatile double pos; - double fps; - double ratio; - int w, h; - Evas_Object *obj; - Emotion_Generic_Video_Shared *shared; - Emotion_Generic_Video_Frame frame; - volatile int fq; - float volume; - float speed; - Emotion_Vis vis; - Eina_Bool initializing : 1; - Eina_Bool ready : 1; - Eina_Bool play : 1; - Eina_Bool video_mute : 1; - Eina_Bool audio_mute : 1; - Eina_Bool spu_mute : 1; - Eina_Bool seekable : 1; - volatile Eina_Bool opening : 1; - volatile Eina_Bool closing : 1; - Eina_Bool file_changed : 1; - Eina_Bool file_ready : 1; - int audio_channels_count; - int audio_channel_current; - Emotion_Generic_Channel *audio_channels; - int video_channels_count; - int video_channel_current; - Emotion_Generic_Channel *video_channels; - int spu_channels_count; - int spu_channel_current; - Emotion_Generic_Channel *spu_channels; - Emotion_Generic_Meta meta; - const char *subtitle_path; -}; - -#endif - diff --git a/src/modules/emotion/generic/meson.build b/src/modules/emotion/generic/meson.build deleted file mode 100644 index 4f62c7a43e..0000000000 --- a/src/modules/emotion/generic/meson.build +++ /dev/null @@ -1,24 +0,0 @@ -generic_src = files([ - 'emotion_generic.c', - 'emotion_generic.h', -]) - -emotion_generic = declare_dependency( - include_directories: include_directories('.'), - dependencies: emotion, -) - -if sys_windows == false - shared_module(emotion_loader, - generic_src, - include_directories : config_dir, - dependencies: [eina, evas, emotion, generic_deps, rt], - install: true, - install_dir : mod_install_dir, - c_args : package_c_args, - ) - - install_headers('Emotion_Generic_Plugin.h', - install_dir : dir_package_include, - ) -endif diff --git a/src/modules/emotion/libvlc/emotion_libvlc.c b/src/modules/emotion/libvlc/emotion_libvlc.c deleted file mode 100644 index 1e8f9d69b4..0000000000 --- a/src/modules/emotion/libvlc/emotion_libvlc.c +++ /dev/null @@ -1,1555 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include -#include -#include - -#include -#include -#include - -#include "emotion_modules.h" - -#ifdef DBG -#undef DBG -#endif -#define DBG(...) EINA_LOG_DOM_DBG(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef INF -#undef INF -#endif -#define INF(...) EINA_LOG_DOM_INFO(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef WRN -#undef WRN -#endif -#define WRN(...) EINA_LOG_DOM_WARN(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef ERR -#undef ERR -#endif -#define ERR(...) EINA_LOG_DOM_ERR(_emotion_libvlc_log_domain, __VA_ARGS__) - -#ifdef CRI -#undef CRI -#endif -#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_libvlc_log_domain, __VA_ARGS__) - -static int _emotion_libvlc_log_domain = -1; -static Eina_Bool debug_fps = EINA_FALSE; -static libvlc_instance_t *libvlc = NULL; - -typedef struct _Emotion_LibVLC Emotion_LibVLC; - -static void em_file_close(void *); - -struct _Emotion_LibVLC -{ - /* Evas object */ - Evas_Object *obj; - Evas_Object *evas_obj; - Emotion_Module_Options opt; - - /* libvlc */ - libvlc_media_t *m; - libvlc_media_player_t *mp; - unsigned int nb_tracks; - libvlc_media_track_t **tracks; - int nb_chapters; - libvlc_chapter_description_t **chapters; - char *subtitle_file; - char *metas[META_TRACK_COUNT]; - - /* options */ - int video_mute; - int video_mute_force; - int audio_mute; - int spu_mute; - int audio_vol; - Emotion_Vis vis; - - /* There can be remaining mainloop callbacks that owns the Emotion_LibVLC - * object when em_del is called. Use a ref_count to delete the ev object - * when em_del is called and when all callbacks are processed. */ - unsigned int ref_count; - - /* locks */ - Eina_Lock lock; - Eina_Condition wait; - Eina_List *event_list; - - /* stats */ - double pos; - double len; - double buffer_cache; - Eina_Bool seeking; - Eina_Bool started; - Eina_Bool invalidate_tracks; -}; - -struct close_data -{ - libvlc_media_player_t *mp; - Evas_Object *evas_obj; -}; - -static const libvlc_event_type_t mp_events[] = { - //libvlc_MediaPlayerMediaChanged, - //libvlc_MediaPlayerNothingSpecial, - //libvlc_MediaPlayerOpening, - libvlc_MediaPlayerBuffering, - libvlc_MediaPlayerPlaying, - //libvlc_MediaPlayerPaused, - libvlc_MediaPlayerStopped, - libvlc_MediaPlayerForward, - //libvlc_MediaPlayerBackward, - libvlc_MediaPlayerEndReached, - libvlc_MediaPlayerEncounteredError, - libvlc_MediaPlayerTimeChanged, - //libvlc_MediaPlayerPositionChanged, - //libvlc_MediaPlayerSeekableChanged, - //libvlc_MediaPlayerPausableChanged, - //libvlc_MediaPlayerTitleChanged, - //libvlc_MediaPlayerSnapshotTaken, - libvlc_MediaPlayerLengthChanged, - //libvlc_MediaPlayerVout, - //libvlc_MediaPlayerScrambledChanged, - libvlc_MediaPlayerESAdded, - libvlc_MediaPlayerESDeleted, - //libvlc_MediaPlayerESSelected, - //libvlc_MediaPlayerCorked, - //libvlc_MediaPlayerUncorked, - //libvlc_MediaPlayerMuted, - //libvlc_MediaPlayerUnmuted, - //libvlc_MediaPlayerAudioVolume, - //libvlc_MediaPlayerAudioDevice, - -1, -}; - -static void -em_del_safe(Emotion_LibVLC *ev) -{ - eina_lock_free(&ev->lock); - eina_condition_free(&ev->wait); - free(ev->subtitle_file); - free(ev); -} - -/* Take the ev->lock from a mainloop callback. - * Returns false if the ev object is destroyed. */ -static Eina_Bool -emotion_mainloop_lock(Emotion_LibVLC *ev) -{ - eina_lock_take(&ev->lock); - _emotion_pending_ecore_end(); - if (--ev->ref_count == 0) - { - eina_lock_release(&ev->lock); - WRN("callbacks ended, deleting Emotion_LibVLC"); - em_del_safe(ev); - return EINA_FALSE; - } - return EINA_TRUE; -} - -/* Send a callback to the mainloop */ -static void -emotion_mainloop_call_locked(Emotion_LibVLC *ev, Ecore_Cb callback) -{ - ++ev->ref_count; - _emotion_pending_ecore_begin(); - ecore_main_loop_thread_safe_call_async(callback, ev); -} - -/* Process one libvlc event from the mainloop. */ -static void -emotion_mainloop_event(Emotion_LibVLC *ev, const libvlc_event_t *event) -{ - switch (event->type) - { - case libvlc_MediaPlayerBuffering: - ev->buffer_cache = event->u.media_player_buffering.new_cache / 100.0; - break; - - case libvlc_MediaPlayerPlaying: - if (!ev->started) - { - _emotion_open_done(ev->obj); - _emotion_playback_started(ev->obj); - ev->started = EINA_TRUE; - } - break; - - case libvlc_MediaPlayerStopped: - case libvlc_MediaPlayerEndReached: - case libvlc_MediaPlayerEncounteredError: - _emotion_decode_stop(ev->obj); - _emotion_playback_finished(ev->obj); - break; - - case libvlc_MediaPlayerTimeChanged: - { - if (ev->seeking) - { - _emotion_seek_done(ev->obj); - ev->seeking = EINA_FALSE; - } - - ev->pos = event->u.media_player_time_changed.new_time / 1000.0; - if (ev->pos > 0 && ev->len > 0) - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - break; - } - - case libvlc_MediaPlayerLengthChanged: - ev->len = event->u.media_player_length_changed.new_length / 1000.0; - if (ev->pos > 0 && ev->len > 0) - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - break; - - case libvlc_MediaPlayerESAdded: - case libvlc_MediaPlayerESDeleted: - ev->invalidate_tracks = EINA_TRUE; - _emotion_channels_change(ev->obj); - break; - } -} - -/* Mainloop callback, sent by libvlc_on_mp_event. It processes a list of libvlc - * event. */ -static void -emotion_mainloop_event_list(void *data) -{ - Emotion_LibVLC *ev = data; - Eina_List *event_list; - libvlc_event_t *event; - - if (!emotion_mainloop_lock(ev)) return; - event_list = ev->event_list; - ev->event_list = NULL; - eina_lock_release(&ev->lock); - - if (!event_list) return; - - EINA_LIST_FREE(event_list, event) - { - if (ev->mp) - emotion_mainloop_event(ev, event); - free(event); - } -} - -/* Libvlc callback, see libvlc_event_manager_t. */ -static void -libvlc_on_mp_event(const libvlc_event_t *event, void *opaque) -{ - Emotion_LibVLC *ev = opaque; - - if (eina_main_loop_is()) - { - /* Process the event directly */ - emotion_mainloop_event(ev, event); - } - else - { - /* Add the event to a list of events that will be processed by the - * mainloop */ - - void *data = malloc(sizeof(libvlc_event_t)); - if (!data) return; - memcpy(data, event, sizeof(libvlc_event_t)); - - eina_lock_take(&ev->lock); - if (!ev->event_list) - emotion_mainloop_call_locked(ev, emotion_mainloop_event_list); - ev->event_list = eina_list_append(ev->event_list, data); - eina_lock_release(&ev->lock); - } -} - -static void -evas_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, - void *event EINA_UNUSED) -{ - Emotion_LibVLC *ev = data; - int w, h; - - evas_object_image_size_get(ev->evas_obj, &w, &h); - _emotion_frame_resize(ev->obj, w, h, w / (double) h); - efl_event_callback_call(ev->obj, EFL_CANVAS_VIDEO_EVENT_FRAME_DECODE, NULL); -} - -/* Fetch all libvlc tracks. */ -static int -libvlc_fetch_tracks(Emotion_LibVLC *ev) -{ - if (ev->invalidate_tracks) - { - if (ev->nb_tracks) - libvlc_media_tracks_release(ev->tracks, ev->nb_tracks); - ev->nb_tracks = libvlc_media_tracks_get(ev->m, &ev->tracks); - ev->invalidate_tracks = EINA_FALSE; - } - return ev->nb_tracks; -} - -/* Get a libvlc tracks from a track_id. */ -static libvlc_media_track_t * -libvlc_get_track(Emotion_LibVLC *ev, libvlc_track_type_t type, int id) -{ - unsigned int i; - - if (!ev->m || id < 0 || type == libvlc_track_unknown) return NULL; - - if (!libvlc_fetch_tracks(ev)) return NULL; - - for (i = 0; i < ev->nb_tracks; ++i) - { - libvlc_media_track_t *track = ev->tracks[i]; - - if (track->i_id == id && track->i_type == type) - return track; - } - - return NULL; -} - -/* Get the current libvlc video track. */ -static libvlc_media_track_t * -libvlc_get_current_video_track(Emotion_LibVLC *ev) -{ - int id = libvlc_video_get_track(ev->mp); - return id >= 0 ? libvlc_get_track(ev, libvlc_track_video, id) : NULL; -} - -/* Get a libvlc video track at a pos. - * XXX: Libvlc use a track_id to get and select a track. The first track_id doesn't - * necessarily starts with 0. Emotion use a position (that starts with 0) to - * get and select a track. */ -static libvlc_media_track_t * -libvlc_get_track_at_pos(Emotion_LibVLC *ev, - int pos, libvlc_track_type_t type) -{ - unsigned int i; - - if (!ev->m || pos < 0 || type == libvlc_track_unknown) return NULL; - - if (!libvlc_fetch_tracks(ev)) return NULL; - - for (i = 0; i < ev->nb_tracks; ++i) - { - libvlc_media_track_t *track = ev->tracks[i]; - - if (type == track->i_type && pos-- == 0) - return track; - } - - return NULL; -} - -/* Get the position of the libvlc track. - * See libvlc_get_track_at_pos. */ -static int -libvlc_get_track_pos(Emotion_LibVLC *ev, int id, libvlc_track_type_t type) -{ - unsigned int i; - int pos = 0; - - if (!ev->m || id < 0 || type == libvlc_track_unknown) return -1; - - if (!libvlc_fetch_tracks(ev)) return -1; - - for (i = 0; i < ev->nb_tracks; ++i) - { - libvlc_media_track_t *track = ev->tracks[i]; - - if (type == track->i_type) - { - if (id == track->i_id) - return pos; - else - pos++; - } - } - - return -1; -} - -static void * -em_add(const Emotion_Engine *api EINA_UNUSED, - Evas_Object *obj, - const Emotion_Module_Options *opt) -{ - Emotion_LibVLC *ev; - ev = calloc(1, sizeof(Emotion_LibVLC)); - EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); - - ev->obj = obj; - ev->opt = *opt; - eina_lock_new(&ev->lock); - eina_condition_new(&ev->wait, &ev->lock); - ev->ref_count = 1; - ev->audio_vol = -1; - - return ev; -} - -static void -em_del(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev) return; - - em_file_close(video); - - eina_lock_take(&ev->lock); - if (--ev->ref_count > 0) - { - eina_lock_release(&ev->lock); - WRN("em_del delayed, some callbacks are still running"); - } - else - { - eina_lock_release(&ev->lock); - em_del_safe(ev); - } -} - -static Eina_Bool -em_file_open(void *video, - const char *file) -{ - int ret, i; - Emotion_LibVLC *ev = video; - libvlc_event_manager_t *event_m; - - if (!file) return EINA_FALSE; - - ev->evas_obj = emotion_object_image_get(ev->obj); - if (!ev->evas_obj) - { - WRN("emotion_object_image_get failed: no video"); - ev->opt.no_video = EINA_TRUE; - } - - evas_object_image_pixels_get_callback_set(ev->evas_obj, NULL, NULL); - - ev->invalidate_tracks = true; - - /* Create libvlc_media */ - ev->m = libvlc_media_new_path(libvlc, file); - if (strstr(file, "://") == NULL) - ev->m = libvlc_media_new_path(libvlc, file); - else - ev->m = libvlc_media_new_location(libvlc, file); - - EINA_SAFETY_ON_NULL_GOTO(ev->m, error); - - if (ev->opt.no_audio || ev->audio_mute) - libvlc_media_add_option(ev->m, ":no-audio"); - - if (ev->opt.no_video || ev->video_mute) - libvlc_media_add_option(ev->m, ":no-video"); - - if (ev->spu_mute) - libvlc_media_add_option(ev->m, ":no-spu"); - - /* Create libvlc_media_player */ - ev->mp = libvlc_media_player_new_from_media(ev->m); - EINA_SAFETY_ON_NULL_GOTO(ev->mp, error); - - event_m = libvlc_media_player_event_manager(ev->mp); - for (i = 0; mp_events[i] != -1; ++i) - libvlc_event_attach(event_m, mp_events[i], libvlc_on_mp_event, ev); - - libvlc_media_player_set_video_title_display(ev->mp, - libvlc_position_disable, 0); - - evas_object_ref(ev->evas_obj); - if (libvlc_media_player_set_evas_object(ev->mp, ev->evas_obj) == -1) - { - CRI("libvlc_media_player_set_evas_object failed"); - libvlc_media_add_option(ev->m, ":no-video"); - ev->video_mute = ev->video_mute_force = 1; - } - - evas_object_event_callback_add(ev->evas_obj, EVAS_CALLBACK_IMAGE_RESIZE, - evas_resize_cb, ev); - - if (ev->audio_vol != -1) - libvlc_audio_set_volume(ev->mp, ev->audio_vol); - - ret = libvlc_media_player_play(ev->mp); - EINA_SAFETY_ON_FALSE_GOTO(ret == 0, error); - - return EINA_TRUE; -error: - em_file_close(video); - return EINA_FALSE; -} - -static void -emotion_close_cb(void *data, Ecore_Thread *thread EINA_UNUSED) -{ - struct close_data *close_data = data; - - libvlc_media_player_release(close_data->mp); -} - -static void -emotion_close_mainloop_cb(void *data, - Ecore_Thread *thread EINA_UNUSED) -{ - struct close_data *close_data = data; - - evas_object_unref(close_data->evas_obj); - free(close_data); - _emotion_pending_ecore_end(); -} - -static void -em_file_close(void *video) -{ - Emotion_LibVLC *ev = video; - unsigned int i; - - if (ev->mp) - { - struct close_data *close_data; - libvlc_event_manager_t *event_m; - - evas_object_event_callback_del(ev->evas_obj, EVAS_CALLBACK_IMAGE_RESIZE, - evas_resize_cb); - - event_m = libvlc_media_player_event_manager(ev->mp); - for (i = 0; mp_events[i] != -1; ++i) - libvlc_event_detach(event_m, mp_events[i], libvlc_on_mp_event, ev); - - libvlc_media_player_set_evas_object(ev->mp, NULL); - - close_data = malloc(sizeof(struct close_data)); - if (close_data) - { - close_data->evas_obj = ev->evas_obj; - close_data->mp = ev->mp; - _emotion_pending_ecore_begin(); - ecore_thread_run(emotion_close_cb, - emotion_close_mainloop_cb, - NULL, close_data); - } - - ev->evas_obj = NULL; - ev->mp = NULL; - - if (ev->seeking) - { - ev->seeking = EINA_FALSE; - _emotion_seek_done(ev->obj); - } - } - if (ev->m) - { - libvlc_media_release(ev->m); - ev->m = NULL; - } - if (ev->nb_tracks > 0) - { - libvlc_media_tracks_release(ev->tracks, ev->nb_tracks); - ev->nb_tracks = 0; - ev->tracks = NULL; - } - if (ev->nb_chapters > 0) - { - libvlc_chapter_descriptions_release(ev->chapters, ev->nb_chapters); - ev->nb_chapters = 0; - ev->chapters = NULL; - } - for (i = 0; i < META_TRACK_COUNT; ++i) - { - free(ev->metas[i]); - ev->metas[i] = NULL; - } - if (ev->subtitle_file) - { - free(ev->subtitle_file); - ev->subtitle_file = NULL; - } - ev->vis = EMOTION_VIS_NONE; - ev->started = ev->seeking = ev->invalidate_tracks = EINA_FALSE; - ev->pos = ev->len = ev->buffer_cache = 0.0; -} - -static void -em_play(void *video, - double pos EINA_UNUSED) -{ - Emotion_LibVLC *ev = video; - - libvlc_media_player_set_pause(ev->mp, false); -} - -static void -em_stop(void *video) -{ - Emotion_LibVLC *ev = video; - - libvlc_media_player_set_pause(ev->mp, true); -} - -static void -em_size_get(void *video, - int *width, - int *height) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!width || !height) return; - *width = 0; - *height = 0; - - if (!ev->started) return; - - track = libvlc_get_current_video_track(ev); - if (track) - { - *width = track->video->i_width; - *height = track->video->i_height; - } -} - -static double -em_pos_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return ev->pos; -} - -static void -em_pos_set(void *video, - double pos) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) - { - _emotion_seek_done(ev->obj); - return; - } - - libvlc_media_player_set_time(ev->mp, pos * 1000); - - ev->seeking = EINA_TRUE; -} - -static double -em_len_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return ev->len; -} - -static double -em_buffer_size_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return ev->buffer_cache; -} - -static void -em_fps_num_den_get(Emotion_LibVLC *ev, int *num, int *den) -{ - libvlc_media_track_t *track; - - if (!ev->started) return; - - track = libvlc_get_current_video_track(ev); - if (track) - { - if (num) - *num = track->video->i_frame_rate_num; - if (den) - *den = track->video->i_frame_rate_den; - } -} - -static int -em_fps_num_get(void *video) -{ - int num = 0; - - em_fps_num_den_get(video, &num, NULL); - return num; -} - -static int -em_fps_den_get(void *video) -{ - int den = 0; - - em_fps_num_den_get(video, NULL, &den); - return den; -} - -static double -em_fps_get(void *video) -{ - int num = 0, den = 0; - - em_fps_num_den_get(video, &num, &den); - if (den > 0) return num / (double)den; - return 0.0; -} - -static void -em_vis_set(void *video, - Emotion_Vis vis) -{ - Emotion_LibVLC *ev = video; - - ev->vis = vis; -} - -static Emotion_Vis -em_vis_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->vis; -} - -static Eina_Bool -em_vis_supported(void *ev EINA_UNUSED, Emotion_Vis vis) -{ - /* FIXME */ - if (vis == EMOTION_VIS_NONE) - return EINA_TRUE; - else - return EINA_FALSE; -} - -static double -em_ratio_get(void *video) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return 0.0; - - track = libvlc_get_current_video_track(ev); - if (track) - { - double ratio = track->video->i_sar_num - / (double)track->video->i_sar_den; - return ratio; - } - else - return 0.0; -} - -static int -em_video_handled(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return libvlc_video_get_track_count(ev->mp) > 0; -} - -static int -em_audio_handled(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0.0; - - return libvlc_audio_get_track_count(ev->mp) > 0; -} - -static int -em_seekable(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0; - - return libvlc_media_player_is_seekable(ev->mp); -} - -static void -em_frame_done(void *video EINA_UNUSED) -{ -} - -static Emotion_Format -em_format_get(void *video EINA_UNUSED) -{ - return EMOTION_FORMAT_NONE; -} - -static void -em_video_data_size_get(void *video EINA_UNUSED, int *w EINA_UNUSED, int *h EINA_UNUSED) -{ -} - -static int -em_yuv_rows_get(void *video EINA_UNUSED, - int w EINA_UNUSED, - int h EINA_UNUSED, - unsigned char **yrows EINA_UNUSED, - unsigned char **urows EINA_UNUSED, - unsigned char **vrows EINA_UNUSED) -{ - return 0; -} - -static int -em_bgra_data_get(void *video EINA_UNUSED, unsigned char **bgra_data EINA_UNUSED) -{ - return 0; -} - -static void -em_event_feed(void *video, int event) -{ - Emotion_LibVLC *ev = video; - unsigned int navigate; - - if (!ev->started) return; - - switch (event) - { - case EMOTION_EVENT_UP: - navigate = libvlc_navigate_up; - break; - - case EMOTION_EVENT_DOWN: - navigate = libvlc_navigate_down; - break; - - case EMOTION_EVENT_LEFT: - navigate = libvlc_navigate_left; - break; - - case EMOTION_EVENT_RIGHT: - navigate = libvlc_navigate_right; - break; - - case EMOTION_EVENT_SELECT: - navigate = libvlc_navigate_activate; - break; - - /* FIXME */ - default: - case EMOTION_EVENT_MENU1: - case EMOTION_EVENT_MENU2: - case EMOTION_EVENT_MENU3: - case EMOTION_EVENT_MENU4: - case EMOTION_EVENT_MENU5: - case EMOTION_EVENT_MENU6: - case EMOTION_EVENT_MENU7: - case EMOTION_EVENT_NEXT: - case EMOTION_EVENT_PREV: - case EMOTION_EVENT_ANGLE_NEXT: - case EMOTION_EVENT_ANGLE_PREV: - case EMOTION_EVENT_FORCE: - case EMOTION_EVENT_0: - case EMOTION_EVENT_1: - case EMOTION_EVENT_2: - case EMOTION_EVENT_3: - case EMOTION_EVENT_4: - case EMOTION_EVENT_5: - case EMOTION_EVENT_6: - case EMOTION_EVENT_7: - case EMOTION_EVENT_8: - case EMOTION_EVENT_9: - case EMOTION_EVENT_10: - return; - } - libvlc_media_player_navigate(ev->mp, navigate); -} - -static void -em_event_mouse_button_feed(void *video EINA_UNUSED, int button EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ - /* Handled directly by VLC evas vout module */ -} - -static void -em_event_mouse_move_feed(void *video EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED) -{ - /* Handled directly by VLC evas vout module */ -} - -static int -em_video_channel_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return -1; - - return libvlc_video_get_track_count(ev->mp); -} - -static void -em_video_channel_set(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - if (channel < 0) - libvlc_video_set_track(ev->mp, -1); - else - { - libvlc_media_track_t *track; - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_video); - if (track) - libvlc_video_set_track(ev->mp, track->i_id); - } -} - -static int -em_video_channel_get(void *video) -{ - Emotion_LibVLC *ev = video; - int id; - - if (!ev->started) return -1; - - id = libvlc_video_get_track(ev->mp); - - return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_video) : -1; -} - -static void -em_video_subtitle_file_set(void *video, - const char *filepath) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - free(ev->subtitle_file); - ev->subtitle_file = filepath ? strdup(filepath) : NULL; - libvlc_video_set_subtitle_file(ev->mp, ev->subtitle_file); -} - -static const char * -em_video_subtitle_file_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->subtitle_file; -} - -static const char * -em_video_channel_name_get(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return NULL; - - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_video); - if (track) - return track->psz_description; - else - return NULL; -} - -static void -em_video_channel_mute_set(void *video, - int mute) -{ - Emotion_LibVLC *ev = video; - - if (ev->video_mute_force) - return; - ev->video_mute = mute; - - if (ev->started) - em_video_channel_set(video, mute ? -1 : 0); -} - -static int -em_video_channel_mute_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->video_mute; -} - -static int -em_channel_count(int vlc_count) -{ - /* vlc count the -1 track that deactivate the channel for audio and spu */ - return vlc_count > 0 ? vlc_count - 1 : vlc_count; -} - -static int -em_audio_channel_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return -1; - - return em_channel_count(libvlc_audio_get_track_count(ev->mp)); -} - -static void -em_audio_channel_set(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - if (channel < 0) - libvlc_audio_set_track(ev->mp, -1); - else - { - libvlc_media_track_t *track; - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_audio); - if (track) - libvlc_audio_set_track(ev->mp, track->i_id); - } -} - -static int -em_audio_channel_get(void *video) -{ - Emotion_LibVLC *ev = video; - int id; - - if (!ev->started) return -1; - - id = libvlc_audio_get_track(ev->mp); - - return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_audio) : -1; -} - -static const char * -em_audio_channel_name_get(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return NULL; - - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_audio); - if (track) - return track->psz_description; - else - return NULL; -} - -static void -em_audio_channel_mute_set(void *video, - int mute) -{ - Emotion_LibVLC *ev = video; - - ev->audio_mute = mute; - - if (ev->started) - em_audio_channel_set(video, mute ? -1 : 0); -} - -static int -em_audio_channel_mute_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->audio_mute; -} - -static void -em_audio_channel_volume_set(void *video, - double vol) -{ - Emotion_LibVLC *ev = video; - - if (vol < 0.0) - vol = 0.0; - else if (vol > 1.0) - vol = 1.0; - ev->audio_vol = vol * 100; - - if (!ev->started) return; - - libvlc_audio_set_volume(ev->mp, ev->audio_vol); -} - -static double -em_audio_channel_volume_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) - return ev->audio_vol / 100.0; - - return libvlc_audio_get_volume(ev->mp) / 100.0; -} - -static int -em_spu_channel_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return -1; - - return em_channel_count(libvlc_video_get_spu_count(ev->mp)); -} - -static void -em_spu_channel_set(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - if (channel < 0) - libvlc_video_set_spu(ev->mp, -1); - else - { - libvlc_media_track_t *track; - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_text); - if (track) - libvlc_video_set_spu(ev->mp, track->i_id); - } -} - -static int -em_spu_channel_get(void *video) -{ - Emotion_LibVLC *ev = video; - int id; - - if (!ev->started) return -1; - - id = libvlc_video_get_spu(ev->mp); - - return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_text) : -1; -} - -static const char * -em_spu_channel_name_get(void *video, - int channel) -{ - Emotion_LibVLC *ev = video; - libvlc_media_track_t *track; - - if (!ev->started) return NULL; - - track = libvlc_get_track_at_pos(ev, channel, libvlc_track_text); - if (track) - return track->psz_description; - else - return NULL; -} - -static void -em_spu_channel_mute_set(void *video, int mute) -{ - Emotion_LibVLC *ev = video; - - ev->spu_mute = mute; - - if (ev->started) - em_spu_channel_set(video, mute ? -1 : 0); -} - -static int -em_spu_channel_mute_get(void *video) -{ - Emotion_LibVLC *ev = video; - - return ev->spu_mute; -} - -static int -em_chapter_count(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0; - - return libvlc_media_player_get_chapter_count(ev->mp); -} - -static void -em_chapter_set(void *video, int chapter) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - libvlc_media_player_set_chapter(ev->mp, chapter); -} - -static int -em_chapter_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 0; - - return libvlc_media_player_get_chapter(ev->mp); -} - -static const char * -em_chapter_name_get(void *video, int chapter) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return NULL; - - if (ev->nb_chapters == 0) - { - ev->nb_chapters = - libvlc_media_player_get_full_chapter_descriptions(ev->mp, - -1, - &ev->chapters); - if (ev->nb_chapters == 0) - ev->nb_chapters = -1; - } - return chapter < ev->nb_chapters ? ev->chapters[chapter]->psz_name : NULL; -} - -static void -em_speed_set(void *video, double speed) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return; - - libvlc_media_player_set_rate(ev->mp, speed); -} - -static double -em_speed_get(void *video) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return 1.0; - - return libvlc_media_player_get_rate(ev->mp); -} - -static int -em_eject(void *video EINA_UNUSED) -{ - return 1; -} - -static const char * -em_meta_get(void *video, int meta) -{ - Emotion_LibVLC *ev = video; - - if (!ev->started) return NULL; - - if (meta <= 0 || meta >= META_TRACK_COUNT) - return NULL; - - if (ev->metas[meta]) - return ev->metas[meta]; - else - { - libvlc_meta_t vlc_meta; - switch (meta) - { - case META_TRACK_TITLE: - vlc_meta = libvlc_meta_Title; - break; - - case META_TRACK_ARTIST: - vlc_meta = libvlc_meta_Artist; - break; - - case META_TRACK_ALBUM: - vlc_meta = libvlc_meta_Album; - break; - - case META_TRACK_YEAR: - vlc_meta = libvlc_meta_Date; - break; - - case META_TRACK_GENRE: - vlc_meta = libvlc_meta_Genre; - break; - - case META_TRACK_COMMENT: - vlc_meta = libvlc_meta_Description; - break; - - case META_TRACK_DISCID: - vlc_meta = libvlc_meta_TrackID; - break; - - default: - return NULL; - break; - } - ev->metas[meta] = libvlc_media_get_meta(ev->m, vlc_meta); - - return ev->metas[meta]; - } -} - -static const Emotion_Engine em_engine = -{ - EMOTION_ENGINE_API_VERSION, - EMOTION_ENGINE_PRIORITY_DEFAULT, - "libvlc", - em_add, /* add */ - em_del, /* del */ - em_file_open, /* file_open */ - em_file_close, /* file_close */ - em_play, /* play */ - em_stop, /* stop */ - em_size_get, /* size_get */ - em_pos_set, /* pos_set */ - em_len_get, /* len_get */ - em_buffer_size_get, /* buffer_size_get */ - em_fps_num_get, /* fps_num_get */ - em_fps_den_get, /* fps_den_get */ - em_fps_get, /* fps_get */ - em_pos_get, /* pos_get */ - em_vis_set, /* vis_set */ - em_vis_get, /* vis_get */ - em_vis_supported, /* vis_supported */ - em_ratio_get, /* ratio_get */ - em_video_handled, /* video_handled */ - em_audio_handled, /* audio_handled */ - em_seekable, /* seekable */ - em_frame_done, /* frame_done */ - em_format_get, /* format_get */ - em_video_data_size_get, /* video_data_size_get */ - em_yuv_rows_get, /* yuv_rows_get */ - em_bgra_data_get, /* bgra_data_get */ - em_event_feed, /* event_feed */ - em_event_mouse_button_feed, /* event_mouse_button_feed */ - em_event_mouse_move_feed, /* event_mouse_move_feed */ - em_video_channel_count, /* video_channel_count */ - em_video_channel_set, /* video_channel_set */ - em_video_channel_get, /* video_channel_get */ - em_video_subtitle_file_set, /* video_subtitle_file_set */ - em_video_subtitle_file_get, /* video_subtitle_file_get */ - em_video_channel_name_get, /* video_channel_name_get */ - em_video_channel_mute_set, /* video_channel_mute_set */ - em_video_channel_mute_get, /* video_channel_mute_get */ - em_audio_channel_count, /* audio_channel_count */ - em_audio_channel_set, /* audio_channel_set */ - em_audio_channel_get, /* audio_channel_get */ - em_audio_channel_name_get, /* audio_channel_name_get */ - em_audio_channel_mute_set, /* audio_channel_mute_set */ - em_audio_channel_mute_get, /* audio_channel_mute_get */ - em_audio_channel_volume_set, /* audio_channel_volume_set */ - em_audio_channel_volume_get, /* audio_channel_volume_get */ - em_spu_channel_count, /* spu_channel_count */ - em_spu_channel_set, /* spu_channel_set */ - em_spu_channel_get, /* spu_channel_get */ - em_spu_channel_name_get, /* spu_channel_name_get */ - em_spu_channel_mute_set, /* spu_channel_mute_set */ - em_spu_channel_mute_get, /* spu_channel_mute_get */ - em_chapter_count, /* chapter_count */ - em_chapter_set, /* chapter_set */ - em_chapter_get, /* chapter_get */ - em_chapter_name_get, /* chapter_name_get */ - em_speed_set, /* speed_set */ - em_speed_get, /* speed_get */ - em_eject, /* eject */ - em_meta_get, /* meta_get */ - NULL, /* priority_set */ - NULL, /* priority_get */ - NULL /* em_meta_artwork_get */ -}; - -static void -libvlc_log(void *data EINA_UNUSED, int level, - const libvlc_log_t *ctx EINA_UNUSED, - const char *fmt, va_list args) -{ - Eina_Log_Level eina_log_level; - const char *name, *header; - uintptr_t id; - - libvlc_log_get_object(ctx, &name, &header, &id); - switch (level) - { - case LIBVLC_DEBUG: - eina_log_level = EINA_LOG_LEVEL_DBG; - break; - - case LIBVLC_NOTICE: - eina_log_level = EINA_LOG_LEVEL_INFO; - break; - - case LIBVLC_WARNING: - eina_log_level = EINA_LOG_LEVEL_WARN; - break; - - case LIBVLC_ERROR: - default: - eina_log_level = EINA_LOG_LEVEL_ERR; - break; - } - eina_log_vprint(_emotion_libvlc_log_domain, eina_log_level, - "", name, id, fmt, args); -} - -static libvlc_instance_t * -libvlc_new_env_args(void) -{ - unsigned int argc = 0, i = 0; - const char **argv = NULL; - char *args_env, *args_dup = NULL, *str = NULL, *token, *saveptr; - libvlc_instance_t *instance = NULL; - - args_env = getenv("EMOTION_LIBVLC_ARGS"); - if (!args_env) - goto fallback; - - /* dup since strtok modify the str */ - args_dup = strdup(args_env); - if (!args_dup) - goto fallback; - - /* call strtok to count the numbers of arguments */ - str = strdup(args_dup); - if (!str) - goto fallback; - - token = strtok_r(str, " ", &saveptr); - while (token) - { - argc++; - token = strtok_r(NULL, " ", &saveptr); - } - if (!argc) - goto fallback; - - /* alloc argv */ - argv = calloc(1, argc * sizeof(char *)); - if (!argv) - goto fallback; - - /* call strtok to fill argv */ - free(str); - str = strdup(args_dup); - if (!str) - goto fallback; - - token = strtok_r(str, " ", &saveptr); - while (token && i < argc) - { - argv[i++] = token; - token = strtok_r(NULL, " ", &saveptr); - } - argc = i; - - for (i = 0; i < argc; ++i) - INF("libvlc_argv[%d]: %s", i, argv[i]); - - instance = libvlc_new(argc, argv); - -fallback: - free(args_dup); - free(str); - free(argv); - return instance ? instance : libvlc_new(0, NULL); -} - -Eina_Bool -libvlc_module_init(void) -{ - if (libvlc) - { - return EINA_TRUE; - } - - if (getenv("EMOTION_FPS_DEBUG")) debug_fps = EINA_TRUE; - - eina_threads_init(); - eina_log_threads_enable(); - _emotion_libvlc_log_domain = eina_log_domain_register - ("emotion-libvlc", EINA_COLOR_ORANGE); - if (_emotion_libvlc_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion-libvlc'"); - return EINA_FALSE; - } - - libvlc = libvlc_new_env_args(); - if (!libvlc) - { - CRI("could not create libvlc instance"); - goto error_register; - } - EINA_LOG_INFO("using libvlc: %s", libvlc_get_version()); - libvlc_log_set(libvlc, libvlc_log, NULL); - - if (!_emotion_module_register(&em_engine)) - { - ERR("Could not register module %p", &em_engine); - goto error_register; - } - - return EINA_TRUE; - -error_register: - if (libvlc) - { - libvlc_release(libvlc); - libvlc = NULL; - } - eina_log_domain_unregister(_emotion_libvlc_log_domain); - _emotion_libvlc_log_domain = -1; - return EINA_FALSE; -} - -void -libvlc_module_shutdown(void) -{ - if (!libvlc) - { - EINA_LOG_ERR("too many libvlc_module_shutdown()"); - return; - } - - _emotion_module_unregister(&em_engine); - - libvlc_release(libvlc); - libvlc = NULL; - - eina_log_domain_unregister(_emotion_libvlc_log_domain); - _emotion_libvlc_log_domain = -1; -} - -#ifndef EMOTION_STATIC_BUILD_LIBVLC - -EINA_MODULE_INIT(libvlc_module_init); -EINA_MODULE_SHUTDOWN(libvlc_module_shutdown); - -#endif diff --git a/src/modules/emotion/libvlc/meson.build b/src/modules/emotion/libvlc/meson.build deleted file mode 100644 index e5646a414d..0000000000 --- a/src/modules/emotion/libvlc/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -generic_src = files([ - 'emotion_libvlc.c', -]) - -generic_deps = [dependency('libvlc', version: '>= 3.0')] - -shared_module(emotion_loader, - generic_src, - include_directories : config_dir, - dependencies: [eina, evas, emotion, generic_deps], - install: true, - install_dir : mod_install_dir, - c_args : package_c_args, -) diff --git a/src/modules/emotion/meson.build b/src/modules/emotion/meson.build index e20729ad22..595557b710 100644 --- a/src/modules/emotion/meson.build +++ b/src/modules/emotion/meson.build @@ -1,19 +1,11 @@ -emotion_loaders = [ -'gstreamer1', -'libvlc', -'xine' -] - -if sys_windows == false - emotion_loaders += 'generic' -endif +emotion_loaders = [ 'gstreamer1' ] foreach emotion_loader : emotion_loaders generic_src = [] generic_deps = [] mod_install_dir = join_paths(dir_lib, 'emotion', 'modules', emotion_loader, version_name) - if get_option('emotion-loaders-disabler').contains(emotion_loader) == false + if get_option('gstreamer') == true subdir(emotion_loader) module_files += join_paths(mod_install_dir, 'lib'+emotion_loader+'.'+sys_mod_extension) config_h.set('EMOTION_BUILD_'+emotion_loader.to_upper(), 1) diff --git a/src/modules/emotion/xine/emotion_xine.c b/src/modules/emotion/xine/emotion_xine.c deleted file mode 100644 index dd84c1cbc7..0000000000 --- a/src/modules/emotion/xine/emotion_xine.c +++ /dev/null @@ -1,1707 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include - -#include "emotion_modules.h" -#include "emotion_xine.h" - -int _emotion_xine_log_domain = -1; -static int _emotion_init_count = 0; - -/* internal util calls */ -static void *_em_slave (void *par); -static void _em_slave_event (void *data, int type, void *arg); -static Eina_Bool _em_fd_active (void *data, Ecore_Fd_Handler *fdh); -static void _em_event (void *data, const xine_event_t *event); -static void _em_module_event (void *data, int type); -static Eina_Bool _em_fd_ev_active (void *data, Ecore_Fd_Handler *fdh); -//static int _em_timer (void *data); -static void *_em_get_pos_len_th(void *par); -static void _em_get_pos_len (Emotion_Xine_Video *ev); - -extern plugin_info_t emotion_xine_plugin_info[]; - -static void em_frame_done(void *ef); - -/* this is a slave controller thread for the xine module - libxine loves - * to deadlock, internally stall and otherwise have unpredictable behavior - * if we use the main process thread for many things - so a lot will be - * farmed off to this slave. its job is to handle opening, closing, file - * opening, recoder init etc. and all sorts of things can that often block. - * anything this thread needs to return, it will return via the event pipe. - */ -static void * -_em_slave(void *par) -{ - Emotion_Xine_Video *ev; - void *buf[2]; - int len; - - ev = (Emotion_Xine_Video *)par; - while ((len = read(ev->fd_slave_read, buf, sizeof(buf))) > 0) - { - if (len == sizeof(buf)) - { - Emotion_Xine_Event *eev; - - ev = buf[0]; - eev = buf[1]; - switch (eev->mtype) - { - case 0: /* noop */ - break; - case 1: /* init */ - { - ev->decoder = xine_new(); - xine_init(ev->decoder); - xine_register_plugins(ev->decoder, emotion_xine_plugin_info); - if (1) - { - xine_cfg_entry_t cf; - if (xine_config_lookup_entry(ev->decoder, "input.dvd_use_readahead", &cf)) - { - cf.num_value = 1; // 0 or 1 - xine_config_update_entry(ev->decoder, &cf); - } - } - DBG("OPEN VIDEO PLUGIN..."); - if (!ev->opt_no_video) - ev->video = xine_open_video_driver(ev->decoder, "emotion", - XINE_VISUAL_TYPE_NONE, ev); - DBG("RESULT: xine_open_video_driver() = %p", ev->video); - // Let xine autodetect the best audio output driver - if (!ev->opt_no_audio) - ev->audio = xine_open_audio_driver(ev->decoder, NULL, ev); - // ev->audio = xine_open_audio_driver(ev->decoder, "oss", ev); - // dont use alsa - alsa has oss emulation. - // ev->audio = xine_open_audio_driver(ev->decoder, "alsa", ev); - // ev->audio = xine_open_audio_driver(ev->decoder, "arts", ev); - // ev->audio = xine_open_audio_driver(ev->decoder, "esd", ev); - ev->stream = xine_stream_new(ev->decoder, ev->audio, ev->video); - ev->queue = xine_event_new_queue(ev->stream); - xine_event_create_listener_thread(ev->queue, _em_event, ev); - ev->opening = 0; - ev->play_ok = 1; - _em_module_event(ev, 1); /* event - open done */ - } - break; - case 3: /* shutdown */ - { - _em_module_event(ev, 3); - DBG("shutdown stop"); - xine_stop(ev->stream); - // pthread_mutex_lock(&(ev->get_pos_len_mutex)); - if (!ev->get_pos_thread_deleted) - { - DBG("closing get_pos thread, %p", ev); - pthread_mutex_lock(&(ev->get_pos_len_mutex)); - pthread_cond_broadcast(&(ev->get_pos_len_cond)); - pthread_mutex_unlock(&(ev->get_pos_len_mutex)); - while (ev->get_poslen); - } - DBG("dispose %p", ev); - xine_dispose(ev->stream); - DBG("dispose evq %p", ev); - xine_event_dispose_queue(ev->queue); - DBG("close video drv %p", ev); - if (ev->video) xine_close_video_driver(ev->decoder, ev->video); - DBG("wait for vo to go"); - while (ev->have_vo); - DBG("vo gone"); - DBG("close audio drv %p", ev); - if (ev->audio) xine_close_audio_driver(ev->decoder, ev->audio); - DBG("xine exit %p", ev); - xine_exit(ev->decoder); - DBG("DONE %p", ev); - close(ev->fd_write); - close(ev->fd_read); - close(ev->fd_ev_write); - close(ev->fd_ev_read); - close(ev->fd_slave_write); - close(ev->fd_slave_read); - ev->closing = 0; - if (eev->xine_event) free(eev->xine_event); - free(eev); - free(ev); - return NULL; - } - break; - case 2: /* file open */ - { - int pos_stream = 0; - int pos_time = 0; - int length_time = 0; - uint32_t v; - char *file; - - file = eev->xine_event; - DBG("OPEN STREAM %s", file); - if (xine_open(ev->stream, file)) - { - if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time)) - { - if (length_time == 0) - { - ev->pos = (double)pos_stream / 65535; - ev->len = 1.0; - ev->no_time = 1; - } - else - { - ev->pos = 0.0; - ev->len = (double)length_time / 1000.0; - } - } - else - { - ev->pos = 0.0; - ev->len = 1.0; - } - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_FRAME_DURATION); - if (v > 0) ev->fps = 90000.0 / (double)v; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_WIDTH); - ev->w = v; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HEIGHT); - ev->h = v; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_RATIO); - ev->ratio = (double)v / 10000.0; - ev->just_loaded = 1; - ev->get_poslen = 0; - xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100); - } - _em_module_event(ev, 2); /* event - open done */ - } - break; - case 11: /* file close */ - { - DBG("done %p", ev); - em_frame_done(ev); - DBG("stop %p", ev); - xine_stop(ev->stream); - DBG("close %p", ev); - xine_close(ev->stream); - DBG("close done %p", ev); - _em_module_event(ev, 11); - } - break; - case 4: /* play */ - { - double pos; - int pos_stream, pos_time, length_time; - - pos = *((double *)eev->xine_event); - if ((xine_get_param(ev->stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE) && - (EINA_DBL_EQ(pos, ev->pos)) && - (!ev->just_loaded)) - { - xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); - } - else - { - if (ev->no_time) - xine_play(ev->stream, pos * 65535, 0); - else - xine_play(ev->stream, 0, pos * 1000); - } - ev->just_loaded = 0; - - if (xine_get_pos_length(ev->stream, - &pos_stream, - &pos_time, - &length_time)) - { - if (length_time == 0) - { - ev->pos = (double)pos_stream / 65535; - ev->len = 1.0; - ev->no_time = 1; - } - else - { - ev->pos = (double)pos_time / 1000.0; - ev->len = (double)length_time / 1000.0; - } - } - _em_module_event(ev, 4); - } - break; - case 5: /* stop */ - { - xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); - _em_module_event(ev, 5); - } - break; - case 6: /* seek */ - { - double pos; - - pos = *((double *)eev->xine_event); - if (ev->no_time) - xine_play(ev->stream, pos * 65535, 0); - else - xine_play(ev->stream, 0, pos * 1000); - if (!ev->play) - xine_set_param(ev->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); - _em_module_event(ev, 6); - } - break; - case 7: /* eject */ - { - xine_eject(ev->stream); - _em_module_event(ev, 7); - } - break; - case 8: /* spu mute */ - { - xine_set_param(ev->stream, XINE_PARAM_IGNORE_SPU, ev->spu_mute); - _em_module_event(ev, 8); - } - break; - case 9: /* channel */ - { - xine_set_param(ev->stream, XINE_PARAM_SPU_CHANNEL, ev->spu_channel); - _em_module_event(ev, 9); - } - break; - case 10: /* vol */ - { - xine_set_param(ev->stream, XINE_PARAM_AUDIO_VOLUME, ev->volume * 100); - _em_module_event(ev, 10); - } - break; - case 12: /* audio mute */ - { - xine_set_param(ev->stream, XINE_PARAM_AUDIO_MUTE, ev->audio_mute); - } - break; - case 13: /* audio mute */ - { - xine_set_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ev->audio_channel); - } - break; - case 14: /* audio mute */ - { - xine_set_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL, ev->video_channel); - } - break; - default: - break; - } - if (eev->xine_event) free(eev->xine_event); - free(eev); - } - } - return NULL; -} -static void -_em_slave_event(void *data, int type, void *arg) -{ - void *buf[2]; - Emotion_Xine_Event *new_ev; - Emotion_Xine_Video *ev; - - ev = data; - new_ev = calloc(1, sizeof(Emotion_Xine_Event)); - if (!new_ev) return; - new_ev->mtype = type; - new_ev->type = -1; - new_ev->xine_event = arg; - buf[0] = data; - buf[1] = new_ev; - if (write(ev->fd_slave_write, buf, sizeof(buf)) < 0) perror("write"); -} - -static void * -em_add(const Emotion_Engine *api EINA_UNUSED, - Evas_Object *obj, - const Emotion_Module_Options *opt) -{ - Emotion_Xine_Video *ev; - int fds[2]; - sigset_t oldset, newset; - - ev = calloc(1, sizeof(Emotion_Xine_Video)); - EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); - ev->obj = obj; - - if (pipe(fds) == 0) - { - ev->fd_read = fds[0]; - ev->fd_write = fds[1]; - fcntl(ev->fd_read, F_SETFL, O_NONBLOCK); - ev->fd_handler = ecore_main_fd_handler_add(ev->fd_read, ECORE_FD_READ, - _em_fd_active, ev, - NULL, NULL); - ecore_main_fd_handler_active_set(ev->fd_handler, ECORE_FD_READ); - } - if (pipe(fds) == 0) - { - ev->fd_ev_read = fds[0]; - ev->fd_ev_write = fds[1]; - fcntl(ev->fd_ev_read, F_SETFL, O_NONBLOCK); - ev->fd_ev_handler = ecore_main_fd_handler_add(ev->fd_ev_read, - ECORE_FD_READ, _em_fd_ev_active, ev, NULL, NULL); - ecore_main_fd_handler_active_set(ev->fd_ev_handler, ECORE_FD_READ); - } - if (pipe(fds) == 0) - { - ev->fd_slave_read = fds[0]; - ev->fd_slave_write = fds[1]; - if (fcntl(ev->fd_slave_write, F_SETFL, O_NONBLOCK) != 0) - ERR("Can't fcntl() slave write fd"); - } - ev->volume = 0.8; - ev->delete_me = 0; - ev->get_pos_thread_deleted = 0; - ev->opening = 1; - ev->play_ok = 0; - - if (opt) - { - ev->opt_no_audio = opt->no_audio; - ev->opt_no_video = opt->no_video; - } - - pthread_cond_init(&(ev->get_pos_len_cond), NULL); - pthread_mutex_init(&(ev->get_pos_len_mutex), NULL); - sigemptyset(&newset); - sigaddset(&newset, SIGPIPE); - sigaddset(&newset, SIGALRM); - sigaddset(&newset, SIGCHLD); - sigaddset(&newset, SIGUSR1); - sigaddset(&newset, SIGUSR2); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGTERM); -#ifdef SIGPWR - sigaddset(&newset, SIGPWR); -#endif - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - pthread_create(&ev->get_pos_len_th, NULL, _em_get_pos_len_th, ev); - pthread_create(&ev->slave_th, NULL, _em_slave, ev); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - - pthread_detach(ev->slave_th); - _em_slave_event(ev, 1, NULL); - - ev->buffer = 1.0; - - return ev; -} - -static void -em_del(void *ef) -{ - Emotion_Xine_Video *ev = ef; - - ev->closing = 1; - ev->delete_me = 1; - DBG("del fds %p", ev); - ecore_main_fd_handler_del(ev->fd_handler); - ev->fd_handler = NULL; - ecore_main_fd_handler_del(ev->fd_ev_handler); - ev->fd_ev_handler = NULL; - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - - ev->closing = 1; - _em_slave_event(ev, 3, NULL); - DBG("done %p", ev); -} - -static Eina_Bool -em_file_open(void *ef, const char *file) -{ - Emotion_Xine_Video *ev = ef; - _em_slave_event(ev, 2, strdup(file)); - return EINA_TRUE; -} - -static void -em_file_close(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (!ev) return; - _em_slave_event(ev, 11, NULL); -} - -static void -em_play(void *ef, double pos) -{ - Emotion_Xine_Video *ev; - double *ppos; - - ev = (Emotion_Xine_Video *)ef; - ev->play = 1; - ev->play_ok = 0; - ppos = malloc(sizeof(double)); - *ppos = pos; - _em_slave_event(ev, 4, ppos); -} - -static void -em_stop(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->play = 0; - ev->play_ok = 0; - _em_slave_event(ev, 5, NULL); -} - -static void -em_size_get(void *ef, int *w, int *h) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (w) *w = ev->w; - if (h) *h = ev->h; -} - -static void -em_pos_set(void *ef, double pos) -{ - Emotion_Xine_Video *ev; - double *ppos; - - ev = (Emotion_Xine_Video *)ef; - ppos = malloc(sizeof(double)); - *ppos = pos; - _em_slave_event(ev, 6, ppos); -} - -static double -em_len_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->len; -} - -static double -em_buffer_size_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->buffer; -} - -static int -em_fps_num_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return (int)(ev->fps * 10000.0); -} - -static int -em_fps_den_get(void *ef EINA_UNUSED) -{ - return 10000; -} - -static double -em_fps_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->fps; -} - -static double -em_pos_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - _em_get_pos_len(ev); - return ev->pos; -} - -static void -em_vis_set(void *ef, Emotion_Vis vis) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->vis == vis) return; - ev->vis = vis; -} - -static Emotion_Vis -em_vis_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - - return ev->vis; -} - -static Eina_Bool -em_vis_supported(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED) -{ - return EINA_FALSE; -} - -static double -em_ratio_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->ratio; -} - -static int -em_video_handled(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED)); -} - -static int -em_audio_handled(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_AUDIO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_HANDLED)); -} - -static int -em_seekable(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_SEEKABLE); -} - -static void -em_frame_done(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->cur_frame) - { - ev->fq--; - if (ev->cur_frame->done_func) - ev->cur_frame->done_func(ev->cur_frame->done_data); - ev->cur_frame = NULL; - } -} - -static Emotion_Format -em_format_get(void *ef) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (fr) return fr->format; - return EMOTION_FORMAT_YV12; -} - -static void -em_video_data_size_get(void *ef, int *w, int *h) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (!fr) - { - if (w) *w = 0; - if (h) *h = 0; - return; - } - if (w) *w = fr->w; - if (h) *h = fr->h; -} - -static int -em_yuv_rows_get(void *ef, int w EINA_UNUSED, int h, unsigned char **yrows, unsigned char **urows, unsigned char **vrows) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (!fr) return 0; - if (fr->y) - { - int i; - - for (i = 0; i < h; i++) yrows[i] = fr->y + (i * fr->y_stride); - for (i = 0; i < (h / 2); i++) urows[i] = fr->u + (i * fr->u_stride); - for (i = 0; i < (h / 2); i++) vrows[i] = fr->v + (i * fr->v_stride); - return 1; - } - return 0; -} - -static int -em_bgra_data_get(void *ef, unsigned char **bgra_data) -{ - Emotion_Xine_Video *ev; - volatile Emotion_Xine_Video_Frame *fr; - - ev = (Emotion_Xine_Video *)ef; - fr = ev->cur_frame; - if (!fr) return 0; - if (fr->bgra_data) - { - *bgra_data = fr->bgra_data; - return 1; - } - return 0; -} - -static void -em_event_feed(void *ef, int event) -{ - Emotion_Xine_Video *ev; - xine_event_t xine_event; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return; - xine_event.data_length = 0; - xine_event.data = NULL; - xine_event.stream = ev->stream; - gettimeofday(&xine_event.tv, NULL); - switch (event) - { - case EMOTION_EVENT_MENU1: - xine_event.type = XINE_EVENT_INPUT_MENU1; - break; - case EMOTION_EVENT_MENU2: - xine_event.type = XINE_EVENT_INPUT_MENU2; - break; - case EMOTION_EVENT_MENU3: - xine_event.type = XINE_EVENT_INPUT_MENU3; - break; - case EMOTION_EVENT_MENU4: - xine_event.type = XINE_EVENT_INPUT_MENU4; - break; - case EMOTION_EVENT_MENU5: - xine_event.type = XINE_EVENT_INPUT_MENU5; - break; - case EMOTION_EVENT_MENU6: - xine_event.type = XINE_EVENT_INPUT_MENU6; - break; - case EMOTION_EVENT_MENU7: - xine_event.type = XINE_EVENT_INPUT_MENU7; - break; - case EMOTION_EVENT_UP: - xine_event.type = XINE_EVENT_INPUT_UP; - break; - case EMOTION_EVENT_DOWN: - xine_event.type = XINE_EVENT_INPUT_DOWN; - break; - case EMOTION_EVENT_LEFT: - xine_event.type = XINE_EVENT_INPUT_LEFT; - break; - case EMOTION_EVENT_RIGHT: - xine_event.type = XINE_EVENT_INPUT_RIGHT; - break; - case EMOTION_EVENT_SELECT: - xine_event.type = XINE_EVENT_INPUT_SELECT; - break; - case EMOTION_EVENT_NEXT: - xine_event.type = XINE_EVENT_INPUT_NEXT; - break; - case EMOTION_EVENT_PREV: - xine_event.type = XINE_EVENT_INPUT_PREVIOUS; - break; - case EMOTION_EVENT_ANGLE_NEXT: - xine_event.type = XINE_EVENT_INPUT_ANGLE_NEXT; - break; - case EMOTION_EVENT_ANGLE_PREV: - xine_event.type = XINE_EVENT_INPUT_ANGLE_PREVIOUS; - break; - case EMOTION_EVENT_FORCE: - xine_event.type = XINE_EVENT_INPUT_BUTTON_FORCE; - break; - case EMOTION_EVENT_0: - xine_event.type = XINE_EVENT_INPUT_NUMBER_0; - break; - case EMOTION_EVENT_1: - xine_event.type = XINE_EVENT_INPUT_NUMBER_1; - break; - case EMOTION_EVENT_2: - xine_event.type = XINE_EVENT_INPUT_NUMBER_2; - break; - case EMOTION_EVENT_3: - xine_event.type = XINE_EVENT_INPUT_NUMBER_3; - break; - case EMOTION_EVENT_4: - xine_event.type = XINE_EVENT_INPUT_NUMBER_4; - break; - case EMOTION_EVENT_5: - xine_event.type = XINE_EVENT_INPUT_NUMBER_5; - break; - case EMOTION_EVENT_6: - xine_event.type = XINE_EVENT_INPUT_NUMBER_6; - break; - case EMOTION_EVENT_7: - xine_event.type = XINE_EVENT_INPUT_NUMBER_7; - break; - case EMOTION_EVENT_8: - xine_event.type = XINE_EVENT_INPUT_NUMBER_8; - break; - case EMOTION_EVENT_9: - xine_event.type = XINE_EVENT_INPUT_NUMBER_9; - break; - case EMOTION_EVENT_10: - xine_event.type = XINE_EVENT_INPUT_NUMBER_10_ADD; - break; - default: - return; - break; - } - xine_event_send(ev->stream, &xine_event); -} - -static void -em_event_mouse_button_feed(void *ef, int button EINA_UNUSED, int x, int y) -{ - Emotion_Xine_Video *ev; - xine_event_t xine_event; - xine_input_data_t xine_input; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return; - xine_event.stream = ev->stream; - gettimeofday(&xine_event.tv, NULL); - xine_event.type = XINE_EVENT_INPUT_MOUSE_BUTTON; - xine_input.button = 1; - xine_input.x = x; - xine_input.y = y; - xine_event.data = &xine_input; - xine_event.data_length = sizeof(xine_input); - xine_event_send(ev->stream, &xine_event); -} - -static void -em_event_mouse_move_feed(void *ef, int x, int y) -{ - Emotion_Xine_Video *ev; - xine_event_t xine_event; - xine_input_data_t xine_input; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return; - xine_event.stream = ev->stream; - gettimeofday(&xine_event.tv, NULL); - xine_event.type = XINE_EVENT_INPUT_MOUSE_MOVE; - xine_input.button = 0; - xine_input.x = x; - xine_input.y = y; - xine_event.data = &xine_input; - xine_event.data_length = sizeof(xine_input); - xine_event_send(ev->stream, &xine_event); -} - -static int -em_video_channel_count(void *ef) -{ - Emotion_Xine_Video *ev; - int v; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - v = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_CHANNELS); - if ((v < 1) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO)) return 1; - return v; -} - -static void -em_video_channel_set(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (channel < 0) channel = 0; - ev->video_channel = channel; - _em_slave_event(ev, 14, NULL); -} - -static int -em_video_channel_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL); -} - -static void -em_video_subtitle_file_set(void *video EINA_UNUSED, - const char *filepath EINA_UNUSED) -{ - DBG("video_subtitle_file_set not implemented for xine yet."); -} - -static const char * -em_video_subtitle_file_get(void *video EINA_UNUSED) -{ - DBG("video_subtitle_file_get not implemented for xine yet."); - return NULL; -} - -static const char * -em_video_channel_name_get(void *ef EINA_UNUSED, int channel EINA_UNUSED) -{ - return NULL; -} - -static void -em_video_channel_mute_set(void *ef, int mute) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->video_mute = mute; -} - -static int -em_video_channel_mute_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->video_mute; -} - -static int -em_audio_channel_count(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL); -} - -static void -em_audio_channel_set(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (channel < -1) channel = -1; - ev->audio_channel = channel; - _em_slave_event(ev, 13, NULL); -} - -static int -em_audio_channel_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL); -} - -static const char * -em_audio_channel_name_get(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - static char lang[XINE_LANG_MAX + 1]; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening) return NULL; - lang[0] = 0; - if (xine_get_audio_lang(ev->stream, channel, lang)) return lang; - return NULL; -} - -static void -em_audio_channel_mute_set(void *ef, int mute) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->audio_mute = mute; - _em_slave_event(ev, 12, NULL); -} - -static int -em_audio_channel_mute_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->audio_mute; -} - -static void -em_audio_channel_volume_set(void *ef, double vol) -{ - Emotion_Xine_Video *ev; - - if (vol < 0.0) vol = 0.0; - else if (vol > 1.0) vol = 1.0; - - ev = (Emotion_Xine_Video *)ef; - ev->volume = vol; - _em_slave_event(ev, 10, NULL); -} - -static double -em_audio_channel_volume_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return ev->volume; - ev->volume = xine_get_param(ev->stream, XINE_PARAM_AUDIO_VOLUME) / 100.0; - return ev->volume; -} - -static int -em_spu_channel_count(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL); -} - -static void -em_spu_channel_set(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (channel < 0) channel = 0; - ev->spu_channel = channel; - _em_slave_event(ev, 9, NULL); -} - -static int -em_spu_channel_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - return xine_get_param(ev->stream, XINE_PARAM_SPU_CHANNEL); -} - -static const char * -em_spu_channel_name_get(void *ef, int channel) -{ - Emotion_Xine_Video *ev; - static char lang[XINE_LANG_MAX + 1]; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening) return NULL; - lang[0] = 0; - if (xine_get_spu_lang(ev->stream, channel, lang)) return lang; - return NULL; -} - -static void -em_spu_channel_mute_set(void *ef, int mute) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - ev->spu_mute = mute; - _em_slave_event(ev, 8, NULL); -} - -static int -em_spu_channel_mute_get(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - return ev->spu_mute; -} - -static int -em_chapter_count(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (ev->opening || (!ev->play_ok)) return 0; - if (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_CHAPTERS)) - return 99; - return 0; -} - -static void -em_chapter_set(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ -} - -static int -em_chapter_get(void *ef EINA_UNUSED) -{ - return 0; -} - -static const char * -em_chapter_name_get(void *ef EINA_UNUSED, int chapter EINA_UNUSED) -{ - return NULL; -} - -static void -em_speed_set(void *ef EINA_UNUSED, double speed EINA_UNUSED) -{ -} - -static double -em_speed_get(void *ef EINA_UNUSED) -{ - return 1.0; -} - -static int -em_eject(void *ef) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - _em_slave_event(ev, 7, NULL); - return 1; -} - -static const char * -em_meta_get(void *ef, int meta) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if ((ev->opening) || (!ev->play_ok)) return NULL; - switch (meta) - { - case META_TRACK_TITLE: - return xine_get_meta_info(ev->stream, XINE_META_INFO_TITLE); - break; - case META_TRACK_ARTIST: - return xine_get_meta_info(ev->stream, XINE_META_INFO_ARTIST); - break; - case META_TRACK_GENRE: - return xine_get_meta_info(ev->stream, XINE_META_INFO_GENRE); - break; - case META_TRACK_COMMENT: - return xine_get_meta_info(ev->stream, XINE_META_INFO_COMMENT); - break; - case META_TRACK_ALBUM: - return xine_get_meta_info(ev->stream, XINE_META_INFO_ALBUM); - break; - case META_TRACK_YEAR: - return xine_get_meta_info(ev->stream, XINE_META_INFO_YEAR); - break; - case META_TRACK_DISCID: - return xine_get_meta_info(ev->stream, XINE_META_INFO_CDINDEX_DISCID); - break; - default: - break; - } - return NULL; -} - -static Eina_Bool -_em_fd_active(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh) -{ - void *buf; - int fd, len; - Emotion_Xine_Video_Frame *fr; - - fd = ecore_main_fd_handler_fd_get(fdh); - if (fd < 0) return EINA_TRUE; - while ((len = read(fd, &buf, sizeof(buf))) > 0) - { - if (len == sizeof(buf)) - { - Emotion_Xine_Video *ev; - - fr = buf; - ev = _emotion_video_get(fr->obj); - if (ev) - { - em_frame_done(ev); - ev->cur_frame = fr; - _em_get_pos_len(ev); - if ((xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO)) && - (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED))) - { - if (ev->video_mute) em_frame_done(ev); - else _emotion_frame_new(fr->obj); - } - _emotion_frame_resize(fr->obj, fr->w, fr->h, fr->ratio); - _emotion_video_pos_update(fr->obj, ev->pos, ev->len); - } - } - } - return EINA_TRUE; -} - -static void -_em_event(void *data, const xine_event_t *event) -{ - void *buf[2]; - Emotion_Xine_Event *new_ev; - Emotion_Xine_Video *ev; - - ev = data; - new_ev = calloc(1, sizeof(Emotion_Xine_Event)); - if (!new_ev) return; - new_ev->mtype = 0; - new_ev->type = event->type; - if (event->data) - { - new_ev->xine_event = malloc(event->data_length); - if (!new_ev->xine_event) - { - free(new_ev); - return; - } - memcpy(new_ev->xine_event, event->data, event->data_length); - } - buf[0] = data; - buf[1] = new_ev; - if (write(ev->fd_ev_write, buf, sizeof(buf)) < 0) perror("write"); -} - -static void -_em_module_event(void *data, int type) -{ - void *buf[2]; - Emotion_Xine_Event *new_ev; - Emotion_Xine_Video *ev; - - ev = data; - new_ev = calloc(1, sizeof(Emotion_Xine_Event)); - if (!new_ev) return; - new_ev->mtype = type; - new_ev->type = -1; - buf[0] = data; - buf[1] = new_ev; - if (write(ev->fd_ev_write, buf, sizeof(buf)) < 0) perror("write"); -} - -static Eina_Bool -_em_audio_only_poller(void *data) -{ - Emotion_Xine_Video *ev; - - ev = data; - _em_get_pos_len(ev); - return EINA_TRUE; -} - -static Eina_Bool -_em_fd_ev_active(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh) -{ - int fd, len; - void *buf[2]; - - fd = ecore_main_fd_handler_fd_get(fdh); - while ((len = read(fd, buf, sizeof(buf))) > 0) - { - if (len == sizeof(buf)) - { - Emotion_Xine_Video *ev; - Emotion_Xine_Event *eev; - - ev = buf[0]; - eev = buf[1]; - if (eev->mtype != 0) - { - switch (eev->mtype) - { - case 1: /* init done */ - ev->play_ok = 1; - break; - case 2: /* open done */ - ev->play_ok = 1; - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - _emotion_open_done(ev->obj); - _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio); - break; - case 3: /* shutdown done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 4: /* play done */ - ev->play_ok = 1; - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - if ((!(xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_VIDEO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_HANDLED))) && - (xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_AUDIO) && - xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_HANDLED))) - ev->anim = ecore_evas_animator_add(ev->obj, _em_audio_only_poller, ev); - _emotion_playback_started(ev->obj); - break; - case 5: /* stop done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 6: /* seek done */ - ev->play_ok = 1; - _emotion_seek_done(ev->obj); - _em_get_pos_len(ev); - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - break; - case 7: /* eject done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 8: /* spu mute done */ - ev->play_ok = 1; - break; - case 9: /* channel done */ - ev->play_ok = 1; - break; - case 10: /* volume done */ - ev->play_ok = 1; - break; - case 11: /* close done */ - if (ev->anim) - { - ecore_animator_del(ev->anim); - ev->anim = NULL; - } - ev->play_ok = 1; - break; - case 15: /* get pos done */ - if (!EINA_DBL_EQ(ev->last_pos, ev->pos)) - { - ev->last_pos = ev->pos; - _emotion_video_pos_update(ev->obj, ev->pos, ev->len); - } - break; - default: - break; - } - } - else - { - switch (eev->type) - { - case XINE_EVENT_UI_PLAYBACK_FINISHED: - { - ev->play = 0; - _emotion_decode_stop(ev->obj); - _emotion_playback_finished(ev->obj); - } - break; - case XINE_EVENT_UI_CHANNELS_CHANGED: - { - _emotion_channels_change(ev->obj); - } - break; - case XINE_EVENT_UI_SET_TITLE: - { - xine_ui_data_t *e; - - e = (xine_ui_data_t *)eev->xine_event; - _emotion_title_set(ev->obj, e->str); - } - break; - case XINE_EVENT_FRAME_FORMAT_CHANGE: - break; - case XINE_EVENT_UI_MESSAGE: - { - WRN("UI Message [FIXME: break this out to emotion api]"); - // e->type = error type(XINE_MSG_NO_ERROR, XINE_MSG_GENERAL_WARNING, XINE_MSG_UNKNOWN_HOST etc.) - // e->messages is a list of messages DOUBLE null terminated - } - break; - case XINE_EVENT_AUDIO_LEVEL: - { - _emotion_audio_level_change(ev->obj); - WRN("Audio Level [FIXME: break this out to emotion api]"); - // e->left (0->100) - // e->right - // e->mute - } - break; - case XINE_EVENT_PROGRESS: - { - xine_progress_data_t *e; - - e = (xine_progress_data_t *)eev->xine_event; - DBG("PROGRESS: %i", e->percent); - ev->buffer = e->percent; - _emotion_progress_set(ev->obj, (char *)e->description, (double)e->percent / 100.0); - } - break; - case XINE_EVENT_MRL_REFERENCE_EXT: - { - xine_mrl_reference_data_ext_t *e; - - e = (xine_mrl_reference_data_ext_t *)eev->xine_event; - _emotion_file_ref_set(ev->obj, e->mrl, e->alternative); - } - break; - case XINE_EVENT_UI_NUM_BUTTONS: - { - xine_ui_data_t *e; - - e = (xine_ui_data_t *)eev->xine_event; - _emotion_spu_button_num_set(ev->obj, e->num_buttons); - } - break; - case XINE_EVENT_SPU_BUTTON: - { - xine_spu_button_t *e; - - e = (xine_spu_button_t *)eev->xine_event; - if (e->direction == 1) - _emotion_spu_button_set(ev->obj, e->button); - else - _emotion_spu_button_set(ev->obj, -1); - } - break; - case XINE_EVENT_DROPPED_FRAMES: - { - xine_dropped_frames_t *e; - - e = (xine_dropped_frames_t *)eev->xine_event; - WRN("Dropped Frames (skipped %i) (discarded %i) [FIXME: break this out to the emotion api]", e->skipped_frames, e->discarded_frames); - // e->skipped_frames = % frames skipped * 10 - // e->discarded_frames = % frames skipped * 10 - } - break; - default: - // DBG("unknown event type %i", eev->type); - break; - } - } - if (eev->xine_event) free(eev->xine_event); - free(eev); - } - } - return EINA_TRUE; -} - -static void * -_em_get_pos_len_th(void *par) -{ - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)par; - - for (;;) - { - pthread_mutex_lock(&(ev->get_pos_len_mutex)); - pthread_cond_wait(&(ev->get_pos_len_cond), &(ev->get_pos_len_mutex)); - pthread_mutex_unlock(&(ev->get_pos_len_mutex)); - if (ev->get_poslen) - { - int pos_stream = 0; - int pos_time = 0; - int length_time = 0; - - if (xine_get_pos_length(ev->stream, &pos_stream, &pos_time, &length_time)) - { - if (length_time == 0) - { - ev->pos = (double)pos_stream / 65535; - ev->len = 1.0; - ev->no_time = 1; - } - else - { - ev->pos = (double)pos_time / 1000.0; - ev->len = (double)length_time / 1000.0; - ev->no_time = 0; - } - } - ev->get_poslen = 0; - _em_module_event(ev, 15); /* event - getpos done */ - //DBG("get pos %3.3f", ev->pos); - } - if (ev->delete_me) - { - ev->get_pos_thread_deleted = 1; - return NULL; - } - } - return NULL; -} - -static void -_em_get_pos_len(Emotion_Xine_Video *ev) -{ - if (!ev->play_ok) return; - ev->get_poslen = 1; - pthread_mutex_lock(&(ev->get_pos_len_mutex)); - pthread_cond_broadcast(&(ev->get_pos_len_cond)); - pthread_mutex_unlock(&(ev->get_pos_len_mutex)); -} - -static const Emotion_Engine em_engine = -{ - EMOTION_ENGINE_API_VERSION, - EMOTION_ENGINE_PRIORITY_DEFAULT, - "xine", - em_add, /* add */ - em_del, /* del */ - em_file_open, /* file_open */ - em_file_close, /* file_close */ - em_play, /* play */ - em_stop, /* stop */ - em_size_get, /* size_get */ - em_pos_set, /* pos_set */ - em_len_get, /* len_get */ - em_buffer_size_get, /* buffer_size_get */ - em_fps_num_get, /* fps_num_get */ - em_fps_den_get, /* fps_den_get */ - em_fps_get, /* fps_get */ - em_pos_get, /* pos_get */ - em_vis_set, /* vis_set */ - em_vis_get, /* vis_get */ - em_vis_supported, /* vis_supported */ - em_ratio_get, /* ratio_get */ - em_video_handled, /* video_handled */ - em_audio_handled, /* audio_handled */ - em_seekable, /* seekable */ - em_frame_done, /* frame_done */ - em_format_get, /* format_get */ - em_video_data_size_get, /* video_data_size_get */ - em_yuv_rows_get, /* yuv_rows_get */ - em_bgra_data_get, /* bgra_data_get */ - em_event_feed, /* event_feed */ - em_event_mouse_button_feed, /* event_mouse_button_feed */ - em_event_mouse_move_feed, /* event_mouse_move_feed */ - em_video_channel_count, /* video_channel_count */ - em_video_channel_set, /* video_channel_set */ - em_video_channel_get, /* video_channel_get */ - em_video_subtitle_file_set, /* video_subtitle_file_set */ - em_video_subtitle_file_get, /* video_subtitle_file_get */ - em_video_channel_name_get, /* video_channel_name_get */ - em_video_channel_mute_set, /* video_channel_mute_set */ - em_video_channel_mute_get, /* video_channel_mute_get */ - em_audio_channel_count, /* audio_channel_count */ - em_audio_channel_set, /* audio_channel_set */ - em_audio_channel_get, /* audio_channel_get */ - em_audio_channel_name_get, /* audio_channel_name_get */ - em_audio_channel_mute_set, /* audio_channel_mute_set */ - em_audio_channel_mute_get, /* audio_channel_mute_get */ - em_audio_channel_volume_set, /* audio_channel_volume_set */ - em_audio_channel_volume_get, /* audio_channel_volume_get */ - em_spu_channel_count, /* spu_channel_count */ - em_spu_channel_set, /* spu_channel_set */ - em_spu_channel_get, /* spu_channel_get */ - em_spu_channel_name_get, /* spu_channel_name_get */ - em_spu_channel_mute_set, /* spu_channel_mute_set */ - em_spu_channel_mute_get, /* spu_channel_mute_get */ - em_chapter_count, /* chapter_count */ - em_chapter_set, /* chapter_set */ - em_chapter_get, /* chapter_get */ - em_chapter_name_get, /* chapter_name_get */ - em_speed_set, /* speed_set */ - em_speed_get, /* speed_get */ - em_eject, /* eject */ - em_meta_get, /* meta_get */ - NULL, /* priority_set */ - NULL, /* priority_get */ - NULL /* em_meta_artwork_get */ -}; - -Eina_Bool -xine_module_init(void) -{ - if (_emotion_init_count > 0) - { - _emotion_init_count++; - return EINA_TRUE; - } - - eina_threads_init(); - eina_log_threads_enable(); - _emotion_xine_log_domain = eina_log_domain_register - ("emotion-xine", EINA_COLOR_LIGHTCYAN); - if (_emotion_xine_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion-xine'"); - return EINA_FALSE; - } - - if (!_emotion_module_register(&em_engine)) - { - CRI("Could not register module %p", &em_engine); - eina_log_domain_unregister(_emotion_xine_log_domain); - _emotion_xine_log_domain = -1; - return EINA_FALSE; - } - - _emotion_init_count = 1; - return EINA_TRUE; -} - -void -xine_module_shutdown(void) -{ - if (_emotion_init_count > 1) - { - _emotion_init_count--; - return; - } - else if (_emotion_init_count == 0) - { - EINA_LOG_ERR("too many xine_module_shutdown()"); - return; - } - _emotion_init_count = 0; - - _emotion_module_unregister(&em_engine); - - eina_log_domain_unregister(_emotion_xine_log_domain); - _emotion_xine_log_domain = -1; -} - -#ifndef EMOTION_STATIC_BUILD_XINE - -EINA_MODULE_INIT(xine_module_init); -EINA_MODULE_SHUTDOWN(xine_module_shutdown); - -#endif - -#if 0 -void -em_debug(Emotion_Xine_Video *ev) -{ - int has_chapters = 0; - int max_spu = 0; - int max_audio = 0; - int video_channels = 0; - int video_streams = 0; - int video_seekable = 0; - char *title; - char *comment; - char *artist; - char *genre; - char *album; - char *year; - char *cdindex_discid; - int video_channel = 0; - int audio_channel = 0; - int spu_channel = 0; - int video_ratio = 0; - int audio_mode = 0; - -// return; - has_chapters = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_HAS_CHAPTERS); - max_spu = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL); - max_audio = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL); - video_channels = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_CHANNELS); - video_streams = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_STREAMS); - video_seekable = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_SEEKABLE); - title = xine_get_meta_info(ev->stream, XINE_META_INFO_TITLE); - comment = xine_get_meta_info(ev->stream, XINE_META_INFO_COMMENT); - artist = xine_get_meta_info(ev->stream, XINE_META_INFO_ARTIST); - genre = xine_get_meta_info(ev->stream, XINE_META_INFO_GENRE); - album = xine_get_meta_info(ev->stream, XINE_META_INFO_ALBUM); - year = xine_get_meta_info(ev->stream, XINE_META_INFO_YEAR); - cdindex_discid = xine_get_meta_info(ev->stream, XINE_META_INFO_CDINDEX_DISCID); - video_channel = xine_get_param(ev->stream, XINE_PARAM_VIDEO_CHANNEL); - audio_channel = xine_get_param(ev->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL); - spu_channel = xine_get_param(ev->stream, XINE_PARAM_SPU_CHANNEL); - video_ratio = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_VIDEO_RATIO); - audio_mode = xine_get_stream_info(ev->stream, XINE_STREAM_INFO_AUDIO_MODE); - DBG("has_chapters = %i", has_chapters); - DBG("max_spu = %i", max_spu); - DBG("max_audio = %i", max_audio); - DBG("video_channels = %i", video_channels); - DBG("video_streams = %i", video_streams); - DBG("video_seekable = %i", video_seekable); - DBG("title = %s", title); - DBG("comment = %s", comment); - DBG("artist = %s", artist); - DBG("genre = %s", genre); - DBG("album = %s", album); - DBG("year = %s", year); - DBG("cdindex_discid = %s", cdindex_discid); - DBG("video_channel = %i", video_channel); - DBG("audio_channel = %i", audio_channel); - DBG("spu_channels = %i", spu_channel); - DBG("video_ratio = %i", video_ratio); - DBG("audio_mode = %i", audio_mode); - { - int i; - - for (i = 0; i <= max_audio; i++) - { - char lang[XINE_LANG_MAX + 1]; - char buf[128] = "NONE"; - - lang[0] = 0; - if (xine_get_audio_lang(ev->stream, i, lang)) - eina_strlcpy(buf, lang, sizeof(buf)); - DBG(" AUDIO %i = %s", i, buf); - } - for (i = 0; i <= max_spu; i++) - { - char lang[XINE_LANG_MAX + 1]; - char buf[128] = "NONE"; - - lang[0] = 0; - if (xine_get_spu_lang(ev->stream, i, lang)) - eina_strlcpy(buf, lang, sizeof(buf)); - DBG(" SPU %i = %s", i, buf); - } - } -} -#endif diff --git a/src/modules/emotion/xine/emotion_xine.h b/src/modules/emotion/xine/emotion_xine.h deleted file mode 100644 index 9807624e14..0000000000 --- a/src/modules/emotion/xine/emotion_xine.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef EMOTION_XINE_H -#define EMOTION_XINE_H - -#include -#include -#include -#include -#include - -typedef struct _Emotion_Xine_Video Emotion_Xine_Video; -typedef struct _Emotion_Xine_Video_Frame Emotion_Xine_Video_Frame; -typedef struct _Emotion_Xine_Event Emotion_Xine_Event; - -struct _Emotion_Xine_Video -{ - xine_t *decoder; - xine_video_port_t *video; - xine_audio_port_t *audio; - xine_stream_t *stream; - xine_event_queue_t *queue; - volatile double len; - volatile double pos; - volatile double last_pos; - volatile double volume; - volatile double buffer; - double fps; - double ratio; - int w, h; - Evas_Object *obj; - volatile Emotion_Xine_Video_Frame *cur_frame; - volatile int get_poslen; - volatile int spu_channel; - volatile int audio_channel; - volatile int video_channel; - volatile int fq; - Emotion_Vis vis; - int fd_read; - int fd_write; - Ecore_Fd_Handler *fd_handler; - int fd_ev_read; - int fd_ev_write; - Ecore_Fd_Handler *fd_ev_handler; - Ecore_Animator *anim; - unsigned char play : 1; - unsigned char just_loaded : 1; - unsigned char video_mute : 1; - unsigned char audio_mute : 1; - unsigned char spu_mute : 1; - Eina_Bool opt_no_video : 1; - Eina_Bool opt_no_audio : 1; - volatile unsigned char delete_me : 1; - volatile unsigned char no_time : 1; - volatile unsigned char opening : 1; - volatile unsigned char closing : 1; - volatile unsigned char have_vo : 1; - volatile unsigned char play_ok : 1; - - pthread_t get_pos_len_th; - pthread_cond_t get_pos_len_cond; - pthread_mutex_t get_pos_len_mutex; - - pthread_t slave_th; - int fd_slave_read; - int fd_slave_write; - - unsigned char get_pos_thread_deleted : 1; -}; - -struct _Emotion_Xine_Video_Frame -{ - int w, h; - double ratio; - Emotion_Format format; - unsigned char *y, *u, *v; - unsigned char *bgra_data; - int y_stride, u_stride, v_stride; - Evas_Object *obj; - double timestamp; - void (*done_func)(void *data); - void *done_data; - void *frame; -}; - -struct _Emotion_Xine_Event -{ - int type; - void *xine_event; - int mtype; -}; - -#ifdef DBG -#undef DBG -#endif -#define DBG(...) EINA_LOG_DOM_DBG(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef INF -#undef INF -#endif -#define INF(...) EINA_LOG_DOM_INFO(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef WRN -#undef WRN -#endif -#define WRN(...) EINA_LOG_DOM_WARN(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef ERR -#undef ERR -#endif -#define ERR(...) EINA_LOG_DOM_ERR(_emotion_xine_log_domain, __VA_ARGS__) - -#ifdef CRI -#undef CRI -#endif -#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_xine_log_domain, __VA_ARGS__) - -extern int _emotion_xine_log_domain; - -#endif diff --git a/src/modules/emotion/xine/emotion_xine_vo_out.c b/src/modules/emotion/xine/emotion_xine_vo_out.c deleted file mode 100644 index 01c18f8894..0000000000 --- a/src/modules/emotion/xine/emotion_xine_vo_out.c +++ /dev/null @@ -1,766 +0,0 @@ -/***************************************************************************/ -/*** emotion xine display engine ***/ -/***************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include - -#include -#include -#include - -#include "emotion_modules.h" -#include "emotion_xine.h" - -#include -#include -#include -#include -#include - -#define BLEND_BYTE(dst, src, o) (((src)*o + ((dst)*(0xf-o)))/0xf) - -/***************************************************************************/ -typedef struct _Emotion_Frame Emotion_Frame; -typedef struct _Emotion_Driver Emotion_Driver; -typedef struct _Emotion_Class Emotion_Class; -typedef struct _Emotion_Lut Emotion_Lut; - -struct _Emotion_Frame -{ - vo_frame_t vo_frame; - int width; - int height; - double ratio; - int format; - xine_t *xine; - - Emotion_Xine_Video_Frame frame; - unsigned char in_use : 1; -}; - -struct _Emotion_Driver -{ - vo_driver_t vo_driver; - config_values_t *config; - int ratio; - xine_t *xine; - Emotion_Xine_Video *ev; -}; - -struct _Emotion_Class -{ - video_driver_class_t driver_class; - config_values_t *config; - xine_t *xine; -}; - -struct _Emotion_Lut -{ - uint8_t cb : 8; - uint8_t cr : 8; - uint8_t y : 8; - uint8_t foo : 8; -} __attribute__ ((packed)); - -typedef void (*done_func_type)(void *data); - -/***************************************************************************/ -static void *_emotion_class_init (xine_t *xine, void *visual); -static void _emotion_class_dispose (video_driver_class_t *driver_class); -static char *_emotion_class_identifier_get (video_driver_class_t *driver_class); -static char *_emotion_class_description_get (video_driver_class_t *driver_class); - -static vo_driver_t *_emotion_open (video_driver_class_t *driver_class, const void *visual); -static void _emotion_dispose (vo_driver_t *vo_driver); - -static int _emotion_redraw (vo_driver_t *vo_driver); - -static uint32_t _emotion_capabilities_get (vo_driver_t *vo_driver); -static int _emotion_gui_data_exchange (vo_driver_t *vo_driver, int data_type, void *data); - -static int _emotion_property_set (vo_driver_t *vo_driver, int property, int value); -static int _emotion_property_get (vo_driver_t *vo_driver, int property); -static void _emotion_property_min_max_get (vo_driver_t *vo_driver, int property, int *min, int *max); - -static vo_frame_t *_emotion_frame_alloc (vo_driver_t *vo_driver); -static void _emotion_frame_dispose (vo_frame_t *vo_frame); -static void _emotion_frame_format_update (vo_driver_t *vo_driver, vo_frame_t *vo_frame, uint32_t width, uint32_t height, double ratio, int format, int flags); -static void _emotion_frame_display (vo_driver_t *vo_driver, vo_frame_t *vo_frame); -static void _emotion_frame_field (vo_frame_t *vo_frame, int which_field); - -static void _emotion_frame_data_free (Emotion_Frame *fr); -static void _emotion_frame_data_unlock (Emotion_Frame *fr); - -static void _emotion_overlay_begin (vo_driver_t *vo_driver, vo_frame_t *vo_frame, int changed); -static void _emotion_overlay_end (vo_driver_t *vo_driver, vo_frame_t *vo_frame); -static void _emotion_overlay_blend (vo_driver_t *vo_driver, vo_frame_t *vo_frame, vo_overlay_t *vo_overlay); - -static void _emotion_overlay_mem_blend_8 (uint8_t *mem, uint8_t val, uint8_t o, size_t sz); -static void _emotion_overlay_blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl, int dst_width, int dst_height, int dst_pitches[3]); - -static void _emotion_yuy2_to_bgra32 (int width, int height, unsigned char *src, unsigned char *dst); - -/***************************************************************************/ -static vo_info_t _emotion_info = -{ - 1, /* priority */ - XINE_VISUAL_TYPE_NONE /* visual type */ -}; - -plugin_info_t emotion_xine_plugin_info[] = -{ - { PLUGIN_VIDEO_OUT, 21, "emotion", XINE_VERSION_CODE, &_emotion_info, _emotion_class_init }, - { PLUGIN_VIDEO_OUT, 22, "emotion", XINE_VERSION_CODE, &_emotion_info, _emotion_class_init }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; - -/***************************************************************************/ -static void * -_emotion_class_init(xine_t *xine, void *visual EINA_UNUSED) -{ - Emotion_Class *cl; - -// DBG(""); - cl = (Emotion_Class *) malloc(sizeof(Emotion_Class)); - if (!cl) return NULL; - cl->driver_class.open_plugin = _emotion_open; -#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) - cl->driver_class.get_identifier = _emotion_class_identifier_get; - cl->driver_class.get_description = _emotion_class_description_get; -#else - cl->driver_class.identifier = _emotion_class_identifier_get(NULL); - cl->driver_class.description = _emotion_class_description_get(NULL); -#endif - cl->driver_class.dispose = _emotion_class_dispose; - cl->config = xine->config; - cl->xine = xine; - - return cl; -} - -static void -_emotion_class_dispose(video_driver_class_t *driver_class) -{ - Emotion_Class *cl; - - cl = (Emotion_Class *)driver_class; - free(cl); -} - -static char * -_emotion_class_identifier_get(video_driver_class_t *driver_class EINA_UNUSED) -{ - return "emotion"; -} - -static char * -_emotion_class_description_get(video_driver_class_t *driver_class EINA_UNUSED) -{ - return "Emotion xine video output plugin"; -} - -/***************************************************************************/ -static vo_driver_t * -_emotion_open(video_driver_class_t *driver_class, const void *visual) -{ - Emotion_Class *cl; - Emotion_Driver *dv; - - cl = (Emotion_Class *)driver_class; - /* visual here is the data ptr passed to xine_open_video_driver() */ -// DBG(""); - dv = (Emotion_Driver *)malloc(sizeof(Emotion_Driver)); - if (!dv) return NULL; - - dv->config = cl->config; - dv->xine = cl->xine; - dv->ratio = XINE_VO_ASPECT_AUTO; - dv->vo_driver.get_capabilities = _emotion_capabilities_get; - dv->vo_driver.alloc_frame = _emotion_frame_alloc; - dv->vo_driver.update_frame_format = _emotion_frame_format_update; - dv->vo_driver.overlay_begin = _emotion_overlay_begin; - dv->vo_driver.overlay_blend = _emotion_overlay_blend; - dv->vo_driver.overlay_end = _emotion_overlay_end; - dv->vo_driver.display_frame = _emotion_frame_display; - dv->vo_driver.get_property = _emotion_property_get; - dv->vo_driver.set_property = _emotion_property_set; - dv->vo_driver.get_property_min_max = _emotion_property_min_max_get; - dv->vo_driver.gui_data_exchange = _emotion_gui_data_exchange; - dv->vo_driver.dispose = _emotion_dispose; - dv->vo_driver.redraw_needed = _emotion_redraw; - dv->ev = (Emotion_Xine_Video *)visual; - dv->ev->have_vo = 1; - DBG("vo_driver = %p", &dv->vo_driver); - return &dv->vo_driver; -} - -static void -_emotion_dispose(vo_driver_t *vo_driver) -{ - Emotion_Driver *dv; - - dv = (Emotion_Driver *)vo_driver; - dv->ev->have_vo = 0; - DBG("vo_driver = %p", dv); - free(dv); -} - -/***************************************************************************/ -static int -_emotion_redraw(vo_driver_t *vo_driver EINA_UNUSED) -{ -// DBG(""); - return 0; -} - -/***************************************************************************/ -static uint32_t -_emotion_capabilities_get(vo_driver_t *vo_driver EINA_UNUSED) -{ -// DBG(""); - return VO_CAP_YV12 | VO_CAP_YUY2; -} - -/***************************************************************************/ -static int -_emotion_gui_data_exchange(vo_driver_t *vo_driver EINA_UNUSED, int data_type, void *data EINA_UNUSED) -{ -// DBG(""); - switch (data_type) - { - case XINE_GUI_SEND_COMPLETION_EVENT: - break; - case XINE_GUI_SEND_DRAWABLE_CHANGED: - break; - case XINE_GUI_SEND_EXPOSE_EVENT: - break; - case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: - break; - case XINE_GUI_SEND_VIDEOWIN_VISIBLE: - break; - case XINE_GUI_SEND_SELECT_VISUAL: - break; - default: - break; - } - return 0; -} - -/***************************************************************************/ -static int -_emotion_property_set(vo_driver_t *vo_driver, int property, int value) -{ - Emotion_Driver *dv; - - dv = (Emotion_Driver *)vo_driver; -// DBG(""); - switch (property) - { - case VO_PROP_ASPECT_RATIO: - if (value >= XINE_VO_ASPECT_NUM_RATIOS) - value = XINE_VO_ASPECT_AUTO; -// DBG("DRIVER RATIO SET %i!", value); - dv->ratio = value; - break; - default: - break; - } - return value; -} - -static int -_emotion_property_get(vo_driver_t *vo_driver, int property) -{ - Emotion_Driver *dv; - - dv = (Emotion_Driver *)vo_driver; -// DBG(""); - switch (property) - { - case VO_PROP_ASPECT_RATIO: - return dv->ratio; - break; - default: - break; - } - return 0; -} - -static void -_emotion_property_min_max_get(vo_driver_t *vo_driver EINA_UNUSED, int property EINA_UNUSED, int *min, int *max) -{ -// DBG(""); - *min = 0; - *max = 0; -} - -/***************************************************************************/ -static vo_frame_t * -_emotion_frame_alloc(vo_driver_t *vo_driver EINA_UNUSED) -{ - Emotion_Frame *fr; - -// DBG(""); - fr = (Emotion_Frame *)calloc(1, sizeof(Emotion_Frame)); - if (!fr) return NULL; - - fr->vo_frame.base[0] = NULL; - fr->vo_frame.base[1] = NULL; - fr->vo_frame.base[2] = NULL; - - fr->vo_frame.proc_slice = NULL; - fr->vo_frame.proc_frame = NULL; - fr->vo_frame.field = _emotion_frame_field; - fr->vo_frame.dispose = _emotion_frame_dispose; - fr->vo_frame.driver = vo_driver; - - return (vo_frame_t *)fr; -} - -static void -_emotion_frame_dispose(vo_frame_t *vo_frame) -{ - Emotion_Frame *fr; - - fr = (Emotion_Frame *)vo_frame; -// DBG(""); - _emotion_frame_data_free(fr); - free(fr); -} - -static void -_emotion_frame_format_update(vo_driver_t *vo_driver, vo_frame_t *vo_frame, uint32_t width, uint32_t height, double ratio, int format, int flags EINA_UNUSED) -{ - Emotion_Driver *dv; - Emotion_Frame *fr; - - dv = (Emotion_Driver *)vo_driver; - fr = (Emotion_Frame *)vo_frame; - - if ((fr->width != (int)width) || (fr->height != (int)height) || - (fr->format != format) || (!fr->vo_frame.base[0])) - { -// DBG(""); - _emotion_frame_data_free(fr); - - fr->width = width; - fr->height = height; - fr->format = format; - - switch (format) - { - case XINE_IMGFMT_YV12: - { - int y_size, uv_size; - - fr->frame.format = EMOTION_FORMAT_YV12; - fr->vo_frame.pitches[0] = 8 * ((width + 7) / 8); - fr->vo_frame.pitches[1] = 8 * ((width + 15) / 16); - fr->vo_frame.pitches[2] = 8 * ((width + 15) / 16); - - y_size = fr->vo_frame.pitches[0] * height; - uv_size = fr->vo_frame.pitches[1] * ((height + 1) / 2); - - fr->vo_frame.base[0] = malloc(y_size + (2 * uv_size)); - fr->vo_frame.base[1] = fr->vo_frame.base[0] + y_size + uv_size; - fr->vo_frame.base[2] = fr->vo_frame.base[0] + y_size; - fr->frame.w = fr->width; - fr->frame.h = fr->height; - fr->frame.ratio = fr->vo_frame.ratio; - fr->frame.y = fr->vo_frame.base[0]; - fr->frame.u = fr->vo_frame.base[1]; - fr->frame.v = fr->vo_frame.base[2]; - fr->frame.bgra_data = NULL; - fr->frame.y_stride = fr->vo_frame.pitches[0]; - fr->frame.u_stride = fr->vo_frame.pitches[1]; - fr->frame.v_stride = fr->vo_frame.pitches[2]; - fr->frame.obj = dv->ev->obj; - } - break; - case XINE_IMGFMT_YUY2: - { - fr->frame.format = EMOTION_FORMAT_BGRA; - fr->vo_frame.pitches[0] = 8 * ((width + 3) / 4); - fr->vo_frame.pitches[1] = 0; - fr->vo_frame.pitches[2] = 0; - - fr->vo_frame.base[0] = malloc(fr->vo_frame.pitches[0] * height); - fr->vo_frame.base[1] = NULL; - fr->vo_frame.base[2] = NULL; - - fr->frame.w = fr->width; - fr->frame.h = fr->height; - fr->frame.ratio = fr->vo_frame.ratio; - fr->frame.y = NULL; - fr->frame.u = NULL; - fr->frame.v = NULL; - fr->frame.bgra_data = malloc(fr->width * fr->height * 4); - fr->frame.y_stride = 0; - fr->frame.u_stride = 0; - fr->frame.v_stride = 0; - fr->frame.obj = dv->ev->obj; - } - break; - default: - break; - } - if (((format == XINE_IMGFMT_YV12) - && ((!fr->vo_frame.base[0]) - || (!fr->vo_frame.base[1]) - || (!fr->vo_frame.base[2]))) - || ((format == XINE_IMGFMT_YUY2) - && ((!fr->vo_frame.base[0]) - || (!fr->frame.bgra_data)))) - { - _emotion_frame_data_free(fr); - } - } - fr->frame.ratio = fr->vo_frame.ratio; - fr->ratio = ratio; -} - -static void -_emotion_frame_display(vo_driver_t *vo_driver, vo_frame_t *vo_frame) -{ - Emotion_Driver *dv; - Emotion_Frame *fr; - - dv = (Emotion_Driver *)vo_driver; - fr = (Emotion_Frame *)vo_frame; -// DBG("fq %i %p", dv->ev->fq, dv->ev); -// if my frame queue is too deep ( > 4 frames) simply block and wait for them -// to drain -// while (dv->ev->fq > 4) usleep(1); - if (dv->ev) - { - void *buf; - - if (dv->ev->closing) return; - if (fr->format == XINE_IMGFMT_YUY2) - { - _emotion_yuy2_to_bgra32(fr->width, fr->height, fr->vo_frame.base[0], fr->frame.bgra_data); - } - - buf = &(fr->frame); - fr->frame.timestamp = (double)fr->vo_frame.vpts / 90000.0; - fr->frame.done_func = (done_func_type)_emotion_frame_data_unlock; - fr->frame.done_data = fr; -// DBG("FRAME FOR %p", dv->ev); - if (write(dv->ev->fd_write, &buf, sizeof(void *)) < 0) perror("write"); -// DBG("-- FRAME DEC %p == %i", fr->frame.obj, ret); - fr->in_use = 1; - dv->ev->fq++; - } - /* hmm - must find a way to sanely copy data out... FIXME problem */ -// fr->vo_frame.free(&fr->vo_frame); -} - -static void -_emotion_frame_field(vo_frame_t *vo_frame EINA_UNUSED, int which_field EINA_UNUSED) -{ -// DBG(""); -} - -/***************************************************************************/ -static void -_emotion_frame_data_free(Emotion_Frame *fr) -{ - if (fr->vo_frame.base[0]) - { - free(fr->vo_frame.base[0]); - fr->vo_frame.base[0] = NULL; - fr->vo_frame.base[1] = NULL; - fr->vo_frame.base[2] = NULL; - fr->frame.y = fr->vo_frame.base[0]; - fr->frame.u = fr->vo_frame.base[1]; - fr->frame.v = fr->vo_frame.base[2]; - } - if (fr->frame.bgra_data) - { - free(fr->frame.bgra_data); - fr->frame.bgra_data = NULL; - } -} - -static void -_emotion_frame_data_unlock(Emotion_Frame *fr) -{ -// DBG(""); - if (fr->in_use) - { - fr->vo_frame.free(&fr->vo_frame); - fr->in_use = 0; - } -} - -/***************************************************************************/ -static void -_emotion_overlay_begin(vo_driver_t *vo_driver EINA_UNUSED, vo_frame_t *vo_frame EINA_UNUSED, int changed EINA_UNUSED) -{ -// DBG(""); -} - -static void -_emotion_overlay_end(vo_driver_t *vo_driver EINA_UNUSED, vo_frame_t *vo_frame EINA_UNUSED) -{ -// DBG(""); -} - -static void -_emotion_overlay_blend(vo_driver_t *vo_driver EINA_UNUSED, vo_frame_t *vo_frame, vo_overlay_t *vo_overlay EINA_UNUSED) -{ - Emotion_Frame *fr; - - fr = (Emotion_Frame *)vo_frame; -// DBG(""); - _emotion_overlay_blend_yuv(fr->vo_frame.base, vo_overlay, - fr->width, fr->height, - fr->vo_frame.pitches); -} - -static void _emotion_overlay_mem_blend_8(uint8_t *mem, uint8_t val, uint8_t o, size_t sz) -{ - uint8_t *limit = mem + sz; - while (mem < limit) - { - *mem = BLEND_BYTE(*mem, val, o); - mem++; - } -} - -static void _emotion_overlay_blend_yuv(uint8_t *dst_base[3], vo_overlay_t * img_overl, int dst_width, int dst_height, int dst_pitches[3]) -{ - Emotion_Lut *my_clut; - uint8_t *my_trans; - int src_width; - int src_height; - rle_elem_t *rle; - rle_elem_t *rle_limit; - int x_off; - int y_off; - int ymask, xmask; - int rle_this_bite; - int rle_remainder; - int rlelen; - int x, y; - int hili_right; - uint8_t clr = 0; - - src_width = img_overl->width; - src_height = img_overl->height; - rle = img_overl->rle; - rle_limit = rle + img_overl->num_rle; - x_off = img_overl->x; - y_off = img_overl->y; - - if (!rle) return; - - uint8_t *dst_y = dst_base[0] + dst_pitches[0] * y_off + x_off; - uint8_t *dst_cr = dst_base[2] + (y_off / 2) * dst_pitches[1] + (x_off / 2) + 1; - uint8_t *dst_cb = dst_base[1] + (y_off / 2) * dst_pitches[2] + (x_off / 2) + 1; - my_clut = (Emotion_Lut *) img_overl->hili_color; - my_trans = img_overl->hili_trans; - - /* avoid wraping overlay if drawing to small image */ - if( (x_off + img_overl->hili_right) < dst_width ) - hili_right = img_overl->hili_right; - else - hili_right = dst_width - 1 - x_off; - - /* avoid buffer overflow */ - if( (src_height + y_off) >= dst_height ) - src_height = dst_height - 1 - y_off; - - rlelen=rle_remainder=0; - for (y = 0; y < src_height; y++) - { - ymask = ((img_overl->hili_top > y) || (img_overl->hili_bottom < y)); - xmask = 0; - - for (x = 0; x < src_width;) - { - uint16_t o; - - if (rlelen == 0) - { - rle_remainder = rlelen = rle->len; - clr = rle->color; - rle++; - } - if (rle_remainder == 0) - { - rle_remainder = rlelen; - } - if ((rle_remainder + x) > src_width) - { - /* Do something for long rlelengths */ - rle_remainder = src_width - x; - } - - if (ymask == 0) - { - if (x <= img_overl->hili_left) - { - /* Starts outside clip area */ - if ((x + rle_remainder - 1) > img_overl->hili_left ) - { - /* Cutting needed, starts outside, ends inside */ - rle_this_bite = (img_overl->hili_left - x + 1); - rle_remainder -= rle_this_bite; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - else - { - /* no cutting needed, starts outside, ends outside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - } - else if (x < hili_right) - { - /* Starts inside clip area */ - if ((x + rle_remainder) > hili_right ) - { - /* Cutting needed, starts inside, ends outside */ - rle_this_bite = (hili_right - x); - rle_remainder -= rle_this_bite; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->hili_color; - my_trans = img_overl->hili_trans; - xmask++; - } - else - { - /* no cutting needed, starts inside, ends inside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->hili_color; - my_trans = img_overl->hili_trans; - xmask++; - } - } - else if (x >= hili_right) - { - /* Starts outside clip area, ends outsite clip area */ - if ((x + rle_remainder ) > src_width ) - { - /* Cutting needed, starts outside, ends at right edge */ - /* It should never reach here due to the earlier test of src_width */ - rle_this_bite = (src_width - x ); - rle_remainder -= rle_this_bite; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - else - { - /* no cutting needed, starts outside, ends outside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - } - } - else - { - /* Outside clip are due to y */ - /* no cutting needed, starts outside, ends outside */ - rle_this_bite = rle_remainder; - rle_remainder = 0; - rlelen -= rle_this_bite; - my_clut = (Emotion_Lut *) img_overl->color; - my_trans = img_overl->trans; - xmask = 0; - } - o = my_trans[clr]; - if (o) - { - if (o >= 15) - { - memset(dst_y + x, my_clut[clr].y, rle_this_bite); - if (y & 1) - { - memset(dst_cr + (x >> 1), my_clut[clr].cr, (rle_this_bite+1) >> 1); - memset(dst_cb + (x >> 1), my_clut[clr].cb, (rle_this_bite+1) >> 1); - } - } - else - { - _emotion_overlay_mem_blend_8(dst_y + x, my_clut[clr].y, o, rle_this_bite); - if (y & 1) - { - /* Blending cr and cb should use a different function, with pre -128 to each sample */ - _emotion_overlay_mem_blend_8(dst_cr + (x >> 1), my_clut[clr].cr, o, (rle_this_bite+1) >> 1); - _emotion_overlay_mem_blend_8(dst_cb + (x >> 1), my_clut[clr].cb, o, (rle_this_bite+1) >> 1); - } - } - } - x += rle_this_bite; - if (rle >= rle_limit) - { - break; - } - } - if (rle >= rle_limit) - { - break; - } - - dst_y += dst_pitches[0]; - - if (y & 1) - { - dst_cr += dst_pitches[2]; - dst_cb += dst_pitches[1]; - } - } -} - -//TODO: Really need to improve this converter! -#define LIMIT(x) ((x) > 0xff ? 0xff : ((x) < 0 ? 0 : (x))) - -static void -_emotion_yuy2_to_bgra32(int width, int height, unsigned char *src, unsigned char *dst) -{ - int i, j; - unsigned char *y, *u, *v; - - y = src; - u = src + 1; - v = src + 3; - for (i = 0; i < width; i++) - { - for (j = 0; j < height; j++) - { - *dst++ = LIMIT(1.164 * (*y - 16) + 2.018 * (*u - 128)); - *dst++ = LIMIT(1.164 * (*y - 16) - 0.813 * (*v - 128) - 0.391 * (*u - 128)); - *dst++ = LIMIT(1.164 * (*y - 16) + 1.596 * (*v - 128)); - *dst++ = 0; - - y += 2; - if (j % 2 == 1) - { - u += 4; - v += 4; - } - } - } -} diff --git a/src/modules/emotion/xine/meson.build b/src/modules/emotion/xine/meson.build deleted file mode 100644 index 038d6d2eb1..0000000000 --- a/src/modules/emotion/xine/meson.build +++ /dev/null @@ -1,16 +0,0 @@ -generic_src = files([ - 'emotion_xine.h', - 'emotion_xine.c', - 'emotion_xine_vo_out.c', -]) - -generic_deps = dependency('libxine') - -shared_module(emotion_loader, - generic_src, - include_directories : config_dir, - dependencies: [eina, evas, emotion, generic_deps], - install: true, - install_dir : mod_install_dir, - c_args : package_c_args, -) diff --git a/src/modules/evas/engines/gl_common/evas_gl_rectangle.c b/src/modules/evas/engines/gl_common/evas_gl_rectangle.c index a188467b58..b070a7157a 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_rectangle.c +++ b/src/modules/evas/engines/gl_common/evas_gl_rectangle.c @@ -12,7 +12,7 @@ evas_gl_common_rect_draw(Evas_Engine_GL_Context *gc, int x, int y, int w, int h) Evas_GL_Texture *mtex = NULL; if ((w <= 0) || (h <= 0)) return; - if (!(RECTS_INTERSECT(x, y, w, h, 0, 0, gc->w, gc->h))) return; + if (!(RECTS_INTERSECT(x, y, w, h, 0, 0, gc->shared->w, gc->shared->h))) return; /* save out clip info */ c = gc->dc->clip.use; cx = gc->dc->clip.x; cy = gc->dc->clip.y; cw = gc->dc->clip.w; ch = gc->dc->clip.h; diff --git a/src/tests/ecore/ecore_suite.c b/src/tests/ecore/ecore_suite.c index b9248a814a..a0f6d19aba 100644 --- a/src/tests/ecore/ecore_suite.c +++ b/src/tests/ecore/ecore_suite.c @@ -30,6 +30,7 @@ static const Efl_Test_Case etc[] = { { "Ecore_Job", ecore_test_ecore_job }, { "Ecore_Args", ecore_test_ecore_args }, { "Ecore_Pipe", ecore_test_ecore_pipe }, + { "Ecore_Evas_Selection", ecore_test_ecore_evas_selection }, { NULL, NULL } }; diff --git a/src/tests/ecore/ecore_suite.h b/src/tests/ecore/ecore_suite.h index a3327412fe..2621535f59 100644 --- a/src/tests/ecore/ecore_suite.h +++ b/src/tests/ecore/ecore_suite.h @@ -23,5 +23,6 @@ void ecore_test_ecore_file(TCase *tc); void ecore_test_ecore_job(TCase *tc); void ecore_test_ecore_args(TCase *tc); void ecore_test_ecore_pipe(TCase *tc); +void ecore_test_ecore_evas_selection(TCase *tc); #endif /* _ECORE_SUITE_H */ diff --git a/src/tests/ecore/ecore_test_ecore_evas.c b/src/tests/ecore/ecore_test_ecore_evas.c index 2e53f62082..0e7b09c41b 100644 --- a/src/tests/ecore/ecore_test_ecore_evas.c +++ b/src/tests/ecore/ecore_test_ecore_evas.c @@ -3,6 +3,7 @@ #endif #include +#include #include "ecore_suite.h" @@ -70,8 +71,51 @@ EFL_START_TEST(ecore_test_ecore_evas_cocoa) } EFL_END_TEST +static Eina_Value +_verify_and_exit(void *data, const Eina_Value value, const Eina_Future *dead_future EINA_UNUSED) +{ + ck_assert_ptr_eq(eina_value_type_get(&value), EINA_VALUE_TYPE_CONTENT); + Eina_Content *content = eina_value_to_content(&value); + Eina_Content *reference = data; + + ck_assert_int_eq(eina_content_data_get(content).len, eina_content_data_get(reference).len); + ck_assert_str_eq(eina_content_data_get(content).mem, eina_content_data_get(reference).mem); + ck_assert_str_eq(eina_content_type_get(content), eina_content_type_get(reference)); + + efl_loop_quit(efl_main_loop_get(), eina_value_int_init(0)); + + return EINA_VALUE_EMPTY; +} + +EFL_START_TEST(ecore_test_ecore_evas_fallback_selection) +{ + Ecore_Evas *ee; + ecore_evas_init(); + + ee = ecore_evas_buffer_new(WINDOW_WIDTH, WINDOW_HEIGHT); + fail_if(ee == NULL); + + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + ck_assert_int_eq(ecore_evas_selection_exists(ee, 0, i), EINA_FALSE); + } + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + Eina_Content *ref = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + ecore_evas_selection_set(ee, 0, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER, content); + + const char *types[] = {eina_stringshare_add("text/plain")}; + + Eina_Future *f = ecore_evas_selection_get(ee, 0, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER, EINA_C_ARRAY_ITERATOR_NEW(types)); + ck_assert_ptr_ne(f, NULL); + eina_future_then(f, _verify_and_exit, ref); + efl_task_run(efl_main_loop_get()); + ecore_evas_shutdown(); +} +EFL_END_TEST + void ecore_test_ecore_evas(TCase *tc) { tcase_add_test(tc, ecore_test_ecore_evas_associate); tcase_add_test(tc, ecore_test_ecore_evas_cocoa); + tcase_add_test(tc, ecore_test_ecore_evas_fallback_selection); } diff --git a/src/tests/ecore/ecore_test_ecore_evas_selection.c b/src/tests/ecore/ecore_test_ecore_evas_selection.c new file mode 100644 index 0000000000..9efc5fe722 --- /dev/null +++ b/src/tests/ecore/ecore_test_ecore_evas_selection.c @@ -0,0 +1,89 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "ecore_suite.h" + +#define WINDOW_HEIGHT 200 +#define WINDOW_WIDTH 200 + +static int log_abort; +static int log_abort_level; + +void +fail_on_errors_teardown(void) +{ + eina_log_abort_on_critical_set(log_abort); + eina_log_abort_on_critical_level_set(log_abort_level); +} + +void +fail_on_errors_setup(void) +{ + log_abort = eina_log_abort_on_critical_get(); + log_abort_level = eina_log_abort_on_critical_level_get(); + eina_log_abort_on_critical_level_set(2); + eina_log_abort_on_critical_set(1); +} + +static Ecore_Evas *ee; + +void +_setup(void) +{ + ecore_evas_init(); + ee = ecore_evas_buffer_new(50, 50); +} + +void +_teardown(void) +{ + ecore_evas_free(ee); + ecore_evas_shutdown(); +} + +EFL_START_TEST(ecore_test_selection_get_twice) +{ + //this is just running this and checking that we do not error + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + const char *types[] = {eina_stringshare_add("text/plain")}; + ck_assert_ptr_ne(ecore_evas_selection_get(ee, 0, i, EINA_C_ARRAY_ITERATOR_NEW(types)), NULL); + } + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + const char *types[] = {eina_stringshare_add("text/plain")}; + ck_assert_ptr_ne(ecore_evas_selection_get(ee, 0, i, EINA_C_ARRAY_ITERATOR_NEW(types)), NULL); + } +} +EFL_END_TEST + +EFL_START_TEST(ecore_test_selection_claim_twice) +{ + //this is just running this and checking that we do not error + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + ck_assert_int_eq(ecore_evas_selection_set(ee, 0, i, content), EINA_TRUE); + } + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) continue; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("asdf"), "text/plain"); + ck_assert_int_eq(ecore_evas_selection_set(ee, 0, i, content), EINA_TRUE); + } +} +EFL_END_TEST +void ecore_test_ecore_evas_selection(TCase *tc) +{ + tcase_add_checked_fixture(tc, fail_on_errors_setup, fail_on_errors_teardown); + tcase_add_checked_fixture(tc, _setup, _teardown); + tcase_add_test(tc, ecore_test_selection_get_twice); + tcase_add_test(tc, ecore_test_selection_claim_twice); +} diff --git a/src/tests/ecore/meson.build b/src/tests/ecore/meson.build index 9ce6848ce2..48c9350638 100644 --- a/src/tests/ecore/meson.build +++ b/src/tests/ecore/meson.build @@ -13,6 +13,7 @@ ecore_suite_src = [ 'ecore_test_job.c', 'ecore_test_args.c', 'ecore_test_pipe.c', + 'ecore_test_ecore_evas_selection.c', 'ecore_suite.h' ] diff --git a/src/tests/efl_mono/Structs.cs b/src/tests/efl_mono/Structs.cs index 151bc8388d..334057c907 100644 --- a/src/tests/efl_mono/Structs.cs +++ b/src/tests/efl_mono/Structs.cs @@ -499,15 +499,14 @@ internal class TestStructTuples #if EFL_BETA public static void test_complex_fields_assign_conversion() { var pos = new Eina.Position2D(1, 2); - var action = Efl.Ui.SelectionAction.Unknown; - var format = Efl.Ui.SelectionFormat.None; - var item = null as Efl.Canvas.Vg.Object; + uint seat = 3; + var types = new System.String[] {"text", "markup"}; - Efl.Dnd.DragPos attr = (pos, action, format, item); - Test.AssertEquals(attr.Pos, pos); - Test.AssertEquals(attr.Action, action); - Test.AssertEquals(attr.Format, format); - Test.AssertEquals(attr.Item, item); + Efl.Ui.DropEvent attr = (pos, seat, types); + Test.AssertEquals(attr.Position, pos); + Test.AssertEquals(attr.Seat, seat); + Test.AssertEquals(attr.AvailableTypes.ElementAt(0), types[0]); + Test.AssertEquals(attr.AvailableTypes.ElementAt(1), types[1]); } #endif } diff --git a/src/tests/eina/eina_suite.c b/src/tests/eina/eina_suite.c index 45316bd462..01ed82a532 100644 --- a/src/tests/eina/eina_suite.c +++ b/src/tests/eina/eina_suite.c @@ -90,6 +90,7 @@ static const Efl_Test_Case etc[] = { { "slstr", eina_test_slstr }, { "Vpath", eina_test_vpath }, { "debug", eina_test_debug }, + { "Abstract Content", eina_test_abstract_content }, { NULL, NULL } }; diff --git a/src/tests/eina/eina_suite.h b/src/tests/eina/eina_suite.h index 102de63193..84d6e60516 100644 --- a/src/tests/eina/eina_suite.h +++ b/src/tests/eina/eina_suite.h @@ -78,5 +78,6 @@ void eina_test_freeq(TCase *tc); void eina_test_slstr(TCase *tc); void eina_test_vpath(TCase *tc); void eina_test_debug(TCase *tc); +void eina_test_abstract_content(TCase *tc); #endif /* EINA_SUITE_H_ */ diff --git a/src/tests/eina/eina_test_abstract_content.c b/src/tests/eina/eina_test_abstract_content.c new file mode 100644 index 0000000000..d2270ddaad --- /dev/null +++ b/src/tests/eina/eina_test_abstract_content.c @@ -0,0 +1,223 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include "eina_suite.h" + +EFL_START_TEST(eina_test_content_create_destroy) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + ck_assert_int_eq(eina_content_data_get(content).len, strlen(text_str) + 1); + ck_assert_str_eq(eina_content_data_get(content).mem, text_str); + + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_as_file) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_File *f; + const char *file_path = eina_content_as_file(content); + + f = eina_file_open(file_path, EINA_FALSE); + const char *file_content = eina_file_map_all(f, EINA_FILE_POPULATE); + ck_assert_str_eq(file_content, text_str); + eina_file_close(f); + + eina_content_free(content); + + const char *file_path2 = eina_content_as_file(content); + ck_assert_str_eq(file_path, file_path2); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_none_existing) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + + EXPECT_ERROR_START; + ck_assert_ptr_eq(eina_content_convert(content, "ThisIsReallyNotHere"), NULL); + EXPECT_ERROR_END; +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_ascii_to_utf8) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8"); + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_ascii_to_latin) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=iso-8859-1"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=iso-8859-1"); + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_utf8_to_latin) +{ + //this means AÄÜÖß + const char text_str[] = {'A', 0xc3, 0x84, 0xc3, 0x9c, 0xc3, 0x96, 0xc3, 0x9f, 0}; + const char text_str_latin[] = {'A', 0xC4, 0xDC, 0xD6, 0xDF, 0}; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str_latin), "text/plain;charset=iso-8859-1"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8"); + ck_assert_int_eq(sizeof(text_str), eina_content_data_get(c).len); + for (unsigned int i = 0; i < eina_content_data_get(c).len; ++i) + { + ck_assert_int_eq(text_str[i], ((char*)eina_content_data_get(c).mem)[i]); + } + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_possible_converstions) +{ + ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "text/plain;charset=utf-8"), 1); + ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "ThisDoesNotExist"), 0); + ck_assert_int_eq(eina_content_converter_convert_can("ThisDoesNotExist", "text/plain;charset=utf-8"), 0); + Eina_Iterator *iterator = eina_content_converter_possible_conversions("text/plain"); + char *text; + int i = 0, j = 0; + + EINA_ITERATOR_FOREACH(iterator, text) + { + if (eina_streq(text, "text/plain;charset=utf-8")) + i ++; + if (eina_streq(text, "text/plain;charset=iso-8859-1")) + j ++; + } + ck_assert_int_eq(i, 1); + ck_assert_int_eq(j, 1); + eina_iterator_free(iterator); +} +EFL_END_TEST + +static Eina_Bool getting_called = EINA_FALSE; + +static Eina_Content* +_test_cb(Eina_Content *content EINA_UNUSED, const char *type EINA_UNUSED) +{ + getting_called = EINA_TRUE; + return eina_content_new(eina_content_data_get(content), type); +} + +EFL_START_TEST(eina_test_register_illegal) +{ + const char *test_str = "AbCdEfG"; + eina_content_converter_conversion_register("Test", "Test2", _test_cb); + EXPECT_ERROR_START; + eina_content_converter_conversion_register("Test", "Test2", _test_cb); + EXPECT_ERROR_END; + + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(test_str), "Test"); + Eina_Content *c2 = eina_content_convert(c, "Test2"); + ck_assert_ptr_ne(c2, NULL); + ck_assert_int_eq(getting_called, EINA_TRUE); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value) +{ + const char *str_a = "All"; + const char *str_b = "Out"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain"); + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Content *d = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "Not_Text"); + Eina_Value *va = eina_value_content_new(a); + Eina_Value *vb = eina_value_content_new(b); + Eina_Value *vc = eina_value_content_new(c); + Eina_Value *vd = eina_value_content_new(d); + Eina_Value *vcopy = eina_value_new(EINA_VALUE_TYPE_CONTENT); + Eina_Content *content; + + ck_assert_int_eq(eina_value_compare(va, vc), 0); + ck_assert_int_ne(eina_value_compare(va, vb), 0); + ck_assert_int_ne(eina_value_compare(va, vd), 0); + ck_assert_int_eq(eina_value_compare(vd, vd), 0); + + ck_assert_int_eq(eina_value_copy(va, vcopy), 1); + ck_assert_int_eq(eina_value_compare(va, vcopy), 0); + + content = eina_value_to_content(vcopy); + Eina_Slice slice = eina_content_data_get(content); + ck_assert_int_eq(slice.len, strlen(str_a) + 1); + ck_assert_str_eq(slice.mem, str_a); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value_set) +{ + const char *str_a = "All"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Value *acopy = eina_value_new(EINA_VALUE_TYPE_CONTENT); + Eina_Content *content; + + eina_value_set(acopy, a); + content = eina_value_to_content(acopy); + Eina_Slice slice = eina_content_data_get(content); + ck_assert_int_eq(slice.len, strlen(str_a) + 1); + ck_assert_str_eq(slice.mem, str_a); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value_convertion) +{ + const char *str_a = "All"; + const char *str_b = "Out"; + const char *str_c = "Life"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain;charset=utf-8"); + Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain"); + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_c), "application/x-elementary-markup"); + Eina_Value *av = eina_value_content_new(a); + Eina_Value *bv = eina_value_content_new(b); + Eina_Value *cv = eina_value_content_new(c); + + ck_assert_str_eq(eina_value_to_string(av), str_a); + ck_assert_str_eq(eina_value_to_string(bv), str_b); + ck_assert_str_ne(eina_value_to_string(cv), str_c); +} +EFL_END_TEST + +void +eina_test_abstract_content(TCase *tc) +{ + tcase_add_test(tc, eina_test_content_create_destroy); + tcase_add_test(tc, eina_test_content_as_file); + tcase_add_test(tc, eina_test_content_convert_none_existing); + tcase_add_test(tc, eina_test_content_convert_ascii_to_utf8); + tcase_add_test(tc, eina_test_content_convert_ascii_to_latin); + tcase_add_test(tc, eina_test_content_convert_utf8_to_latin); + tcase_add_test(tc, eina_test_content_possible_converstions); + tcase_add_test(tc, eina_test_register_illegal); + tcase_add_test(tc, eina_test_content_value); + tcase_add_test(tc, eina_test_content_value_set); + tcase_add_test(tc, eina_test_content_value_convertion); +} diff --git a/src/tests/eina/meson.build b/src/tests/eina/meson.build index f755be4c2a..18c8f91ced 100644 --- a/src/tests/eina/meson.build +++ b/src/tests/eina/meson.build @@ -54,7 +54,8 @@ eina_test_src = files( 'eina_test_slice.c', 'eina_test_freeq.c', 'eina_test_slstr.c', -'eina_test_vpath.c' +'eina_test_vpath.c', +'eina_test_abstract_content.c', ) diff --git a/src/tests/elementary/efl_ui_test_text.c b/src/tests/elementary/efl_ui_test_text.c index b7886544f1..0944afa0ef 100644 --- a/src/tests/elementary/efl_ui_test_text.c +++ b/src/tests/elementary/efl_ui_test_text.c @@ -44,6 +44,12 @@ EFL_START_TEST(text_cnp) } EFL_END_TEST +static void +_stop_event_soon(void *data EINA_UNUSED, const Efl_Event *ev) +{ + efl_event_callback_stop(ev->object); +} + EFL_START_TEST(text_all_select_all_unselect) { Eo *txt; @@ -57,7 +63,7 @@ EFL_START_TEST(text_all_select_all_unselect) efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_SELECTION_CHANGED, increment_int_changed, &i_selection) ); - + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_text_set(txt, "Hello"); efl_text_interactive_all_select(txt); Efl_Text_Cursor *c1=NULL, *c2 =NULL; @@ -122,6 +128,7 @@ EFL_START_TEST(text_selection) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); get_me_to_those_events(txt); @@ -160,7 +167,7 @@ EFL_START_TEST(text_user_change) txt = efl_add(EFL_UI_TEXTBOX_CLASS, win, efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, user_changed, &info) ); - + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_text_set(txt, "Hello"); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_interactive_all_select(txt); @@ -177,6 +184,7 @@ EFL_START_TEST(text_scroll_mode) Eo *txt, *win, *cur; win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); cur = efl_text_interactive_main_cursor_get(txt); efl_text_set(txt, "Hello"); /*scroll mode is false by default*/ @@ -199,6 +207,7 @@ EFL_START_TEST(text_change_event) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); int i_changed = 0; @@ -223,6 +232,7 @@ EFL_START_TEST(text_keys_handler) Eo *win = win_add(); txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL); efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300)); efl_text_set(txt, "Hello"); diff --git a/src/tests/elementary/efl_ui_window_cnp_dnd_slave.c b/src/tests/elementary/efl_ui_window_cnp_dnd_slave.c new file mode 100644 index 0000000000..bf8c6d50bd --- /dev/null +++ b/src/tests/elementary/efl_ui_window_cnp_dnd_slave.c @@ -0,0 +1,191 @@ +#define EFL_BETA_API_SUPPORT 1 + +#include +#include +#include +#include "efl_ui_grid_view.eo.h" + +static Ecore_Evas *ee; + +static Eina_Value +_deliverty_cb(void *data, const Eina_Value value, const Eina_Future *dead_future EINA_UNUSED) +{ + Ecore_Evas_Selection_Buffer buffer = (intptr_t)data; + Eina_Content *content; + + if (eina_value_type_get(&value) != EINA_VALUE_TYPE_CONTENT) + { + char *error = eina_value_to_string(&value); + printf("Value not a content, message: \"%s\"\n", error); + return EINA_VALUE_EMPTY; + } + + content = eina_value_to_content(&value); + printf("Got Content of selection %d with type %s\n", buffer, eina_content_type_get(content)); + if (!strncmp(eina_content_type_get(content), "text", strlen("text"))) + { + printf("Content: %s\n", (char*)eina_content_data_get(content).mem); + } + + return EINA_VALUE_EMPTY; +} + +static void +_selection_changed(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + printf("Selection %d of %p has changed\n", selection, ee); +} + +static void +_request_selection(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection) +{ + const char *types[] = {eina_stringshare_add("text/plain"), eina_stringshare_add("text/plain;charset=utf-8")}; + printf("Selection %d of %p has changed\n", selection, ee); + Eina_Future *future = ecore_evas_selection_get(ee, 0, selection, EINA_C_ARRAY_ITERATOR_NEW(types)); + eina_future_then(future, _deliverty_cb, .data = ((void*)(intptr_t)selection)); +} + +static void +_motion_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p) +{ + printf("Drag and Drop has moved on the window %p (%d, %d)\n", ee, p.x, p.y); +} + +static void +_enter_state_change_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, Eina_Bool inside) +{ + if (inside) + printf("Drag and Drop has entered the window %p (%d, %d)\n", ee, p.x, p.y); + else + printf("Drag and Drop has left the window %p (%d, %d)\n", ee, p.x, p.y); +} + +static void +_drop_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, const char *action EINA_UNUSED) +{ + const char *types[] = {eina_stringshare_add("text/plain")}; + printf("Drag and Drop has droped on the window %p (%d, %d)\n", ee, p.x, p.y); + Eina_Future *f = ecore_evas_selection_get(ee, 0, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, EINA_C_ARRAY_ITERATOR_NEW(types)); + eina_future_then(f, _deliverty_cb, .data = ((void*)(intptr_t)ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)); +} + +static void +_efl_ui_terminated(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, void *data, Eina_Bool accepted EINA_UNUSED) +{ + efl_del(data); +} + +static Eo* +_start_dnd(Ecore_Evas *ee) +{ + Ecore_Evas *ee2; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL("This is sample content"), "text/plain"); + Efl_Ui_Win *win; + Efl_Ui_Button *btn; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get()); + ee2 = ecore_evas_ecore_evas_get(evas_object_evas_get(win)); + + btn = efl_add(EFL_UI_BUTTON_CLASS, win); + efl_text_set(btn, "Test"); + efl_content_set(win, btn); + + evas_object_geometry_set(win, 0, 0, 100, 100); + + ecore_evas_drag_start(ee, 0, content, ee2, "copy", _efl_ui_terminated, win); + + return win; +} + +static void +_start_op(void *data, const Efl_Event *ev EINA_UNUSED) +{ + _start_dnd(data); +} + +static Eina_Value +_delete_cb(Eo *obj, void *data EINA_UNUSED, const Eina_Value value EINA_UNUSED) +{ + Ecore_Evas *ee ; + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + + ecore_evas_drag_cancel(ee, 0); + + return EINA_VALUE_EMPTY; +} + +static void +_start_delayed_del_op(void *data, const Efl_Event *ev EINA_UNUSED) +{ + _start_dnd(data); + efl_future_then(ev->object, efl_loop_timeout(efl_main_loop_get(), 2.0), _delete_cb); +} + +EAPI_MAIN void +efl_main(void *data EINA_UNUSED, const Efl_Event *ev) +{ + Efl_Ui_Textbox *txt, *win, *bx, *btn; + Efl_Loop_Arguments *args = ev->info; + char *goal; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get()); + ee = ecore_evas_ecore_evas_get(evas_object_evas_get(win)); + + bx = efl_add(EFL_UI_BOX_CLASS, win); + + txt = efl_add(EFL_UI_TEXTBOX_CLASS, win); + efl_text_set(txt, "Sample for CNP and DND interaction"); + efl_pack_end(bx, txt); + + btn = efl_add(EFL_UI_BUTTON_CLASS, win); + efl_gfx_hint_weight_set(btn, 1.0, 0.0); + efl_event_callback_add(btn, EFL_INPUT_EVENT_PRESSED, _start_op, ee); + efl_text_set(btn, "Start DND op"); + efl_pack_end(bx, btn); + + btn = efl_add(EFL_UI_BUTTON_CLASS, win); + efl_gfx_hint_weight_set(btn, 1.0, 0.0); + efl_event_callback_add(btn, EFL_INPUT_EVENT_PRESSED, _start_delayed_del_op, ee); + efl_text_set(btn, "Start DND op self destroy after 2 sec"); + efl_pack_end(bx, btn); + + efl_content_set(win, bx); + efl_gfx_entity_size_set(win, EINA_SIZE2D(320, 320)); + + goal = eina_array_data_get(args->argv, 1); + + if (eina_streq(goal, "--monitor")) + { + ecore_evas_callback_selection_changed_set(ee, _selection_changed); + ecore_evas_callback_drop_drop_set(ee, _drop_cb); + ecore_evas_callback_drop_motion_set(ee, _motion_cb); + ecore_evas_callback_drop_state_changed_set(ee, _enter_state_change_cb); + } + else if (eina_streq(goal, "--show-selections")) + { + ecore_evas_callback_selection_changed_set(ee, _request_selection); + } + else if (eina_streq(goal, "--set-selection")) + { + if (eina_array_count(args->argv) < 3) + { + printf("Error, --set-selection only requires exactly 1 keyword (The selection to set).\n"); + return; + } + char *selection = eina_array_data_get(args->argv, 2); + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(selection), "text/plain"); + ecore_evas_selection_set(ee, 0, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER, content); + } + else if (eina_streq(goal, "--show-owner")) + { + for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) + { + printf("Selection buffer %d : %d\n", i, ecore_evas_selection_exists(ee, 0, i)); + } + } + else + { + printf("Error, goal %s not found\n", goal); + } +} +EFL_MAIN() diff --git a/src/tests/elementary/meson.build b/src/tests/elementary/meson.build index 7f5fd03733..1b43da7064 100644 --- a/src/tests/elementary/meson.build +++ b/src/tests/elementary/meson.build @@ -187,6 +187,11 @@ efl_ui_compile_test = executable('efl_ui_compile_test', dependencies: [elementary, eio], ) +executable('efl_ui_window_cnp_dnd_slave', + 'efl_ui_window_cnp_dnd_slave.c', + dependencies: [elementary], +) + test('elementary-suite', elementary_suite, env : test_env )