Import src
This commit is contained in:
parent
c6124b2180
commit
2958defd9e
|
@ -0,0 +1,25 @@
|
|||
Copyright notice for Enlightenment:
|
||||
|
||||
Copyright (C) 2022-2023 Carsten Haitzler and various contributors (see AUTHORS)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,9 @@
|
|||
# EFM
|
||||
|
||||
## Remake of Enlightenment's file manager
|
||||
|
||||
This redose EFM so it can be used in and out-of-process too in E. This
|
||||
moves the FS layer entirely to a child process that EFM talks to over
|
||||
stdio. The only direct file access is via local "cached" files in
|
||||
$HOME that are intended to always be fast access (the location could
|
||||
move somewhere - but this is the only sane way).
|
|
@ -0,0 +1,81 @@
|
|||
# Things To Do
|
||||
|
||||
## Now
|
||||
|
||||
* View
|
||||
* List detailed mode
|
||||
* Free x/y position
|
||||
* Vertical icon view
|
||||
* Free x/y cleanup/grid align
|
||||
* Icon with no labels
|
||||
* Icons with flush view (like rage video browser view)
|
||||
* .dir.desktop support for changing view type and looks etc. etc.
|
||||
* DND auto-open dir on hover-over
|
||||
* File properties dialog
|
||||
* File Ops
|
||||
* mv
|
||||
* cp
|
||||
* rm
|
||||
* "Job" tracking + management (cancel pending ones)
|
||||
* Trashcan impl
|
||||
* Progress feedback from file ops
|
||||
* Display dir usage (# files, size)
|
||||
* Display dir + subdir usage
|
||||
* Each file/dir needs a busy status (eg while running du -s in a dir tree)
|
||||
* In-fm
|
||||
* Status - icon overlay label, icon, progress, busy spinner
|
||||
* Status - progress/busy spinner + label + icon
|
||||
* Dialog - label + icon + entry + buttons (ok/cancel etc.)
|
||||
* Typebuf select/filter/cmd
|
||||
* Choose fs abstraction dir setup etc.
|
||||
* Live icons - desktop file runs binary with plug/socket efl app
|
||||
* Filesystem info (df like with total available)
|
||||
* List mode ".order" files
|
||||
* Remember scroll pos, view size/pos
|
||||
* Set window icon correctly for dir
|
||||
* Save x,y per icon
|
||||
* Set custom icon per file
|
||||
* Special icons for special filenames/paths (~/Desktop, ~/Videos etc.)
|
||||
* Favorites view move (manual .order changes, cb's for selecting single click)
|
||||
* Single click/select mode
|
||||
* Hide/show hidden files
|
||||
* Immutable dirs (no moving files/changes - just browse/launch)
|
||||
* Dir info pane
|
||||
* Pane
|
||||
* Table of label + icons
|
||||
* List of items (label + 2 icons)
|
||||
* Device monitoring/listing
|
||||
* Device mount/unmount
|
||||
* Custom target vfs dir (eg sshfs) controls
|
||||
* Find filename in tree
|
||||
* Show dir has no permission to view/go into (eg missing r/x on other/group)
|
||||
* Right click context menu
|
||||
* Open file with mime handler
|
||||
* Open with ...
|
||||
* File actions (separate to open with...)
|
||||
|
||||
## Medium term
|
||||
|
||||
* Edit desktop file support (dialog)
|
||||
* Network fs monitoring/listing (smb/nfs/etc.)
|
||||
* View background / overlay images/edj files
|
||||
* Typebuf commands (ls, rm, cd, mv, ...)
|
||||
* Special drop handling per dir (eg favorites adds links)
|
||||
* Support running back-end cmds as another user
|
||||
* Chmod support
|
||||
* Thumbnail multiple pages from pdf, ps etc.
|
||||
* Thumbnails multiple timepoints from video files
|
||||
* Tooltip previews
|
||||
* Multi-page show multiple pages
|
||||
* Video files show multiple timepoints
|
||||
|
||||
## Long term
|
||||
|
||||
* Encrypted drives/volumes
|
||||
* Partitioning and formatting tool (chnage volume labels etc)
|
||||
* Encryption added to partitioning/formatitng tool
|
||||
* Lvm support in partitioning/formatting tool
|
||||
* Fstrim support
|
||||
* Smart support for devices
|
||||
* Badblocks support
|
||||
* Lsattr/chattr support
|
|
@ -0,0 +1,3 @@
|
|||
dir = join_paths(dir_data, 'efm')
|
||||
install_data('checkme',
|
||||
install_dir: dir)
|
|
@ -0,0 +1,37 @@
|
|||
project('efm', 'c', version: '0.0.0', license: 'GPL2',
|
||||
default_options: [ 'buildtype=plain', 'c_std=gnu99' ],
|
||||
meson_version: '>= 0.47.0')
|
||||
proj = meson.project_name()
|
||||
ver = meson.project_version()
|
||||
base_url = 'https://www.enlightenment.org/about-'
|
||||
cc = meson.get_compiler('c')
|
||||
m_dep = cc.find_library('m', required : false)
|
||||
deps = [
|
||||
dependency('elementary', version: '>= 1.26.0'),
|
||||
dependency('emotion', version: '>= 1.26.0'),
|
||||
m_dep
|
||||
]
|
||||
dir_prefix = get_option('prefix')
|
||||
dir_bin = join_paths(dir_prefix, get_option('bindir'))
|
||||
dir_lib = join_paths(dir_prefix, get_option('libdir'))
|
||||
dir_data = join_paths(dir_prefix, get_option('datadir'))
|
||||
dir_locale = join_paths(dir_prefix, get_option('localedir'))
|
||||
cfg = configuration_data()
|
||||
cfg.set_quoted('PACKAGE' , proj)
|
||||
cfg.set_quoted('PACKAGE_NAME' , proj)
|
||||
cfg.set_quoted('PACKAGE_VERSION' , ver)
|
||||
cfg.set_quoted('PACKAGE_STRING' , proj + ' ' + ver)
|
||||
cfg.set_quoted('PACKAGE_URL' , base_url + proj)
|
||||
cfg.set_quoted('PACKAGE_BIN_DIR' , dir_bin)
|
||||
cfg.set_quoted('PACKAGE_LIB_DIR' , dir_lib)
|
||||
cfg.set_quoted('PACKAGE_DATA_DIR' , join_paths(dir_data, proj))
|
||||
cfg.set_quoted('LOCALEDIR' , dir_locale)
|
||||
cfg.set ('_GNU_SOURCE' , 1)
|
||||
cfg.set ('__EXTENSIONS__' , 1)
|
||||
cfg.set ('_POSIX_PTHREAD_SEMANTICS', 1)
|
||||
cfg.set ('_ALL_SOURCE' , 1)
|
||||
cfg.set ('_POSIX_SOURCE' , 1)
|
||||
cfg.set ('_POSIX_1_SOURCE' , 1)
|
||||
configure_file(output: 'efm_config.h', configuration: cfg)
|
||||
subdir('src')
|
||||
subdir('data')
|
|
@ -0,0 +1,65 @@
|
|||
CMD dir-set path=/home/raster/C/efm2
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00943.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/53/f957ab4d5460f00628a587556e35629caa0e53.eet label=DSC00943.JPG user=raster group=raster mode=1ed inode=18749257 nlink=1 gid=1000 size=26574848 blksize=4096 blocks=51904 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/efm type=file label=efm user=raster group=raster mode=1ed inode=23724617 nlink=1 gid=1000 size=537192 blksize=4096 blocks=1056 atime=1648769404 mtime=1648769404 ctime=1648769404
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00932.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/6e/cb788e0e6e03c5bcc98dcfbde5ea7449ced476.eet label=DSC00932.JPG user=raster group=raster mode=1ed inode=18749251 nlink=1 gid=1000 size=18448384 blksize=4096 blocks=36032 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/cmd.c\x7e type=file mime=application/x-trash mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-trash.svg label=cmd.c\x7e user=raster group=raster mode=1a4 inode=23729908 nlink=1 gid=1000 size=6155 blksize=4096 blocks=16 atime=1648747518 mtime=1648747518 ctime=1648747544
|
||||
CMD file-add path=/home/raster/C/efm2/dir1 type=dir label=dir1 user=raster group=raster mode=1ed inode=23732294 nlink=2 gid=1000 size=4096 blksize=4096 blocks=8 atime=1644011527 mtime=1644011527 ctime=1644011527
|
||||
CMD file-add path=/home/raster/C/efm2/cmd.h type=file mime=text/x-chdr mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-chdr.svg label=cmd.h user=raster group=raster mode=1a4 inode=23729901 nlink=1 gid=1000 size=980 blksize=4096 blocks=8 atime=1648747535 mtime=1648747535 ctime=1648747535
|
||||
CMD file-add path=/home/raster/C/efm2/build.sh type=file mime=application/x-shellscript mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-shellscript.svg label=build.sh user=raster group=raster mode=1ed inode=23724920 nlink=1 gid=1000 size=323 blksize=4096 blocks=8 atime=1646442369 mtime=1646442369 ctime=1646442369
|
||||
CMD file-add path=/home/raster/C/efm2/mplayer.desktop type=file mime=application/x-desktop mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-desktop.svg label=MPlayer desktop-generic-name=true desktop-comment=Watch\x20movies\x20and\x20videos desktop-icon=video_player desktop-try-exec= desktop-exec=mplayer\x20\x25U desktop-url= desktop-no-display=false desktop-hidden=false desktop-terminal=false desktop-startup-notify=false desktop-icon.lookup=/usr/local/share/enlightenment/data/icons/video_player.png user=raster group=raster mode=1a4 inode=23724916 nlink=1 gid=1000 size=2404 blksize=4096 blocks=8 atime=1645890199 mtime=1645890199 ctime=1645890199
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00945.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/14/c9fbb4214ab4b8a622025509fdd38c8fa276b8.eet label=DSC00945.JPG user=raster group=raster mode=1ed inode=18749262 nlink=1 gid=1000 size=26116096 blksize=4096 blocks=51008 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/sha.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=sha.c user=raster group=raster mode=1a4 inode=23727830 nlink=1 gid=1000 size=3663 blksize=4096 blocks=8 atime=1645965283 mtime=1645965283 ctime=1645965283
|
||||
CMD file-add path=/home/raster/C/efm2/dir2 type=dir label=dir2 user=raster group=raster mode=1ed inode=23732493 nlink=2 gid=1000 size=4096 blksize=4096 blocks=8 atime=1644011530 mtime=1644011530 ctime=1644011530
|
||||
CMD file-add path=/home/raster/C/efm2/main.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=main.c user=raster group=raster mode=1a4 inode=23729913 nlink=1 gid=1000 size=3752 blksize=4096 blocks=8 atime=1648762748 mtime=1648762748 ctime=1648762748
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00946.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/99/641dd8d01cb0f212f4295cea418fe4637835b5.eet label=DSC00946.JPG user=raster group=raster mode=1ed inode=18749264 nlink=1 gid=1000 size=23396352 blksize=4096 blocks=45696 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/blah type=link link=/home/raster/ link-type=dir link-label=blah link-user=raster link-group=raster link-mode=1ed link-inode=18219010 link-nlink=116 link-gid=1000 link-size=12288 link-blksize=4096 link-blocks=24 link-atime=1586903708 link-mtime=1648890971 link-ctime=1648890971 user=raster group=raster mode=1ff inode=23724046 nlink=1 gid=1000 size=13 blksize=4096 blocks=0 atime=1643917174 mtime=1643906454 ctime=1643917174
|
||||
CMD file-add path=/home/raster/C/efm2/yyb type=dir label=yyb user=raster group=raster mode=1ed inode=23732491 nlink=2 gid=1000 size=4096 blksize=4096 blocks=8 atime=1643917174 mtime=1643909696 ctime=1643917174
|
||||
CMD file-add path=/home/raster/C/efm2/efm_structs.h type=file mime=text/x-chdr mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-chdr.svg label=efm_structs.h user=raster group=raster mode=1a4 inode=23726366 nlink=1 gid=1000 size=3546 blksize=4096 blocks=8 atime=1648764496 mtime=1648764496 ctime=1648764496
|
||||
CMD file-add path=/home/raster/C/efm2/xxa type=file label=xxa user=raster group=raster mode=1a4 inode=18770119 nlink=1 gid=1000 size=0 blksize=4096 blocks=0 atime=1643917175 mtime=1643908180 ctime=1645954000
|
||||
CMD file-add path=/home/raster/C/efm2/xxb type=file label=xxb user=raster group=raster mode=1a4 inode=18770120 nlink=1 gid=1000 size=0 blksize=4096 blocks=0 atime=1643917175 mtime=1643908180 ctime=1645954000
|
||||
CMD file-add path=/home/raster/C/efm2/yyc type=dir label=yyc user=raster group=raster mode=1ed inode=23732492 nlink=2 gid=1000 size=4096 blksize=4096 blocks=8 atime=1643917174 mtime=1643909696 ctime=1643917174
|
||||
CMD file-add path=/home/raster/C/efm2/Sam_Perry_-_Prince_-_When_doves_cry.mkv type=file mime=video/x-matroska mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/video-x-matroska.svg thumb=/home/raster/.e/e/thumbs/c5/bd5935e1f3f395d53a576e48aec7e39110a2ec.eet label=Sam_Perry_-_Prince_-_When_doves_cry.mkv user=raster group=raster mode=1a4 inode=23724895 nlink=1 gid=1000 size=46915391 blksize=4096 blocks=91640 atime=1646086494 mtime=1646086494 ctime=1647031857
|
||||
CMD file-add path=/home/raster/C/efm2/xxc type=file label=xxc user=raster group=raster mode=1a4 inode=18770121 nlink=1 gid=1000 size=0 blksize=4096 blocks=0 atime=1643917175 mtime=1643908180 ctime=1645954000
|
||||
CMD file-add path=/home/raster/C/efm2/efm_private.h\x7e type=file mime=application/x-trash mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-trash.svg label=efm_private.h\x7e user=raster group=raster mode=1a4 inode=23729902 nlink=1 gid=1000 size=1193 blksize=4096 blocks=8 atime=1648752425 mtime=1648752425 ctime=1648762883
|
||||
CMD file-add path=/home/raster/C/efm2/efm_util.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=efm_util.c user=raster group=raster mode=1a4 inode=23729811 nlink=1 gid=1000 size=31886 blksize=4096 blocks=64 atime=1648769288 mtime=1648769288 ctime=1648769288
|
||||
CMD file-add path=/home/raster/C/efm2/efm_icon.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=efm_icon.c user=raster group=raster mode=1a4 inode=23730949 nlink=1 gid=1000 size=11078 blksize=4096 blocks=24 atime=1648209986 mtime=1648209986 ctime=1648209986
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00929.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/3f/4a8b9b2c79314c676db1ea0d29136058d5aaab.eet label=DSC00929.JPG user=raster group=raster mode=1ed inode=18749248 nlink=1 gid=1000 size=14516224 blksize=4096 blocks=28352 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/efm_back_end.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=efm_back_end.c user=raster group=raster mode=1a4 inode=18746021 nlink=1 gid=1000 size=15235 blksize=4096 blocks=32 atime=1647210250 mtime=1647206422 ctime=1647210250
|
||||
CMD file-add path=/home/raster/C/efm2/sort.h type=file mime=text/x-chdr mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-chdr.svg label=sort.h user=raster group=raster mode=1a4 inode=23730766 nlink=1 gid=1000 size=538 blksize=4096 blocks=8 atime=1643992534 mtime=1643992534 ctime=1643992534
|
||||
CMD file-add path=/home/raster/C/efm2/thumb.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=thumb.c user=raster group=raster mode=1a4 inode=23724123 nlink=1 gid=1000 size=7007 blksize=4096 blocks=16 atime=1646085700 mtime=1646085700 ctime=1646085700
|
||||
CMD file-add path=/home/raster/C/efm2/efm_private.h type=file mime=text/x-chdr mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-chdr.svg label=efm_private.h user=raster group=raster mode=1a4 inode=23728355 nlink=1 gid=1000 size=1213 blksize=4096 blocks=8 atime=1648762883 mtime=1648762883 ctime=1648762883
|
||||
CMD file-add path=/home/raster/C/efm2/cmd.h\x7e type=file mime=application/x-trash mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-trash.svg label=cmd.h\x7e user=raster group=raster mode=1a4 inode=23724625 nlink=1 gid=1000 size=974 blksize=4096 blocks=8 atime=1648747530 mtime=1648747530 ctime=1648747535
|
||||
CMD file-add path=/home/raster/C/efm2/fs_backend_core.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=fs_backend_core.c user=raster group=raster mode=1a4 inode=23724929 nlink=1 gid=1000 size=2629 blksize=4096 blocks=8 atime=1646248242 mtime=1646248242 ctime=1646248242
|
||||
CMD file-add path=/home/raster/C/efm2/.hidden1 type=dir label=.hidden1 user=raster group=raster mode=1ed inode=24512350 nlink=2 gid=1000 size=4096 blksize=4096 blocks=8 atime=1646596578 mtime=1646596578 ctime=1646596578
|
||||
CMD file-add path=/home/raster/C/efm2/efm.h type=file mime=text/x-chdr mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-chdr.svg label=efm.h user=raster group=raster mode=1a4 inode=23730930 nlink=1 gid=1000 size=1079 blksize=4096 blocks=8 atime=1647632307 mtime=1647632307 ctime=1647632307
|
||||
CMD file-add path=/home/raster/C/efm2/ark.desktop type=file mime=application/x-desktop mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-desktop.svg label=ARK:\x20Normal desktop-generic-name=false desktop-comment=Play\x20this\x20game\x20on\x20Steam desktop-icon=/home/raster/.icons/ark.png desktop-try-exec= desktop-exec=steam\x20steam://rungameid/346110 desktop-url= desktop-no-display=false desktop-hidden=false desktop-terminal=false desktop-startup-notify=false desktop-icon.lookup= label-clicked=Ark:\x20Clicked label-selected=Ark:\x20Selected desktop-icon-clicked=/home/raster/.icons/wechat.png desktop-icon-selected=/home/raster/.icons/sweethome3d.png user=raster group=raster mode=1a4 inode=23724926 nlink=1 gid=1000 size=319 blksize=4096 blocks=8 atime=1647026562 mtime=1647026562 ctime=1647026562
|
||||
CMD file-add path=/home/raster/C/efm2/tig.desktop type=file mime=application/x-desktop mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-desktop.svg label=Tiggy\x20SVG desktop-generic-name=false desktop-comment=Play\x20this\x20game\x20on\x20Steam desktop-icon=/home/raster/C/efm2/tiger.svg desktop-try-exec= desktop-exec=steam\x20steam://rungameid/346110 desktop-url= desktop-no-display=false desktop-hidden=false desktop-terminal=false desktop-startup-notify=false desktop-icon.lookup= user=raster group=raster mode=1a4 inode=23727828 nlink=1 gid=1000 size=166 blksize=4096 blocks=8 atime=1646596358 mtime=1646596358 ctime=1646596358
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00931.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/cd/fb485ec9e20bad55b5b6f76d3e8976eb438399.eet label=DSC00931.JPG user=raster group=raster mode=1ed inode=18749250 nlink=1 gid=1000 size=14024704 blksize=4096 blocks=27392 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/dir3 type=dir label=dir3 user=raster group=raster mode=1ed inode=23732494 nlink=2 gid=1000 size=4096 blksize=4096 blocks=8 atime=1644011532 mtime=1644011532 ctime=1644011532
|
||||
CMD file-add path=/home/raster/C/efm2/xxd type=file label=xxd user=raster group=raster mode=1a4 inode=18770149 nlink=1 gid=1000 size=0 blksize=4096 blocks=0 atime=1643917175 mtime=1643908180 ctime=1645954000
|
||||
CMD file-add path=/home/raster/C/efm2/efm.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=efm.c user=raster group=raster mode=1a4 inode=23729823 nlink=1 gid=1000 size=28335 blksize=4096 blocks=56 atime=1648769134 mtime=1648769134 ctime=1648769134
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00928.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/aa/bfc32b248723656c48a31d446999fd3f8913f9.eet label=DSC00928.JPG user=raster group=raster mode=1ed inode=18745989 nlink=1 gid=1000 size=22773760 blksize=4096 blocks=44480 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/cmd.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=cmd.c user=raster group=raster mode=1a4 inode=23729897 nlink=1 gid=1000 size=6161 blksize=4096 blocks=16 atime=1648747544 mtime=1648747544 ctime=1648747544
|
||||
CMD file-add path=/home/raster/C/efm2/efm.c\x7e type=file mime=application/x-trash mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-trash.svg label=efm.c\x7e user=raster group=raster mode=1a4 inode=23724064 nlink=1 gid=1000 size=28357 blksize=4096 blocks=56 atime=1648768644 mtime=1648768644 ctime=1648769134
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00941.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/14/020bf44c8ddce48364d5ede7e9ee74e378f70a.eet label=DSC00941.JPG user=raster group=raster mode=1ed inode=18749252 nlink=1 gid=1000 size=14647296 blksize=4096 blocks=28608 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/beast.desktop type=file mime=application/x-desktop mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-desktop.svg label=BEEAAST desktop-generic-name=false desktop-comment=Da\x20Biiieest desktop-icon=/home/raster/C/efm2/beast-art.jpg desktop-try-exec= desktop-exec=xterm desktop-url= desktop-no-display=false desktop-hidden=false desktop-terminal=false desktop-startup-notify=false desktop-icon.lookup= user=raster group=raster mode=1a4 inode=23724921 nlink=1 gid=1000 size=122 blksize=4096 blocks=8 atime=1645890552 mtime=1645890552 ctime=1645890552
|
||||
CMD file-add path=/home/raster/C/efm2/sort.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=sort.c user=raster group=raster mode=1a4 inode=23729895 nlink=1 gid=1000 size=2789 blksize=4096 blocks=8 atime=1644017056 mtime=1644017056 ctime=1644017056
|
||||
CMD file-add path=/home/raster/C/efm2/home.desktop type=file mime=application/x-desktop mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-desktop.svg label=Home desktop-generic-name=false desktop-comment=The\x20Directory\x20containing\x20all\x20your\x20personal\x20files desktop-icon=user-home desktop-try-exec= desktop-exec= desktop-url=file:\x24HOME desktop-no-display=false desktop-hidden=false desktop-terminal=false desktop-startup-notify=false desktop-icon.lookup=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/places/scalable/user-home.svg user=raster group=raster mode=1a4 inode=18770054 nlink=1 gid=1000 size=765 blksize=4096 blocks=8 atime=1643917175 mtime=1643906431 ctime=1643917175
|
||||
CMD file-add path=/home/raster/C/efm2/beast-art.jpg type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/9f/0fdd2433a4c6914e3685f6f203b0cab4342702.eet label=beast-art.jpg user=raster group=raster mode=1a4 inode=23724917 nlink=1 gid=1000 size=557108 blksize=4096 blocks=1096 atime=1645960418 mtime=1645960418 ctime=1645960418
|
||||
CMD file-add path=/home/raster/C/efm2/main.c\x7e type=file mime=application/x-trash mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-trash.svg label=main.c\x7e user=raster group=raster mode=1a4 inode=18746023 nlink=1 gid=1000 size=3230 blksize=4096 blocks=8 atime=1647133165 mtime=1647120355 ctime=1648762748
|
||||
CMD file-add path=/home/raster/C/efm2/DSC00930.JPG type=file mime=image/jpeg mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-jpeg.svg thumb=/home/raster/.e/e/thumbs/2a/e2b0646970fa380c2641db83d0bb64e10973db.eet label=DSC00930.JPG user=raster group=raster mode=1ed inode=18749249 nlink=1 gid=1000 size=19038208 blksize=4096 blocks=37184 atime=1646005748 mtime=1645991014 ctime=1646005748
|
||||
CMD file-add path=/home/raster/C/efm2/cities.desktop type=file mime=application/x-desktop mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-desktop.svg label=City4 desktop-generic-name=false desktop-comment=Play\x20this\x20game\x20on\x20Steam desktop-icon=steam_icon_255710 desktop-try-exec= desktop-exec=steam\x20steam://rungameid/255710 desktop-url= desktop-no-display=false desktop-hidden=false desktop-terminal=false desktop-startup-notify=false desktop-icon.lookup=/home/raster/.local/share/icons/hicolor/128x128/apps/steam_icon_255710.png user=raster group=raster mode=1a4 inode=23727046 nlink=1 gid=1000 size=167 blksize=4096 blocks=8 atime=1645911516 mtime=1645911516 ctime=1646086457
|
||||
CMD file-add path=/home/raster/C/efm2/efm_icon.h type=file mime=text/x-chdr mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-chdr.svg label=efm_icon.h user=raster group=raster mode=1a4 inode=23724919 nlink=1 gid=1000 size=414 blksize=4096 blocks=8 atime=1646596453 mtime=1646596453 ctime=1646596453
|
||||
CMD file-add path=/home/raster/C/efm2/sh-open type=file label=sh-open user=raster group=raster mode=1ed inode=18770068 nlink=1 gid=1000 size=296 blksize=4096 blocks=8 atime=1643917175 mtime=1643906431 ctime=1643917175
|
||||
CMD file-add path=/home/raster/C/efm2/efm_util.c\x7e type=file mime=application/x-trash mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-trash.svg label=efm_util.c\x7e user=raster group=raster mode=1a4 inode=23724141 nlink=1 gid=1000 size=31835 blksize=4096 blocks=64 atime=1648768645 mtime=1648768645 ctime=1648769288
|
||||
CMD file-add path=/home/raster/C/efm2/beast2.desktop type=file mime=application/x-desktop mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-desktop.svg label=BEEAAST2 desktop-generic-name=false desktop-comment=Da\x20Biiieest desktop-icon=/home/raster/C/efm2/beast-shot.gif desktop-try-exec= desktop-exec=xterm desktop-url= desktop-no-display=false desktop-hidden=false desktop-terminal=false desktop-startup-notify=false desktop-icon.lookup= user=raster group=raster mode=1a4 inode=23724922 nlink=1 gid=1000 size=117 blksize=4096 blocks=8 atime=1645890953 mtime=1645890953 ctime=1645890953
|
||||
CMD file-add path=/home/raster/C/efm2/open.c type=file mime=text/x-csrc mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/text-x-csrc.svg label=open.c user=raster group=raster mode=1a4 inode=23726403 nlink=1 gid=1000 size=27651 blksize=4096 blocks=56 atime=1647027930 mtime=1647027930 ctime=1647027930
|
||||
CMD file-add path=/home/raster/C/efm2/broken type=link broken-link=true user=raster group=raster mode=1ff inode=23724048 nlink=1 gid=1000 size=7 blksize=4096 blocks=0 atime=1643917174 mtime=1643906443 ctime=1643917174
|
||||
CMD file-add path=/home/raster/C/efm2/beast-shot.gif type=file mime=image/gif mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-gif.svg thumb=/home/raster/.e/e/thumbs/b2/9787354aa1c33816b2a53d5a85542d751f81d4.eet label=beast-shot.gif user=raster group=raster mode=1a4 inode=23724918 nlink=1 gid=1000 size=18854 blksize=4096 blocks=40 atime=1645890492 mtime=1645890492 ctime=1645954000
|
||||
CMD file-add path=/home/raster/C/efm2/order.pdf type=file mime=application/pdf mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/categories/scalable/application-pdf.svg thumb=/home/raster/.e/e/thumbs/37/bd6ec0ae6bfaa4035c40efaf73fcfbfcf57045.eet label=order.pdf user=raster group=raster mode=1a4 inode=23724126 nlink=1 gid=1000 size=184544 blksize=4096 blocks=368 atime=1646596700 mtime=1646596700 ctime=1647031857
|
||||
CMD file-add path=/home/raster/C/efm2/efm_structs.h\x7e type=file mime=application/x-trash mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/application-x-trash.svg label=efm_structs.h\x7e user=raster group=raster mode=1a4 inode=23730938 nlink=1 gid=1000 size=3510 blksize=4096 blocks=8 atime=1648489751 mtime=1648489751 ctime=1648764496
|
||||
CMD file-add path=/home/raster/C/efm2/open type=file label=open user=raster group=raster mode=1ed inode=23724049 nlink=1 gid=1000 size=283680 blksize=4096 blocks=560 atime=1648769403 mtime=1648769403 ctime=1648769403
|
||||
CMD file-add path=/home/raster/C/efm2/yya type=dir label=yya user=raster group=raster mode=1ed inode=23732295 nlink=2 gid=1000 size=4096 blksize=4096 blocks=8 atime=1643917174 mtime=1643909696 ctime=1643917174
|
||||
CMD file-add path=/home/raster/C/efm2/ark.png type=file mime=image/png mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-png.svg thumb=/home/raster/.e/e/thumbs/d9/0f5094c9a5019a065dbc42ca9db28f56441836.eet label=ark.png user=raster group=raster mode=1a4 inode=23724913 nlink=1 gid=1000 size=65829 blksize=4096 blocks=136 atime=1646596853 mtime=1646596895 ctime=1647031857
|
||||
CMD file-add path=/home/raster/C/efm2/thumb type=file label=thumb user=raster group=raster mode=1ed inode=23724056 nlink=1 gid=1000 size=399696 blksize=4096 blocks=784 atime=1648769403 mtime=1648769404 ctime=1648769404
|
||||
CMD file-add path=/home/raster/C/efm2/tiger.svg type=file mime=image/svg+xml mime-icon=/home/raster/.local/share/icons/Flat-Remix-Yellow-Dark/mimetypes/scalable/image-svg+xml.svg thumb=/home/raster/.e/e/thumbs/28/d53be4c4a7bc03dde866cc2a189ebc40b62648.eet label=tiger.svg user=raster group=raster mode=1a4 inode=18219382 nlink=1 gid=1000 size=86486 blksize=4096 blocks=176 atime=1646577034 mtime=1646577034 ctime=1648769263
|
|
@ -0,0 +1,130 @@
|
|||
// this is a template file to drive any fs backend that sets up stdin/out
|
||||
// and the core parsers and init/shutdown funcs. the expectation is you build
|
||||
// this along with an implementation file that implements that fs
|
||||
#include <Eina.h>
|
||||
#include <Ecore.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "cmd.h"
|
||||
|
||||
void do_handle_cmd(Cmd *c);
|
||||
int do_init(int argc, const char **argv);
|
||||
void do_shutdown(void);
|
||||
|
||||
static Ecore_Fd_Handler *fdh = NULL;
|
||||
static Eina_Strbuf *strbuf = NULL;
|
||||
|
||||
static Eina_Bool
|
||||
_cb_stdio_in_read(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
|
||||
{
|
||||
ssize_t ret;
|
||||
char buf[4096 + 1];
|
||||
|
||||
errno = 0;
|
||||
ret = read(0, buf, sizeof(buf) - 1);
|
||||
|
||||
if (ret < 1)
|
||||
{
|
||||
int e = errno;
|
||||
|
||||
if ((e == EIO) || (e == EBADF) || (e == EPIPE) || (e == EINVAL) ||
|
||||
(e == ENOSPC) || (!((e == EAGAIN) || (e == EINTR))))
|
||||
{
|
||||
ecore_main_loop_quit();
|
||||
goto done;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *nl, *str;
|
||||
|
||||
buf[ret] = '\0';
|
||||
eina_strbuf_append(strbuf, buf);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char *s;
|
||||
Cmd *c;
|
||||
|
||||
str = eina_strbuf_string_get(strbuf);
|
||||
nl = strchr(str, '\n');
|
||||
if (!nl) break;
|
||||
|
||||
s = strndup(str, nl - str);
|
||||
if (!s) break;
|
||||
c = cmd_parse(s);
|
||||
if (c)
|
||||
{
|
||||
do_handle_cmd(c);
|
||||
cmd_free(c);
|
||||
}
|
||||
free(s);
|
||||
eina_strbuf_remove(strbuf, 0, nl - str + 1);
|
||||
}
|
||||
}
|
||||
done:
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_init(void)
|
||||
{
|
||||
strbuf = eina_strbuf_new();
|
||||
if (!strbuf)
|
||||
{
|
||||
fprintf(stderr, "ERR: Can't allocate strbuf\n");
|
||||
goto err;
|
||||
}
|
||||
if (fcntl(0, F_SETFL, O_NONBLOCK) != 0)
|
||||
{
|
||||
fprintf(stderr, "ERR: Can't set stdin to O_NONBLOCK\n");
|
||||
goto err;
|
||||
}
|
||||
fdh = ecore_main_fd_handler_add(0, ECORE_FD_READ, _cb_stdio_in_read,
|
||||
NULL, NULL, NULL);
|
||||
if (!fdh) goto err;
|
||||
return;
|
||||
err:
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void
|
||||
_shutdown(void)
|
||||
{
|
||||
ecore_main_fd_handler_del(fdh);
|
||||
fdh = NULL;
|
||||
eina_strbuf_free(strbuf);
|
||||
strbuf = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
eina_init();
|
||||
ecore_init();
|
||||
|
||||
_init();
|
||||
|
||||
ret = do_init(argc, argv);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
ecore_main_loop_begin();
|
||||
do_shutdown();
|
||||
}
|
||||
|
||||
_shutdown();
|
||||
|
||||
ecore_shutdown();
|
||||
eina_shutdown();
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
dir = join_paths(dir_lib, 'efm', 'backends', 'default')
|
||||
inc = include_directories(
|
||||
'.',
|
||||
'../../..',
|
||||
'../../efm',
|
||||
'../../shared/commands',
|
||||
'../../shared/common',
|
||||
'../../backends/common'
|
||||
)
|
||||
executable('open', [
|
||||
'../../shared/common/cmd.c',
|
||||
'../../shared/common/sha.c',
|
||||
'../../backends/common/fs_backend_core.c',
|
||||
'open.c'
|
||||
],
|
||||
include_directories: inc,
|
||||
dependencies: deps,
|
||||
install: true,
|
||||
install_dir: dir)
|
||||
executable('thumb', [
|
||||
'../../shared/common/sha.c',
|
||||
'thumb.c',
|
||||
'thumb_util_img.c',
|
||||
'thumb_util_search.c',
|
||||
'thumb_util_url.c',
|
||||
'thumb_image.c',
|
||||
'thumb_font.c',
|
||||
'thumb_paged.c',
|
||||
'thumb_music.c',
|
||||
'thumb_video.c',
|
||||
'thumb_edje.c'
|
||||
],
|
||||
include_directories: inc,
|
||||
dependencies: deps,
|
||||
install: true,
|
||||
install_dir: dir)
|
|
@ -0,0 +1,838 @@
|
|||
// fs backend for regular fs files - opens a dir, lists, monitors and
|
||||
// sends all files it finds nd all metadata and any changes that happen
|
||||
// to that dir. it only handles a single dir. in theory you can write complex
|
||||
// fs handlers that could do this over a network protocol or merge multiple
|
||||
// real fs locations into a single apparent dir to the user. the idea is
|
||||
// the front end that consumes the output of this should do NO file access
|
||||
// itself at all and do everything via fs handlers for open, delete, rename
|
||||
// copy, import, export etc.
|
||||
#include "cmd.h"
|
||||
#include "sha.h"
|
||||
#include <Ecore_File.h>
|
||||
#include <Efreet.h>
|
||||
#include <Efreet_Mime.h>
|
||||
#include <Eet.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "thumb_check.h"
|
||||
|
||||
static const char *icon_theme = NULL;
|
||||
static const char *config_dir = NULL;
|
||||
static const char *home_dir = NULL;
|
||||
|
||||
static Ecore_File_Monitor *mon = NULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *path;
|
||||
const char *mime;
|
||||
const char *thumb;
|
||||
Ecore_Exe *exe;
|
||||
Ecore_Timer *busy_delay_timer;
|
||||
} Thumb;
|
||||
|
||||
static Ecore_Event_Handler *thumb_exe_del_handler = NULL;
|
||||
static Eina_List *thumb_queue = NULL;
|
||||
static Eina_List *thumb_busy_queue = NULL;
|
||||
static unsigned int thumb_busy_max = 8;
|
||||
static double thumb_update_delay = 0.25;
|
||||
|
||||
static Eina_Bool _file_add_mod_info(Eina_Strbuf *strbuf, const char *path, Eina_Bool delay);
|
||||
|
||||
static void
|
||||
_strbuf_append_file_escaped(Eina_Strbuf *strbuf, const char *path)
|
||||
{ // append a filename and escape special chars for cmdline args
|
||||
const char *s;
|
||||
|
||||
for (s = path; *s; s++)
|
||||
{
|
||||
// if it's a special char - escale it
|
||||
if ((*s == ' ') || (*s == '\t') || (*s == '\n') || (*s == '\\') ||
|
||||
(*s == '\'') || (*s == '\"') || (*s == ';') || (*s == '!') ||
|
||||
(*s == '#') || (*s == '$') || (*s == '%') || (*s == '&') ||
|
||||
(*s == '*') || (*s == '(') || (*s == ')') || (*s == '[') ||
|
||||
(*s == ']') || (*s == '{') || (*s == '}') || (*s == '|') ||
|
||||
(*s == '<') || (*s == '>') || (*s == '?'))
|
||||
eina_strbuf_append_char(strbuf, '\\');
|
||||
eina_strbuf_append_char(strbuf, *s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_file_thumb_flush(void)
|
||||
{ // while count of busy list < max, pick from queue and launch ecore exe
|
||||
Thumb *th;
|
||||
Eina_List *l;
|
||||
Eina_Strbuf *strbuf;
|
||||
const char *dir = getenv("EFM_BACKEND_DIR");
|
||||
|
||||
if (!dir)
|
||||
{
|
||||
fprintf(stderr, "EFM_BACKEND_DIR not set to path to backend dirs\n");
|
||||
abort();
|
||||
}
|
||||
strbuf = eina_strbuf_new();
|
||||
if (!strbuf) return;
|
||||
// run up to thumb_busy_max thumbnailers in the background. this is
|
||||
// set in the init func.
|
||||
while (eina_list_count(thumb_busy_queue) < thumb_busy_max)
|
||||
{
|
||||
if (!thumb_queue) break;
|
||||
|
||||
// find first item in out queue that is noy delaying until it is busy
|
||||
EINA_LIST_FOREACH(thumb_queue, l, th)
|
||||
{
|
||||
if (!th->busy_delay_timer) break;
|
||||
th = NULL;
|
||||
}
|
||||
if (!th) break; // we didn't find anything that is not busy sleeping
|
||||
// remove from queue and put on busys queue
|
||||
thumb_queue = eina_list_remove_list(thumb_queue, l);
|
||||
thumb_busy_queue = eina_list_append(thumb_busy_queue, th);
|
||||
// build thumb command:
|
||||
// thumb FILE_PATH MIME THUMBNAIL_PATH
|
||||
// e.g.
|
||||
// thumb /path/to/f.jpg image/jpeg /home/u/.e/e/thumbs/f8/2a18.eet
|
||||
eina_strbuf_reset(strbuf);
|
||||
eina_strbuf_append(strbuf, getenv("EFM_BACKEND_DIR"));
|
||||
eina_strbuf_append(strbuf, "/thumb ");
|
||||
_strbuf_append_file_escaped(strbuf, th->path);
|
||||
eina_strbuf_append_char(strbuf, ' ');
|
||||
_strbuf_append_file_escaped(strbuf, th->mime);
|
||||
eina_strbuf_append_char(strbuf, ' ');
|
||||
_strbuf_append_file_escaped(strbuf, th->thumb);
|
||||
th->exe = ecore_exe_run(eina_strbuf_string_get(strbuf), th);
|
||||
}
|
||||
eina_strbuf_free(strbuf);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_file_thumb(const char *path EINA_UNUSED, const char *mime)
|
||||
{ // return true if we should have/generate a thumb for this
|
||||
return check_thumb_any(path, mime);
|
||||
}
|
||||
|
||||
static char *
|
||||
_file_thumb_find(const char *path, const char *mime EINA_UNUSED)
|
||||
{ // find the thumb file
|
||||
unsigned char sha[20];
|
||||
char buf[PATH_MAX], shastr[41];
|
||||
|
||||
eina_sha1((const unsigned char *)path, strlen(path), sha);
|
||||
sha1_str(sha, shastr);
|
||||
snprintf(buf, sizeof(buf), "%s/thumbs/%c%c/%s.eet", config_dir,
|
||||
shastr[0], shastr[1], shastr + 2);
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_thumb_delay(void *data)
|
||||
{ // when a delay timer expires - flush the queue to the busy queue
|
||||
Thumb *th = data;
|
||||
|
||||
th->busy_delay_timer = NULL;
|
||||
_file_thumb_flush();
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_file_thumb_queue(const char *path, const char *mime, Eina_Bool delay)
|
||||
{ // append a thumb generation item to the queue with a delay timer
|
||||
Thumb *th = calloc(1, sizeof(Thumb));
|
||||
char *thumb;
|
||||
|
||||
if (!th) return;
|
||||
thumb = _file_thumb_find(path, mime);
|
||||
if (!thumb)
|
||||
{
|
||||
free(th);
|
||||
return;
|
||||
}
|
||||
th->path = eina_stringshare_add(path);
|
||||
th->mime = eina_stringshare_add(mime);
|
||||
th->thumb = eina_stringshare_add(thumb);
|
||||
if (delay)
|
||||
th->busy_delay_timer = ecore_timer_add(thumb_update_delay,
|
||||
_cb_thumb_delay, th);
|
||||
thumb_queue = eina_list_append(thumb_queue, th);
|
||||
free(thumb);
|
||||
}
|
||||
|
||||
static void
|
||||
_file_thumb_gen(const char *path, const char *mime, Eina_Bool delay)
|
||||
{ // queue path + mime and kick off queue porcessor if idle
|
||||
Eina_List *l;
|
||||
Thumb *th;
|
||||
Eina_Bool found = EINA_FALSE;
|
||||
|
||||
// if already on queue - just moved to back
|
||||
EINA_LIST_FOREACH(thumb_queue, l, th)
|
||||
{
|
||||
if (!strcmp(th->path, path))
|
||||
{
|
||||
// move to end of queue
|
||||
thumb_queue = eina_list_demote_list(thumb_queue, l);
|
||||
// reset timer to start again
|
||||
ecore_timer_reset(th->busy_delay_timer);
|
||||
found = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) _file_thumb_queue(path, mime, delay);
|
||||
_file_thumb_flush();
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_thumb_exe_del(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event)
|
||||
{ // thumb slave exited - exit code 0 == all ok
|
||||
Ecore_Exe_Event_Del *ev = event;
|
||||
Thumb *th;
|
||||
Eina_List *l;
|
||||
|
||||
// find exe in our busy queue - if it is there
|
||||
EINA_LIST_FOREACH(thumb_busy_queue, l, th)
|
||||
{
|
||||
if (th->exe != ev->exe) continue; // it's not our desired exe - next
|
||||
// remove this thumb from the busy list
|
||||
thumb_busy_queue = eina_list_remove_list(thumb_busy_queue, l);
|
||||
if (ev->exit_code == 0)
|
||||
{ // thumb generation was all ok so send a file update
|
||||
Eina_Strbuf *strbuf = cmd_strbuf_new("file-mod");
|
||||
cmd_strbuf_append(strbuf, "path", th->path);
|
||||
if (!_file_add_mod_info(strbuf, th->path, EINA_FALSE))
|
||||
eina_strbuf_free(strbuf);
|
||||
else
|
||||
cmd_strbuf_print_consume(strbuf);
|
||||
}
|
||||
// free up this thumb in our busy queue as we're done with it
|
||||
eina_stringshare_del(th->path);
|
||||
eina_stringshare_del(th->mime);
|
||||
eina_stringshare_del(th->thumb);
|
||||
free(th);
|
||||
// we may have spare spots on our busy queue so flush to it
|
||||
_file_thumb_flush();
|
||||
break;
|
||||
}
|
||||
return ECORE_CALLBACK_PASS_ON; // let others handle this exe if they want
|
||||
}
|
||||
|
||||
static void
|
||||
_file_thumb_handle(Eina_Strbuf *strbuf, const char *path, const char *mime, struct stat *st, Eina_Bool delay)
|
||||
{ // handle finding the thumb of file and checking it's valid etc.
|
||||
char *thumb;
|
||||
|
||||
// does this file type do/need thumbnails
|
||||
if (!_file_thumb(path, mime)) return;
|
||||
|
||||
// get what the path to the target thumb should be
|
||||
thumb = _file_thumb_find(path, mime);
|
||||
if (thumb)
|
||||
{ // open the thumb and let's see if the stat info is up to date
|
||||
Eet_File *ef = eet_open(thumb, EET_FILE_MODE_READ);
|
||||
|
||||
if (ef)
|
||||
{ // thumb file exists - check meta data
|
||||
int size = 0;
|
||||
unsigned char statsha1[20];
|
||||
unsigned char *origstatsha1;
|
||||
Eina_Bool ok = EINA_FALSE;
|
||||
|
||||
// sha1 the relevant stat data at this point
|
||||
sha1_stat(st, statsha1);
|
||||
// load the stored sha1 of stat data from the thumb file
|
||||
origstatsha1 = eet_read(ef, "orig/stat/sha1", &size);
|
||||
if ((origstatsha1) && (size == 20))
|
||||
{
|
||||
if (!memcmp(statsha1, origstatsha1, 20))
|
||||
ok = EINA_TRUE; // sha1 of stat data matches - ok
|
||||
}
|
||||
eet_close(ef);
|
||||
if (!ok)
|
||||
{ // thumb stat data doesn'yt match file state data
|
||||
free(thumb);
|
||||
thumb = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // doesn't exist so no valid thumb
|
||||
free(thumb);
|
||||
thumb = NULL;
|
||||
}
|
||||
}
|
||||
if (!thumb)
|
||||
{ // no valid thumb - generate one
|
||||
_file_thumb_gen(path, mime, delay);
|
||||
}
|
||||
else
|
||||
{ // add the thumb property with full path to thumb
|
||||
cmd_strbuf_append(strbuf, "thumb", thumb);
|
||||
// XXX: add if tumb has alpha or not...
|
||||
free(thumb);
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
_icon_resolve(const char *path, const char *icon, struct stat *st)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char buf[PATH_MAX], *dir, *p, *user;
|
||||
|
||||
if (!icon) return NULL;
|
||||
// /path/to/file.png
|
||||
if (icon[0] == '/') return strdup(icon);
|
||||
if ((icon[0] == '.') && (icon[1] == '/'))
|
||||
{ // ./path/file.png
|
||||
if ((st->st_mode & S_IFMT) == S_IFDIR)
|
||||
dir = strdup(path);
|
||||
else
|
||||
dir = ecore_file_dir_get(path);
|
||||
if (dir)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s/%s", dir, icon + 2);
|
||||
return strdup(buf);
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
if ((icon[0] == '~') && (icon[1] == '/'))
|
||||
{ // ~/path/file.png
|
||||
pw = getpwuid(st->st_uid);
|
||||
if ((pw) && (pw->pw_dir))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, icon + 2);
|
||||
return strdup(buf);
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
if (icon[0] == '~')
|
||||
{ // ~user/path/file.png
|
||||
p = strchr(icon, '/');
|
||||
if (p)
|
||||
{
|
||||
user = malloc(p - icon);
|
||||
if (user)
|
||||
{
|
||||
strncpy(user, icon + 1, p - icon - 1);
|
||||
user[p - icon - 1] = 0;
|
||||
pw = getpwnam(user);
|
||||
if ((pw) && (pw->pw_dir))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, p + 1);
|
||||
return strdup(buf);
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
_desktop_x_field(Efreet_Desktop *desktop, const char *key)
|
||||
{
|
||||
if (!desktop->x) return NULL;
|
||||
return eina_hash_find(desktop->x, key);
|
||||
}
|
||||
|
||||
static void
|
||||
_cmd_desktop_x_field_append(Eina_Strbuf *strbuf, Efreet_Desktop *desktop, const char *cmd_key, const char *key)
|
||||
{
|
||||
const char *s = _desktop_x_field(desktop, key);
|
||||
if (s) cmd_strbuf_append(strbuf, cmd_key, s);
|
||||
}
|
||||
|
||||
static void
|
||||
_cmd_desktop_x_field_icon_resolve_append(Eina_Strbuf *strbuf, Efreet_Desktop *desktop, const char *cmd_key, const char *key, const char *path, struct stat *st)
|
||||
{
|
||||
const char *s = _desktop_x_field(desktop, key);
|
||||
char *icf;
|
||||
|
||||
if (!s) return;
|
||||
icf = _icon_resolve(path, s, st);
|
||||
if (!icf) return;
|
||||
cmd_strbuf_append(strbuf, cmd_key, icf);
|
||||
free(icf);
|
||||
}
|
||||
|
||||
const char *
|
||||
_mime_get(const char *file)
|
||||
{
|
||||
if (eina_fnmatch("*.edj", file, EINA_FNMATCH_CASEFOLD))
|
||||
return "application/x-edje";
|
||||
return efreet_mime_type_get(file);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_file_add_mod_info(Eina_Strbuf *strbuf, const char *path, Eina_Bool delay)
|
||||
{ // add file metadata info on file add or modfiy
|
||||
char dst[PATH_MAX], buf[256], buf2[PATH_MAX], *icf;
|
||||
struct stat st;
|
||||
int mode;
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
const char *mime, *ext, *icon;
|
||||
Efreet_Desktop *desktop;
|
||||
Eina_Bool have_label = EINA_FALSE;
|
||||
// XXX: x & y pos @ wxh view
|
||||
|
||||
if (lstat(path, &st) != 0) return EINA_FALSE;
|
||||
if ((st.st_mode & S_IFMT) == S_IFLNK)
|
||||
{
|
||||
struct stat stdst;
|
||||
|
||||
cmd_strbuf_append(strbuf, "type", "link");
|
||||
if (stat(path, &stdst) == 0)
|
||||
{
|
||||
ssize_t sz;
|
||||
|
||||
sz = readlink(path, dst, sizeof(dst) - 1);
|
||||
if (sz > 0)
|
||||
{
|
||||
dst[sz] = 0;
|
||||
cmd_strbuf_append(strbuf, "link", dst);
|
||||
if ((stdst.st_mode & S_IFMT) == S_IFLNK)
|
||||
cmd_strbuf_append(strbuf, "link-type", "link");
|
||||
else if ((stdst.st_mode & S_IFMT) == S_IFBLK)
|
||||
cmd_strbuf_append(strbuf, "link-type", "block");
|
||||
else if ((stdst.st_mode & S_IFMT) == S_IFCHR)
|
||||
cmd_strbuf_append(strbuf, "link-type", "char");
|
||||
else if ((stdst.st_mode & S_IFMT) == S_IFIFO)
|
||||
cmd_strbuf_append(strbuf, "link-type", "fifo");
|
||||
else if ((stdst.st_mode & S_IFMT) == S_IFSOCK)
|
||||
cmd_strbuf_append(strbuf, "link-type", "socket");
|
||||
else if ((stdst.st_mode & S_IFMT) == S_IFDIR)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "link-type", "dir");
|
||||
snprintf(buf2, sizeof(buf2), "%s/.dir.desktop", path);
|
||||
desktop = efreet_desktop_get(buf2);
|
||||
if (desktop)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "link-label", desktop->name ? desktop->name : ecore_file_file_get(path));
|
||||
cmd_strbuf_append(strbuf, "link-desktop-generic-name", desktop->generic_name ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-comment", desktop->comment ? desktop->comment : "");
|
||||
icf = _icon_resolve(path, desktop->icon, &stdst);
|
||||
if (icf)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "link-desktop-icon", icf);
|
||||
free(icf);
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "link-desktop-icon", desktop->icon ? desktop->icon : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-try-exec", desktop->try_exec ? desktop->try_exec : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-exec", desktop->exec ? desktop->exec : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-url", desktop->url ? desktop->url : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-no-display", desktop->no_display ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-hidden", desktop->hidden ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-terminal", desktop->terminal ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-startup-notify", desktop->startup_notify ? "true" : "false");
|
||||
if ((desktop->icon) && (desktop->icon[0] != '/'))
|
||||
{
|
||||
icon = efreet_mime_type_icon_get(desktop->icon, icon_theme, 128);
|
||||
cmd_strbuf_append(strbuf, "link-desktop-icon.lookup", icon ? icon : "");
|
||||
}
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "link-label-clicked", "X-NameClicked");
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "link-label-selected", "X-NameSelected");
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "link-desktop-icon-clicked", "X-IconClicked", path, &stdst);
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "link-desktop-icon-selected", "X-IconSelected", path, &stdst);
|
||||
efreet_desktop_free(desktop);
|
||||
have_label = EINA_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "link-type", "file");
|
||||
mime = _mime_get(dst);
|
||||
if (mime)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "mime", mime);
|
||||
icon = efreet_mime_type_icon_get(mime, icon_theme, 128);
|
||||
if (icon) cmd_strbuf_append(strbuf, "mime-icon", icon);
|
||||
_file_thumb_handle(strbuf, dst, mime, &stdst, delay);
|
||||
}
|
||||
ext = strrchr(dst, '.');
|
||||
if ((ext) && (!strcasecmp(ext, ".desktop")) && (S_ISREG(stdst.st_mode)))
|
||||
{
|
||||
desktop = efreet_desktop_get(path);
|
||||
if (desktop)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "link-label", desktop->name ? desktop->name : ecore_file_file_get(path));
|
||||
cmd_strbuf_append(strbuf, "link-desktop-generic-name", desktop->generic_name ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-comment", desktop->comment ? desktop->comment : "");
|
||||
icf = _icon_resolve(path, desktop->icon, &stdst);
|
||||
if (icf)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "link-desktop-icon", icf);
|
||||
free(icf);
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "link-desktop-icon", desktop->icon ? desktop->icon : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-try-exec", desktop->try_exec ? desktop->try_exec : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-exec", desktop->exec ? desktop->exec : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-url", desktop->url ? desktop->url : "");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-no-display", desktop->no_display ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-hidden", desktop->hidden ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-terminal", desktop->terminal ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "link-desktop-startup-notify", desktop->startup_notify ? "true" : "false");
|
||||
if ((desktop->icon) && (desktop->icon[0] != '/'))
|
||||
{
|
||||
icon = efreet_mime_type_icon_get(desktop->icon, icon_theme, 128);
|
||||
cmd_strbuf_append(strbuf, "link-desktop-icon.lookup", icon ? icon : "");
|
||||
}
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "link-label-clicked", "X-NameClicked");
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "link-label-selected", "X-NameSelected");
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "link-desktop-icon-clicked", "X-IconClicked", path, &stdst);
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "link-desktop-icon-selected", "X-IconSelected", path, &stdst);
|
||||
efreet_desktop_free(desktop);
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "link-label", ecore_file_file_get(path));
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "link-label", ecore_file_file_get(path));
|
||||
pw = getpwuid(stdst.st_uid);
|
||||
if (pw) cmd_strbuf_append(strbuf, "link-user", pw->pw_name);
|
||||
gr = getgrgid(stdst.st_gid);
|
||||
if (gr) cmd_strbuf_append(strbuf, "link-group", gr->gr_name);
|
||||
mode = stdst.st_mode &
|
||||
(S_ISUID | S_ISGID | S_ISVTX | S_IRUSR | S_IWUSR | S_IXUSR |
|
||||
S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
|
||||
snprintf(buf, sizeof(buf), "%x", mode);
|
||||
cmd_strbuf_append(strbuf, "link-mode", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_ino);
|
||||
cmd_strbuf_append(strbuf, "link-inode", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_nlink);
|
||||
cmd_strbuf_append(strbuf, "link-nlink", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_gid);
|
||||
cmd_strbuf_append(strbuf, "link-gid", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_size);
|
||||
cmd_strbuf_append(strbuf, "link-size", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_blksize);
|
||||
cmd_strbuf_append(strbuf, "link-blksize", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_blocks);
|
||||
cmd_strbuf_append(strbuf, "link-blocks", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_atime);
|
||||
cmd_strbuf_append(strbuf, "link-atime", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_mtime);
|
||||
cmd_strbuf_append(strbuf, "link-mtime", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)stdst.st_ctime);
|
||||
cmd_strbuf_append(strbuf, "link-ctime", buf);
|
||||
}
|
||||
}
|
||||
else // stat of original failed - what do we do?
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "broken-link", "true");
|
||||
mime = _mime_get(path);
|
||||
if (mime)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "mime", mime);
|
||||
icon = efreet_mime_type_icon_get(mime, icon_theme, 128);
|
||||
if (icon) cmd_strbuf_append(strbuf, "mime-icon", icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((st.st_mode & S_IFMT) == S_IFBLK)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "type", "block");
|
||||
snprintf(buf, sizeof(buf), "%i", (int)st.st_dev);
|
||||
cmd_strbuf_append(strbuf, "dev", buf);
|
||||
snprintf(buf, sizeof(buf), "%i", (int)st.st_rdev);
|
||||
cmd_strbuf_append(strbuf, "rdev", buf);
|
||||
}
|
||||
else if ((st.st_mode & S_IFMT) == S_IFCHR)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "type", "char");
|
||||
snprintf(buf, sizeof(buf), "%i", (int)st.st_dev);
|
||||
cmd_strbuf_append(strbuf, "dev", buf);
|
||||
snprintf(buf, sizeof(buf), "%i", (int)st.st_rdev);
|
||||
cmd_strbuf_append(strbuf, "rdev", buf);
|
||||
}
|
||||
else if ((st.st_mode & S_IFMT) == S_IFIFO)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "type", "fifo");
|
||||
}
|
||||
else if ((st.st_mode & S_IFMT) == S_IFSOCK)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "type", "socket");
|
||||
}
|
||||
else if ((st.st_mode & S_IFMT) == S_IFDIR)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "type", "dir");
|
||||
snprintf(buf2, sizeof(buf2), "%s/.dir.desktop", path);
|
||||
desktop = efreet_desktop_get(buf2);
|
||||
if (desktop)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "label", desktop->name ? desktop->name : ecore_file_file_get(path));
|
||||
cmd_strbuf_append(strbuf, "desktop-generic-name", desktop->generic_name ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-comment", desktop->comment ? desktop->comment : "");
|
||||
icf = _icon_resolve(path, desktop->icon, &st);
|
||||
if (icf)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "desktop-icon", icf);
|
||||
free(icf);
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "desktop-icon", desktop->icon ? desktop->icon : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-try-exec", desktop->try_exec ? desktop->try_exec : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-exec", desktop->exec ? desktop->exec : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-url", desktop->url ? desktop->url : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-no-display", desktop->no_display ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-hidden", desktop->hidden ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-terminal", desktop->terminal ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-startup-notify", desktop->startup_notify ? "true" : "false");
|
||||
if ((desktop->icon) && (desktop->icon[0] != '/'))
|
||||
{
|
||||
icon = efreet_mime_type_icon_get(desktop->icon, icon_theme, 128);
|
||||
cmd_strbuf_append(strbuf, "desktop-icon.lookup", icon ? icon : "");
|
||||
}
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "label-clicked", "X-NameClicked");
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "label-selected", "X-NameSelected");
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "desktop-icon-clicked", "X-IconClicked", path, &st);
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "desktop-icon-selected", "X-IconSelected", path, &st);
|
||||
efreet_desktop_free(desktop);
|
||||
have_label = EINA_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "type", "file");
|
||||
mime = _mime_get(path);
|
||||
if (mime)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "mime", mime);
|
||||
icon = efreet_mime_type_icon_get(mime, icon_theme, 128);
|
||||
if (icon) cmd_strbuf_append(strbuf, "mime-icon", icon);
|
||||
_file_thumb_handle(strbuf, path, mime, &st, delay);
|
||||
}
|
||||
ext = strrchr(path, '.');
|
||||
if ((ext) && (!strcasecmp(ext, ".desktop")) && (S_ISREG(st.st_mode)))
|
||||
{
|
||||
desktop = efreet_desktop_get(path);
|
||||
if (desktop)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "label", desktop->name ? desktop->name : ecore_file_file_get(path));
|
||||
cmd_strbuf_append(strbuf, "desktop-generic-name", desktop->generic_name ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-comment", desktop->comment ? desktop->comment : "");
|
||||
icf = _icon_resolve(path, desktop->icon, &st);
|
||||
if (icf)
|
||||
{
|
||||
cmd_strbuf_append(strbuf, "desktop-icon", icf);
|
||||
free(icf);
|
||||
}
|
||||
else
|
||||
cmd_strbuf_append(strbuf, "desktop-icon", desktop->icon ? desktop->icon : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-try-exec", desktop->try_exec ? desktop->try_exec : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-exec", desktop->exec ? desktop->exec : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-url", desktop->url ? desktop->url : "");
|
||||
cmd_strbuf_append(strbuf, "desktop-no-display", desktop->no_display ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-hidden", desktop->hidden ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-terminal", desktop->terminal ? "true" : "false");
|
||||
cmd_strbuf_append(strbuf, "desktop-startup-notify", desktop->startup_notify ? "true" : "false");
|
||||
if ((desktop->icon) && (desktop->icon[0] != '/'))
|
||||
{
|
||||
icon = efreet_mime_type_icon_get(desktop->icon, icon_theme, 128);
|
||||
cmd_strbuf_append(strbuf, "desktop-icon.lookup", icon ? icon : "");
|
||||
}
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "label-clicked", "X-NameClicked");
|
||||
_cmd_desktop_x_field_append(strbuf, desktop, "label-selected", "X-NameSelected");
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "desktop-icon-clicked", "X-IconClicked", path, &st);
|
||||
_cmd_desktop_x_field_icon_resolve_append(strbuf, desktop, "desktop-icon-selected", "X-IconSelected", path, &st);
|
||||
efreet_desktop_free(desktop);
|
||||
}
|
||||
else if (!have_label)
|
||||
cmd_strbuf_append(strbuf, "label", ecore_file_file_get(path));
|
||||
}
|
||||
else if (!have_label)
|
||||
cmd_strbuf_append(strbuf, "label", ecore_file_file_get(path));
|
||||
}
|
||||
pw = getpwuid(st.st_uid);
|
||||
if (pw) cmd_strbuf_append(strbuf, "user", pw->pw_name);
|
||||
gr = getgrgid(st.st_gid);
|
||||
if (gr) cmd_strbuf_append(strbuf, "group", gr->gr_name);
|
||||
mode = st.st_mode /*&
|
||||
(S_ISUID | S_ISGID | S_ISVTX | S_IRUSR | S_IWUSR | S_IXUSR |
|
||||
S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH)*/;
|
||||
snprintf(buf, sizeof(buf), "%x", mode);
|
||||
cmd_strbuf_append(strbuf, "mode", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_ino);
|
||||
cmd_strbuf_append(strbuf, "inode", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_nlink);
|
||||
cmd_strbuf_append(strbuf, "nlink", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_gid);
|
||||
cmd_strbuf_append(strbuf, "gid", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_size);
|
||||
cmd_strbuf_append(strbuf, "size", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_blksize);
|
||||
cmd_strbuf_append(strbuf, "blksize", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_blocks);
|
||||
cmd_strbuf_append(strbuf, "blocks", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_atime);
|
||||
cmd_strbuf_append(strbuf, "atime", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_mtime);
|
||||
cmd_strbuf_append(strbuf, "mtime", buf);
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)st.st_ctime);
|
||||
cmd_strbuf_append(strbuf, "ctime", buf);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_file_add(const char *path)
|
||||
{
|
||||
Eina_Strbuf *strbuf;
|
||||
|
||||
strbuf = cmd_strbuf_new("file-add");
|
||||
cmd_strbuf_append(strbuf, "path", path);
|
||||
if (!_file_add_mod_info(strbuf, path, EINA_FALSE))
|
||||
eina_strbuf_free(strbuf);
|
||||
else
|
||||
cmd_strbuf_print_consume(strbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
_file_del(const char *path)
|
||||
{
|
||||
Eina_Strbuf *strbuf;
|
||||
|
||||
strbuf = cmd_strbuf_new("file-del");
|
||||
cmd_strbuf_append(strbuf, "path", path);
|
||||
cmd_strbuf_print_consume(strbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
_file_mod(const char *path)
|
||||
{
|
||||
Eina_Strbuf *strbuf;
|
||||
|
||||
strbuf = cmd_strbuf_new("file-mod");
|
||||
cmd_strbuf_append(strbuf, "path", path);
|
||||
if (!_file_add_mod_info(strbuf, path, EINA_TRUE))
|
||||
eina_strbuf_free(strbuf);
|
||||
else
|
||||
cmd_strbuf_print_consume(strbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
_dir_del(const char *path)
|
||||
{
|
||||
Eina_Strbuf *strbuf;
|
||||
|
||||
strbuf = cmd_strbuf_new("dir-del");
|
||||
cmd_strbuf_append(strbuf, "path", path);
|
||||
cmd_strbuf_print_consume(strbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_mon(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED, Ecore_File_Event event, const char *path)
|
||||
{
|
||||
if ((event == ECORE_FILE_EVENT_CREATED_FILE) ||
|
||||
(event == ECORE_FILE_EVENT_CREATED_DIRECTORY))
|
||||
_file_add(path);
|
||||
else if ((event == ECORE_FILE_EVENT_DELETED_FILE) ||
|
||||
(event == ECORE_FILE_EVENT_DELETED_DIRECTORY))
|
||||
_file_del(path);
|
||||
else if (event == ECORE_FILE_EVENT_MODIFIED)
|
||||
_file_mod(path);
|
||||
else if (event == ECORE_FILE_EVENT_DELETED_SELF)
|
||||
_dir_del(path);
|
||||
}
|
||||
|
||||
static void
|
||||
_monitor(const char *path)
|
||||
{
|
||||
Eina_Iterator *it;
|
||||
Eina_File_Direct_Info *info;
|
||||
Eina_Strbuf *strbuf;
|
||||
|
||||
if (mon) return;
|
||||
|
||||
// tell the front end out listing is beginning
|
||||
strbuf = cmd_strbuf_new("list-begin");
|
||||
cmd_strbuf_print_consume(strbuf);
|
||||
|
||||
mon = ecore_file_monitor_add(path, _cb_mon, NULL);
|
||||
it = eina_file_direct_ls(path);
|
||||
if (!it)
|
||||
{
|
||||
// XXX: error output
|
||||
goto err;
|
||||
}
|
||||
EINA_ITERATOR_FOREACH(it, info) _file_add(info->path);
|
||||
eina_iterator_free(it);
|
||||
err:
|
||||
// tell the front end out listing is done
|
||||
strbuf = cmd_strbuf_new("list-end");
|
||||
cmd_strbuf_print_consume(strbuf);
|
||||
}
|
||||
|
||||
void
|
||||
do_handle_cmd(Cmd *c)
|
||||
{
|
||||
if (!strcmp(c->command, "dir-set"))
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; c->dict[i]; i += 2)
|
||||
{
|
||||
if (!strcmp(c->dict[i], "path")) _monitor(c->dict[i + 1]);
|
||||
}
|
||||
}
|
||||
// cmd_dump_sterr(c);
|
||||
}
|
||||
|
||||
int
|
||||
do_init(int argc EINA_UNUSED, const char **argv EINA_UNUSED)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
ecore_file_init();
|
||||
efreet_init();
|
||||
efreet_mime_init();
|
||||
|
||||
icon_theme = getenv("E_ICON_THEME");
|
||||
config_dir = getenv("E_HOME_DIR");
|
||||
home_dir = getenv("HOME");
|
||||
if (!home_dir) return 0;
|
||||
if (!config_dir)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/.e/e", home_dir);
|
||||
home_dir = eina_stringshare_add(buf);
|
||||
}
|
||||
|
||||
// maximum number of back-end thumbnailer slaves is num cores - 2
|
||||
// with a minimum of 1 (so dual core systems will be limited to 1
|
||||
// thumbnailer at once. quad core will run 2. 8 core will run 6, 16
|
||||
// core will run 14, 32 core will run 30 etc. - this can get overidden
|
||||
// by env var of course
|
||||
s = getenv("E_THUMB_MAX");
|
||||
if (s)
|
||||
{
|
||||
thumb_busy_max = atoi(s);
|
||||
}
|
||||
else thumb_busy_max = eina_cpu_count() - 2;
|
||||
if (thumb_busy_max < 1) thumb_busy_max = 1;
|
||||
|
||||
// we want to listen for when thumbnails slaves finish
|
||||
thumb_exe_del_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
|
||||
_cb_thumb_exe_del, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
do_shutdown(void)
|
||||
{
|
||||
ecore_event_handler_del(thumb_exe_del_handler);
|
||||
thumb_exe_del_handler = NULL;
|
||||
|
||||
if (mon) ecore_file_monitor_del(mon);
|
||||
mon = NULL;
|
||||
|
||||
efreet_mime_shutdown();
|
||||
efreet_shutdown();
|
||||
ecore_file_shutdown();
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
read -r CMD
|
||||
|
||||
sleep 1;
|
||||
echo -e "CMD add type=file file=hello.txt icon=plain path=/xx/yy/hello.txt"
|
||||
sleep 1
|
||||
echo -e "CMD add type=file file=blah.txt icon=folder path=/xx/yy/blah.txt"
|
||||
echo -e "CMD add type=file file=boo.txt icon=blank path=/xx/yy/boo.txt"
|
||||
while [ 1 ]; do sleep 1; done
|
|
@ -0,0 +1,108 @@
|
|||
#include "thumb.h"
|
||||
|
||||
Evas_Object *win = NULL;
|
||||
Evas_Object *subwin = NULL;
|
||||
Evas_Object *image = NULL;
|
||||
|
||||
static void
|
||||
_thumb_dir_make(const char *thumb)
|
||||
{ // create dir for the thumb to live in
|
||||
char *dir = ecore_file_dir_get(thumb);
|
||||
if (!dir) return;
|
||||
ecore_file_mkpath(dir);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
static Eet_File *
|
||||
_thumb_output_open(const char *thumb)
|
||||
{ // open target thumb tmp file we will later atomically replace target with
|
||||
char buf[PATH_MAX];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s.tmp", thumb);
|
||||
return eet_open(buf, EET_FILE_MODE_WRITE);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_output_close(Eet_File *ef, const char *thumb)
|
||||
{ // close thumnb file and atomically rename tmp file on top of target
|
||||
char buf[PATH_MAX];
|
||||
|
||||
eet_close(ef);
|
||||
snprintf(buf, sizeof(buf), "%s.tmp", thumb);
|
||||
ecore_file_mv(buf, thumb);
|
||||
}
|
||||
|
||||
EAPI_MAIN int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
Eet_File *ef;
|
||||
const char *path, *mime, *thumb;
|
||||
int ret;
|
||||
struct stat st;
|
||||
unsigned char statsha1[20];
|
||||
|
||||
if (argc < 4) return 100;
|
||||
|
||||
path = argv[1];
|
||||
mime = argv[2];
|
||||
thumb = argv[3];
|
||||
|
||||
// set up buffer win/canvas with sub win rendered inline as image
|
||||
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
|
||||
elm_config_preferred_engine_set("buffer");
|
||||
win = elm_win_add(NULL, "Efm-Thumb", ELM_WIN_BASIC);
|
||||
subwin = elm_win_add(win, "inlined", ELM_WIN_INLINED_IMAGE);
|
||||
elm_win_alpha_set(subwin, EINA_TRUE);
|
||||
image = elm_win_inlined_image_object_get(subwin);
|
||||
evas_object_show(subwin);
|
||||
evas_object_show(win);
|
||||
// manual rendering as we won't run the loop - only render then get results
|
||||
elm_win_norender_push(subwin);
|
||||
elm_win_norender_push(win);
|
||||
|
||||
// stat orig file and store the state info we care about as a sha1 hash
|
||||
if (stat(path, &st) != 0) exit(1);
|
||||
sha1_stat(&st, statsha1);
|
||||
|
||||
// ensure dest dir for thumb exists
|
||||
_thumb_dir_make(thumb);
|
||||
// open our thubm file ti write thnigs into it
|
||||
ef = _thumb_output_open(thumb);
|
||||
if (!ef) exit(3);
|
||||
|
||||
// an edj file (theme, background, icon .... groups inside matter
|
||||
if (check_thumb_edje(path, mime))
|
||||
ret = thumb_edje(ef, path, mime, thumb);
|
||||
// if it's a font - load it and render some text as thumb/preview
|
||||
else if (check_thumb_font(path, mime))
|
||||
ret = thumb_font(ef, path, mime, thumb);
|
||||
// a paged document - load multiple pages into thumb
|
||||
else if (check_thumb_paged(path, mime))
|
||||
ret = thumb_paged(ef, path, mime, thumb);
|
||||
// a music track/file
|
||||
else if (check_thumb_music(path, mime))
|
||||
ret = thumb_music(ef, path, mime, thumb);
|
||||
// a video file of a moive, series episode or something else
|
||||
else if (check_thumb_video(path, mime))
|
||||
ret = thumb_video(ef, path, mime, thumb);
|
||||
// otherwise handle as an image
|
||||
else
|
||||
ret = thumb_image(ef, path, mime, thumb);
|
||||
|
||||
// write out the original file path so we could walk through all thumbs
|
||||
// and find which thumbs no longer have an original file left
|
||||
eet_write(ef, "orig/path", path, strlen(path),
|
||||
EET_COMPRESSION_LOW);
|
||||
// write out our sha1 of the file stat info - quick and mostly right way
|
||||
// to heck if the thumb is up to date with file
|
||||
eet_write(ef, "orig/stat/sha1", statsha1, 20,
|
||||
EET_COMPRESSION_NONE);
|
||||
// done - finish file write and atomic rename
|
||||
_thumb_output_close(ef, thumb);
|
||||
|
||||
// if we failed to generate the thumb - delete what we were building
|
||||
if (ret != 0) unlink(thumb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
ELM_MAIN()
|
|
@ -0,0 +1,71 @@
|
|||
#include <Elementary.h>
|
||||
#include "efm_config.h"
|
||||
#include "sha.h"
|
||||
#include "thumb_check.h"
|
||||
|
||||
extern Evas_Object *win;
|
||||
extern Evas_Object *subwin;
|
||||
extern Evas_Object *image;
|
||||
|
||||
void thumb_image_write(Eet_File *ef, const char *key, Evas_Object *img, Eina_Bool a, Eina_Bool lossy);
|
||||
|
||||
void thumb_url_str_get(const char *url, size_t max, void (*cb) (void *data, const char *result), const void *data);
|
||||
void thumb_url_bin_get(const char *url, size_t max, void (*cb) (void *data, const void *result, size_t size), const void *data);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *url;
|
||||
int w, h;
|
||||
} Search_Result;
|
||||
|
||||
void thumb_search_image(const char *str, void (*cb) (void *data, Eina_List *results_orig, Eina_List *results_cached), void *data);
|
||||
|
||||
int thumb_image (Eet_File *ef, const char *path, const char *mime, const char *thumb);
|
||||
int thumb_font (Eet_File *ef, const char *path, const char *mime, const char *thumb);
|
||||
int thumb_paged (Eet_File *ef, const char *path, const char *mime, const char *thumb);
|
||||
int thumb_music (Eet_File *ef, const char *path, const char *mime, const char *thumb);
|
||||
int thumb_video (Eet_File *ef, const char *path, const char *mime, const char *thumb);
|
||||
int thumb_edje (Eet_File *ef, const char *path, const char *mime, const char *thumb);
|
||||
|
||||
// utility
|
||||
static inline void
|
||||
scale(int *w, int *h, int maxw, int maxh, Eina_Bool no_scale_up)
|
||||
{ // write a big 1024x1024 preview (but no larger than the original image)
|
||||
int ww, hh;
|
||||
|
||||
ww = maxw;
|
||||
hh = (*h * maxw) / *w;
|
||||
if (hh > maxh)
|
||||
{ // too tall = so limit height and scale down keeping aspect
|
||||
hh = maxh;
|
||||
ww = (*w * maxh) / *h;
|
||||
}
|
||||
if ((no_scale_up) && ((ww > *h) || (hh > *h)))
|
||||
{
|
||||
ww = *w;
|
||||
hh = *h;
|
||||
}
|
||||
*w = ww;
|
||||
*h = hh;
|
||||
}
|
||||
|
||||
static inline void
|
||||
scale_out(int *w, int *h, int maxw, int maxh, Eina_Bool no_scale_up)
|
||||
{ // write a big 1024x1024 preview (but no larger than the original image)
|
||||
int ww, hh;
|
||||
|
||||
ww = maxw;
|
||||
hh = (*h * maxw) / *w;
|
||||
if (hh < maxh)
|
||||
{ // not tall enough = so limit height and scale down keeping aspect
|
||||
hh = maxh;
|
||||
ww = (*w * maxh) / *h;
|
||||
}
|
||||
if ((no_scale_up) && ((ww > *h) || (hh > *h)))
|
||||
{
|
||||
ww = *w;
|
||||
hh = *h;
|
||||
}
|
||||
*w = ww;
|
||||
*h = hh;
|
||||
}
|
|
@ -0,0 +1,378 @@
|
|||
// generate thumbnail for images
|
||||
#include "thumb.h"
|
||||
|
||||
// XXX: can do progressive resize down ie scale to 512 then take 512 and
|
||||
// halve to 256 then halve it to 128 etc. rather than render from orig to
|
||||
// target size....
|
||||
|
||||
static Evas_Object *edj = NULL;
|
||||
static Evas_Object *subsubwin = NULL;
|
||||
static Evas_Object *subimage = NULL;
|
||||
static int iw = 0, ih = 0;
|
||||
static char *grp_first = NULL;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EDJ_NONE, // does not appear to have groups
|
||||
EDJ_THEME, // what looks like a full theme
|
||||
EDJ_BACKGROUND, // a wallpaper background file
|
||||
EDJ_ICON, // an icon edje file
|
||||
EDJ_FIRST // just use the first group found
|
||||
} Edj_Type;
|
||||
|
||||
static void
|
||||
_thumb_image_setup(void)
|
||||
{ // create and show image
|
||||
subsubwin = elm_win_add(subwin, "inlined2", ELM_WIN_INLINED_IMAGE);
|
||||
subimage = elm_win_inlined_image_object_get(subsubwin);
|
||||
elm_win_alpha_set(subsubwin, EINA_TRUE);
|
||||
evas_object_show(subsubwin);
|
||||
|
||||
edj = edje_object_add(evas_object_evas_get(subsubwin));
|
||||
evas_object_show(edj);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_file_background_set(const char *file)
|
||||
{
|
||||
edje_object_file_set(edj, file, "e/desktop/background");
|
||||
iw = 1920;
|
||||
ih = 1080;
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_file_icon_set(const char *file)
|
||||
{
|
||||
edje_object_file_set(edj, file, "icon");
|
||||
edje_object_size_min_get(edj, &iw, &ih);
|
||||
if ((iw <= 0) || (ih < 0))
|
||||
{
|
||||
iw = 256;
|
||||
ih = 256;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_file_first_group_set(const char *file, const char *grp)
|
||||
{
|
||||
edje_object_file_set(edj, file, grp);
|
||||
edje_object_size_min_get(edj, &iw, &ih);
|
||||
if (iw <= 0)
|
||||
{
|
||||
edje_object_size_min_restricted_calc(edj, &iw, &ih, 256, 256);
|
||||
}
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_quit(void *data EINA_UNUSED)
|
||||
{
|
||||
elm_exit();
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_file_theme_set(const char *file)
|
||||
{
|
||||
const char *s;
|
||||
Evas_Object *o, *o_comp, *o_border, *o_win_table, *o_win_bg;
|
||||
Evas_Object *o_toolbar, *o_list, *o_frame, *o_box;
|
||||
Evas_Object *o_check1, *o_check2, *o_check3, *o_sep;
|
||||
Evas_Object *o_radio1, *o_radio2, *o_radio3;
|
||||
Evas_Object *o_slider, *o_progress;
|
||||
Evas_Object *o_button1, *o_button2;
|
||||
Elm_Object_Item *it;
|
||||
|
||||
elm_theme_overlay_add(NULL, file);
|
||||
|
||||
s = elm_theme_group_path_find(NULL, "e/desktop/background");
|
||||
edje_object_file_set(edj, s, "e/desktop/background");
|
||||
iw = 512;
|
||||
ih = 512;
|
||||
|
||||
o = o_comp = edje_object_add(evas_object_evas_get(subsubwin));
|
||||
s = elm_theme_group_path_find(NULL, "e/comp/frame/default");
|
||||
edje_object_file_set(o, s, "e/comp/frame/default");
|
||||
edje_object_signal_emit(o, "e,state,visible", "e");
|
||||
|
||||
o = o_border = edje_object_add(evas_object_evas_get(subsubwin));
|
||||
s = elm_theme_group_path_find(NULL, "e/widgets/border/default/border");
|
||||
edje_object_file_set(o, s, "e/widgets/border/default/border");
|
||||
edje_object_part_text_set(o, "e.text.title", "Title");
|
||||
edje_object_signal_emit(o, "e,state,focused", "e");
|
||||
evas_object_show(o);
|
||||
edje_object_part_swallow(o_comp, "e.swallow.content", o);
|
||||
|
||||
o = o_win_table = elm_table_add(subsubwin);
|
||||
edje_object_part_swallow(o_border, "e.swallow.client", o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_win_bg = elm_bg_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
elm_table_pack(o_win_table, o, 0, 0, 10, 10);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_toolbar = elm_toolbar_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.0);
|
||||
elm_toolbar_homogeneous_set(o, EINA_TRUE);
|
||||
elm_toolbar_align_set(o, 0.5);
|
||||
elm_table_pack(o_win_table, o, 0, 0, 10, 1);
|
||||
evas_object_show(o);
|
||||
|
||||
it = elm_toolbar_item_append(o_toolbar, "folder", "Folder", NULL, NULL);
|
||||
elm_toolbar_item_selected_set(it, EINA_TRUE);
|
||||
it = elm_toolbar_item_append(o_toolbar, "computer", "Computer", NULL, NULL);
|
||||
it = elm_toolbar_item_append(o_toolbar, "audio-volume", "Volume", NULL, NULL);
|
||||
it = elm_toolbar_item_append(o_toolbar, "user-available", "User", NULL, NULL);
|
||||
it = elm_toolbar_item_append(o_toolbar, "mail-send", "Mail", NULL, NULL);
|
||||
|
||||
o = o_list = elm_list_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
elm_table_pack(o_win_table, o, 0, 1, 5, 6);
|
||||
evas_object_show(o);
|
||||
|
||||
it = elm_list_item_append(o_list, "This", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "List", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Contains", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Items", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Long list item", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Short item", NULL, NULL, NULL, NULL);
|
||||
elm_list_item_selected_set(it, EINA_TRUE);
|
||||
it = elm_list_item_append(o_list, "More text here", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Less text", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Text", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Yet more items", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "And even longer items", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Shorter items", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Short items", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Shortest item", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Second last item", NULL, NULL, NULL, NULL);
|
||||
it = elm_list_item_append(o_list, "Last item", NULL, NULL, NULL, NULL);
|
||||
|
||||
elm_list_go(o_list);
|
||||
|
||||
o = o_frame = elm_frame_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
elm_object_text_set(o, "Frame");
|
||||
elm_table_pack(o_win_table, o, 5, 1, 5, 6);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_box = elm_box_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
elm_box_horizontal_set(o, EINA_FALSE);
|
||||
elm_box_align_set(o, 0.5, 0.0);
|
||||
elm_object_content_set(o_frame, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_check1 = elm_check_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
|
||||
elm_object_text_set(o, "This option");
|
||||
elm_box_pack_end(o_box, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_check2 = elm_check_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
|
||||
elm_object_text_set(o, "Something");
|
||||
elm_check_state_set(o, EINA_TRUE);
|
||||
elm_box_pack_end(o_box, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_check3 = elm_check_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
|
||||
elm_object_text_set(o, "And another thing");
|
||||
elm_check_state_set(o, EINA_TRUE);
|
||||
elm_box_pack_end(o_box, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_sep = elm_separator_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
|
||||
elm_separator_horizontal_set(o, EINA_TRUE);
|
||||
elm_box_pack_end(o_box, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_radio1 = elm_radio_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
|
||||
elm_radio_state_value_set(o, 1);
|
||||
elm_object_text_set(o, "First");
|
||||
elm_box_pack_end(o_box, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_radio2 = elm_radio_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
|
||||
elm_radio_state_value_set(o, 2);
|
||||
elm_radio_group_add(o, o_radio1);
|
||||
elm_object_text_set(o, "Second");
|
||||
elm_box_pack_end(o_box, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_radio3 = elm_radio_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
|
||||
elm_radio_state_value_set(o, 3);
|
||||
elm_radio_group_add(o, o_radio1);
|
||||
elm_object_text_set(o, "Third");
|
||||
elm_box_pack_end(o_box, o);
|
||||
evas_object_show(o);
|
||||
|
||||
elm_radio_value_set(o_radio1, 2);
|
||||
|
||||
o = o_slider = elm_slider_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 1.0);
|
||||
elm_object_text_set(o, "Slider");
|
||||
elm_slider_unit_format_set(o, "%1.1f");
|
||||
elm_slider_min_max_set(o, 0, 10);
|
||||
elm_slider_value_set(o, 3.7);
|
||||
elm_table_pack(o_win_table, o, 0, 7, 10, 1);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_progress = elm_progressbar_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 1.0);
|
||||
elm_object_text_set(o, "Progress");
|
||||
elm_progressbar_value_set(o, 0.7);
|
||||
elm_progressbar_unit_format_set(o, "%1.1f");
|
||||
elm_table_pack(o_win_table, o, 0, 8, 10, 1);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_button1 = elm_button_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 1.0);
|
||||
elm_object_text_set(o, "Select");
|
||||
elm_table_pack(o_win_table, o, 0, 9, 5, 1);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_button2 = elm_button_add(o_win_table);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 1.0);
|
||||
elm_object_text_set(o, "Cancel");
|
||||
elm_table_pack(o_win_table, o, 5, 9, 5, 1);
|
||||
evas_object_show(o);
|
||||
|
||||
o = o_comp;
|
||||
evas_object_move(o, 64, 64);
|
||||
evas_object_resize(o, 384, 384);
|
||||
evas_object_show(o);
|
||||
|
||||
ecore_timer_add(1.0, _cb_quit, NULL);
|
||||
elm_run();
|
||||
}
|
||||
|
||||
static Edj_Type
|
||||
_thumb_edje_type_guess(const char *file)
|
||||
{
|
||||
Eina_List *l;
|
||||
const char *s;
|
||||
Eina_List *groups = edje_file_collection_list(file);
|
||||
if (!groups) return EDJ_NONE;
|
||||
Eina_Bool have_icon = EINA_FALSE;
|
||||
Eina_Bool have_e_background = EINA_FALSE;
|
||||
Eina_Bool have_e_border = EINA_FALSE;
|
||||
Eina_Bool have_elm_button = EINA_FALSE;
|
||||
Eina_Bool have_elm_check = EINA_FALSE;
|
||||
Eina_Bool have_elm_genlist = EINA_FALSE;
|
||||
Eina_Bool have_elm_frame = EINA_FALSE;
|
||||
|
||||
EINA_LIST_FOREACH(groups, l, s)
|
||||
{
|
||||
if (!grp_first) grp_first = strdup(s);
|
||||
#define MATCH(__str, __val) (!strcmp(s, __str)) have_ ## __val = EINA_TRUE
|
||||
if MATCH("icon", icon);
|
||||
else if MATCH("e/desktop/background", e_background);
|
||||
else if MATCH("e/widgets/border/default/border", e_border);
|
||||
else if MATCH("elm/button/base/default", elm_button);
|
||||
else if MATCH("elm/check/base/default", elm_check);
|
||||
else if MATCH("elm/genlist/item/default/default", elm_genlist);
|
||||
else if MATCH("elm/frame/base/default", elm_frame);
|
||||
}
|
||||
edje_file_collection_list_free(groups);
|
||||
|
||||
if (have_e_background && have_e_border && have_elm_button &&
|
||||
have_elm_check && have_elm_genlist && have_elm_frame)
|
||||
return EDJ_THEME;
|
||||
else if (have_e_background)
|
||||
return EDJ_BACKGROUND;
|
||||
else if (have_icon)
|
||||
return EDJ_ICON;
|
||||
return EDJ_FIRST;
|
||||
}
|
||||
|
||||
int
|
||||
thumb_edje(Eet_File *ef, const char *path, const char *mime EINA_UNUSED, const char *thumb EINA_UNUSED)
|
||||
{
|
||||
const int sizes[] = { 512, 256, 128, 64, 32, 16, 0 };
|
||||
int w, h, i;
|
||||
char buf[128];
|
||||
Edj_Type etype = _thumb_edje_type_guess(path);
|
||||
|
||||
if (etype == EDJ_NONE) return 2;
|
||||
|
||||
elm_config_scale_set(1.0);
|
||||
_thumb_image_setup();
|
||||
|
||||
if (etype == EDJ_BACKGROUND)
|
||||
{ // add filled background
|
||||
_thumb_image_file_background_set(path);
|
||||
}
|
||||
else if (etype == EDJ_ICON)
|
||||
{ // an edj icon file
|
||||
_thumb_image_file_icon_set(path);
|
||||
}
|
||||
else if (etype == EDJ_THEME)
|
||||
{ // it's a theme - let's fake up some gui setup
|
||||
_thumb_image_file_theme_set(path);
|
||||
}
|
||||
else if (etype == EDJ_FIRST)
|
||||
{ // just load first group we find
|
||||
_thumb_image_file_first_group_set(path, grp_first);
|
||||
}
|
||||
// if size is bunk - we can't load it...
|
||||
if ((iw <= 0) || (ih < 0)) return 2;
|
||||
|
||||
// write a big 1024x1024 preview (but no larger than the original image)
|
||||
w = iw; h = ih; scale(&w, &h, 1024, 1024, EINA_TRUE);
|
||||
|
||||
// resize to target size
|
||||
evas_object_resize(edj, iw, ih);
|
||||
evas_object_resize(subsubwin, iw, ih);
|
||||
|
||||
// preview
|
||||
evas_object_resize(subimage, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subsubwin);
|
||||
elm_win_render(subwin);
|
||||
// save out preview size
|
||||
snprintf(buf, sizeof(buf), "image/preview");
|
||||
thumb_image_write(ef, buf, image, EINA_TRUE, EINA_TRUE);
|
||||
snprintf(buf, sizeof(buf), "%i %i", w, h);
|
||||
eet_write(ef, "image/preview/size", buf, strlen(buf) + 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
|
||||
// multiple thumb sizes so can load/pick the best one at runtime
|
||||
for (i = 0; sizes[i] != 0; i++)
|
||||
{
|
||||
// scale down and keep aspect
|
||||
w = iw; h = ih; scale(&w, &h, sizes[i], sizes[i], EINA_FALSE);
|
||||
// resize to target size
|
||||
evas_object_resize(subimage, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out thumb size
|
||||
snprintf(buf, sizeof(buf), "image/thumb/%i", sizes[i]);
|
||||
thumb_image_write(ef, buf, image, EINA_TRUE, EINA_TRUE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
// generate thumbnail files for fonts
|
||||
#include "thumb.h"
|
||||
|
||||
static Evas_Object *
|
||||
_thumb_text_setup(const char *file, const char *str, int maxw, int maxh, int size, int *size_chosen)
|
||||
{
|
||||
Evas_Object *o;
|
||||
Evas_Coord w, h;
|
||||
int sizeup, sizedn, psize;
|
||||
|
||||
o = evas_object_text_add(evas_object_evas_get(subwin));
|
||||
evas_object_color_set(o, 255, 255, 255, 255);
|
||||
evas_object_text_text_set(o, str);
|
||||
if (size == 0)
|
||||
evas_object_text_font_set(o, file, maxh);
|
||||
else
|
||||
evas_object_text_font_set(o, file, size);
|
||||
evas_object_show(o);
|
||||
if (size == 0)
|
||||
{ // auto find a size that fits in maxw/maxh
|
||||
size = maxh;
|
||||
sizeup = size * 2;
|
||||
sizedn = 1;
|
||||
psize = size + 100; // dummy psize for first loop
|
||||
for (;;)
|
||||
{
|
||||
evas_object_geometry_get(o, NULL, NULL, &w, &h);
|
||||
if ((w <= maxw) && (h <= maxh))
|
||||
{ // it fits
|
||||
if (abs(size - psize) <= 1) break; // we found the best size
|
||||
psize = size;
|
||||
size = (size + sizeup) / 2;
|
||||
sizedn = psize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (abs(size - psize) <= 1) break; // we found the best size
|
||||
psize = size;
|
||||
size = (size + sizedn) / 2;
|
||||
sizeup = psize;
|
||||
}
|
||||
evas_object_text_font_set(o, file, size);
|
||||
}
|
||||
}
|
||||
*size_chosen = size;
|
||||
return o;
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_font_2_line(const char *str1, const char *str2, Eet_File *ef, const char *path, int szw, int szh, const char *key)
|
||||
{
|
||||
Evas_Object *tx1, *tx2;
|
||||
int sz1, sz2, w, h;
|
||||
|
||||
tx1 = _thumb_text_setup(path, str1, szw, szh / 2, 0, &sz1);
|
||||
tx2 = _thumb_text_setup(path, str2, szw, szh / 2, 0, &sz2);
|
||||
if (sz1 < sz2)
|
||||
{
|
||||
evas_object_del(tx2);
|
||||
sz2 = sz1;
|
||||
tx2 = _thumb_text_setup(path, str2, szw, szh / 2, sz2, &sz2);
|
||||
}
|
||||
else if (sz2 < sz1)
|
||||
{
|
||||
evas_object_del(tx1);
|
||||
sz1 = sz2;
|
||||
tx1 = _thumb_text_setup(path, str1, szw, szh / 2, sz1, &sz1);
|
||||
}
|
||||
evas_object_geometry_get(tx1, NULL, NULL, &w, &h);
|
||||
evas_object_move(tx1, (szw - w) / 2, ((szh / 2) - h) / 2);
|
||||
evas_object_geometry_get(tx2, NULL, NULL, &w, &h);
|
||||
evas_object_move(tx2, (szw - w) / 2, (szh / 2) + (((szh / 2) - h) / 2));
|
||||
evas_object_resize(subwin, szw, szh);
|
||||
elm_win_render(subwin);
|
||||
thumb_image_write(ef, key, image, EINA_TRUE, EINA_FALSE);
|
||||
evas_object_del(tx1);
|
||||
evas_object_del(tx2);
|
||||
}
|
||||
|
||||
int
|
||||
thumb_font(Eet_File *ef, const char *path, const char *mime EINA_UNUSED, const char *thumb EINA_UNUSED)
|
||||
{
|
||||
const int sizes[] = { 512, 256, 128, 64, 32, 16, 0 };
|
||||
char buf[128];
|
||||
int i;
|
||||
char one = 1;
|
||||
|
||||
// XXX: we don't handle any font load errors - eg 0 sized
|
||||
for (i = 0; sizes[i] != 0; i++)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "image/thumb/%i", sizes[i]);
|
||||
_thumb_font_2_line("ABC",
|
||||
"def",
|
||||
ef, path, sizes[i], sizes[i], buf);
|
||||
}
|
||||
_thumb_font_2_line("Lorem ipsum dolor sit amet 012/789 #!?",
|
||||
"日本語 にほんご ソフト 中文 華語 한국",
|
||||
ef, path, 2048, 256, "image/preview");
|
||||
eet_write(ef, "image/thumb/mono", &one, 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
// generate thumbnail for images
|
||||
#include "thumb.h"
|
||||
|
||||
// XXX: can do progressive resize down ie scale to 512 then take 512 and
|
||||
// halve to 256 then halve it to 128 etc. rather than render from orig to
|
||||
// target size....
|
||||
|
||||
static Evas_Object *im = NULL;
|
||||
static Eina_Bool alpha = EINA_FALSE;
|
||||
static int iw = 0, ih = 0;
|
||||
|
||||
static void
|
||||
_thumb_image_setup(void)
|
||||
{ // create and show image
|
||||
im = evas_object_image_filled_add(evas_object_evas_get(subwin));
|
||||
evas_object_show(im);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_file_set(const char *file)
|
||||
{ // set file to image, get size & alpha
|
||||
evas_object_image_file_set(im, file, NULL);
|
||||
evas_object_image_size_get(im, &iw, &ih);
|
||||
alpha = evas_object_image_alpha_get(im);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_hsv_sort_render(unsigned int *dst, int w, int h)
|
||||
{ // render image down to a specific size (small) and copy to dest
|
||||
void *pixels;
|
||||
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
elm_win_render(subwin);
|
||||
pixels = evas_object_image_data_get(image, EINA_FALSE);
|
||||
if (!pixels) return;
|
||||
memcpy(dst, pixels, w * h * sizeof(int));
|
||||
evas_object_image_data_set(image, pixels);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_hsv_sort_key_write(Eet_File *ef, const char *key)
|
||||
{ // get rendered pixels from image representing subwin and write out AHVS key
|
||||
unsigned int *data4x4, *data2x2, *data1x1;
|
||||
unsigned char id2[256];
|
||||
int n, i, hi, si, vi;
|
||||
float h, s, v;
|
||||
const int pat2x2[4] = { 0, 3, 1, 2 };
|
||||
const int pat4x4[16] = { 5, 10, 6, 9,
|
||||
0, 15, 3, 12,
|
||||
1, 14, 7, 8,
|
||||
4, 11, 2, 13 };
|
||||
|
||||
data4x4 = malloc(4 * 4 * sizeof(int));
|
||||
data2x2 = malloc(2 * 2 * sizeof(int));
|
||||
data1x1 = malloc(1 * 1 * sizeof(int));
|
||||
|
||||
if ((!data4x4) || (!data2x2) || (!data1x1)) goto err;
|
||||
|
||||
_thumb_image_hsv_sort_render(data4x4, 4, 4);
|
||||
_thumb_image_hsv_sort_render(data2x2, 2, 2);
|
||||
_thumb_image_hsv_sort_render(data1x1, 1, 1);
|
||||
|
||||
n = 0;
|
||||
|
||||
#define A(v) (((v) >> 24) & 0xff)
|
||||
#define R(v) (((v) >> 16) & 0xff)
|
||||
#define G(v) (((v) >> 8 ) & 0xff)
|
||||
#define B(v) (((v) ) & 0xff)
|
||||
#define HSV(p) do { \
|
||||
evas_color_rgb_to_hsv(R(p), G(p), B(p), &h, &s, &v); \
|
||||
hi = 20 * (h / 360.0); \
|
||||
si = 20 * s; \
|
||||
vi = 20 * v; \
|
||||
if (si < 2) hi = 25; \
|
||||
} while (0)
|
||||
#define SAVEX(x) id2[n++] = 'a' + (x)
|
||||
|
||||
SAVEX(A(data1x1[0]));
|
||||
for (i = 0; i < 4 ; i++) SAVEX(A(data2x2[pat2x2[i]]));
|
||||
for (i = 0; i < 16; i++) SAVEX(A(data4x4[pat4x4[i]]));
|
||||
|
||||
#define STORE(val) \
|
||||
HSV(data1x1[0]); \
|
||||
SAVEX(val); \
|
||||
for (i = 0; i < 4; i++) { \
|
||||
HSV(data2x2[pat2x2[i]]); \
|
||||
SAVEX(val); \
|
||||
} \
|
||||
for (i = 0; i < 16; i++) { \
|
||||
HSV(data4x4[pat4x4[i]]); \
|
||||
SAVEX(val); \
|
||||
}
|
||||
|
||||
STORE(hi);
|
||||
STORE(vi);
|
||||
STORE(si);
|
||||
|
||||
id2[n++] = 0;
|
||||
|
||||
eet_write(ef, key, id2, n,
|
||||
EET_COMPRESSION_NONE);
|
||||
err:
|
||||
free(data4x4);
|
||||
free(data2x2);
|
||||
free(data1x1);
|
||||
}
|
||||
|
||||
int
|
||||
thumb_image(Eet_File *ef, const char *path, const char *mime EINA_UNUSED, const char *thumb EINA_UNUSED)
|
||||
{
|
||||
const int sizes[] = { 512, 256, 128, 64, 32, 16, 0 };
|
||||
int w, h, i;
|
||||
char buf[128];
|
||||
unsigned char a;
|
||||
|
||||
_thumb_image_setup();
|
||||
// add filled image to then size accordingly
|
||||
_thumb_image_file_set(path);
|
||||
// if size is bunk - we can't load it...
|
||||
if ((iw <= 0) || (ih < 0)) return 2;
|
||||
|
||||
// write a big 1024x1024 preview (but no larger than the original image)
|
||||
w = iw; h = ih; scale(&w, &h, 1024, 1024, EINA_TRUE);
|
||||
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out preview size
|
||||
snprintf(buf, sizeof(buf), "image/preview");
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
snprintf(buf, sizeof(buf), "%i %i", w, h);
|
||||
eet_write(ef, "image/preview/size", buf, strlen(buf) + 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
|
||||
// multiple thumb sizes so can load/pick the best one at runtime
|
||||
for (i = 0; sizes[i] != 0; i++)
|
||||
{
|
||||
// scale down and keep aspect
|
||||
w = iw; h = ih; scale(&w, &h, sizes[i], sizes[i], EINA_FALSE);
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out thumb size
|
||||
snprintf(buf, sizeof(buf), "image/thumb/%i", sizes[i]);
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
}
|
||||
|
||||
_thumb_image_hsv_sort_key_write(ef, "image/sort_key");
|
||||
|
||||
// write original alpha flag
|
||||
a = alpha;
|
||||
if (alpha)
|
||||
eet_write(ef, "orig/image/alpha", &a, 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
// write original size
|
||||
snprintf(buf, sizeof(buf), "%i %i", iw, ih);
|
||||
eet_write(ef, "orig/image/size", buf, strlen(buf) + 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
// generate thumbnail for music files - look for album art on google
|
||||
#include "thumb.h"
|
||||
#include <Emotion.h>
|
||||
|
||||
// XXX: can do progressive resize down ie scale to 512 then take 512 and
|
||||
// halve to 256 then halve it to 128 etc. rather than render from orig to
|
||||
// target size....
|
||||
|
||||
static Evas_Object *im = NULL;
|
||||
static Eina_Bool alpha = EINA_FALSE;
|
||||
static int iw = 0, ih = 0;
|
||||
|
||||
static Eina_List *results = NULL;
|
||||
|
||||
static void *mem_data = NULL;
|
||||
static int mem_size = 0;
|
||||
static int query_pass = 0;
|
||||
|
||||
static char *title = NULL;
|
||||
static char *artist = NULL;
|
||||
static char *album = NULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *url;
|
||||
int w, h;
|
||||
unsigned long long fitness;
|
||||
} Result;
|
||||
|
||||
static void
|
||||
_thumb_image_setup(void)
|
||||
{ // create and show image
|
||||
im = evas_object_image_filled_add(evas_object_evas_get(subwin));
|
||||
evas_object_show(im);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_mem_set(void *data, int size)
|
||||
{ // set file to image, get size & alpha
|
||||
evas_object_image_memfile_set(im, data, size, "jpg", NULL);
|
||||
evas_object_image_size_get(im, &iw, &ih);
|
||||
alpha = evas_object_image_alpha_get(im);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_file_set(const char *file)
|
||||
{ // set file to image, get size & alpha
|
||||
evas_object_image_file_set(im, file, NULL);
|
||||
evas_object_image_size_get(im, &iw, &ih);
|
||||
alpha = evas_object_image_alpha_get(im);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_vid_open_done_timeout(void *data EINA_UNUSED)
|
||||
{
|
||||
elm_exit();
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vid_open_done(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
|
||||
{ // we finished opening - get netadata
|
||||
const char *s;
|
||||
|
||||
s = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_TITLE);
|
||||
if (s) title = strdup(s);
|
||||
s = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_ARTIST);
|
||||
if (s) artist = strdup(s);
|
||||
s = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_ALBUM);
|
||||
if (s) album = strdup(s);
|
||||
// finish loop
|
||||
elm_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
_video_metadata_get(const char *path)
|
||||
{
|
||||
Ecore_Timer *t;
|
||||
Evas_Object *o = emotion_object_add(evas_object_evas_get(subwin));
|
||||
|
||||
evas_object_smart_callback_add(o, "open_done", _cb_vid_open_done, NULL);
|
||||
emotion_object_file_set(o, path);
|
||||
emotion_object_audio_mute_set(o, EINA_TRUE);
|
||||
emotion_object_audio_volume_set(o, 0.0);
|
||||
// a timeout for the loop
|
||||
t = ecore_timer_add(10.0, _cb_vid_open_done_timeout, NULL);
|
||||
elm_run();
|
||||
ecore_timer_del(t);
|
||||
evas_object_del(o);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_results(void *data EINA_UNUSED, Eina_List *results_orig, Eina_List *results_cached EINA_UNUSED)
|
||||
{
|
||||
Eina_List *l;
|
||||
Search_Result *res;
|
||||
Result *r;
|
||||
unsigned long long fit_size, fit_square, fit_jpg, fit_listpos, fit_pass;
|
||||
|
||||
// we need to re-score results first square better than not suqare
|
||||
// next - higher est better than lower rest
|
||||
// ends in .jpg, .jpeg better than not
|
||||
fit_listpos = 100;
|
||||
EINA_LIST_FOREACH(results_orig, l, res)
|
||||
{
|
||||
// skip results that are 0 sized or with no url
|
||||
if ((res->w <= 0) || (res->h <= 0) || (!res->url)) continue;
|
||||
// new result
|
||||
r = calloc(1, sizeof(Result));
|
||||
if (!r) continue;
|
||||
r->w = res->w;
|
||||
r->h = res->h;
|
||||
r->url = strdup(res->url);
|
||||
// jpegs preferred
|
||||
if ((eina_fnmatch("*.jpg", res->url, EINA_FNMATCH_CASEFOLD)) ||
|
||||
(eina_fnmatch("*.jpeg", res->url, EINA_FNMATCH_CASEFOLD)) ||
|
||||
(eina_fnmatch("*.jpe", res->url, EINA_FNMATCH_CASEFOLD)))
|
||||
fit_jpg = 100;
|
||||
else
|
||||
fit_jpg = 50;
|
||||
// bigger is better
|
||||
fit_size = (r->w / 10) * (r->h / 10);
|
||||
// if it's bigger than 1000x1000 it's not really better
|
||||
if (fit_size > 10000) fit_size = 10000;
|
||||
// more square is better
|
||||
fit_square = (100 * r->w) / r->h;
|
||||
if (fit_square > 100) fit_square = (100 * r->h) / r->w;
|
||||
// first pass gets a higher multiplier than latter passes
|
||||
fit_pass = ((10 - query_pass) * 100) / 10;
|
||||
// store fitness and result
|
||||
r->fitness = fit_listpos * fit_size * fit_square * fit_jpg * fit_pass;
|
||||
results = eina_list_append(results, r);
|
||||
// list position fitness goes down by .9 of previous list pos fitness
|
||||
fit_listpos = (90 * fit_listpos) / 100;
|
||||
if (fit_listpos < 1) fit_listpos = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_cb_fitness_sort(const void *data1, const void *data2)
|
||||
{
|
||||
const Result *r1 = data1, *r2 = data2;
|
||||
|
||||
if (r1->fitness < r2->fitness) return 1;
|
||||
else if (r1->fitness > r2->fitness) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_url_bin(void *data EINA_UNUSED, const void *result, size_t size)
|
||||
{ // handle in memory fetch of image
|
||||
// too big - 64M
|
||||
if (size > (64 * 1024 * 1024)) return;
|
||||
if (mem_data) free(mem_data);
|
||||
mem_data = malloc(size);
|
||||
mem_size = size;
|
||||
memcpy(mem_data, result, size);
|
||||
elm_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_online_search(const char *path)
|
||||
{
|
||||
Eina_Strbuf *query_buf;
|
||||
const char *file, *ext;
|
||||
Eina_List *l;
|
||||
Result *r;
|
||||
int i;
|
||||
|
||||
// get file and where extension starts to be removed
|
||||
file = ecore_file_file_get(path);
|
||||
ext = strchr(file, '.');
|
||||
|
||||
_video_metadata_get(path);
|
||||
|
||||
if ((title) || (album) || (artist))
|
||||
{
|
||||
query_buf = eina_strbuf_new();
|
||||
if (artist)
|
||||
{
|
||||
eina_strbuf_append(query_buf, artist);
|
||||
eina_strbuf_append(query_buf, " ");
|
||||
}
|
||||
if (artist)
|
||||
{
|
||||
eina_strbuf_append(query_buf, artist);
|
||||
eina_strbuf_append(query_buf, " ");
|
||||
}
|
||||
if (title)
|
||||
{
|
||||
eina_strbuf_append(query_buf, title);
|
||||
eina_strbuf_append(query_buf, " ");
|
||||
}
|
||||
thumb_search_image(eina_strbuf_string_get(query_buf), _cb_results, NULL);
|
||||
eina_strbuf_free(query_buf);
|
||||
// we have real metasata - make filename searches lhave lower
|
||||
// fitness by bumping query pass
|
||||
query_pass += 4;
|
||||
free(title);
|
||||
free(album);
|
||||
free(artist);
|
||||
}
|
||||
|
||||
// search using filename as our search
|
||||
// search for munged filename + "album art"
|
||||
query_buf = eina_strbuf_new();
|
||||
if (ext) // append all but extension and dot
|
||||
eina_strbuf_append_n(query_buf, file, ext - file);
|
||||
else // append the whole filename
|
||||
eina_strbuf_append(query_buf, file);
|
||||
eina_strbuf_append(query_buf, " album art");
|
||||
thumb_search_image(eina_strbuf_string_get(query_buf), _cb_results, NULL);
|
||||
eina_strbuf_free(query_buf);
|
||||
query_pass++;
|
||||
|
||||
// now search for just the munged filename without any extra string
|
||||
query_buf = eina_strbuf_new();
|
||||
if (ext) // append all but extension and dot
|
||||
eina_strbuf_append_n(query_buf, file, ext - file);
|
||||
else // append the whole filename
|
||||
eina_strbuf_append(query_buf, file);
|
||||
thumb_search_image(eina_strbuf_string_get(query_buf), _cb_results, NULL);
|
||||
eina_strbuf_free(query_buf);
|
||||
|
||||
// sort results by fitness
|
||||
results = eina_list_sort(results, eina_list_count(results),
|
||||
_cb_fitness_sort);
|
||||
|
||||
i = 0;
|
||||
EINA_LIST_FOREACH(results, l, r)
|
||||
{
|
||||
// get image max 64M
|
||||
thumb_url_bin_get(r->url, 64 * 1024 * 1024, _cb_url_bin, NULL);
|
||||
elm_run();
|
||||
if (mem_data)
|
||||
{
|
||||
// add filled image to then size accordingly
|
||||
_thumb_image_mem_set(mem_data, mem_size);
|
||||
free(mem_data);
|
||||
mem_data = NULL;
|
||||
if ((iw > 0) && (ih > 0)) break;
|
||||
i++;
|
||||
}
|
||||
// tried 10 - give up
|
||||
if (i >= 10) break;
|
||||
}
|
||||
if (mem_data) free(mem_data);
|
||||
}
|
||||
|
||||
static char *
|
||||
_thumb_explicit_find(const char *path)
|
||||
{
|
||||
char *tmp = alloca(strlen(path) + 1 + 100);
|
||||
char *dir, *fraw, *s;
|
||||
const char *fname, *e, *c;
|
||||
const char *ext[] = {
|
||||
"png", "PNG",
|
||||
"jpg", "JPG",
|
||||
"jpeg", "JPEG",
|
||||
"jpe", "JPE",
|
||||
NULL };
|
||||
const char *cover[] = {
|
||||
"cover", "Cover", "COVER",
|
||||
"front", "Front", "FRONT",
|
||||
"folder", "Folder", "FOLDER",
|
||||
".cover", ".Cover", ".COVER",
|
||||
".front", ".Front", ".FRONT",
|
||||
".folder", ".Folder", ".FOLDER",
|
||||
NULL };
|
||||
int i, j;
|
||||
|
||||
// from here example comments assume /dir/file.mp3 as the path
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/file.mp3.png etc.
|
||||
sprintf(tmp, "%s.%s", path, e);
|
||||
if (ecore_file_exists(tmp)) return strdup(tmp);
|
||||
}
|
||||
|
||||
dir = ecore_file_dir_get(path);
|
||||
if (!dir)
|
||||
{ // if no dir we are /file.mp3 thus "" works find for following code
|
||||
dir = strdup("");
|
||||
if (!dir) return NULL;
|
||||
}
|
||||
fname = ecore_file_file_get(path);
|
||||
if (!fname)
|
||||
{ // this shouldn't happen - but handle it anyway
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
fraw = strdup(fname); // fraw will be filename for e.g. filename.mp3
|
||||
if (!fraw)
|
||||
{
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
s = strrchr(fraw, '.');
|
||||
if (s) *s = 0;
|
||||
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/file.png etc.
|
||||
sprintf(tmp, "%s/.%s.%s", dir, fraw, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/file.mp3.png etc.
|
||||
sprintf(tmp, "%s/.%s.%s", dir, fname, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/.file.png etc.
|
||||
sprintf(tmp, "%s/.%s.%s", dir, fraw, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/.file.mp3.png etc.
|
||||
sprintf(tmp, "%s/.thumb/%s.%s", dir, fname, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/.thumb/file.png etc.
|
||||
sprintf(tmp, "%s/.thumb/%s.%s", dir, fraw, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
|
||||
// XXX: should we do this for every file in that dir? really?
|
||||
for (j = 0; (c = cover[j]) && c; j++)
|
||||
{ // /dir/cover.png etc. - single img for everything in the dir...
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{
|
||||
sprintf(tmp, "%s/%s.%s", dir, c, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(fraw);
|
||||
return NULL;
|
||||
found:
|
||||
free(dir);
|
||||
free(fraw);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
int
|
||||
thumb_music(Eet_File *ef, const char *path, const char *mime EINA_UNUSED, const char *thumb EINA_UNUSED)
|
||||
{
|
||||
const int sizes[] = { 512, 256, 128, 64, 32, 16, 0 };
|
||||
int w, h, i;
|
||||
char buf[128];
|
||||
char *thumb_file;
|
||||
|
||||
|
||||
_thumb_image_setup();
|
||||
|
||||
// look for an explicitly "requested" file for the thumb path
|
||||
thumb_file = _thumb_explicit_find(path);
|
||||
|
||||
// if we didn't find an explicit matching thumb path in dir or nearby...
|
||||
if (thumb_file) _thumb_image_file_set(thumb_file);
|
||||
// explicit thumb not found or the load failed as image size is not sane
|
||||
if ((iw <= 0) || (ih < 0)) _thumb_online_search(path);
|
||||
|
||||
// if size is bunk - we can't load it...
|
||||
if ((iw <= 0) || (ih < 0)) return 2;
|
||||
|
||||
// write a big 1024x1024 preview (but no larger than the original image)
|
||||
w = iw; h = ih; scale_out(&w, &h, 1024, 1024, EINA_FALSE);
|
||||
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_move(im, (1024 - w) / 2, 0);
|
||||
evas_object_resize(subwin, 1024, 1024);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out preview size
|
||||
snprintf(buf, sizeof(buf), "image/preview");
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
snprintf(buf, sizeof(buf), "%i %i", w, h);
|
||||
eet_write(ef, "image/preview/size", buf, strlen(buf) + 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
|
||||
// multiple thumb sizes so can load/pick the best one at runtime
|
||||
for (i = 0; sizes[i] != 0; i++)
|
||||
{
|
||||
// scale down and keep aspect
|
||||
w = iw; h = ih; scale_out(&w, &h, sizes[i], sizes[i], EINA_FALSE);
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_move(im, (sizes[i] - w) / 2, 0);
|
||||
evas_object_resize(subwin, sizes[i], sizes[i]);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out thumb size
|
||||
snprintf(buf, sizeof(buf), "image/thumb/%i", sizes[i]);
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
// generate thumbnail for images
|
||||
#include "thumb.h"
|
||||
|
||||
// XXX: can do progressive resize down ie scale to 512 then take 512 and
|
||||
// halve to 256 then halve it to 128 etc. rather than render from orig to
|
||||
// target size....
|
||||
|
||||
static Evas_Object *im = NULL;
|
||||
static Eina_Bool alpha = EINA_FALSE;
|
||||
static int iw = 0, ih = 0;
|
||||
|
||||
static void
|
||||
_thumb_page_setup(void)
|
||||
{ // create and show image
|
||||
im = evas_object_image_filled_add(evas_object_evas_get(subwin));
|
||||
evas_object_show(im);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_thumb_page_file_set(const char *file, int page)
|
||||
{ // set file to image, get size & alpha
|
||||
char buf[32];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%i", page);
|
||||
evas_object_image_file_set(im, file, buf);
|
||||
evas_object_image_size_get(im, &iw, &ih);
|
||||
if ((iw > 0) && (ih > 0)) return EINA_TRUE;
|
||||
alpha = evas_object_image_alpha_get(im);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
thumb_paged(Eet_File *ef, const char *path, const char *mime EINA_UNUSED, const char *thumb EINA_UNUSED)
|
||||
{
|
||||
const int sizes[] = { 512, 256, 128, 64, 32, 16, 0 };
|
||||
int w, h, i;
|
||||
char buf[128];
|
||||
unsigned char a;
|
||||
|
||||
_thumb_page_setup();
|
||||
// add filled image to then size accordingly
|
||||
_thumb_page_file_set(path, 0);
|
||||
// if size is bunk - we can't load it...
|
||||
if ((iw <= 0) || (ih < 0)) return 2;
|
||||
|
||||
// write a big 1024x1024 preview (but no larger than the original doc)
|
||||
w = iw; h = ih; scale(&w, &h, 1024, 1024, EINA_TRUE);
|
||||
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out preview size
|
||||
snprintf(buf, sizeof(buf), "image/preview");
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
snprintf(buf, sizeof(buf), "%i %i", w, h);
|
||||
eet_write(ef, "image/preview/size", buf, strlen(buf) + 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
|
||||
// multiple thumb sizes so can load/pick the best one at runtime
|
||||
for (i = 0; sizes[i] != 0; i++)
|
||||
{
|
||||
// scale down and keep aspect
|
||||
w = sizes[i];
|
||||
h = (ih * sizes[i]) / iw;
|
||||
if (h > sizes[i])
|
||||
{ // too tall = so limit height and scale down keeping aspect
|
||||
h = sizes[i];
|
||||
w = (iw * sizes[i]) / ih;
|
||||
}
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out thumb size
|
||||
snprintf(buf, sizeof(buf), "image/thumb/%i", sizes[i]);
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
}
|
||||
|
||||
// write original alpha flag
|
||||
a = alpha;
|
||||
if (alpha)
|
||||
eet_write(ef, "orig/image/alpha", &a, 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
// write original size
|
||||
snprintf(buf, sizeof(buf), "%i %i", iw, ih);
|
||||
eet_write(ef, "orig/image/size", buf, strlen(buf) + 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
|
||||
// write page previews of the first 32 pages
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
if (!_thumb_page_file_set(path, i)) break;
|
||||
w = iw; h = ih; scale(&w, &h, 512, 512, EINA_TRUE);
|
||||
snprintf(buf, sizeof(buf), "image/page/%i", i);
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out thumb size
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include "thumb.h"
|
||||
|
||||
void
|
||||
thumb_image_write(Eet_File *ef, const char *key, Evas_Object *img, Eina_Bool a, Eina_Bool lossy)
|
||||
{ // get rendered pixels from image representing subwin
|
||||
void *pixels = evas_object_image_data_get(img, EINA_FALSE);
|
||||
int w, h;
|
||||
|
||||
if (!pixels) return;
|
||||
evas_object_image_size_get(img, &w, &h);
|
||||
if (lossy)
|
||||
eet_data_image_write(ef, key, pixels, w, h, a,
|
||||
0, /* compr */
|
||||
80, /* qual */
|
||||
EET_IMAGE_JPEG);
|
||||
else
|
||||
eet_data_image_write(ef, key, pixels, w, h, a,
|
||||
EET_COMPRESSION_HI, /* compr */
|
||||
0, /* qual */
|
||||
EET_IMAGE_LOSSLESS);
|
||||
evas_object_image_data_set(img, pixels); // put pixels back we borrowed
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
// search for
|
||||
#include "thumb.h"
|
||||
|
||||
// look for these divs:
|
||||
//
|
||||
// <div class="xxxx"...
|
||||
// data-ow="640"
|
||||
// data-oh="640"
|
||||
// data-ou="http://xxxxx"
|
||||
// >
|
||||
//
|
||||
// data-xxx could be in any order so parse tag until end of tag and store
|
||||
// each X=Y
|
||||
//
|
||||
// other option - low res but google served imaage in img tags
|
||||
//
|
||||
// <img ...
|
||||
// data-src="http://xxxx"
|
||||
// >
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Eina_Bool in_div;
|
||||
Eina_Bool in_img;
|
||||
Eina_Hash *attr;
|
||||
void (*cb) (void *data, Eina_List *results_orig, Eina_List *results_cached);
|
||||
void *data;
|
||||
Eina_List *results_orig;
|
||||
Eina_List *results_cached;
|
||||
int magic;
|
||||
} State;
|
||||
|
||||
static Eina_Bool
|
||||
_cb_attr(void *data, const char *key, const char *val)
|
||||
{
|
||||
State *state = data;
|
||||
|
||||
// only if in div or img - add tag
|
||||
if (state->in_div || state->in_img)
|
||||
eina_hash_add(state->attr, key, strdup(val));
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_tag(void *data, Eina_Simple_XML_Type type,
|
||||
const char *content, unsigned offset EINA_UNUSED, unsigned int len)
|
||||
{
|
||||
State *state = data;
|
||||
const char *tags, *ow, *oh, *img;
|
||||
int w, h;
|
||||
Search_Result *res;
|
||||
|
||||
if (type == EINA_SIMPLE_XML_OPEN)
|
||||
{ // start sokme tag
|
||||
state->in_div = EINA_FALSE;
|
||||
state->in_img = EINA_FALSE;
|
||||
if (state->attr)
|
||||
{ // clean up previous hash from previous tag if there
|
||||
eina_hash_free(state->attr);
|
||||
state->attr = NULL;
|
||||
}
|
||||
if (!strncmp(content, "div ", 4))
|
||||
{ // we have a div - we're interested in those
|
||||
state->in_div = EINA_TRUE;
|
||||
state->attr = eina_hash_string_superfast_new(free);
|
||||
}
|
||||
else if (!strncmp(content, "img ", 4))
|
||||
{ // we have an img - we're also interested in those
|
||||
state->in_img = EINA_TRUE;
|
||||
state->attr = eina_hash_string_superfast_new(free);
|
||||
}
|
||||
|
||||
if ((state->in_div) || (state->in_img))
|
||||
{ // pars the tag attributes
|
||||
tags = eina_simple_xml_tag_attributes_find(content, len);
|
||||
if (tags)
|
||||
{ // pars a tag - div or img
|
||||
eina_simple_xml_attributes_parse(tags,
|
||||
len - (tags - content),
|
||||
_cb_attr, state);
|
||||
img = eina_hash_find(state->attr, "data-ou");
|
||||
if (img)
|
||||
{ // this is an origial url entry with size
|
||||
ow = eina_hash_find(state->attr, "data-ow");
|
||||
oh = eina_hash_find(state->attr, "data-oh");
|
||||
if ((ow) && (oh))
|
||||
{ // we need a width and height string and have them
|
||||
w = atoi(ow);
|
||||
h = atoi(oh);
|
||||
res = calloc(1, sizeof(Search_Result));
|
||||
if (res)
|
||||
{
|
||||
res->w = w;
|
||||
res->h = h;
|
||||
res->url = strdup(img);
|
||||
state->results_orig =
|
||||
eina_list_append(state->results_orig, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
img = eina_hash_find(state->attr, "data-src");
|
||||
if (img)
|
||||
{ // this is a cached/scaled down version withotu size
|
||||
res = calloc(1, sizeof(Search_Result));
|
||||
if (res)
|
||||
{
|
||||
res->url = strdup(img);
|
||||
state->results_cached =
|
||||
eina_list_append(state->results_cached, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_query(void *data, const char *reply)
|
||||
{ // parse the query result from searching
|
||||
State *state = data;
|
||||
Search_Result *res;
|
||||
|
||||
if (!reply) goto err;
|
||||
eina_simple_xml_parse(reply, strlen(reply), EINA_TRUE, _cb_tag, state);
|
||||
if (state->attr)
|
||||
{ // clean up any left over attributes hash
|
||||
eina_hash_free(state->attr);
|
||||
state->attr = NULL;
|
||||
}
|
||||
state->cb(state->data, state->results_orig, state->results_cached);
|
||||
// clean up lists of results we no longer need
|
||||
EINA_LIST_FREE(state->results_orig, res)
|
||||
{
|
||||
free(res->url);
|
||||
free(res);
|
||||
}
|
||||
EINA_LIST_FREE(state->results_cached, res)
|
||||
{
|
||||
free(res->url);
|
||||
free(res);
|
||||
}
|
||||
err:
|
||||
elm_exit();
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_search_append(Eina_Strbuf *sb, const char *str, Eina_Bool hadword)
|
||||
{ // take input string "as typed" and convert to part of query with +'s
|
||||
// like "this is a set of words" -> "this+is+a+set+of+words"
|
||||
// hadwords indicates if we had words before this call so to add a +
|
||||
// at the start to appeand to previous words
|
||||
const char *s;
|
||||
Eina_Bool word = EINA_FALSE;
|
||||
|
||||
for (s = str; *s; s++)
|
||||
{
|
||||
// only use a-z, A-Z and 0-9 chars as words
|
||||
if (((*s >= 'a') && (*s <= 'z')) ||
|
||||
((*s >= 'A') && (*s <= 'Z')) ||
|
||||
((*s >= '0') && (*s <= '9')))
|
||||
{
|
||||
if (!word)
|
||||
{ // we're not inside a word now
|
||||
if (hadword)
|
||||
{ // we had a word before so add + between words
|
||||
eina_strbuf_append_char(sb, '+');
|
||||
word = EINA_FALSE;
|
||||
}
|
||||
}
|
||||
eina_strbuf_append_char(sb, *s);
|
||||
word = EINA_TRUE;
|
||||
hadword = EINA_TRUE;
|
||||
}
|
||||
else word = EINA_FALSE;
|
||||
// stop when we hit a .
|
||||
if (*s == '.') break;
|
||||
}
|
||||
return hadword;
|
||||
}
|
||||
|
||||
void
|
||||
thumb_search_image(const char *str, void (*cb) (void *data, Eina_List *results_orig, Eina_List *results_cached), void *data)
|
||||
{ // search for images given the str string
|
||||
Eina_Strbuf *query_buf;
|
||||
const char *query;
|
||||
State state = { 0 };
|
||||
|
||||
state.cb = cb;
|
||||
state.data = data;
|
||||
state.magic = 1234567;
|
||||
|
||||
query_buf = eina_strbuf_new();
|
||||
// add beginning of query
|
||||
eina_strbuf_append
|
||||
(query_buf,
|
||||
"http://www.google.com/search?as_st=y&tbm=isch&hl=en&as_q=");
|
||||
// add a search string like typed in like "this is a search"
|
||||
_search_append(query_buf, str, EINA_FALSE);
|
||||
// add rest of query
|
||||
eina_strbuf_append
|
||||
(query_buf,
|
||||
"&as_epq=&as_oq=&as_eq=&cr=&as_sitesearch=&safe=images&tbs=ift:jpg");
|
||||
query = eina_strbuf_string_get(query_buf);
|
||||
// send that query off and handle it in _cb_query - max 8M
|
||||
thumb_url_str_get(query, 8 * 1024 * 1024, _cb_query, &state);
|
||||
elm_run();
|
||||
eina_strbuf_free(query_buf);
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
#include "thumb.h"
|
||||
|
||||
static Ecore_Con_Url *fetch = NULL;
|
||||
static Ecore_Event_Handler *handle_data = NULL;
|
||||
static Ecore_Event_Handler *handle_complete = NULL;
|
||||
|
||||
static Eina_Strbuf *buf_str = NULL;
|
||||
static size_t buf_str_max = 0;
|
||||
static void *cb_str_data = NULL;
|
||||
static void (*cb_str) (void *data, const char *result) = NULL;
|
||||
|
||||
static Eina_Strbuf *buf_bin = NULL;
|
||||
static size_t buf_bin_max = 0;
|
||||
static void *cb_bin_data = NULL;
|
||||
static void (*cb_bin) (void *data, const void *result, size_t size) = NULL;
|
||||
|
||||
static Eina_Bool
|
||||
_cb_http_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
||||
{
|
||||
Ecore_Con_Event_Url_Data *ev = event;
|
||||
|
||||
if (ev->url_con != fetch) return EINA_TRUE;
|
||||
if (buf_str)
|
||||
{
|
||||
eina_strbuf_append_length(buf_str, (char *)ev->data, (size_t)ev->size);
|
||||
if (eina_strbuf_length_get(buf_str) > buf_str_max)
|
||||
{ // too big - abort whole fetch entirely
|
||||
ecore_con_url_free(fetch);
|
||||
fetch = NULL;
|
||||
cb_str(cb_str_data, NULL);
|
||||
cb_str = NULL;
|
||||
cb_str_data = NULL;
|
||||
eina_strbuf_free(buf_str);
|
||||
buf_str = NULL;
|
||||
}
|
||||
}
|
||||
else if (buf_bin)
|
||||
{
|
||||
eina_binbuf_append_length(buf_bin, (unsigned char *)ev->data, (size_t)ev->size);
|
||||
if (eina_binbuf_length_get(buf_bin) > buf_bin_max)
|
||||
{ // too big - abort whole fetch entirely
|
||||
ecore_con_url_free(fetch);
|
||||
fetch = NULL;
|
||||
cb_bin(cb_bin_data, NULL, 0);
|
||||
cb_bin = NULL;
|
||||
cb_bin_data = NULL;
|
||||
eina_strbuf_free(buf_bin);
|
||||
buf_bin = NULL;
|
||||
}
|
||||
}
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_http_complete(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
||||
{
|
||||
Ecore_Con_Event_Url_Complete *ev = event;
|
||||
Eina_Strbuf *buf;
|
||||
|
||||
if (ev->url_con != fetch) return EINA_TRUE;
|
||||
if (buf_str)
|
||||
{
|
||||
buf = buf_str;
|
||||
buf_str = NULL;
|
||||
ecore_con_url_free(fetch);
|
||||
fetch = NULL;
|
||||
cb_str(cb_str_data,
|
||||
eina_strbuf_string_get(buf));
|
||||
cb_str = NULL;
|
||||
cb_str_data = NULL;
|
||||
eina_strbuf_free(buf);
|
||||
}
|
||||
else if (buf_bin)
|
||||
{
|
||||
buf = buf_bin;
|
||||
buf_bin = NULL;
|
||||
ecore_con_url_free(fetch);
|
||||
fetch = NULL;
|
||||
cb_bin(cb_bin_data,
|
||||
eina_binbuf_string_get(buf),
|
||||
eina_binbuf_length_get(buf));
|
||||
cb_bin = NULL;
|
||||
cb_bin_data = NULL;
|
||||
eina_binbuf_free(buf);
|
||||
}
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static Ecore_Con_Url *
|
||||
_url_init(const char *url)
|
||||
{
|
||||
Ecore_Con_Url *f;
|
||||
|
||||
if (!handle_data)
|
||||
handle_data = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA,
|
||||
_cb_http_data, NULL);
|
||||
if (!handle_complete)
|
||||
handle_complete = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE,
|
||||
_cb_http_complete, NULL);
|
||||
f = ecore_con_url_new(url);
|
||||
ecore_con_url_additional_header_add
|
||||
(f, "user-agent",
|
||||
"Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19");
|
||||
ecore_con_url_get(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
void
|
||||
thumb_url_str_get(const char *url, size_t max, void (*cb) (void *data, const char *result), const void *data)
|
||||
{
|
||||
cb_str_data = (void *)data;
|
||||
cb_str = cb;
|
||||
buf_str = eina_strbuf_new();
|
||||
buf_str_max = max;
|
||||
fetch = _url_init(url);
|
||||
}
|
||||
|
||||
void
|
||||
thumb_url_bin_get(const char *url, size_t max, void (*cb) (void *data, const void *result, size_t size), const void *data)
|
||||
{
|
||||
cb_bin_data = (void *)data;
|
||||
cb_bin = cb;
|
||||
buf_bin = eina_binbuf_new();
|
||||
buf_bin_max = max;
|
||||
fetch = _url_init(url);
|
||||
}
|
|
@ -0,0 +1,444 @@
|
|||
// generate thumbnail for video files - look for posters on google or frames
|
||||
#include "thumb.h"
|
||||
#include <Emotion.h>
|
||||
|
||||
// XXX: can do progressive resize down ie scale to 512 then take 512 and
|
||||
// halve to 256 then halve it to 128 etc. rather than render from orig to
|
||||
// target size....
|
||||
|
||||
static Evas_Object *im = NULL;
|
||||
static Eina_Bool alpha = EINA_FALSE;
|
||||
static int iw = 0, ih = 0;
|
||||
|
||||
static Eina_List *results = NULL;
|
||||
|
||||
static void *mem_data = NULL;
|
||||
static int mem_size = 0;
|
||||
static int query_pass = 0;
|
||||
|
||||
static char *title = NULL;
|
||||
static char *artist = NULL;
|
||||
static char *album = NULL;
|
||||
static double len = 0.0;
|
||||
static double aspect = 0.0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *url;
|
||||
int w, h;
|
||||
unsigned long long fitness;
|
||||
} Result;
|
||||
|
||||
static void
|
||||
_thumb_image_setup(void)
|
||||
{ // create and show image
|
||||
im = evas_object_image_filled_add(evas_object_evas_get(subwin));
|
||||
evas_object_show(im);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_mem_set(void *data, int size)
|
||||
{ // set file to image, get size & alpha
|
||||
evas_object_image_memfile_set(im, data, size, "jpg", NULL);
|
||||
evas_object_image_size_get(im, &iw, &ih);
|
||||
alpha = evas_object_image_alpha_get(im);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_image_file_set(const char *file, double pos)
|
||||
{ // set file to image, get size & alpha
|
||||
char buf[32];
|
||||
|
||||
if (pos >= 0.0)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)(pos * 1000.0));
|
||||
evas_object_image_file_set(im, file, buf);
|
||||
}
|
||||
else evas_object_image_file_set(im, file, NULL);
|
||||
evas_object_image_size_get(im, &iw, &ih);
|
||||
alpha = evas_object_image_alpha_get(im);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_vid_open_done_timeout(void *data EINA_UNUSED)
|
||||
{
|
||||
elm_exit();
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vid_open_done(void *data EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
|
||||
{ // we finished opening - get netadata also size/aspect
|
||||
const char *s;
|
||||
int w = 0, h = 0;
|
||||
|
||||
s = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_TITLE);
|
||||
if (s) title = strdup(s);
|
||||
s = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_ARTIST);
|
||||
if (s) artist = strdup(s);
|
||||
s = emotion_object_meta_info_get(obj, EMOTION_META_INFO_TRACK_ALBUM);
|
||||
if (s) album = strdup(s);
|
||||
len = emotion_object_play_length_get(obj);
|
||||
aspect = emotion_object_ratio_get(obj);
|
||||
if (aspect <= 0.0)
|
||||
{
|
||||
emotion_object_size_get(obj, &w, &h);
|
||||
if (h > 0) aspect = (double)w / (double)h;
|
||||
}
|
||||
// finish loop
|
||||
elm_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
_video_metadata_get(const char *path)
|
||||
{
|
||||
Ecore_Timer *t;
|
||||
Evas_Object *o = emotion_object_add(evas_object_evas_get(subwin));
|
||||
|
||||
evas_object_smart_callback_add(o, "open_done", _cb_vid_open_done, NULL);
|
||||
emotion_object_file_set(o, path);
|
||||
emotion_object_audio_mute_set(o, EINA_TRUE);
|
||||
emotion_object_audio_volume_set(o, 0.0);
|
||||
// a timeout for the loop
|
||||
t = ecore_timer_add(10.0, _cb_vid_open_done_timeout, NULL);
|
||||
elm_run();
|
||||
ecore_timer_del(t);
|
||||
evas_object_del(o);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_results(void *data EINA_UNUSED, Eina_List *results_orig, Eina_List *results_cached EINA_UNUSED)
|
||||
{
|
||||
Eina_List *l;
|
||||
Search_Result *res;
|
||||
Result *r;
|
||||
unsigned long long fit_size, fit_ratio2to3, fit_jpg, fit_listpos, fit_pass;
|
||||
|
||||
// we need to re-score results first ratio 2:3 better than not suqare
|
||||
// next - higher est better than lower rest
|
||||
// ends in .jpg, .jpeg better than not
|
||||
fit_listpos = 100;
|
||||
EINA_LIST_FOREACH(results_orig, l, res)
|
||||
{
|
||||
// skip results that are 0 sized or with no url
|
||||
if ((res->w <= 0) || (res->h <= 0) || (!res->url)) continue;
|
||||
// new result
|
||||
r = calloc(1, sizeof(Result));
|
||||
if (!r) continue;
|
||||
r->w = res->w;
|
||||
r->h = res->h;
|
||||
r->url = strdup(res->url);
|
||||
// jpegs preferred
|
||||
if ((eina_fnmatch("*.jpg", res->url, EINA_FNMATCH_CASEFOLD)) ||
|
||||
(eina_fnmatch("*.jpeg", res->url, EINA_FNMATCH_CASEFOLD)) ||
|
||||
(eina_fnmatch("*.jpe", res->url, EINA_FNMATCH_CASEFOLD)))
|
||||
fit_jpg = 5000;
|
||||
else
|
||||
fit_jpg = 100;
|
||||
// bigger is better
|
||||
fit_size = (r->w / 10) * (r->h / 10);
|
||||
// if it's bigger than 1000x1000 it's not really better
|
||||
if (fit_size > 10000) fit_size = 10000;
|
||||
// 2:3 poster better
|
||||
fit_ratio2to3 = (100 * r->w * 3) / (r->h * 2);
|
||||
if (fit_ratio2to3 > 100) fit_ratio2to3 = (100 * r->h * 2) / (r->w * 3);
|
||||
fit_ratio2to3 *= 10; // ratio is VERY important
|
||||
// first pass gets a higher multiplier than latter passes
|
||||
fit_pass = (10 - query_pass) * 1000;
|
||||
// store fitness and result
|
||||
r->fitness = fit_listpos * fit_size * fit_ratio2to3 * fit_jpg * fit_pass;
|
||||
results = eina_list_append(results, r);
|
||||
// list position fitness goes down by .9 of previous list pos fitness
|
||||
fit_listpos = (90 * fit_listpos) / 100;
|
||||
if (fit_listpos < 1) fit_listpos = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_cb_fitness_sort(const void *data1, const void *data2)
|
||||
{
|
||||
const Result *r1 = data1, *r2 = data2;
|
||||
|
||||
if (r1->fitness < r2->fitness) return 1;
|
||||
else if (r1->fitness > r2->fitness) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_url_bin(void *data EINA_UNUSED, const void *result, size_t size)
|
||||
{ // handle in memory fetch of image
|
||||
// too big - 64M
|
||||
if (size > (64 * 1024 * 1024)) return;
|
||||
if (mem_data) free(mem_data);
|
||||
mem_data = malloc(size);
|
||||
mem_size = size;
|
||||
memcpy(mem_data, result, size);
|
||||
elm_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_online_search(const char *path)
|
||||
{
|
||||
Eina_Strbuf *query_buf;
|
||||
const char *file, *ext;
|
||||
Eina_List *l;
|
||||
Result *r;
|
||||
int i;
|
||||
|
||||
// get file and where extension starts to be removed
|
||||
file = ecore_file_file_get(path);
|
||||
ext = strchr(file, '.');
|
||||
|
||||
if ((title) || (album) || (artist))
|
||||
{
|
||||
query_buf = eina_strbuf_new();
|
||||
if (artist)
|
||||
{
|
||||
eina_strbuf_append(query_buf, artist);
|
||||
eina_strbuf_append(query_buf, " ");
|
||||
}
|
||||
if (artist)
|
||||
{
|
||||
eina_strbuf_append(query_buf, artist);
|
||||
eina_strbuf_append(query_buf, " ");
|
||||
}
|
||||
if (title)
|
||||
{
|
||||
eina_strbuf_append(query_buf, title);
|
||||
eina_strbuf_append(query_buf, " ");
|
||||
}
|
||||
eina_strbuf_append(query_buf, " movie poster");
|
||||
thumb_search_image(eina_strbuf_string_get(query_buf), _cb_results, NULL);
|
||||
eina_strbuf_free(query_buf);
|
||||
// we have real metasata - make filename searches lhave lower
|
||||
// fitness by bumping query pass
|
||||
query_pass += 4;
|
||||
free(title);
|
||||
free(album);
|
||||
free(artist);
|
||||
}
|
||||
|
||||
// search using filename as our search
|
||||
// search for munged filename + "album art"
|
||||
query_buf = eina_strbuf_new();
|
||||
if (ext) // append all but extension and dot
|
||||
eina_strbuf_append_n(query_buf, file, ext - file);
|
||||
else // append the whole filename
|
||||
eina_strbuf_append(query_buf, file);
|
||||
eina_strbuf_append(query_buf, " movie poster");
|
||||
thumb_search_image(eina_strbuf_string_get(query_buf), _cb_results, NULL);
|
||||
eina_strbuf_free(query_buf);
|
||||
query_pass++;
|
||||
|
||||
// now search for just the munged filename without any extra string
|
||||
query_buf = eina_strbuf_new();
|
||||
if (ext) // append all but extension and dot
|
||||
eina_strbuf_append_n(query_buf, file, ext - file);
|
||||
else // append the whole filename
|
||||
eina_strbuf_append(query_buf, file);
|
||||
thumb_search_image(eina_strbuf_string_get(query_buf), _cb_results, NULL);
|
||||
eina_strbuf_free(query_buf);
|
||||
|
||||
// sort results by fitness
|
||||
results = eina_list_sort(results, eina_list_count(results),
|
||||
_cb_fitness_sort);
|
||||
|
||||
i = 0;
|
||||
EINA_LIST_FOREACH(results, l, r)
|
||||
{
|
||||
// get image max 64M
|
||||
thumb_url_bin_get(r->url, 64 * 1024 * 1024, _cb_url_bin, NULL);
|
||||
elm_run();
|
||||
if (mem_data)
|
||||
{
|
||||
// add filled image to then size accordingly
|
||||
_thumb_image_mem_set(mem_data, mem_size);
|
||||
free(mem_data);
|
||||
mem_data = NULL;
|
||||
if ((iw > 0) && (ih > 0)) break;
|
||||
i++;
|
||||
}
|
||||
// tried 10 - give up
|
||||
if (i >= 10) break;
|
||||
}
|
||||
if (mem_data) free(mem_data);
|
||||
}
|
||||
|
||||
static char *
|
||||
_thumb_explicit_find(const char *path)
|
||||
{
|
||||
char *tmp = alloca(strlen(path) + 1 + 100);
|
||||
char *dir, *fraw, *s;
|
||||
const char *fname, *e;
|
||||
const char *ext[] = {
|
||||
"png", "PNG",
|
||||
"jpg", "JPG",
|
||||
"jpeg", "JPEG",
|
||||
"jpe", "JPE",
|
||||
NULL };
|
||||
int i;
|
||||
|
||||
// from here example comments assume /dir/file.mp3 as the path
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/file.mp3.png etc.
|
||||
sprintf(tmp, "%s.%s", path, e);
|
||||
if (ecore_file_exists(tmp)) return strdup(tmp);
|
||||
}
|
||||
|
||||
dir = ecore_file_dir_get(path);
|
||||
if (!dir)
|
||||
{ // if no dir we are /file.mp3 thus "" works find for following code
|
||||
dir = strdup("");
|
||||
if (!dir) return NULL;
|
||||
}
|
||||
fname = ecore_file_file_get(path);
|
||||
if (!fname)
|
||||
{ // this shouldn't happen - but handle it anyway
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
fraw = strdup(fname); // fraw will be filename for e.g. filename.mp3
|
||||
if (!fraw)
|
||||
{
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
s = strrchr(fraw, '.');
|
||||
if (s) *s = 0;
|
||||
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/file.png etc.
|
||||
sprintf(tmp, "%s/.%s.%s", dir, fraw, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/file.mp3.png etc.
|
||||
sprintf(tmp, "%s/.%s.%s", dir, fname, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/.file.png etc.
|
||||
sprintf(tmp, "%s/.%s.%s", dir, fraw, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/.file.mp3.png etc.
|
||||
sprintf(tmp, "%s/.thumb/%s.%s", dir, fname, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
for (i = 0; (e = ext[i]) && e; i++)
|
||||
{ // /dir/.thumb/file.png etc.
|
||||
sprintf(tmp, "%s/.thumb/%s.%s", dir, fraw, e);
|
||||
if (ecore_file_exists(tmp)) goto found;
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(fraw);
|
||||
return NULL;
|
||||
found:
|
||||
free(dir);
|
||||
free(fraw);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
_thumb_file_snap_pos_set(Eet_File *ef, const char *path, int snap, double pos)
|
||||
{
|
||||
char buf[128];
|
||||
int w, h;
|
||||
|
||||
_thumb_image_file_set(path, pos);
|
||||
snprintf(buf, sizeof(buf), "image/snap/%i", snap);
|
||||
w = iw; h = ih; scale(&w, &h, 512, 512, EINA_TRUE);
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out thumb size
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
}
|
||||
|
||||
int
|
||||
thumb_video(Eet_File *ef, const char *path, const char *mime EINA_UNUSED, const char *thumb EINA_UNUSED)
|
||||
{
|
||||
const int sizes[] = { 512, 256, 128, 64, 32, 16, 0 };
|
||||
int w, h, i;
|
||||
char buf[128];
|
||||
char *thumb_file;
|
||||
double p;
|
||||
|
||||
_thumb_image_setup();
|
||||
|
||||
// look for an explicitly "requested" file for the thumb path
|
||||
thumb_file = _thumb_explicit_find(path);
|
||||
|
||||
// if we didn't find an explicit matching thumb path in dir or nearby...
|
||||
if (thumb_file) _thumb_image_file_set(thumb_file, -1);
|
||||
|
||||
// explicit thumb not found or the load failed as image size is not sane
|
||||
if ((iw <= 0) || (ih < 0))
|
||||
{
|
||||
_video_metadata_get(path);
|
||||
|
||||
if ((len > (65.0 * 60.0)) && // more than 65 mins - like movies
|
||||
(aspect > 1.6)) // is 16:9 or wider like a movie
|
||||
_thumb_online_search(path);
|
||||
}
|
||||
// if size is bunk - we hven;'t found something yet
|
||||
if ((iw <= 0) || (ih < 0)) _thumb_image_file_set(path, len / 2.0);
|
||||
|
||||
// if size is bunk - we can't load it...
|
||||
if ((iw <= 0) || (ih < 0)) return 2;
|
||||
|
||||
// write a big 1024x1024 preview (but no larger than the original image)
|
||||
w = iw; h = ih; scale(&w, &h, 1024, 1024, EINA_FALSE);
|
||||
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out preview size
|
||||
snprintf(buf, sizeof(buf), "image/preview");
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
snprintf(buf, sizeof(buf), "%i %i", w, h);
|
||||
eet_write(ef, "image/preview/size", buf, strlen(buf) + 1,
|
||||
EET_COMPRESSION_NONE);
|
||||
|
||||
// multiple thumb sizes so can load/pick the best one at runtime
|
||||
for (i = 0; sizes[i] != 0; i++)
|
||||
{
|
||||
// scale down and keep aspect
|
||||
w = iw; h = ih; scale(&w, &h, sizes[i], sizes[i], EINA_FALSE);
|
||||
// resize to target size
|
||||
evas_object_resize(im, w, h);
|
||||
evas_object_resize(subwin, w, h);
|
||||
// render our current state and pick up pixel results
|
||||
elm_win_render(subwin);
|
||||
// save out thumb size
|
||||
snprintf(buf, sizeof(buf), "image/thumb/%i", sizes[i]);
|
||||
thumb_image_write(ef, buf, image, alpha, EINA_TRUE);
|
||||
}
|
||||
|
||||
evas_object_del(im);
|
||||
im = NULL;
|
||||
|
||||
_thumb_image_setup();
|
||||
if (len < (1 * 60.0)) // less than 1 min
|
||||
{
|
||||
for (i = 0, p = 0.25; i < 3; i++, p += 0.25)
|
||||
_thumb_file_snap_pos_set(ef, path, i, p * len);
|
||||
}
|
||||
else if (len < (10 * 60.0)) // less than 10 min
|
||||
{
|
||||
for (i = 0, p = 0.10; i < 9; i++, p += 0.10)
|
||||
_thumb_file_snap_pos_set(ef, path, i, p * len);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0, p = 0.05; i < 19; i++, p += 0.05)
|
||||
_thumb_file_snap_pos_set(ef, path, i, p * len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
subdir('default')
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,66 @@
|
|||
#ifndef EFM_H
|
||||
# define EFM_H 1
|
||||
|
||||
# include <Elementary.h>
|
||||
|
||||
#include "efm_config.h"
|
||||
|
||||
typedef enum {
|
||||
EFM_VIEW_MODE_ICONS,
|
||||
EFM_VIEW_MODE_ICONS_CUSTOM,
|
||||
EFM_VIEW_MODE_LIST,
|
||||
EFM_VIEW_MODE_LIST_DETAILED
|
||||
} Efm_View_Mode;
|
||||
|
||||
typedef enum {
|
||||
EFM_SORT_MODE_FLAGS = (0xffff << 16), // upper 16 bits for flags
|
||||
// flags - apper 16 bits
|
||||
EFM_SORT_MODE_DIRS_FIRST = ( 1 << 16), // show dirs first then files
|
||||
EFM_SORT_MODE_NOCASE = ( 1 << 17), // don't account for case when sorting by label or path
|
||||
EFM_SORT_MODE_LABEL_NOT_PATH = ( 1 << 18), // use label either in path filename or inside a desktop file
|
||||
// mask for field
|
||||
EFM_SORT_MODE_MASK = 0xffff, // lower 16 bits is the sort field
|
||||
// fields
|
||||
EFM_SORT_MODE_NAME = ( 0 << 0),
|
||||
EFM_SORT_MODE_SIZE = ( 1 << 0),
|
||||
EFM_SORT_MODE_DATE = ( 2 << 0),
|
||||
EFM_SORT_MODE_MIME = ( 3 << 0),
|
||||
EFM_SORT_MODE_USER = ( 4 << 0),
|
||||
EFM_SORT_MODE_GROUP = ( 5 << 0),
|
||||
EFM_SORT_MODE_PERMISSIONS = ( 6 << 0),
|
||||
} Efm_Sort_Mode;
|
||||
|
||||
typedef enum {
|
||||
EFM_FOCUS_DIR_UP,
|
||||
EFM_FOCUS_DIR_DOWN,
|
||||
EFM_FOCUS_DIR_LEFT,
|
||||
EFM_FOCUS_DIR_RIGHT,
|
||||
EFM_FOCUS_DIR_PGDN,
|
||||
EFM_FOCUS_DIR_PGUP
|
||||
} Efm_Focus_Dir;
|
||||
|
||||
Evas_Object *efm_add(Evas_Object *parent);
|
||||
void efm_scroller_set(Evas_Object *obj, Evas_Object *scroller);
|
||||
Evas_Object *efm_scroller_get(Evas_Object *obj);
|
||||
Evas_Object *efm_detail_header_get(Evas_Object *obj);
|
||||
void efm_path_set(Evas_Object *obj, const char *path);
|
||||
const char *efm_path_get(Evas_Object *obj);
|
||||
void efm_path_view_mode_set(Evas_Object *obj, Efm_View_Mode mode);
|
||||
Efm_View_Mode efm_path_view_mode_get(Evas_Object *obj);
|
||||
void efm_path_sort_mode_set(Evas_Object *obj, Efm_Sort_Mode mode);
|
||||
Efm_Sort_Mode efm_path_sort_mode_get(Evas_Object *obj);
|
||||
Evas_Coord efm_column_min_get(Evas_Object *obj, int col);
|
||||
|
||||
// XXX: set/get column sizes
|
||||
// XXX: callback when column sizes change
|
||||
// XXX: set/get icon size
|
||||
// XXX: hidden files show set/get
|
||||
|
||||
#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
|
||||
#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
|
||||
#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
|
||||
#define CRI(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
|
||||
extern int _log_dom;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,608 @@
|
|||
static void
|
||||
_size_message(Evas_Object *o, double v)
|
||||
{
|
||||
Edje_Message_Float msg;
|
||||
|
||||
// display sqrt of 0.0-?1.0 so we don't have single huge files push every
|
||||
// other bar out
|
||||
if (v > 0.0) v = sqrt(v);
|
||||
msg.val = v;
|
||||
edje_object_message_send(o, EDJE_MESSAGE_FLOAT, 1, &msg);
|
||||
edje_object_message_signal_process(o);
|
||||
}
|
||||
|
||||
static void
|
||||
_size_bars_update(Smart_Data *sd)
|
||||
{
|
||||
Eina_List *bl, *il;
|
||||
Icon *icon;
|
||||
Block *block;
|
||||
const char *s;
|
||||
|
||||
if (sd->config.view_mode != EFM_VIEW_MODE_LIST_DETAILED) return;
|
||||
EINA_LIST_FOREACH(sd->blocks, bl, block)
|
||||
{
|
||||
if (block->realized_num <= 0) continue;
|
||||
EINA_LIST_FOREACH(block->icons, il, icon)
|
||||
{
|
||||
if (!icon->realized) continue;
|
||||
s = cmd_key_find(icon->cmd, "size");
|
||||
if (s)
|
||||
{
|
||||
unsigned long long size = atoll(s);
|
||||
|
||||
if (sd->file_max > 0)
|
||||
_size_message(icon->o_list_detail_swallow2[0],
|
||||
(double)size / (double)sd->file_max);
|
||||
else
|
||||
_size_message(icon->o_list_detail_swallow2[0], 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_size_bars_update_job(void *data)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
|
||||
sd->size_bars_update_job = NULL;
|
||||
_size_bars_update(sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_size_bars_update_queue(Smart_Data *sd)
|
||||
{
|
||||
if (sd->size_bars_update_job) ecore_job_del(sd->size_bars_update_job);
|
||||
sd->size_bars_update_job = ecore_job_add(_cb_size_bars_update_job, sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_size_max_update_job(void *data)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
Eina_List *il;
|
||||
Icon *icon;
|
||||
const char *s;
|
||||
unsigned long long new_max = 0;
|
||||
|
||||
sd->size_max_update_job = NULL;
|
||||
EINA_LIST_FOREACH(sd->icons, il, icon)
|
||||
{
|
||||
s = cmd_key_find(icon->cmd, "size");
|
||||
if (s)
|
||||
{
|
||||
unsigned long long size = atoll(s);
|
||||
|
||||
if (size > new_max) new_max = size;
|
||||
}
|
||||
}
|
||||
if (sd->file_max != new_max)
|
||||
{
|
||||
sd->file_max = new_max;
|
||||
_size_bars_update_queue(sd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_size_bars_max_update_queue(Smart_Data *sd)
|
||||
{
|
||||
if (sd->size_max_update_job) ecore_job_del(sd->size_max_update_job);
|
||||
sd->size_max_update_job = ecore_job_add(_cb_size_max_update_job, sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_command(Smart_Data *sd, const char *cmd)
|
||||
{
|
||||
Cmd *c = cmd_parse(cmd);
|
||||
Msg *msg;
|
||||
void *ref;
|
||||
|
||||
if (!c) return;
|
||||
// send the cmd to our thread to deal with
|
||||
msg = eina_thread_queue_send(sd->thread_data->thq, sizeof(Msg), &ref);
|
||||
msg->c = c;
|
||||
eina_thread_queue_send_done(sd->thread_data->thq, ref);
|
||||
}
|
||||
|
||||
static void
|
||||
_process(Smart_Data_Thread *std, Ecore_Thread *th, Eina_List *batch)
|
||||
{ // process a batch of commands that come from the back-end open process
|
||||
Cmd *c, *c_tmp = NULL;
|
||||
Eina_List *batch_new = NULL;
|
||||
Eina_List *batch_tmp = NULL;
|
||||
|
||||
if (!batch) return;
|
||||
|
||||
// sort batch into batch_new where each set of things like add, mod, del
|
||||
// if they are the same cmd then the files are sorted by path. we do this
|
||||
// to speed up inserts in the main loop so we can assume a sorted list
|
||||
// per batch. this speeds up file adds a lot as we can just do a walk of
|
||||
// the batch (as long as commands stay the same like file-add) and then also
|
||||
// walk the current file/icon list at the same time and skip to the insert
|
||||
// spot which makes inserts very fast as both lists are known to be
|
||||
// pre-sorted so at worst we walk N file icons in the current icon list
|
||||
// per batch (and loading a dir is probably a series of batches of N
|
||||
// file-add's where N is white reasonable
|
||||
EINA_LIST_FREE(batch, c)
|
||||
{
|
||||
c->sort_mode = std->sd->config.sort_mode;
|
||||
if (!batch_tmp)
|
||||
{
|
||||
batch_tmp = eina_list_append(batch_tmp, c);
|
||||
c_tmp = c;
|
||||
}
|
||||
else if (!strcmp(c->command, c_tmp->command))
|
||||
{
|
||||
// works for file-add, file-del, file-mod
|
||||
batch_tmp = eina_list_sorted_insert(batch_tmp, sort_cmd, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
batch_new = eina_list_merge(batch_new, batch_tmp);
|
||||
batch_tmp = NULL;
|
||||
}
|
||||
}
|
||||
if (batch_tmp)
|
||||
{
|
||||
batch_new = eina_list_merge(batch_new, batch_tmp);
|
||||
batch_tmp = NULL;
|
||||
}
|
||||
if (batch_new) ecore_thread_feedback(th, batch_new);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_exe_del(void *data, int ev_type EINA_UNUSED, void *event)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
Ecore_Exe_Event_Del *ev = event;
|
||||
Eina_List *l;
|
||||
Pending_Exe_Del *pend;
|
||||
|
||||
// remove this exited slave process from our pending exe deletions
|
||||
// this list should be pretty small of pending deletions so we don't
|
||||
// need to optimize this with a hash or whatever
|
||||
EINA_LIST_FOREACH(_pending_exe_dels, l, pend)
|
||||
{
|
||||
if (pend->exe == ev->exe)
|
||||
{
|
||||
pend->exe = NULL;
|
||||
if (pend->timer)
|
||||
{
|
||||
ecore_timer_del(pend->timer);
|
||||
pend->timer = NULL;
|
||||
}
|
||||
free(pend);
|
||||
_pending_exe_dels = eina_list_remove_list(_pending_exe_dels, l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ev->exe == sd->exe_open)
|
||||
{ // this process exiting is the back-end open process for active view
|
||||
printf("ERROR: back-end open process died unexpectedly\n");
|
||||
return ECORE_CALLBACK_DONE;
|
||||
}
|
||||
return ECORE_CALLBACK_PASS_ON;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_exe_data(void *data, int ev_type EINA_UNUSED, void *event)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
Ecore_Exe_Event_Data *ev = event;
|
||||
int i;
|
||||
|
||||
// if this exe doesn't match the view it is for - pass it on and skip
|
||||
if (ev->exe != sd->exe_open) return ECORE_CALLBACK_PASS_ON;
|
||||
// this exe data is for thijs view
|
||||
for (i = 0; ev->lines[i].line; i++) _command(sd, ev->lines[i].line);
|
||||
return ECORE_CALLBACK_DONE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_exe_pending_timer(void *data)
|
||||
{ // timeout trying to kill off back-end open process
|
||||
Pending_Exe_Del *pend = data;
|
||||
|
||||
pend->timer = NULL;
|
||||
_pending_exe_dels = eina_list_remove(_pending_exe_dels, pend);
|
||||
if (pend->exe)
|
||||
{ // forcibly kill the back-end process as it did not exit on its own
|
||||
ecore_exe_kill(pend->exe);
|
||||
pend->exe = NULL;
|
||||
}
|
||||
free(pend);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_thread_main(void *data, Ecore_Thread *th)
|
||||
{ // thread sits processing commands read from stdout from the back-end open
|
||||
Smart_Data_Thread *std = data;
|
||||
Msg *msg;
|
||||
void *ref;
|
||||
Cmd *c;
|
||||
Eina_Bool block = EINA_FALSE;
|
||||
const char *prev_cmd = NULL;
|
||||
Eina_List *batch = NULL;
|
||||
|
||||
for (;;)
|
||||
{ // sit in a loop soaking up commands on the input queue
|
||||
if (ecore_thread_check(th)) break;
|
||||
if (!block) msg = eina_thread_queue_poll(std->thq, &ref);
|
||||
else
|
||||
{
|
||||
usleep(4000); // wait 4ms to collect more msg's
|
||||
msg = eina_thread_queue_wait(std->thq, &ref);
|
||||
block = EINA_FALSE;
|
||||
}
|
||||
if (msg)
|
||||
{
|
||||
if (!batch)
|
||||
{
|
||||
batch = eina_list_append(batch, msg->c);
|
||||
eina_stringshare_replace(&(prev_cmd), msg->c->command);
|
||||
}
|
||||
else if ((prev_cmd) && (!strcmp(msg->c->command, prev_cmd)))
|
||||
{
|
||||
batch = eina_list_append(batch, msg->c);
|
||||
}
|
||||
else
|
||||
{
|
||||
_process(std, th, batch);
|
||||
batch = NULL;
|
||||
eina_stringshare_replace(&(prev_cmd), NULL);
|
||||
batch = eina_list_append(batch, msg->c);
|
||||
}
|
||||
eina_thread_queue_wait_done(std->thq, ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
block = EINA_TRUE;
|
||||
_process(std, th, batch);
|
||||
batch = NULL;
|
||||
eina_stringshare_replace(&(prev_cmd), NULL);
|
||||
}
|
||||
}
|
||||
EINA_LIST_FREE(batch, c)
|
||||
{
|
||||
cmd_free(c);
|
||||
}
|
||||
eina_stringshare_replace(&(prev_cmd), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_thread_notify(void *data, Ecore_Thread *th EINA_UNUSED, void *msg)
|
||||
{ // handle data from the view thread to the UI - this will be a batch of cmds
|
||||
Smart_Data_Thread *std = data;
|
||||
Smart_Data *sd = std->sd;
|
||||
Eina_List *batch = msg;
|
||||
Cmd *c, *cprev = NULL;
|
||||
Eina_List *l, *il2, *il = NULL;
|
||||
Icon *icon, *icon2;
|
||||
Block *block;
|
||||
const char *file, *label, *s;
|
||||
int file_adds = 0, file_dels = 0;
|
||||
|
||||
if (!sd)
|
||||
{ // on cusp point - view gone but buffered thread feedback exists
|
||||
EINA_LIST_FREE(batch, c) cmd_free(c);
|
||||
return;
|
||||
}
|
||||
printf("XXXXX BATCH %i\n", eina_list_count(batch));
|
||||
EINA_LIST_FOREACH(batch, l, c)
|
||||
{
|
||||
c->sort_mode = sd->config.sort_mode;
|
||||
#define CMD_DONE cmd_free(c); continue
|
||||
if (!strcmp(c->command, "list-begin"))
|
||||
{
|
||||
printf("XXXXX LIST BEGIN\n");
|
||||
edje_object_part_text_set(sd->o_overlay_info,
|
||||
"e.text.busy_label",
|
||||
"Loading");
|
||||
edje_object_signal_emit(sd->o_overlay_info,
|
||||
"e,state,busy,start", "e");
|
||||
CMD_DONE;
|
||||
}
|
||||
else if (!strcmp(c->command, "list-end"))
|
||||
{
|
||||
printf("XXXXX LIST END\n");
|
||||
edje_object_signal_emit(sd->o_overlay_info,
|
||||
"e,state,busy,stop", "e");
|
||||
CMD_DONE;
|
||||
}
|
||||
file = cmd_key_find(c, "path");
|
||||
printf("XXXXX [%s] [%s]\n", c->command, file);
|
||||
if (file)
|
||||
{
|
||||
s = strrchr(file, '/');
|
||||
if (s) file = s + 1;
|
||||
if (file[0] == '.') // XXX filter dor files or not
|
||||
{
|
||||
CMD_DONE;
|
||||
}
|
||||
}
|
||||
if ((!file) || (!file[0]))
|
||||
{ // somehow we didn't get a sane filename from the back-end
|
||||
CMD_DONE;
|
||||
}
|
||||
label = cmd_key_find(c, "link-label");
|
||||
if (!label) label = cmd_key_find(c, "label");
|
||||
|
||||
if ((!cprev) || (!!strcmp(cprev->command, c->command)))
|
||||
{ // we start a new batch of commands - these are sorted
|
||||
il = sd->icons;
|
||||
}
|
||||
|
||||
if (!strcmp(c->command, "file-add"))
|
||||
{
|
||||
icon = calloc(1, sizeof(Icon));
|
||||
if (!icon) abort();
|
||||
|
||||
file_adds++;
|
||||
icon->sd = sd;
|
||||
icon->cmd = c;
|
||||
icon->changed = EINA_TRUE;
|
||||
icon->info.file = eina_stringshare_add(file);
|
||||
eina_stringshare_replace(&(icon->info.label), label);
|
||||
s = cmd_key_find(c, "label-clicked");
|
||||
if (!s) s = cmd_key_find(c, "link-label-clicked");
|
||||
eina_stringshare_replace(&(icon->info.label_clicked), s);
|
||||
s = cmd_key_find(c, "label-selected");
|
||||
if (!s) s = cmd_key_find(c, "link-label-selected");
|
||||
eina_stringshare_replace(&(icon->info.label_selected), s);
|
||||
s = cmd_key_find(c, "mime");
|
||||
if (s) eina_stringshare_replace(&(icon->info.mime), s);
|
||||
if (s) printf("XXXXX mime=%s\n", icon->info.mime);
|
||||
s = cmd_key_find(c, "desktop-icon");
|
||||
if (!s) s = cmd_key_find(c, "link-desktop-icon");
|
||||
if (s) eina_stringshare_replace(&(icon->info.pre_lookup_icon), s);
|
||||
s = cmd_key_find(c, "desktop-icon.lookup");
|
||||
if (!s) s = cmd_key_find(c, "link-desktop-icon.lookup");
|
||||
if (!s) s = cmd_key_find(c, "icon");
|
||||
if ((s) && (s[0] == '/')) eina_stringshare_replace(&(icon->info.icon), s);
|
||||
s = cmd_key_find(c, "link-desktop-icon-clicked");
|
||||
if (!s) s = cmd_key_find(c, "desktop-icon-clicked");
|
||||
if (s) eina_stringshare_replace(&(icon->info.icon_clicked), s);
|
||||
s = cmd_key_find(c, "link-desktop-icon-selected");
|
||||
if (!s) s = cmd_key_find(c, "desktop-icon-selected");
|
||||
if (s) eina_stringshare_replace(&(icon->info.icon_selected), s);
|
||||
s = cmd_key_find(c, "mime-icon");
|
||||
if (s) eina_stringshare_replace(&(icon->info.mime_icon), s);
|
||||
s = cmd_key_find(c, "thumb");
|
||||
if (s) eina_stringshare_replace(&(icon->info.thumb), s);
|
||||
s = cmd_key_find(c, "type");
|
||||
if (s)
|
||||
{
|
||||
if (!strcmp(s, "link"))
|
||||
{
|
||||
icon->info.link = EINA_TRUE;
|
||||
s = cmd_key_find(c, "broken-link");
|
||||
if ((s) && (!strcmp(s, "true")))
|
||||
icon->info.broken = EINA_TRUE;
|
||||
s = cmd_key_find(c, "link-type");
|
||||
}
|
||||
if (s)
|
||||
{
|
||||
if (!strcmp(s, "dir"))
|
||||
{
|
||||
icon->info.dir = EINA_TRUE;
|
||||
eina_stringshare_replace((&icon->info.mime),
|
||||
"inode/directory");
|
||||
}
|
||||
else if (!strcmp(s, "block"))
|
||||
{
|
||||
icon->info.special = EINA_TRUE;
|
||||
eina_stringshare_replace((&icon->info.mime),
|
||||
"inode/blockdevice");
|
||||
}
|
||||
else if (!strcmp(s, "char"))
|
||||
{
|
||||
icon->info.special = EINA_TRUE;
|
||||
eina_stringshare_replace((&icon->info.mime),
|
||||
"inode/chardevice");
|
||||
}
|
||||
else if (!strcmp(s, "fifo"))
|
||||
{
|
||||
icon->info.special = EINA_TRUE;
|
||||
eina_stringshare_replace((&icon->info.mime),
|
||||
"inode/fifo");
|
||||
}
|
||||
else if (!strcmp(s, "socket"))
|
||||
{
|
||||
icon->info.special = EINA_TRUE;
|
||||
eina_stringshare_replace((&icon->info.mime),
|
||||
"inode/socket");
|
||||
}
|
||||
}
|
||||
}
|
||||
s = cmd_key_find(c, "size");
|
||||
if (s)
|
||||
{
|
||||
unsigned long long size = atoll(s);
|
||||
|
||||
if (size > sd->file_max)
|
||||
{
|
||||
sd->file_max = size;
|
||||
_size_bars_update_queue(sd);
|
||||
}
|
||||
}
|
||||
if (!icon->info.mime)
|
||||
eina_stringshare_replace((&icon->info.mime),
|
||||
"inode/file");
|
||||
|
||||
for ( ; il; il = il->next)
|
||||
{
|
||||
icon2 = il->data;
|
||||
if (!strcmp(file, icon2->info.file))
|
||||
{ // handle the case we get an add for an existing file
|
||||
file_dels++;
|
||||
il2 = il->next;
|
||||
sd->icons = eina_list_remove_list(sd->icons, il);
|
||||
il = il2;
|
||||
if (sd->last_focused)
|
||||
{
|
||||
// XXX: select prev or next icon
|
||||
}
|
||||
s = cmd_key_find(icon->cmd, "size");
|
||||
if (s)
|
||||
{
|
||||
unsigned long long size = atoll(s);
|
||||
|
||||
if (size == sd->file_max)
|
||||
{
|
||||
_size_bars_max_update_queue(sd);
|
||||
}
|
||||
}
|
||||
_icon_free(icon2);
|
||||
if (il) icon2 = il->data;
|
||||
else break;
|
||||
}
|
||||
if (sort_cmd(icon2->cmd, icon->cmd) > 0)
|
||||
{
|
||||
sd->icons = eina_list_prepend_relative_list
|
||||
(sd->icons, icon, il);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!il)
|
||||
{
|
||||
sd->icons = eina_list_append(sd->icons, icon);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(c->command, "file-del"))
|
||||
{
|
||||
for ( ; il; il = il->next)
|
||||
{
|
||||
icon = il->data;
|
||||
if (!strcmp(file, icon->info.file))
|
||||
{
|
||||
file_dels++;
|
||||
il2 = il->next;
|
||||
sd->icons = eina_list_remove_list(sd->icons, il);
|
||||
il = il2;
|
||||
if (sd->last_focused)
|
||||
{
|
||||
// XXX: select prev or next icon
|
||||
}
|
||||
s = cmd_key_find(icon->cmd, "size");
|
||||
if (s)
|
||||
{
|
||||
unsigned long long size = atoll(s);
|
||||
|
||||
if (size == sd->file_max)
|
||||
{
|
||||
_size_bars_max_update_queue(sd);
|
||||
}
|
||||
}
|
||||
_icon_free(icon);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmd_free(c);
|
||||
c = NULL;
|
||||
}
|
||||
else if (!strcmp(c->command, "file-mod"))
|
||||
{
|
||||
for ( ; il; il = il->next)
|
||||
{
|
||||
icon = il->data;
|
||||
if (!strcmp(file, icon->info.file))
|
||||
{
|
||||
icon->changed = EINA_TRUE;
|
||||
eina_stringshare_replace(&(icon->info.label), label);
|
||||
s = cmd_key_find(c, "label-clicked");
|
||||
if (!s) s = cmd_key_find(c, "link-label-clicked");
|
||||
eina_stringshare_replace(&(icon->info.label_clicked), s);
|
||||
s = cmd_key_find(c, "label-selected");
|
||||
if (!s) s = cmd_key_find(c, "link-label-selected");
|
||||
eina_stringshare_replace(&(icon->info.label_selected), s);
|
||||
s = cmd_key_find(c, "mime");
|
||||
if (s) eina_stringshare_replace(&(icon->info.mime), s);
|
||||
if (!icon->info.mime)
|
||||
eina_stringshare_replace((&icon->info.mime),
|
||||
"inode/file");
|
||||
s = cmd_key_find(c, "desktop-icon");
|
||||
if (!s) s = cmd_key_find(c, "link-desktop-icon");
|
||||
if (s) eina_stringshare_replace(&(icon->info.pre_lookup_icon), s);
|
||||
s = cmd_key_find(c, "desktop-icon.lookup");
|
||||
if (!s) s = cmd_key_find(c, "link-desktop-icon.lookup");
|
||||
if (!s) s = cmd_key_find(c, "icon");
|
||||
if ((s) && (s[0] == '/')) eina_stringshare_replace(&(icon->info.icon), s);
|
||||
s = cmd_key_find(c, "link-desktop-icon-clicked");
|
||||
if (!s) s = cmd_key_find(c, "desktop-icon-clicked");
|
||||
if (s) eina_stringshare_replace(&(icon->info.icon_clicked), s);
|
||||
s = cmd_key_find(c, "link-desktop-icon-selected");
|
||||
if (!s) s = cmd_key_find(c, "desktop-icon-selected");
|
||||
if (s) eina_stringshare_replace(&(icon->info.icon_selected), s);
|
||||
s = cmd_key_find(c, "mime-icon");
|
||||
if (s) eina_stringshare_replace(&(icon->info.mime_icon), s);
|
||||
s = cmd_key_find(c, "thumb");
|
||||
if (s) eina_stringshare_replace(&(icon->info.thumb), s);
|
||||
s = cmd_key_find(c, "broken-link");
|
||||
if ((s) && (!strcmp(s, "true")))
|
||||
icon->info.broken = EINA_TRUE;
|
||||
else
|
||||
icon->info.broken = EINA_FALSE;
|
||||
s = cmd_key_find(icon->cmd, "size");
|
||||
if (s)
|
||||
{
|
||||
unsigned long long size = atoll(s);
|
||||
|
||||
if (size == sd->file_max)
|
||||
{
|
||||
_size_bars_max_update_queue(sd);
|
||||
}
|
||||
}
|
||||
s = cmd_key_find(c, "size");
|
||||
if (s)
|
||||
{
|
||||
unsigned long long size = atoll(s);
|
||||
|
||||
if (size > sd->file_max)
|
||||
{
|
||||
sd->file_max = size;
|
||||
_size_bars_update_queue(sd);
|
||||
}
|
||||
}
|
||||
cmd_free(icon->cmd);
|
||||
icon->cmd = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cprev = c;
|
||||
}
|
||||
eina_list_free(batch);
|
||||
if ((sd->config.view_mode >= EFM_VIEW_MODE_LIST) &&
|
||||
((file_adds > 0) || (file_dels > 0)))
|
||||
{ // if it's one of the list modes, unrealize realized icons
|
||||
EINA_LIST_FOREACH(sd->blocks, l, block)
|
||||
{
|
||||
if (block->realized_num <= 0) continue;
|
||||
EINA_LIST_FOREACH(block->icons, il, icon)
|
||||
{ // unrealize the icon - we odd/event forces this
|
||||
if (!icon->realized) continue;
|
||||
icon->realized = EINA_FALSE;
|
||||
icon->block->realized_num--;
|
||||
_icon_object_clear(icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sd->reblock_job) ecore_job_del(sd->reblock_job);
|
||||
sd->reblock_job = ecore_job_add(_cb_reblock, sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_thread_done(void *data, Ecore_Thread *th EINA_UNUSED)
|
||||
{
|
||||
Smart_Data_Thread *std = data;
|
||||
|
||||
if (std->sd) std->sd->thread_data = NULL;
|
||||
if (std->thq)
|
||||
{
|
||||
eina_thread_queue_free(std->thq);
|
||||
std->thq = NULL;
|
||||
}
|
||||
free(std);
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
// utils for draga and drop handling
|
||||
static Eina_Bool
|
||||
_cb_dnd_scroll_timer(void *data)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
Evas_Coord fmx, fmy, sx, sy, sw, sh, x, y;
|
||||
Evas_Coord scr_edge_x, scr_edge_y, scr_mul;
|
||||
|
||||
evas_object_geometry_get(sd->o_smart, &fmx, &fmy, NULL, NULL);
|
||||
evas_object_geometry_get(sd->o_scroller, &sx, &sy, &sw, &sh);
|
||||
scr_mul = 4;
|
||||
scr_edge_x = sd->icon_min_w / 2;
|
||||
scr_edge_y = sd->icon_min_h / 2;
|
||||
if (sd->dnd_scroll_x < scr_edge_x)
|
||||
x = sx - fmx + sd->dnd_scroll_x - scr_edge_x - ((scr_edge_x - sd->dnd_scroll_x) * scr_mul);
|
||||
else if (sd->dnd_scroll_x > (sw - scr_edge_x))
|
||||
x = sx - fmx + sd->dnd_scroll_x + scr_edge_x + ((sd->dnd_scroll_x - (sw - scr_edge_x)) * scr_mul);
|
||||
else
|
||||
x = sx - fmx + sd->dnd_scroll_x;
|
||||
if (sd->dnd_scroll_y < scr_edge_y)
|
||||
y = sy - fmy + sd->dnd_scroll_y - scr_edge_y - ((scr_edge_y - sd->dnd_scroll_y) * scr_mul);
|
||||
else if (sd->dnd_scroll_y > (sh - scr_edge_y))
|
||||
y = sy - fmy + sd->dnd_scroll_y + scr_edge_y + ((sd->dnd_scroll_y - (sh - scr_edge_y)) * scr_mul);
|
||||
else
|
||||
y = sy - fmy + sd->dnd_scroll_y;
|
||||
printf("SSS %i %i | %i %i %ix%i | %i %i\n", x, y, sx, sy, sw, sh, sd->dnd_scroll_x, sd->dnd_scroll_y);
|
||||
elm_scroller_region_bring_in(sd->o_scroller, x, y, 1, 1);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_dnd_scroll_handle(Smart_Data *sd, Evas_Coord x, Evas_Coord y)
|
||||
{
|
||||
sd->dnd_scroll_x = x;
|
||||
sd->dnd_scroll_y = y;
|
||||
if (!sd->dnd_scroll_timer)
|
||||
sd->dnd_scroll_timer = ecore_timer_add
|
||||
(SCROLL_DND_TIMER, _cb_dnd_scroll_timer, sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_dnd_scroll_end_handle(Smart_Data *sd)
|
||||
{
|
||||
if (sd->dnd_scroll_timer)
|
||||
{
|
||||
ecore_timer_del(sd->dnd_scroll_timer);
|
||||
sd->dnd_scroll_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_dnd_over(Icon *icon)
|
||||
{
|
||||
_icon_over_on(icon);
|
||||
}
|
||||
|
||||
static void
|
||||
_dnd_over_none_handle(Smart_Data *sd)
|
||||
{
|
||||
if (sd->over_icon) _icon_over_off(sd->over_icon);
|
||||
}
|
||||
|
||||
static void
|
||||
_dnd_over_handle(Smart_Data *sd, Evas_Coord x, Evas_Coord y)
|
||||
{
|
||||
Icon *icon;
|
||||
Eina_List *bl, *il;
|
||||
Block *block;
|
||||
|
||||
EINA_LIST_FOREACH(sd->blocks, bl, block)
|
||||
{
|
||||
if (!eina_rectangle_coords_inside(&(block->bounds), x, y)) continue;
|
||||
EINA_LIST_FOREACH(block->icons, il, icon)
|
||||
{
|
||||
if (!eina_rectangle_coords_inside(&(icon->geom), x, y)) continue;
|
||||
_dnd_over(icon);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_dnd_over_none_handle(sd);
|
||||
}
|
||||
|
||||
// drop handling
|
||||
static void
|
||||
_cb_drop_in(void *data EINA_UNUSED, Evas_Object *o EINA_UNUSED)
|
||||
{
|
||||
// Smart_Data *sd = data;
|
||||
printf("XXX: drop in.....\n");
|
||||
// XXX: call drop in smart callback}
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_drop_out(void *data, Evas_Object *o EINA_UNUSED)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
_dnd_scroll_end_handle(sd);
|
||||
_dnd_over_none_handle(sd);
|
||||
printf("XXX: drop out.....\n");
|
||||
// XXX: call drop out smart callback}
|
||||
}
|
||||
|
||||
void
|
||||
_cb_drop_pos(void *data, Evas_Object *o EINA_UNUSED, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action EINA_UNUSED)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
Evas_Coord fmx, fmy, fmw, fmh;
|
||||
Evas_Coord sx, sy, sw, sh;
|
||||
|
||||
sd->dnd_action = action;
|
||||
evas_object_geometry_get(sd->o_smart, &fmx, &fmy, &fmw, &fmh);
|
||||
evas_object_geometry_get(sd->o_scroller, &sx, &sy, &sw, &sh);
|
||||
_dnd_scroll_handle(sd, x - sx, y - sy);
|
||||
if (((x - sx) > 0) && ((y - sy) > 0) &&
|
||||
((x - sx) < sw) && ((y - sy) < sh))
|
||||
_dnd_over_handle(sd, x - fmx, y - fmy);
|
||||
else
|
||||
_dnd_over_none_handle(sd);
|
||||
if (sd->over_icon) sd->drop_over = sd->over_icon;
|
||||
else sd->drop_over = NULL;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_drop(void *data, Evas_Object *o EINA_UNUSED, Elm_Selection_Data *ev)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
char **plist, **p, *esc, *tmp;
|
||||
|
||||
if (sd->drop_over) printf("XXX: DND DROP OVER [%s]\n", sd->drop_over->info.file);
|
||||
else printf("XXX: DND DROP ...\n");
|
||||
tmp = malloc(ev->len + 1);
|
||||
if (!tmp) goto err;
|
||||
memcpy(tmp, ev->data, ev->len);
|
||||
tmp[ev->len] = 0;
|
||||
plist = eina_str_split(tmp, "\n", -1);
|
||||
for (p = plist; *p != NULL; ++p)
|
||||
{
|
||||
if (**p)
|
||||
{
|
||||
esc = _escape_parse(*p);
|
||||
if (!esc) continue;
|
||||
printf("XXX: DROP FILE: [%s]\n", esc);
|
||||
}
|
||||
}
|
||||
free(*plist);
|
||||
free(plist);
|
||||
free(tmp);
|
||||
err:
|
||||
sd->drop_over = NULL;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_drop_init(Smart_Data *sd)
|
||||
{ // called once we have our elm scroller around our file view
|
||||
elm_drop_target_add(sd->o_scroller,
|
||||
ELM_SEL_FORMAT_URILIST,
|
||||
_cb_drop_in, sd,
|
||||
_cb_drop_out, sd,
|
||||
_cb_drop_pos, sd,
|
||||
_cb_drop, sd);
|
||||
}
|
||||
|
||||
// drag handling
|
||||
static Evas_Object *
|
||||
_cb_drag_icon_add(void *data, Evas_Object *parent, Evas_Coord *xoff, Evas_Coord *yoff)
|
||||
{
|
||||
Icon *icon = data;
|
||||
Icon *icon2;
|
||||
Block *block;
|
||||
Evas_Object *obj = icon->sd->o_smart;
|
||||
Evas_Object *o;
|
||||
const char *theme_edj_file;
|
||||
Evas *e;
|
||||
ENTRY NULL;
|
||||
Eina_List *bl, *il;
|
||||
int num = 0;
|
||||
|
||||
if (sd->config.view_mode >= EFM_VIEW_MODE_LIST)
|
||||
{
|
||||
EINA_LIST_FOREACH(sd->blocks, bl, block)
|
||||
{
|
||||
if (block->realized_num <= 0)
|
||||
{
|
||||
num += eina_list_count(block->icons);
|
||||
continue;
|
||||
}
|
||||
EINA_LIST_FOREACH(block->icons, il, icon2)
|
||||
{
|
||||
if (icon == icon2) goto found;
|
||||
num++;
|
||||
}
|
||||
num += eina_list_count(block->icons);
|
||||
}
|
||||
}
|
||||
found:
|
||||
e = evas_object_evas_get(parent);
|
||||
theme_edj_file = elm_theme_group_path_find(NULL,
|
||||
"e/fileman/default/icon/fixed");
|
||||
_icon_object_add(icon, icon->sd, e, theme_edj_file, EINA_FALSE, num);
|
||||
o = icon->o_base;
|
||||
evas_object_resize(o, icon->geom.w, icon->geom.h);
|
||||
if (xoff) *xoff = (icon->geom.x + icon->sd->geom.x);
|
||||
if (yoff) *yoff = (icon->geom.y + icon->sd->geom.y);
|
||||
if (xoff && yoff)
|
||||
printf("DND: drag begin %p %p off: %i %i\n", obj, o, *xoff, *yoff);
|
||||
else
|
||||
printf("DND: drag begin %p %p\n", obj, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_drag_pos(void *data EINA_UNUSED, Evas_Object *obj_drag EINA_UNUSED, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action)
|
||||
{
|
||||
printf("DND: %i %i act=%i\n", x, y, action);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_drag_accept(void *data EINA_UNUSED, Evas_Object *obj_drag EINA_UNUSED, Eina_Bool accept)
|
||||
{
|
||||
printf("DND: accept %i\n", accept);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_drag_done(void *data, Evas_Object *obj_drag EINA_UNUSED)
|
||||
{
|
||||
Icon *icon = data;
|
||||
Evas_Object *obj;
|
||||
|
||||
if (icon->sd)
|
||||
{
|
||||
obj = icon->sd->o_smart;
|
||||
ENTRY;
|
||||
|
||||
printf("DND: drag done %p %p\n", obj, obj_drag);
|
||||
sd->drag = EINA_FALSE;
|
||||
icon->o_base = NULL; // try and not del this as dnd will do it
|
||||
icon->sd->drag_icon = NULL;
|
||||
}
|
||||
_icon_free(icon);
|
||||
}
|
||||
|
||||
static void
|
||||
_drag_start(Icon *icon)
|
||||
{
|
||||
Eina_Strbuf *strbuf;
|
||||
Icon *icon_dup;
|
||||
|
||||
strbuf = eina_strbuf_new();
|
||||
if (!strbuf) return;
|
||||
icon_dup = _icon_dup(icon);
|
||||
if (!icon_dup) goto err;
|
||||
|
||||
if (icon->sd->rename_icon) _icon_rename_end(icon->sd->rename_icon);
|
||||
printf("XXX: begin dnd\n");
|
||||
|
||||
icon->sd->drag = EINA_TRUE;
|
||||
icon->sd->just_dragged = EINA_TRUE;
|
||||
icon->sd->drag_icon = icon_dup;
|
||||
if (_selected_icons_uri_strbuf_append(icon->sd, strbuf))
|
||||
{ // begin the drag with that list of files
|
||||
// XXX: if you use no modifier - do default (move)
|
||||
// XXX: if you hold ctrl then do copy
|
||||
// XXX: on win ... to/from removable drive it copies always
|
||||
// XXX: if you hold shift then do move
|
||||
// XXX; on mac option key forces a copy normally except from
|
||||
// removable device then it forces a move
|
||||
// XXX: this "except to/from removable drive" is bad/inconsistent imho
|
||||
elm_drag_start(icon_dup->sd->o_scroller,
|
||||
ELM_SEL_FORMAT_URILIST,
|
||||
eina_strbuf_string_get(strbuf),
|
||||
ELM_XDND_ACTION_MOVE,
|
||||
_cb_drag_icon_add, icon_dup,
|
||||
_cb_drag_pos, icon_dup,
|
||||
_cb_drag_accept, icon_dup,
|
||||
_cb_drag_done, icon_dup);
|
||||
}
|
||||
err:
|
||||
eina_strbuf_free(strbuf);
|
||||
}
|
|
@ -0,0 +1,650 @@
|
|||
#include "efm_icon.h"
|
||||
#include <Emotion.h>
|
||||
|
||||
// XXX: support animated files (anim gif etc.)
|
||||
// XXX: support video files (mp4 etc.)
|
||||
// XXX: support edj files ???
|
||||
// XXX: url's ?
|
||||
|
||||
typedef struct _Smart_Data Smart_Data;
|
||||
|
||||
struct _Smart_Data
|
||||
{
|
||||
Evas_Object_Smart_Clipped_Data __clipped_data;
|
||||
|
||||
Eina_Rectangle geom;
|
||||
|
||||
Evas_Object *o_smart; // the smart object container itself
|
||||
Evas_Object *o_image; // the image to be shown right now
|
||||
Evas_Object *o_image2; // the image being loaded still
|
||||
Evas_Object *o_video; // the image used for video/audio playback
|
||||
|
||||
Ecore_Timer *settle_timer; // time to figure out when
|
||||
Ecore_Job *wakeup; // a job to wake up the loop
|
||||
Eina_Stringshare *file; // file path or...
|
||||
Eina_Stringshare *thumb; // thumb path
|
||||
Eina_Stringshare *video; // video path
|
||||
Ecore_Timer *anim_timer; // timer for animation frame flipping
|
||||
|
||||
int load_size; // the sie we want to load now
|
||||
int orig_w, orig_h; // the sie of the img we loaded
|
||||
int frame; // current frame to display
|
||||
int frame_count; // number of frames in anim
|
||||
double video_ratio; // aspect ratio for videos
|
||||
Evas_Image_Animated_Loop_Hint loop_type; // animated loop type
|
||||
Eina_Bool alpha : 1; // does the img have alpha
|
||||
Eina_Bool svg : 1; // is the img a svg
|
||||
Eina_Bool newfile : 1; // did we just set a new file
|
||||
Eina_Bool animated : 1; // is this animated?
|
||||
Eina_Bool vid_stream : 1; // is this video (has video frames?)
|
||||
Eina_Bool audio : 1; // is this audio (has audo)
|
||||
Eina_Bool mono_thumb : 1; // is thumb of mono white alpha img
|
||||
};
|
||||
|
||||
static Evas_Smart *_smart = NULL;
|
||||
static Evas_Smart_Class _sc = EVAS_SMART_CLASS_INIT_NULL;
|
||||
static Evas_Smart_Class _sc_parent = EVAS_SMART_CLASS_INIT_NULL;
|
||||
|
||||
static void _image_add(Smart_Data *sd);
|
||||
static int _size_choose(Smart_Data *sd, const int *sizes);
|
||||
static void _cb_wakeup(void *data);
|
||||
static void _wakeup(Smart_Data *sd);
|
||||
static void _image_file_set(Smart_Data *sd);
|
||||
static void _image_thumb_set(Smart_Data *sd);
|
||||
static void _image_resized(Smart_Data *sd);
|
||||
static Eina_Bool _cb_settle_timer(void *data);
|
||||
static void _cb_image_preload(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED);
|
||||
static void _handle_frame(Smart_Data *sd);
|
||||
|
||||
// sizes stored in thumbnail files that we might want to look at
|
||||
static const int _thumb_sizes[] = { 512, 256, 128, 64, 32, 16, 0 };
|
||||
// sizes we might want to load/render svg's at
|
||||
static const int _svg_sizes[] = { 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 0 };
|
||||
|
||||
#define ENTRY Smart_Data *sd = evas_object_smart_data_get(obj); if (!sd) return
|
||||
|
||||
static void
|
||||
_image_add(Smart_Data *sd)
|
||||
{ // add a new hidden image object (image2) that will be busy loading
|
||||
Evas_Object *o;
|
||||
|
||||
if (sd->o_image2) evas_object_del(sd->o_image2);
|
||||
sd->o_image2 = o = evas_object_image_filled_add
|
||||
(evas_object_evas_get(sd->o_smart));
|
||||
evas_object_image_scale_hint_set(o, EVAS_IMAGE_SCALE_HINT_STATIC);
|
||||
evas_object_smart_member_add(o, sd->o_smart); // this is a member
|
||||
evas_object_image_load_head_skip_set(o, EINA_TRUE); // fileset no load head
|
||||
// when the image is fully loaded then call this callback so its all
|
||||
// ready and no more i/o is happening (this happens in a thread)
|
||||
evas_object_event_callback_add(o, EVAS_CALLBACK_IMAGE_PRELOADED,
|
||||
_cb_image_preload, sd);
|
||||
}
|
||||
|
||||
static int
|
||||
_size_choose(Smart_Data *sd, const int *sizes)
|
||||
{ // find the next size up we want given the current object size
|
||||
int i, max_size = 0;
|
||||
|
||||
// use the biggest axis as our desired size
|
||||
if (sd->geom.w > sd->geom.h) max_size = sd->geom.w;
|
||||
else max_size = sd->geom.h;
|
||||
for (i = 0; sizes[i] > 0; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{ // if we're not the first item in the sizes
|
||||
// if size is bigger than this slot - return the size up
|
||||
if (max_size > sizes[i]) return sizes[i - 1];
|
||||
}
|
||||
else
|
||||
{ // we're after the first item in our sizes so use biggest
|
||||
if (max_size > sizes[i]) return sizes[i];
|
||||
}
|
||||
}
|
||||
return sizes[i - 1]; // no size found - choose smallest
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_wakeup(void *data)
|
||||
{ // we woke up - mark obj as changed....
|
||||
Smart_Data *sd = data;
|
||||
sd->wakeup = NULL;
|
||||
evas_object_smart_changed(sd->o_smart);
|
||||
}
|
||||
|
||||
static void
|
||||
_wakeup(Smart_Data *sd)
|
||||
{ // wake up the main loop so we spin around and do things
|
||||
if (sd->wakeup) ecore_job_del(sd->wakeup);
|
||||
sd->wakeup = ecore_job_add(_cb_wakeup, sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_image_file_set_final(Smart_Data *sd, const char *file, const char *group)
|
||||
{ // complete image file load/setup, gtrigger preload etc.
|
||||
const char *ext;
|
||||
|
||||
// skip head will make animated not work - so skip it if format might
|
||||
// be animated so we can flip frames
|
||||
ext = strrchr(file, '.');
|
||||
if (ext && ((!strcasecmp(ext, ".gif")) ||
|
||||
(!strcasecmp(ext, ".webp")) ||
|
||||
(!strcasecmp(ext, ".avif")) ||
|
||||
(!strcasecmp(ext, ".avifs")) ||
|
||||
(!strcasecmp(ext, ".jxl"))))
|
||||
evas_object_image_load_head_skip_set(sd->o_image2, EINA_FALSE);
|
||||
evas_object_image_file_set(sd->o_image2, file, group);
|
||||
evas_object_image_preload(sd->o_image2, EINA_FALSE);
|
||||
evas_object_smart_changed(sd->o_smart);
|
||||
_wakeup(sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_image_file_set(Smart_Data *sd)
|
||||
{ // set a generic target image file
|
||||
int load_size = _size_choose(sd, _svg_sizes);
|
||||
|
||||
if (sd->o_video)
|
||||
{ // nuke previous video object if there
|
||||
evas_object_del(sd->o_video);
|
||||
sd->o_video = NULL;
|
||||
}
|
||||
if (sd->svg)
|
||||
{ // if it's a svg file...
|
||||
if (!sd->settle_timer)
|
||||
{ // if we dont have a pending settle timer anymore use an EXACT sz
|
||||
if (sd->geom.w > sd->geom.h) load_size = sd->geom.w;
|
||||
else load_size = sd->geom.h;
|
||||
}
|
||||
}
|
||||
// we already have this thumbnail size so no point loading it again
|
||||
if (load_size == sd->load_size) return;
|
||||
_image_add(sd);
|
||||
sd->load_size = load_size;
|
||||
if (sd->svg)
|
||||
{ // it's a svg so tell the svg loader to render at this size
|
||||
if (sd->load_size == 0) return;
|
||||
evas_object_image_load_size_set(sd->o_image2,
|
||||
sd->load_size, sd->load_size);
|
||||
}
|
||||
_image_file_set_final(sd, sd->file, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_image_thumb_set(Smart_Data *sd)
|
||||
{ // set a thumb file from our stored thumbnails
|
||||
char buf[64];
|
||||
int load_size = _size_choose(sd, _thumb_sizes);
|
||||
|
||||
// we already have this thumbnail size so no point loading it again
|
||||
if (load_size == sd->load_size) return;
|
||||
_image_add(sd);
|
||||
if (sd->newfile)
|
||||
{
|
||||
Eet_File *ef = eet_open(sd->thumb, EET_FILE_MODE_READ);
|
||||
if (ef)
|
||||
{
|
||||
int size;
|
||||
char *mono = eet_read(ef, "image/thumb/mono", &size);
|
||||
|
||||
if (mono)
|
||||
{
|
||||
sd->mono_thumb = *mono;
|
||||
free(mono);
|
||||
}
|
||||
eet_close(ef);
|
||||
}
|
||||
}
|
||||
sd->load_size = load_size;
|
||||
snprintf(buf, sizeof(buf), "image/thumb/%i", sd->load_size);
|
||||
_image_file_set_final(sd, sd->thumb, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vid_frame(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
|
||||
{ // we decoded a frame - make sure vide3o is shown now we have a frame
|
||||
Smart_Data *sd = data;
|
||||
|
||||
evas_object_show(sd->o_video);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vid_resize(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
|
||||
{ // the video changed video size - tell owner we loaded or resized
|
||||
Smart_Data *sd = data;
|
||||
|
||||
emotion_object_size_get(sd->o_video, &(sd->orig_w), &(sd->orig_h));
|
||||
sd->video_ratio = emotion_object_ratio_get(sd->o_video);
|
||||
if (sd->newfile)
|
||||
{ // it's a new file, so say we loaded as its the first time
|
||||
evas_object_smart_callback_call(sd->o_smart, "loaded", NULL);
|
||||
sd->newfile = EINA_FALSE;
|
||||
}
|
||||
else // already playing the file - not new, si resized
|
||||
evas_object_smart_callback_call(sd->o_smart, "resized", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vid_open_done(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
|
||||
{ // we finished opening - now go to 0 and play
|
||||
Smart_Data *sd = data;
|
||||
|
||||
emotion_object_position_set(sd->o_video, 0.0);
|
||||
emotion_object_play_set(sd->o_video, EINA_TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vid_play_finish(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
|
||||
{ // we finished playing go back to 0 and restart so we loop
|
||||
Smart_Data *sd = data;
|
||||
|
||||
emotion_object_play_set(sd->o_video, EINA_FALSE);
|
||||
emotion_object_position_set(sd->o_video, 0.0);
|
||||
emotion_object_play_set(sd->o_video, EINA_TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
_image_video_set(Smart_Data *sd)
|
||||
{ // set a video file
|
||||
static Eina_Bool emotion_initted = EINA_FALSE;
|
||||
Evas_Object *o;
|
||||
|
||||
if (sd->o_image)
|
||||
{ // nuke previous image object if there
|
||||
evas_object_del(sd->o_image);
|
||||
sd->o_image = NULL;
|
||||
}
|
||||
if (sd->o_image2)
|
||||
{ // nuke previous image object if there
|
||||
evas_object_del(sd->o_image2);
|
||||
sd->o_image2 = NULL;
|
||||
}
|
||||
if (sd->o_video)
|
||||
{ // nuke previous video object if there
|
||||
evas_object_del(sd->o_video);
|
||||
sd->o_video = NULL;
|
||||
}
|
||||
|
||||
if (!emotion_initted)
|
||||
{ // emotion needs an init - so init it first time only
|
||||
emotion_init();
|
||||
emotion_initted = EINA_TRUE;
|
||||
}
|
||||
// XXX: sometimes this stalls because gstreamer is updating registry data
|
||||
// in gstreamer_module_init -> gst_init_check -> g_option_context_parse
|
||||
// -> gst_update_registry -> gst_poll_wait
|
||||
sd->o_video = o = emotion_object_add(evas_object_evas_get(sd->o_smart));
|
||||
emotion_object_keep_aspect_set(o, EMOTION_ASPECT_KEEP_NONE);
|
||||
evas_object_smart_member_add(o, sd->o_smart); // this is a member
|
||||
evas_object_smart_callback_add(o, "frame_decode", _cb_vid_frame, sd);
|
||||
evas_object_smart_callback_add(o, "frame_resize", _cb_vid_resize, sd);
|
||||
evas_object_smart_callback_add(o, "open_done", _cb_vid_open_done, sd);
|
||||
evas_object_smart_callback_add(o, "playback_finished", _cb_vid_play_finish, sd);
|
||||
// other callbacks - we don't need these for now
|
||||
// evas_object_smart_callback_add(o, "decode_stop", _cb_vid_stop, obj);
|
||||
// evas_object_smart_callback_add(o, "progress_change", _cb_vid_progress, obj);
|
||||
// evas_object_smart_callback_add(o, "position_update", _cb_position_update, obj);
|
||||
// evas_object_smart_callback_add(o, "length_change", _cb_length_change, obj);
|
||||
// evas_object_smart_callback_add(o, "title_change", _cb_title_change, obj);
|
||||
// evas_object_smart_callback_add(o, "audio_level_change", _cb_audio_change, obj);
|
||||
// evas_object_smart_callback_add(o, "playback_started", _cb_play_start, obj);
|
||||
emotion_object_file_set(o, sd->video);
|
||||
emotion_object_audio_mute_set(o, EINA_TRUE);
|
||||
emotion_object_audio_volume_set(o, 0.0);
|
||||
}
|
||||
|
||||
static void
|
||||
_image_resized(Smart_Data *sd)
|
||||
{ // the image was just resized to handle that settling "idle" timer
|
||||
if (sd->svg)
|
||||
{ // it's an svg - so set up a timer so if we dont resize again for 0.2s
|
||||
if (sd->settle_timer) ecore_timer_reset(sd->settle_timer);
|
||||
else sd->settle_timer = ecore_timer_add(0.2, _cb_settle_timer, sd);
|
||||
}
|
||||
else
|
||||
{ // not a svg - nuke settle timer from space - the only way to be sure
|
||||
if (sd->settle_timer)
|
||||
{
|
||||
ecore_timer_del(sd->settle_timer);
|
||||
sd->settle_timer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_image_update(Smart_Data *sd)
|
||||
{ // update the image - perhaps size changed...
|
||||
if (sd->thumb) _image_thumb_set(sd);
|
||||
else if (sd->file) _image_file_set(sd);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_settle_timer(void *data)
|
||||
{ // when the image settles and stops being resized after a bit...
|
||||
Smart_Data *sd = data;
|
||||
|
||||
sd->settle_timer = NULL;
|
||||
_image_update(sd);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
_frame_num_get(Smart_Data *sd)
|
||||
{
|
||||
int fr, fr2;
|
||||
|
||||
// ping pong - first and last frame only appear once at each end
|
||||
if (sd->loop_type == EVAS_IMAGE_ANIMATED_HINT_PINGPONG)
|
||||
{
|
||||
fr = sd->frame % ((sd->frame_count * 2) - 2);
|
||||
fr2 = sd->frame % sd->frame_count + 1;
|
||||
if (fr >= sd->frame_count) fr = sd->frame_count - 1 - fr2;
|
||||
}
|
||||
// loop
|
||||
else fr = sd->frame % sd->frame_count;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_anim_timer(void *data)
|
||||
{
|
||||
Smart_Data *sd = data;
|
||||
int fr;
|
||||
|
||||
sd->anim_timer = NULL;
|
||||
sd->frame++;
|
||||
fr = _frame_num_get(sd);
|
||||
printf("T: %1.3f %i / %i\n", ecore_time_get(), fr, sd->frame_count);
|
||||
evas_object_image_animated_frame_set(sd->o_image, fr);
|
||||
_handle_frame(sd);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_handle_frame(Smart_Data *sd)
|
||||
{
|
||||
int fr;
|
||||
double t;
|
||||
|
||||
fr = _frame_num_get(sd);
|
||||
t = evas_object_image_animated_frame_duration_get(sd->o_image, fr, 0);
|
||||
if (sd->anim_timer) ecore_timer_del(sd->anim_timer);
|
||||
sd->anim_timer = ecore_timer_add(t, _cb_anim_timer, sd);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_image_preload(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||
{ // whenb an image that was being loaded in the background has now finished
|
||||
Smart_Data *sd = data;
|
||||
|
||||
if (sd->o_image) evas_object_del(sd->o_image);
|
||||
sd->o_image = sd->o_image2;
|
||||
if (!sd->o_image2) return;
|
||||
sd->o_image2 = NULL;
|
||||
evas_object_image_size_get(sd->o_image, &(sd->orig_w), &(sd->orig_h));
|
||||
sd->alpha = evas_object_image_alpha_get(sd->o_image);
|
||||
evas_object_show(sd->o_image);
|
||||
if (sd->newfile)
|
||||
{
|
||||
sd->newfile = EINA_FALSE;
|
||||
evas_object_smart_callback_call(sd->o_smart, "loaded", NULL);
|
||||
}
|
||||
sd->animated = evas_object_image_animated_get(sd->o_image);
|
||||
if (sd->animated)
|
||||
{
|
||||
sd->loop_type = evas_object_image_animated_loop_type_get(sd->o_image);
|
||||
sd->frame_count = evas_object_image_animated_frame_count_get(sd->o_image);
|
||||
if (sd->frame_count < 3) sd->loop_type = EVAS_IMAGE_ANIMATED_HINT_LOOP;
|
||||
else if (sd->frame_count < 2) sd->animated = EINA_FALSE;
|
||||
if (sd->animated) _handle_frame(sd);
|
||||
}
|
||||
}
|
||||
|
||||
// gui code
|
||||
static void
|
||||
_smart_add(Evas_Object *obj)
|
||||
{ // create a new efm icon
|
||||
Smart_Data *sd;
|
||||
|
||||
sd = calloc(1, sizeof(Smart_Data));
|
||||
if (!sd) return;
|
||||
evas_object_smart_data_set(obj, sd);
|
||||
|
||||
_sc_parent.add(obj);
|
||||
|
||||
sd->o_smart = obj;
|
||||
}
|
||||
|
||||
static void
|
||||
_smart_del(Evas_Object *obj)
|
||||
{ // delete/free efm view
|
||||
ENTRY;
|
||||
|
||||
if (sd->o_image)
|
||||
{
|
||||
evas_object_del(sd->o_image);
|
||||
sd->o_image = NULL;
|
||||
}
|
||||
if (sd->o_image2)
|
||||
{
|
||||
evas_object_del(sd->o_image2);
|
||||
sd->o_image2 = NULL;
|
||||
}
|
||||
if (sd->o_video)
|
||||
{
|
||||
evas_object_del(sd->o_video);
|
||||
sd->o_video = NULL;
|
||||
}
|
||||
if (sd->settle_timer)
|
||||
{
|
||||
ecore_timer_del(sd->settle_timer);
|
||||
sd->settle_timer = NULL;
|
||||
}
|
||||
if (sd->wakeup)
|
||||
{
|
||||
ecore_job_del(sd->wakeup);
|
||||
sd->wakeup = NULL;
|
||||
}
|
||||
if (sd->anim_timer)
|
||||
{
|
||||
ecore_timer_del(sd->anim_timer);
|
||||
sd->anim_timer = NULL;
|
||||
}
|
||||
eina_stringshare_replace(&(sd->thumb), NULL);
|
||||
eina_stringshare_replace(&(sd->file), NULL);
|
||||
eina_stringshare_replace(&(sd->video), NULL);
|
||||
|
||||
_sc_parent.del(obj);
|
||||
evas_object_smart_data_set(obj, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
|
||||
{ // efm icon object moved
|
||||
ENTRY;
|
||||
|
||||
if ((sd->geom.x == x) && (sd->geom.y == y)) return;
|
||||
sd->geom.x = x;
|
||||
sd->geom.y = y;
|
||||
evas_object_smart_changed(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
|
||||
{ // efm icon object resized
|
||||
ENTRY;
|
||||
|
||||
if ((sd->geom.w == w) && (sd->geom.h == h)) return;
|
||||
sd->geom.w = w;
|
||||
sd->geom.h = h;
|
||||
_image_resized(sd);
|
||||
_image_update(sd);
|
||||
evas_object_smart_changed(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
_smart_calculate(Evas_Object *obj)
|
||||
{ // recalce position/size
|
||||
ENTRY;
|
||||
|
||||
if (sd->o_image)
|
||||
evas_object_geometry_set(sd->o_image,
|
||||
sd->geom.x, sd->geom.y,
|
||||
sd->geom.w, sd->geom.h);
|
||||
if (sd->o_image2)
|
||||
evas_object_geometry_set(sd->o_image2,
|
||||
sd->geom.x, sd->geom.y,
|
||||
sd->geom.w, sd->geom.h);
|
||||
if (sd->o_video)
|
||||
evas_object_geometry_set(sd->o_video,
|
||||
sd->geom.x, sd->geom.y,
|
||||
sd->geom.w, sd->geom.h);
|
||||
_image_update(sd);
|
||||
}
|
||||
|
||||
Evas_Object *
|
||||
efm_icon_add(Evas_Object *parent)
|
||||
{ // add new icon object
|
||||
if (!_smart)
|
||||
{
|
||||
evas_object_smart_clipped_smart_set(&_sc_parent);
|
||||
_sc = _sc_parent;
|
||||
_sc.name = "efm_icon";
|
||||
_sc.version = EVAS_SMART_CLASS_VERSION;
|
||||
_sc.add = _smart_add;
|
||||
_sc.del = _smart_del;
|
||||
_sc.resize = _smart_resize;
|
||||
_sc.move = _smart_move;
|
||||
_sc.calculate = _smart_calculate;
|
||||
};
|
||||
if (!_smart) _smart = evas_smart_class_new(&_sc);
|
||||
return evas_object_smart_add(evas_object_evas_get(parent), _smart);
|
||||
}
|
||||
|
||||
void
|
||||
efm_icon_file_set(Evas_Object *obj, const char *file)
|
||||
{ // set a regular file as the icon
|
||||
ENTRY;
|
||||
|
||||
if ((sd->file) && (file) && (!strcmp(sd->file, file))) return;
|
||||
if ((!sd->file) && (!file)) return;
|
||||
eina_stringshare_replace(&(sd->thumb), NULL);
|
||||
eina_stringshare_replace(&(sd->file), file);
|
||||
eina_stringshare_replace(&(sd->video), NULL);
|
||||
sd->svg = EINA_FALSE;
|
||||
if ((sd->file) &&
|
||||
((eina_fnmatch("*.svg", sd->file, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("*.svgz", sd->file, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("*.svg.gz", sd->file, EINA_FNMATCH_CASEFOLD))))
|
||||
sd->svg = EINA_TRUE;
|
||||
sd->load_size = -1;
|
||||
sd->newfile = EINA_TRUE;
|
||||
sd->mono_thumb = EINA_FALSE;
|
||||
sd->frame = 0;
|
||||
if (sd->anim_timer)
|
||||
{
|
||||
ecore_timer_del(sd->anim_timer);
|
||||
sd->anim_timer = NULL;
|
||||
}
|
||||
if (sd->settle_timer)
|
||||
{ // thumbnails dont need settle timers like svg's might
|
||||
ecore_timer_del(sd->settle_timer);
|
||||
sd->settle_timer = NULL;
|
||||
}
|
||||
_image_resized(sd);
|
||||
_image_file_set(sd);
|
||||
}
|
||||
|
||||
void
|
||||
efm_icon_thumb_set(Evas_Object *obj, const char *thumb)
|
||||
{ // specifically add generated thumb file
|
||||
ENTRY;
|
||||
|
||||
if ((sd->thumb) && (thumb) && (!strcmp(sd->thumb, thumb))) return;
|
||||
if ((!sd->thumb) && (!thumb)) return;
|
||||
eina_stringshare_replace(&(sd->file), NULL);
|
||||
eina_stringshare_replace(&(sd->thumb), thumb);
|
||||
eina_stringshare_replace(&(sd->video), NULL);
|
||||
sd->svg = EINA_FALSE;
|
||||
sd->load_size = -1;
|
||||
sd->newfile = EINA_TRUE;
|
||||
sd->mono_thumb = EINA_FALSE;
|
||||
sd->frame = 0;
|
||||
if (sd->anim_timer)
|
||||
{
|
||||
ecore_timer_del(sd->anim_timer);
|
||||
sd->anim_timer = NULL;
|
||||
}
|
||||
if (sd->settle_timer)
|
||||
{ // thumbnails dont need settle timers like svg's might
|
||||
ecore_timer_del(sd->settle_timer);
|
||||
sd->settle_timer = NULL;
|
||||
}
|
||||
_image_thumb_set(sd);
|
||||
}
|
||||
|
||||
void
|
||||
efm_icon_video_set(Evas_Object *obj, const char *video)
|
||||
{ // specifically load file as a video (or audio) and not as a still image
|
||||
ENTRY;
|
||||
|
||||
if ((sd->video) && (video) && (!strcmp(sd->video, video))) return;
|
||||
if ((!sd->video) && (!video)) return;
|
||||
eina_stringshare_replace(&(sd->file), NULL);
|
||||
eina_stringshare_replace(&(sd->thumb), NULL);
|
||||
eina_stringshare_replace(&(sd->video), video);
|
||||
sd->svg = EINA_FALSE;
|
||||
sd->load_size = -1;
|
||||
sd->newfile = EINA_TRUE;
|
||||
sd->mono_thumb = EINA_FALSE;
|
||||
sd->frame = 0;
|
||||
sd->video_ratio = 0.0;
|
||||
if (sd->anim_timer)
|
||||
{
|
||||
ecore_timer_del(sd->anim_timer);
|
||||
sd->anim_timer = NULL;
|
||||
}
|
||||
if (sd->settle_timer)
|
||||
{ // thumbnails dont need settle timers like svg's might
|
||||
ecore_timer_del(sd->settle_timer);
|
||||
sd->settle_timer = NULL;
|
||||
}
|
||||
_image_resized(sd);
|
||||
_image_video_set(sd);
|
||||
}
|
||||
|
||||
void
|
||||
efm_icon_size_get(Evas_Object *obj, int *w, int *h)
|
||||
{ // get image pixel size
|
||||
ENTRY;
|
||||
|
||||
if ((sd->o_video) && (sd->video_ratio > 0.0))
|
||||
{
|
||||
int vid_w, vid_h;
|
||||
|
||||
vid_w = ((double)sd->orig_h + 0.5) * sd->video_ratio;
|
||||
vid_h = sd->orig_h;
|
||||
if (w) *w = vid_w;
|
||||
if (h) *h = vid_h;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (w) *w = sd->orig_w;
|
||||
if (h) *h = sd->orig_h;
|
||||
}
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
efm_icon_alpha_get(Evas_Object *obj)
|
||||
{ // get image alpha flag
|
||||
ENTRY EINA_FALSE;
|
||||
|
||||
return sd->alpha;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
efm_icon_mono_get(Evas_Object *obj)
|
||||
{ // get thumb mono flag
|
||||
ENTRY EINA_FALSE;
|
||||
|
||||
return sd->mono_thumb;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef EFM_ICON_H
|
||||
# define EFM_ICON_H 1
|
||||
|
||||
# include <Elementary.h>
|
||||
|
||||
Evas_Object *efm_icon_add(Evas_Object *parent);
|
||||
void efm_icon_file_set(Evas_Object *obj, const char *file);
|
||||
void efm_icon_thumb_set(Evas_Object *obj, const char *thumb);
|
||||
void efm_icon_video_set(Evas_Object *obj, const char *video);
|
||||
void efm_icon_size_get(Evas_Object *obj, int *w, int *h);
|
||||
Eina_Bool efm_icon_alpha_get(Evas_Object *obj);
|
||||
Eina_Bool efm_icon_mono_get(Evas_Object *obj);
|
||||
|
||||
// smart callbacks:
|
||||
// "loaded"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
// functions used between the split up parts of the efm view
|
||||
|
||||
static void _command (Smart_Data *sd, const char *cmd);
|
||||
static void _process (Smart_Data_Thread *std, Ecore_Thread *th, Eina_List *batch);
|
||||
|
||||
static Eina_Bool _cb_exe_del (void *data, int ev_type EINA_UNUSED, void *event);
|
||||
static Eina_Bool _cb_exe_data (void *data, int ev_type EINA_UNUSED, void *event);
|
||||
static Eina_Bool _cb_exe_pending_timer (void *data);
|
||||
|
||||
static void _cb_thread_main (void *data, Ecore_Thread *th);
|
||||
static void _cb_thread_notify (void *data, Ecore_Thread *th EINA_UNUSED, void *msg);
|
||||
static void _cb_thread_done (void *data, Ecore_Thread *th EINA_UNUSED);
|
||||
|
||||
static void _icon_object_clear (Icon *icon);
|
||||
static void _icon_object_add (Icon *icon, Smart_Data *sd, Evas *e, const char *theme_edj_file, Eina_Bool clip_set, int num);
|
||||
static void _icon_free (Icon *icon);
|
||||
static void _block_free (Block *block);
|
||||
static void _cb_reblock (void *data);
|
||||
|
||||
static void _drag_start (Icon *icon);
|
|
@ -0,0 +1,175 @@
|
|||
// data structs used for the efm view
|
||||
//
|
||||
typedef struct _Smart_Data Smart_Data;
|
||||
typedef struct _Smart_Data_Thread Smart_Data_Thread;
|
||||
typedef struct _Block Block;
|
||||
typedef struct _Icon Icon;
|
||||
|
||||
typedef struct _File_Info File_Info;
|
||||
|
||||
// data kept around as long as the thread is so it knows what it is for
|
||||
struct _Smart_Data_Thread
|
||||
{
|
||||
Smart_Data *sd;
|
||||
Eina_Thread_Queue *thq;
|
||||
};
|
||||
|
||||
// an icon view gui data
|
||||
struct _Smart_Data
|
||||
{
|
||||
Evas_Object_Smart_Clipped_Data __clipped_data;
|
||||
|
||||
Eina_Rectangle geom;
|
||||
|
||||
Evas_Object *o_smart;
|
||||
Evas_Object *o_back;
|
||||
Evas_Object *o_clip;
|
||||
Evas_Object *o_scroller;
|
||||
Evas_Object *o_focus;
|
||||
Evas_Object *o_sel;
|
||||
Evas_Object *o_over;
|
||||
Evas_Object *o_detail_header;
|
||||
Evas_Object *o_detail_header_item[7];
|
||||
|
||||
Evas_Object *o_list_detailed_dummy;
|
||||
Evas_Object *o_list_detail[6];
|
||||
Evas_Object *o_list_detail_swallow[6];
|
||||
Evas_Object *o_overlay_grid_fill;
|
||||
Evas_Object *o_overlay_grid;
|
||||
Evas_Object *o_overlay_info;
|
||||
|
||||
Eina_Stringshare *path;
|
||||
|
||||
Ecore_Exe *exe_open;
|
||||
Ecore_Event_Handler *handler_exe_del;
|
||||
Ecore_Event_Handler *handler_exe_data;
|
||||
|
||||
Smart_Data_Thread *thread_data;
|
||||
Ecore_Thread *thread;
|
||||
|
||||
Eina_List *icons;
|
||||
Eina_List *blocks;
|
||||
Ecore_Job *reblock_job;
|
||||
Ecore_Job *refocus_job;
|
||||
Ecore_Job *size_bars_update_job;
|
||||
Ecore_Job *size_max_update_job;
|
||||
Icon *last_selected;
|
||||
Icon *last_focused_before;
|
||||
Icon *last_focused;
|
||||
Icon *drag_icon;
|
||||
Icon *over_icon;
|
||||
Icon *drop_over;
|
||||
Icon *rename_icon;
|
||||
|
||||
Evas_Coord icon_min_w, icon_min_h;
|
||||
Evas_Coord list_min_w, list_min_h;
|
||||
Evas_Coord list_detailed_min_w, list_detailed_min_h;
|
||||
Evas_Coord back_down_x, back_down_y;
|
||||
Evas_Coord back_x, back_y;
|
||||
Evas_Coord sel_x1, sel_y1, sel_x2, sel_y2;
|
||||
Evas_Coord dnd_scroll_x, dnd_scroll_y;
|
||||
Evas_Coord detail_down_x, detail_down_y;
|
||||
Evas_Coord detail_down_start_min_w;
|
||||
Evas_Coord detail_min_w[6];
|
||||
Evas_Coord detail_header_min_h[7];
|
||||
double focus_start_time;
|
||||
double focus_pos;
|
||||
Ecore_Animator *focus_animator;
|
||||
Ecore_Timer *scroll_timer;
|
||||
Ecore_Timer *dnd_scroll_timer;
|
||||
Ecore_Timer *dnd_over_open_timer;
|
||||
Elm_Xdnd_Action dnd_action;
|
||||
|
||||
unsigned long long file_max;
|
||||
|
||||
Eina_Bool reblocked : 1;
|
||||
Eina_Bool relayout : 1;
|
||||
Eina_Bool focused : 1;
|
||||
Eina_Bool focus_show : 1;
|
||||
Eina_Bool key_control : 1;
|
||||
Eina_Bool back_down : 1;
|
||||
Eina_Bool sel_show : 1;
|
||||
Eina_Bool drag : 1;
|
||||
Eina_Bool just_dragged : 1;
|
||||
Eina_Bool cnp_have : 1;
|
||||
Eina_Bool cnp_cut : 1;
|
||||
Eina_Bool detail_down : 1;
|
||||
|
||||
struct {
|
||||
Efm_View_Mode view_mode;
|
||||
Efm_Sort_Mode sort_mode;
|
||||
int icon_size;
|
||||
} config;
|
||||
};
|
||||
|
||||
// file info gagthered
|
||||
struct _File_Info
|
||||
{
|
||||
const char *file;
|
||||
const char *label;
|
||||
const char *label_selected;
|
||||
const char *label_clicked;
|
||||
const char *mime;
|
||||
const char *icon;
|
||||
const char *icon_selected;
|
||||
const char *icon_clicked;
|
||||
const char *mime_icon;
|
||||
const char *pre_lookup_icon;
|
||||
const char *thumb;
|
||||
Eina_Bool dir : 1;
|
||||
Eina_Bool link : 1;
|
||||
Eina_Bool broken : 1;
|
||||
Eina_Bool special : 1;
|
||||
};
|
||||
|
||||
// a block of icons as a group
|
||||
struct _Block
|
||||
{
|
||||
Eina_Rectangle bounds; // relative to top-left of obj
|
||||
Smart_Data *sd;
|
||||
Eina_List *icons;
|
||||
int realized_num;
|
||||
int selected_num;
|
||||
Eina_Bool changed : 1;
|
||||
};
|
||||
|
||||
// an icon in a block of icons
|
||||
struct _Icon
|
||||
{
|
||||
Eina_Rectangle geom;
|
||||
Evas_Object *o_base;
|
||||
Evas_Object *o_icon;
|
||||
Evas_Object *o_entry;
|
||||
Evas_Object *o_list_detail_swallow[6];
|
||||
Evas_Object *o_list_detail_swallow2[6];
|
||||
Smart_Data *sd;
|
||||
Cmd *cmd;
|
||||
Block *block;
|
||||
Eina_List *block_list;
|
||||
Ecore_Timer *longpress_timer;
|
||||
File_Info info;
|
||||
Evas_Coord down_x, down_y;
|
||||
Eina_Bool realized : 1;
|
||||
Eina_Bool selected : 1;
|
||||
Eina_Bool down : 1;
|
||||
Eina_Bool over : 1;
|
||||
Eina_Bool changed : 1;
|
||||
Eina_Bool edje : 1;
|
||||
Eina_Bool renaming : 1;
|
||||
};
|
||||
|
||||
typedef struct _Pending_Exe_Del Pending_Exe_Del;
|
||||
|
||||
// an entry in our list of back-end open processes waiting to exit
|
||||
struct _Pending_Exe_Del
|
||||
{
|
||||
Ecore_Exe *exe;
|
||||
Ecore_Timer *timer;
|
||||
};
|
||||
|
||||
// a message from thread to front-end ui in main loop
|
||||
typedef struct
|
||||
{
|
||||
Eina_Thread_Queue_Msg head;
|
||||
Cmd *c;
|
||||
} Msg;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,189 @@
|
|||
// test gui front-end for new efm
|
||||
#include "efm.h"
|
||||
|
||||
//#include "efm_icon.h"
|
||||
|
||||
static Evas_Object *o_detail_header_box = NULL;
|
||||
static Evas_Object *o_detail_header = NULL;
|
||||
|
||||
static void
|
||||
_cb_icons(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||
{
|
||||
efm_path_view_mode_set(data, EFM_VIEW_MODE_ICONS);
|
||||
if (o_detail_header)
|
||||
{
|
||||
evas_object_del(o_detail_header);
|
||||
o_detail_header = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_icons_custom(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||
{
|
||||
efm_path_view_mode_set(data, EFM_VIEW_MODE_ICONS_CUSTOM);
|
||||
if (o_detail_header)
|
||||
{
|
||||
evas_object_del(o_detail_header);
|
||||
o_detail_header = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_list(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||
{
|
||||
efm_path_view_mode_set(data, EFM_VIEW_MODE_LIST);
|
||||
if (o_detail_header)
|
||||
{
|
||||
evas_object_del(o_detail_header);
|
||||
o_detail_header = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_list_detailed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||
{
|
||||
Evas_Object *o;
|
||||
|
||||
efm_path_view_mode_set(data, EFM_VIEW_MODE_LIST_DETAILED);
|
||||
|
||||
if (!o_detail_header)
|
||||
{
|
||||
o_detail_header = o = efm_detail_header_get(data);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
|
||||
elm_box_pack_end(o_detail_header_box, o);
|
||||
evas_object_show(o);
|
||||
}
|
||||
}
|
||||
|
||||
EAPI_MAIN int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
const char *path;
|
||||
Evas_Object *o, *win, *sc, *efm, *bx, *bx2;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
path = ecore_file_realpath(argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
getcwd(buf, sizeof(buf));
|
||||
path = buf;
|
||||
}
|
||||
|
||||
elm_need_efreet();
|
||||
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
|
||||
elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
|
||||
elm_app_compile_lib_dir_set(PACKAGE_LIB_DIR);
|
||||
elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
|
||||
elm_app_info_set(elm_main, "efm", "checkme");
|
||||
|
||||
win = o = elm_win_util_standard_add("Main", "Files");
|
||||
elm_win_icon_name_set(o, "Files");
|
||||
elm_win_role_set(o, "efm_win_files");
|
||||
elm_win_autodel_set(o, EINA_TRUE);
|
||||
|
||||
/*
|
||||
ic = o = evas_object_image_add(evas_object_evas_get(win));
|
||||
icon = efreet_icon_path_find(elm_config_icon_theme_get(),
|
||||
"inode-directory", 0);
|
||||
if (icon) printf("%s\n", icon);
|
||||
evas_object_image_file_set(o, icon, NULL);
|
||||
elm_win_icon_object_set(win, o);
|
||||
evas_object_show(o);
|
||||
*/
|
||||
|
||||
bx = o = elm_box_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
elm_box_horizontal_set(o, EINA_FALSE);
|
||||
elm_win_resize_object_add(win, o);
|
||||
evas_object_show(o);
|
||||
|
||||
bx2 = o = elm_box_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_box_homogeneous_set(o, EINA_TRUE);
|
||||
elm_box_horizontal_set(o, EINA_TRUE);
|
||||
elm_box_pack_end(bx, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = elm_button_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_object_text_set(o, "X");
|
||||
elm_box_pack_end(bx2, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o_detail_header_box = o = elm_box_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_box_pack_end(bx, o);
|
||||
evas_object_show(o);
|
||||
|
||||
sc = o = elm_scroller_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
elm_box_pack_end(bx, o);
|
||||
evas_object_show(o);
|
||||
|
||||
efm = o = efm_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
elm_object_content_set(sc, o);
|
||||
efm_scroller_set(o, sc);
|
||||
efm_path_set(o, path);
|
||||
evas_object_show(o);
|
||||
|
||||
bx2 = o = elm_box_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_box_homogeneous_set(o, EINA_TRUE);
|
||||
elm_box_horizontal_set(o, EINA_TRUE);
|
||||
elm_box_pack_end(bx, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = elm_button_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_object_text_set(o, "Icons");
|
||||
evas_object_smart_callback_add(o, "clicked", _cb_icons, efm);
|
||||
elm_box_pack_end(bx2, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = elm_button_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_object_text_set(o, "List");
|
||||
evas_object_smart_callback_add(o, "clicked", _cb_list, efm);
|
||||
elm_box_pack_end(bx2, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = elm_button_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_object_text_set(o, "Detailed");
|
||||
evas_object_smart_callback_add(o, "clicked", _cb_list_detailed, efm);
|
||||
elm_box_pack_end(bx2, o);
|
||||
evas_object_show(o);
|
||||
|
||||
o = elm_button_add(win);
|
||||
evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, 0);
|
||||
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0);
|
||||
elm_object_text_set(o, "Custom");
|
||||
evas_object_smart_callback_add(o, "clicked", _cb_icons_custom, efm);
|
||||
elm_box_pack_end(bx2, o);
|
||||
evas_object_show(o);
|
||||
|
||||
evas_object_resize(win, ELM_SCALE_SIZE(700), ELM_SCALE_SIZE(300));
|
||||
evas_object_show(win);
|
||||
|
||||
elm_object_focus_set(sc, EINA_TRUE);
|
||||
|
||||
elm_run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
ELM_MAIN()
|
|
@ -0,0 +1,18 @@
|
|||
dir = join_paths(dir_bin)
|
||||
inc = include_directories(
|
||||
'.',
|
||||
'../..',
|
||||
'../shared/commands',
|
||||
'../shared/common'
|
||||
)
|
||||
executable('efm', [
|
||||
'../shared/common/cmd.c',
|
||||
'efm.c',
|
||||
'sort.c',
|
||||
'efm_icon.c',
|
||||
'main.c'
|
||||
],
|
||||
include_directories: inc,
|
||||
dependencies: deps,
|
||||
install: true,
|
||||
install_dir: dir)
|
|
@ -0,0 +1,240 @@
|
|||
#include "cmd.h"
|
||||
#include "sort.h"
|
||||
#include "efm.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// sorting helpers
|
||||
enum
|
||||
{
|
||||
SORT_LESS = -1,
|
||||
SORT_MORE = 1,
|
||||
SORT_INVALID = -100
|
||||
};
|
||||
|
||||
static char
|
||||
_str_mode_file_type(int mode)
|
||||
{
|
||||
char c = '?';
|
||||
|
||||
if (S_ISREG(mode)) c = '-';
|
||||
else if (S_ISDIR(mode)) c = 'd';
|
||||
else if (S_ISBLK(mode)) c = 'b';
|
||||
else if (S_ISCHR(mode)) c = 'c';
|
||||
#ifdef S_ISFIFO
|
||||
else if (S_ISFIFO(mode)) c = 'p';
|
||||
#endif
|
||||
#ifdef S_ISLNK
|
||||
else if (S_ISLNK(mode)) c = 'l';
|
||||
#endif
|
||||
#ifdef S_ISSOCK
|
||||
else if (S_ISSOCK(mode)) c = 's';
|
||||
#endif
|
||||
#ifdef S_ISDOOR
|
||||
else if (S_ISDOOR(mode)) c = 'D';
|
||||
#endif
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
_str_mode(int mode, char str[11])
|
||||
{ // generate string mode i9nto dest str buffer
|
||||
static const char *rwx[] = {
|
||||
"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"
|
||||
};
|
||||
|
||||
str[0] = _str_mode_file_type(mode);
|
||||
strcpy(&str[1], rwx[(mode >> 6)& 7]);
|
||||
strcpy(&str[4], rwx[(mode >> 3)& 7]);
|
||||
strcpy(&str[7], rwx[(mode & 7)]);
|
||||
if (mode & S_ISUID) str[3] = (mode & S_IXUSR) ? 's' : 'S';
|
||||
if (mode & S_ISGID) str[6] = (mode & S_IXGRP) ? 's' : 'l';
|
||||
if (mode & S_ISVTX) str[9] = (mode & S_IXOTH) ? 't' : 'T';
|
||||
str[10] = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_sort_str_field(const Cmd *c1, const Cmd *c2, int (*cmpfn) (const char *s1, const char *s2), const char *field)
|
||||
{ // a string fields - get it and sort using compare func
|
||||
const char *field1, *field2, *path1, *path2;
|
||||
int res;
|
||||
|
||||
field1 = cmd_key_find(c1, field);
|
||||
if (!field1) return 0;
|
||||
|
||||
field2 = cmd_key_find(c2, field);
|
||||
if (!field2) return 0;
|
||||
|
||||
res = cmpfn(field1, field2);
|
||||
if (!res)
|
||||
{ // they are the same string! use pure filename path as it's unique
|
||||
path1 = cmd_key_find(c1, "path");
|
||||
path2 = cmd_key_find(c2, "path");
|
||||
res = cmpfn(path1, path2);
|
||||
if (!res) return strcmp(path1, path2);
|
||||
return res;
|
||||
}
|
||||
return cmpfn(field1, field2);
|
||||
}
|
||||
|
||||
static int
|
||||
_sort_num_field(const Cmd *c1, const Cmd *c2, const char *field)
|
||||
{ // user a named field that is a number like mtime, ctime, size etc ...
|
||||
const char *f, *path1, *path2;
|
||||
unsigned long long field1 = 0, field2 = 0;
|
||||
|
||||
// get field and convert to ulonglong
|
||||
f = cmd_key_find(c1, field);
|
||||
if (f) field1 = strtoull(f, NULL, 10);
|
||||
|
||||
// get field and convert to ulonglong
|
||||
f = cmd_key_find(c2, field);
|
||||
if (f) field2 = strtoull(f, NULL, 10);
|
||||
|
||||
if (field1 == field2)
|
||||
{ // they are the same string! use pure filename path as it's unique
|
||||
path1 = cmd_key_find(c1, "path");
|
||||
path2 = cmd_key_find(c2, "path");
|
||||
return strcmp(path1, path2);
|
||||
}
|
||||
// sort result
|
||||
if (field1 > field2) return SORT_MORE;
|
||||
return SORT_LESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_sort_path(const Cmd *c1, const Cmd *c2, int (*cmpfn) (const char *s1, const char *s2))
|
||||
{ // use pure filename path not label
|
||||
return _sort_str_field(c1, c2, cmpfn, "path");
|
||||
}
|
||||
|
||||
static int
|
||||
_sort_label(const Cmd *c1, const Cmd *c2, int (*cmpfn) (const char *s1, const char *s2))
|
||||
{ // sort by label or path - some files like .desktop files have labels
|
||||
const char *path1, *path2;
|
||||
int res;
|
||||
|
||||
// get a label instead of filename path element if available
|
||||
path1 = cmd_key_find(c1, "label");
|
||||
if (!path1) path1 = cmd_key_find(c1, "path");
|
||||
|
||||
// get a label instead of filename path element if available
|
||||
path2 = cmd_key_find(c2, "label");
|
||||
if (!path2) path2 = cmd_key_find(c2, "path");
|
||||
|
||||
res = cmpfn(path1, path2);
|
||||
if (!res)
|
||||
{ // they are the same string! use pure filename path as it's unique
|
||||
path1 = cmd_key_find(c1, "path");
|
||||
path2 = cmd_key_find(c2, "path");
|
||||
res = cmpfn(path1, path2);
|
||||
if (!res) return strcmp(path1, path2);
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
_sort_mode(const Cmd *c1, const Cmd *c2)
|
||||
{ // sort by mode string like "drwxr-xr-x" or "-rw-r--r--"
|
||||
const char *f;
|
||||
int mode1 = 0, mode2 = 0, ret = 0;
|
||||
char m1[11], m2[11];
|
||||
|
||||
// get mdoe and generate mode string
|
||||
f = cmd_key_find(c1, "mode");
|
||||
if (f) mode1 = strtoull(f, NULL, 16);
|
||||
_str_mode(mode1, m1);
|
||||
|
||||
// get mdoe and generate mode string
|
||||
f = cmd_key_find(c2, "mode");
|
||||
if (f) mode2 = strtoull(f, NULL, 16);
|
||||
_str_mode(mode2, m2);
|
||||
|
||||
// sort by the mode string
|
||||
ret = strcmp(m1, m2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_sort_dir_not_dir(const Cmd *c1, const Cmd *c2)
|
||||
{
|
||||
const char *type1, *type2;
|
||||
|
||||
// get file types for both - and if link resolve the link dest type
|
||||
type1 = cmd_key_find(c1, "type");
|
||||
if ((type1) && (!strcmp(type1, "link")))
|
||||
type1 = cmd_key_find(c1, "link-type");
|
||||
if (!type1) type1 = "file";
|
||||
|
||||
type2 = cmd_key_find(c2, "type");
|
||||
if ((type2) && (!strcmp(type2, "link")))
|
||||
type2 = cmd_key_find(c2, "link-type");
|
||||
if (!type2) type2 = "file";
|
||||
|
||||
// 1st is dir, 2nd is not dir
|
||||
if (( !strcmp(type1, "dir")) && (!!strcmp(type2, "dir"))) return SORT_LESS;
|
||||
// 1st is not dir, 2nd is dir
|
||||
if ((!!strcmp(type1, "dir")) && ( !strcmp(type2, "dir"))) return SORT_MORE;
|
||||
// both are dir or both are not dir
|
||||
return SORT_INVALID;
|
||||
}
|
||||
|
||||
// sorter logic
|
||||
static int
|
||||
_sort_cmd_do(const Cmd *c1, const Cmd *c2)
|
||||
{
|
||||
int dir_not_dir = SORT_INVALID;
|
||||
Efm_Sort_Mode sort_mode;
|
||||
int (*cmpfn) (const char *s1, const char *s2) = strcmp;
|
||||
Eina_Bool label_sort = EINA_FALSE;
|
||||
|
||||
sort_mode = c1->sort_mode;
|
||||
// handle flags
|
||||
if (sort_mode & EFM_SORT_MODE_DIRS_FIRST)
|
||||
dir_not_dir = _sort_dir_not_dir(c1, c2);
|
||||
if (sort_mode & EFM_SORT_MODE_NOCASE)
|
||||
cmpfn = strcasecmp;
|
||||
if (sort_mode & EFM_SORT_MODE_LABEL_NOT_PATH)
|
||||
label_sort = EINA_TRUE;
|
||||
|
||||
// handle each sort mode
|
||||
|
||||
// if one is a dir and one is not - other sorting compares are not useful
|
||||
// so just return this status
|
||||
if (dir_not_dir != SORT_INVALID) return dir_not_dir;
|
||||
|
||||
// handle the actual specific sort field to use
|
||||
switch (sort_mode & EFM_SORT_MODE_MASK)
|
||||
{
|
||||
case EFM_SORT_MODE_NAME:
|
||||
if (label_sort) return _sort_label(c1, c2, cmpfn);
|
||||
return _sort_path(c1, c2, cmpfn);
|
||||
case EFM_SORT_MODE_SIZE:
|
||||
return _sort_num_field(c1, c2, "size");
|
||||
case EFM_SORT_MODE_DATE:
|
||||
return _sort_num_field(c1, c2, "mtime");
|
||||
case EFM_SORT_MODE_MIME:
|
||||
return _sort_str_field(c1, c2, strcmp, "mime");
|
||||
case EFM_SORT_MODE_USER:
|
||||
return _sort_str_field(c1, c2, strcmp, "user");
|
||||
case EFM_SORT_MODE_GROUP:
|
||||
return _sort_str_field(c1, c2, strcmp, "group");
|
||||
case EFM_SORT_MODE_PERMISSIONS:
|
||||
return _sort_mode(c1, c2);
|
||||
default: // unknown - so just plain path
|
||||
goto def;
|
||||
break;
|
||||
}
|
||||
def:
|
||||
return _sort_path(c1, c2, cmpfn);
|
||||
}
|
||||
|
||||
int
|
||||
sort_cmd(const void *c1, const void *c2)
|
||||
{
|
||||
return _sort_cmd_do(c1, c2);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef SORT_H
|
||||
# define SORT_H 1
|
||||
|
||||
int sort_cmd(const void *c1, const void *c2);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,2 @@
|
|||
subdir('backends')
|
||||
subdir('efm')
|
|
@ -0,0 +1,226 @@
|
|||
// basic command parsing, building and sending funcs used by other files to
|
||||
// deal with a string command stream sanely so all the parsing of the core
|
||||
// formatting is on one place
|
||||
#include "cmd.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// parse a single command line that is:
|
||||
// cmd xxx=yyy a=bbb ...
|
||||
// and return the command struct
|
||||
Cmd *
|
||||
cmd_parse(const char *cmd)
|
||||
{
|
||||
char *b;
|
||||
const char *s, *begin;
|
||||
int d, dmax;
|
||||
Cmd *cnew, *c = malloc(sizeof(Cmd) + (2 * sizeof(char *)));
|
||||
|
||||
if (strncmp(cmd, "CMD ", 4)) return NULL;
|
||||
cmd += 4;
|
||||
if (!c) return NULL;
|
||||
c->buf_size = strlen(cmd) + 1;
|
||||
c->buf = malloc(c->buf_size); // buf that unescapes always same/smaller
|
||||
c->command = NULL;
|
||||
c->dict[0] = c->dict[1] = NULL;
|
||||
// parse out command string until spaces - then skip them, then begin dict
|
||||
b = c->buf;
|
||||
for (s = cmd; (!isspace(*s)) && (*s); s++)
|
||||
{
|
||||
*b = *s;
|
||||
b++;
|
||||
}
|
||||
*b = 0;
|
||||
b++;
|
||||
c->command = c->buf;
|
||||
for (; (*s) && isspace(*s); s++);
|
||||
d = 0;
|
||||
dmax = 2;
|
||||
while (*s)
|
||||
{
|
||||
begin = b;
|
||||
// parse up to =
|
||||
while ((*s) && (*s != '=') && !isspace(*s)) *b++ = *s++;
|
||||
if (*s == '=')
|
||||
{
|
||||
s++; // skip =
|
||||
*b++ = 0;
|
||||
c->dict[d++] = begin;
|
||||
begin = b;
|
||||
// parse up to space - handle escapes
|
||||
while ((*s) && (!isspace(*s)))
|
||||
{
|
||||
if (*s == '\\')
|
||||
{
|
||||
s++;
|
||||
if (*s == 'x')
|
||||
{
|
||||
s++;
|
||||
if (s[0] && s[1])
|
||||
{
|
||||
int hex1 = 0, hex2 = 0;
|
||||
if ((s[0] >= '0') && (s[0] <= '9')) hex1 = s[0] - '0';
|
||||
if ((s[0] >= 'a') && (s[0] <= 'f')) hex1 = 10 + s[0] - 'a';
|
||||
if ((s[0] >= 'A') && (s[0] <= 'F')) hex1 = 10 + s[0] - 'A';
|
||||
if ((s[1] >= '0') && (s[1] <= '9')) hex2 = s[1] - '0';
|
||||
if ((s[1] >= 'a') && (s[1] <= 'f')) hex2 = 10 + s[1] - 'a';
|
||||
if ((s[1] >= 'A') && (s[1] <= 'F')) hex2 = 10 + s[1] - 'A';
|
||||
*b++ = (hex1 << 4) | hex2;
|
||||
s += 2;
|
||||
}
|
||||
}
|
||||
else if (*s == ' ') *b++ = ' ';
|
||||
else if (*s == 'a') *b++ = '\a';
|
||||
else if (*s == 'b') *b++ = '\b';
|
||||
else if (*s == 't') *b++ = '\t';
|
||||
else if (*s == 'n') *b++ = '\n';
|
||||
else if (*s == 'v') *b++ = '\v';
|
||||
else if (*s == 'f') *b++ = '\f';
|
||||
else if (*s == 'r') *b++ = '\r';
|
||||
else if (*s == '`') *b++ = '`';
|
||||
else if (((*s >= '>') && (*s <= '*')) ||
|
||||
((*s >= ';') && (*s <= '?')) ||
|
||||
((*s >= '[') && (*s <= ']')) ||
|
||||
((*s >= '{') && (*s <= '~')))
|
||||
*b++ = *s++;
|
||||
}
|
||||
else *b++ = *s++;
|
||||
}
|
||||
*b++ = 0;
|
||||
c->dict[d++] = begin;
|
||||
dmax += 2;
|
||||
cnew = realloc(c, sizeof(Cmd) + (sizeof(char *) * (dmax + 2)));
|
||||
if (!cnew)
|
||||
{
|
||||
free(c->buf);
|
||||
free(c);
|
||||
return NULL;
|
||||
}
|
||||
c = cnew;
|
||||
c->dict[d] = NULL;
|
||||
c->dict[d + 1] = NULL;
|
||||
}
|
||||
// skip spaces
|
||||
for (; (*s) && isspace(*s); s++);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
cmd_free(Cmd *c)
|
||||
{
|
||||
if (!c) return;
|
||||
free(c->buf);
|
||||
free(c);
|
||||
}
|
||||
|
||||
Cmd *
|
||||
cmd_dup(const Cmd *c)
|
||||
{
|
||||
Cmd *c2;
|
||||
int i, dict_num = 0;
|
||||
|
||||
for (i = 0; c->dict[i]; i++); // count dict keys
|
||||
dict_num = i + 2;
|
||||
c2 = calloc(1, sizeof(Cmd) + (sizeof(char *) * (dict_num + 2)));
|
||||
if (!c2) return NULL;
|
||||
c2->buf_size = c->buf_size;
|
||||
if (c2->buf_size != 0)
|
||||
{
|
||||
c2->buf = malloc(c->buf_size);
|
||||
if (!c2->buf) goto err;
|
||||
memcpy(c2->buf, c->buf, c->buf_size);
|
||||
}
|
||||
c2->command = c2->buf;
|
||||
for (i = 0; c->dict[i]; i++)
|
||||
c2->dict[i] = c2->buf + (c->dict[i] - c->buf);
|
||||
return c2;
|
||||
err:
|
||||
cmd_free(c2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
cmd_dump_sterr(Cmd *c)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
fprintf(stderr, "CMD: [%s]\n", c->command);
|
||||
while (c->dict[i])
|
||||
{
|
||||
fprintf(stderr, " %s=%s\n", c->dict[i], c->dict[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
Eina_Strbuf *
|
||||
cmd_strbuf_new(const char *command)
|
||||
{
|
||||
Eina_Strbuf *strbuf;
|
||||
|
||||
strbuf = eina_strbuf_new();
|
||||
eina_strbuf_append(strbuf, "CMD ");
|
||||
eina_strbuf_append(strbuf, command);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
void
|
||||
cmd_strbuf_append(Eina_Strbuf *strbuf, const char *key, const char *val)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
eina_strbuf_append_char(strbuf, ' ');
|
||||
eina_strbuf_append(strbuf, key);
|
||||
eina_strbuf_append_char(strbuf, '=');
|
||||
for (s = val; *s; s++)
|
||||
{
|
||||
if ((*s <= '*') ||
|
||||
((*s >= ';') && (*s <= '?')) ||
|
||||
((*s >= '[') && (*s <= ']')) ||
|
||||
(*s == '`') ||
|
||||
(*s >= '{'))
|
||||
{
|
||||
unsigned char tmp;
|
||||
|
||||
tmp = s[0];
|
||||
eina_strbuf_append_printf(strbuf, "\\x%02x", tmp);
|
||||
}
|
||||
else
|
||||
eina_strbuf_append_char(strbuf, *s);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cmd_strbuf_print_consume(Eina_Strbuf *strbuf)
|
||||
{
|
||||
eina_strbuf_append_char(strbuf, '\n');
|
||||
write(1,
|
||||
eina_strbuf_string_get(strbuf),
|
||||
eina_strbuf_length_get(strbuf));
|
||||
eina_strbuf_free(strbuf);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_strbuf_exe_consume(Eina_Strbuf *strbuf, Ecore_Exe *exe)
|
||||
{
|
||||
eina_strbuf_append_char(strbuf, '\n');
|
||||
ecore_exe_send(exe,
|
||||
eina_strbuf_string_get(strbuf),
|
||||
eina_strbuf_length_get(strbuf));
|
||||
eina_strbuf_free(strbuf);
|
||||
}
|
||||
|
||||
const char *
|
||||
cmd_key_find(const Cmd *c, const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; c->dict[i]; i += 2)
|
||||
{
|
||||
if (!strcmp(key, c->dict[i])) return c->dict[i + 1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef CMD_H
|
||||
# define CMD_H 1
|
||||
|
||||
# include <Eina.h>
|
||||
# include <Ecore.h>
|
||||
# include "efm.h"
|
||||
|
||||
// commands:
|
||||
// file-add // a dile in a dir being monitored has been added
|
||||
// file-del // a file in a dir being monitored has been deleted
|
||||
// file-mod // a file in a dir being monitored has been modified
|
||||
// dir-del // the dir being monitored/listed has been deleted
|
||||
//
|
||||
// future:
|
||||
// dir-usage // how much data, number of files, dirs etc.
|
||||
|
||||
typedef struct _Cmd
|
||||
{
|
||||
size_t buf_size;
|
||||
char *buf;
|
||||
const char *command;
|
||||
Efm_Sort_Mode sort_mode;
|
||||
const char *dict[];
|
||||
} Cmd;
|
||||
|
||||
Cmd *cmd_parse(const char *cmd);
|
||||
void cmd_free(Cmd *c);
|
||||
Cmd *cmd_dup(const Cmd *c);
|
||||
void cmd_dump_sterr(Cmd *c);
|
||||
|
||||
Eina_Strbuf *cmd_strbuf_new(const char *command);
|
||||
void cmd_strbuf_append(Eina_Strbuf *strbuf, const char *key, const char *val);
|
||||
void cmd_strbuf_print_consume(Eina_Strbuf *strbuf);
|
||||
void cmd_strbuf_exe_consume(Eina_Strbuf *strbuf, Ecore_Exe *exe);
|
||||
const char *cmd_key_find(const Cmd *c, const char *key);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
#include "sha.h"
|
||||
#include <Eina.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
sha1_stat(const struct stat *st, unsigned char dst[20])
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
#ifdef STAT_NSEC
|
||||
# if (defined __USE_MISC && defined st_mtime)
|
||||
# define STAT_NSEC_MTIME(st) (unsigned long long)((st)->st_mtim.tv_nsec)
|
||||
# define STAT_NSEC_CTIME(st) (unsigned long long)((st)->st_ctim.tv_nsec)
|
||||
# else
|
||||
# define STAT_NSEC_MTIME(st) (unsigned long long)((st)->st_mtimensec)
|
||||
# define STAT_NSEC_CTIME(st) (unsigned long long)((st)->st_ctimensec)
|
||||
# endif
|
||||
#else
|
||||
# define STAT_NSEC_MTIME(st) (unsigned long long)(0)
|
||||
# define STAT_NSEC_CTIME(st) (unsigned long long)(0)
|
||||
#endif
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"%llu %llu %llu %llu %llu %llu %llu %llu",
|
||||
(unsigned long long)(st->st_mode),
|
||||
(unsigned long long)(st->st_uid),
|
||||
(unsigned long long)(st->st_gid),
|
||||
(unsigned long long)(st->st_size),
|
||||
(unsigned long long)(st->st_mtime),
|
||||
(unsigned long long)(st->st_ctime),
|
||||
STAT_NSEC_MTIME(st),
|
||||
STAT_NSEC_CTIME(st));
|
||||
eina_sha1((unsigned char *)buf, strlen(buf), dst);
|
||||
}
|
||||
|
||||
void
|
||||
sha1_str(unsigned char sha[20], char shastr[41])
|
||||
{
|
||||
const char *chmap = "0123456789abcdef";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
shastr[(i * 2) ] = chmap[(sha[i] >> 4) & 0xf];
|
||||
shastr[(i * 2) + 1] = chmap[ sha[i] & 0xf];
|
||||
}
|
||||
shastr[i * 2] = 0;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef SHA_H
|
||||
# define SHA_H 1
|
||||
|
||||
// get nsec in stat
|
||||
#define STAT_NSEC 1
|
||||
#include <sys/stat.h>
|
||||
|
||||
void sha1_stat(const struct stat *st, unsigned char dst[20]);
|
||||
void sha1_str(unsigned char sha[20], char shastr[41]);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,73 @@
|
|||
// XXX: should make this config
|
||||
|
||||
static inline Eina_Bool
|
||||
check_thumb_image(const char *path EINA_UNUSED, const char *mime)
|
||||
{
|
||||
if (eina_fnmatch("image/*", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/x-docbook+xml", mime, EINA_FNMATCH_CASEFOLD))
|
||||
return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
check_thumb_font(const char *path EINA_UNUSED, const char *mime)
|
||||
{
|
||||
if (eina_fnmatch("font/*", mime, EINA_FNMATCH_CASEFOLD))
|
||||
return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
check_thumb_paged(const char *path EINA_UNUSED, const char *mime)
|
||||
{
|
||||
if (eina_fnmatch("application/*pdf", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/acrobat", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/postscript", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/vnd.ms-powerpoint", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/msword", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/vnd.ms-word", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/vnd.openxmlformats-officedocument.wordprocessingml.document", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("application/vnd.oasis.opendocument.text*", mime, EINA_FNMATCH_CASEFOLD))
|
||||
return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
check_thumb_music(const char *path EINA_UNUSED, const char *mime)
|
||||
{
|
||||
if (eina_fnmatch("audio/mpeg", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("audio/ogg", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("audio/aac", mime, EINA_FNMATCH_CASEFOLD) ||
|
||||
eina_fnmatch("audio/flac", mime, EINA_FNMATCH_CASEFOLD))
|
||||
return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
check_thumb_video(const char *path EINA_UNUSED, const char *mime)
|
||||
{
|
||||
if (eina_fnmatch("video/*", mime, EINA_FNMATCH_CASEFOLD))
|
||||
return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
check_thumb_edje(const char *path EINA_UNUSED, const char *mime)
|
||||
{
|
||||
if (eina_fnmatch("application/x-edje", mime, EINA_FNMATCH_CASEFOLD))
|
||||
return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
check_thumb_any(const char *path, const char *mime)
|
||||
{
|
||||
if (check_thumb_image(path, mime) ||
|
||||
check_thumb_font (path, mime) ||
|
||||
check_thumb_paged(path, mime) ||
|
||||
check_thumb_music(path, mime) ||
|
||||
check_thumb_video(path, mime) ||
|
||||
check_thumb_edje (path, mime))
|
||||
return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
Loading…
Reference in New Issue