summaryrefslogtreecommitdiff
path: root/lib/icon_buffer.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:29:28 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:29:28 +0200
commit75c07011b7c4d06acd7b45dabdcd60ab9d80f385 (patch)
tree8853c3978dd152ef377e652239448b1352320206 /lib/icon_buffer.cpp
parent5.22 (diff)
downloadFreeFileSync-75c07011b7c4d06acd7b45dabdcd60ab9d80f385.tar.gz
FreeFileSync-75c07011b7c4d06acd7b45dabdcd60ab9d80f385.tar.bz2
FreeFileSync-75c07011b7c4d06acd7b45dabdcd60ab9d80f385.zip
5.23
Diffstat (limited to 'lib/icon_buffer.cpp')
-rw-r--r--lib/icon_buffer.cpp674
1 files changed, 0 insertions, 674 deletions
diff --git a/lib/icon_buffer.cpp b/lib/icon_buffer.cpp
deleted file mode 100644
index e78b308e..00000000
--- a/lib/icon_buffer.cpp
+++ /dev/null
@@ -1,674 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#include "icon_buffer.h"
-#include <queue>
-#include <set>
-#include <zen/thread.h> //includes <boost/thread.hpp>
-#include <zen/scope_guard.h>
-
-#ifdef ZEN_WIN
-#include <zen/dll.h>
-#include <zen/win_ver.h>
-#include <wx/image.h>
-#include "Thumbnail/thumbnail.h"
-
-#elif defined ZEN_LINUX
-#include <gtk/gtk.h>
-
-#elif defined ZEN_MAC
-#include "osx_file_icon.h"
-#endif
-
-using namespace zen;
-
-
-namespace
-{
-const size_t BUFFER_SIZE_MAX = 600; //maximum number of icons to hold in buffer
-
-#ifndef NDEBUG
-boost::thread::id mainThreadId = boost::this_thread::get_id();
-#endif
-
-#ifdef ZEN_WIN
-const bool isXpOrLater = winXpOrLater(); //VS2010 compiled DLLs are not supported on Win 2000: Popup dialog "DecodePointer not found"
-
-#define DEF_DLL_FUN(name) const auto name = isXpOrLater ? DllFun<thumb::FunType_##name>(thumb::getDllName(), thumb::funName_##name) : DllFun<thumb::FunType_##name>();
-DEF_DLL_FUN(getIconByIndex); //
-DEF_DLL_FUN(getThumbnail); //let's spare the boost::call_once hustle and allocate statically
-DEF_DLL_FUN(releaseImageData); //
-#endif
-
-class IconHolder //handle HICON/GdkPixbuf ownership supporting thread-safe usage (in contrast to wxIcon/wxBitmap)
-{
-public:
-#ifdef ZEN_WIN
- typedef const thumb::ImageData* HandleType;
-#elif defined ZEN_LINUX
- typedef GdkPixbuf* HandleType;
-#elif defined ZEN_MAC
- typedef osx::ImageData* HandleType;
-#endif
-
- explicit IconHolder(HandleType handle = nullptr) : handle_(handle) {} //take ownership!
-
- IconHolder(IconHolder&& other) : handle_(other.release()) {}
-
- IconHolder& operator=(IconHolder other) //unifying assignment
- {
- other.swap(*this);
- return *this;
- }
-
- ~IconHolder()
- {
- if (handle_ != nullptr)
-#ifdef ZEN_WIN
- releaseImageData(handle_); //should be checked already before creating IconHolder!
-#elif defined ZEN_LINUX
- ::g_object_unref(handle_); //superseedes "::gdk_pixbuf_unref"!
-#elif defined ZEN_MAC
- delete handle_;
-#endif
- }
-
- HandleType release()
- {
- ZEN_ON_SCOPE_EXIT(handle_ = nullptr);
- return handle_;
- }
-
- void swap(IconHolder& other) { std::swap(handle_, other.handle_); } //throw()
-
- //destroys raw icon! Call from GUI thread only!
- wxBitmap extractWxBitmap()
- {
- ZEN_ON_SCOPE_EXIT(assert(!*this));
- assert(boost::this_thread::get_id() == mainThreadId );
-
- if (!handle_)
- return wxNullBitmap;
-
-#ifdef ZEN_WIN
- ZEN_ON_SCOPE_EXIT(IconHolder().swap(*this)); //destroy after extraction
-
- //let wxImage reference data without taking ownership:
- wxImage fileIcon(handle_->width, handle_->height, handle_->rgb, true);
- fileIcon.SetAlpha(handle_->alpha, true);
- return wxBitmap(fileIcon);
-
-#elif defined ZEN_LINUX
- return wxBitmap(release()); //ownership passed!
-
-#elif defined ZEN_MAC
- ZEN_ON_SCOPE_EXIT(IconHolder().swap(*this)); //destroy after extraction
-
- //let wxImage reference data without taking ownership:
- if (!handle_->rgb.empty())
- {
- wxImage fileIcon(handle_->width, handle_->height, &handle_->rgb[0], true);
- if (!handle_->alpha.empty())
- fileIcon.SetAlpha(&handle_->alpha[0], true);
- return wxBitmap(fileIcon);
- }
- assert(false); //rgb and alpha should never be empty
- return wxBitmap();
-#endif
- }
-
-private:
- HandleType handle_;
-
- IconHolder(const IconHolder& other); //move semantics!
- struct ConversionToBool { int dummy; };
-public:
- //use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20)
- operator int ConversionToBool::* () const { return handle_ != nullptr ? &ConversionToBool::dummy : nullptr; }
-};
-
-
-#ifdef ZEN_WIN
-Zstring getFileExtension(const Zstring& filename)
-{
- const Zstring shortName = afterLast(filename, Zchar('\\')); //warning: using windows file name separator!
-
- return contains(shortName, Zchar('.')) ?
- afterLast(filename, Zchar('.')) :
- Zstring();
-}
-
-
-std::set<Zstring, LessFilename> priceyExtensions; //thread-safe!
-boost::once_flag initExtensionsOnce = BOOST_ONCE_INIT; //
-
-//test for extension for non-thumbnail icons that physically have to be retrieved from disc
-bool isCheapExtension(const Zstring& extension)
-{
- boost::call_once(initExtensionsOnce, []()
- {
- priceyExtensions.insert(L"exe");
- priceyExtensions.insert(L"ico");
- priceyExtensions.insert(L"ani");
- priceyExtensions.insert(L"cur");
- priceyExtensions.insert(L"msc");
- priceyExtensions.insert(L"scr");
-
- priceyExtensions.insert(L"lnk"); //
- priceyExtensions.insert(L"url"); //make sure shortcuts are pricey to get them to be detected by SHGetFileInfo
- priceyExtensions.insert(L"pif"); //
- priceyExtensions.insert(L"website"); //
-
- });
- return priceyExtensions.find(extension) == priceyExtensions.end();
-}
-
-const bool wereVistaOrLater = vistaOrLater(); //thread-safety: init at startup
-
-
-thumb::IconSizeType getThumbSizeType(IconBuffer::IconSize sz)
-{
- using namespace thumb;
- switch (sz)
- {
- case IconBuffer::SIZE_SMALL:
- return ICON_SIZE_16;
- case IconBuffer::SIZE_MEDIUM:
- if (!wereVistaOrLater) return ICON_SIZE_32; //48x48 doesn't look sharp on XP
- return ICON_SIZE_48;
- case IconBuffer::SIZE_LARGE:
- return ICON_SIZE_128;
- }
- return ICON_SIZE_16;
-}
-
-
-IconHolder getIconByAttribute(LPCWSTR pszPath, DWORD dwFileAttributes, IconBuffer::IconSize sz)
-{
- //NOTE: CoInitializeEx()/CoUninitialize() needs to be called for THIS thread!
- SHFILEINFO fileInfo = {}; //initialize hIcon
- DWORD_PTR imgList = ::SHGetFileInfo(pszPath, //Windows 7 doesn't like this parameter to be an empty string
- dwFileAttributes,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
- if (!imgList) //no need to IUnknown::Release() imgList!
- return IconHolder();
-
- if (getIconByIndex && releaseImageData)
- return IconHolder(getIconByIndex(fileInfo.iIcon, getThumbSizeType(sz)));
-
- return IconHolder();
-}
-
-
-IconHolder getAssociatedIconByExt(const Zstring& extension, IconBuffer::IconSize sz)
-{
- //no read-access to disk! determine icon by extension
- return getIconByAttribute((L"dummy." + extension).c_str(), FILE_ATTRIBUTE_NORMAL, sz);
-}
-
-#elif defined ZEN_LINUX
-IconHolder iconHolderFromGicon(GIcon* gicon, IconBuffer::IconSize sz)
-{
- if (gicon)
- if (GtkIconTheme* defaultTheme = ::gtk_icon_theme_get_default()) //not owned!
- if (GtkIconInfo* iconInfo = ::gtk_icon_theme_lookup_by_gicon(defaultTheme, gicon, IconBuffer::getSize(sz), GTK_ICON_LOOKUP_USE_BUILTIN)) //this may fail if icon is not installed on system
- {
- ZEN_ON_SCOPE_EXIT(::gtk_icon_info_free(iconInfo);)
- if (GdkPixbuf* pixBuf = ::gtk_icon_info_load_icon(iconInfo, nullptr))
- return IconHolder(pixBuf); //pass ownership
- }
- return IconHolder();
-}
-#endif
-}
-
-//################################################################################################################################################
-
-IconHolder getThumbnailIcon(const Zstring& filename, int requestedSize) //return 0 on failure
-{
-#ifdef ZEN_WIN
- if (getThumbnail && releaseImageData)
- return IconHolder(getThumbnail(filename.c_str(), requestedSize));
-
-#elif defined ZEN_LINUX
- gint width = 0;
- gint height = 0;
- if (GdkPixbufFormat* fmt = ::gdk_pixbuf_get_file_info(filename.c_str(), &width, &height))
- {
- (void)fmt;
- if (width > 0 && height > 0 && requestedSize > 0)
- {
- int trgWidth = width;
- int trgHeight = height;
-
- const int maxExtent = std::max(width, height); //don't stretch small images, but shrink large ones instead!
- if (requestedSize < maxExtent)
- {
- trgWidth = width * requestedSize / maxExtent;
- trgHeight = height * requestedSize / maxExtent;
- }
- if (GdkPixbuf* pixBuf = ::gdk_pixbuf_new_from_file_at_size(filename.c_str(), trgWidth, trgHeight, nullptr))
- return IconHolder(pixBuf); //pass ownership
- }
- }
-
-#elif defined ZEN_MAC
- try
- {
- return IconHolder(new osx::ImageData(osx::getThumbnail(filename.c_str(), requestedSize))); //throw SysError
- }
- catch (zen::SysError&) {}
-#endif
- return IconHolder();
-}
-
-
-IconHolder getGenericFileIcon(IconBuffer::IconSize sz)
-{
- //we're called by getAssociatedIcon()! -> avoid endless recursion!
-#ifdef ZEN_WIN
- return getIconByAttribute(L"dummy", FILE_ATTRIBUTE_NORMAL, sz);
-
-#elif defined ZEN_LINUX
- const char* mimeFileIcons[] =
- {
- "application-x-zerosize", //Kubuntu: /usr/share/icons/oxygen/48x48/mimetypes
- "text-x-generic", //http://live.gnome.org/GnomeArt/Tutorials/IconThemes
- "empty", //Ubuntu: /usr/share/icons/Humanity/mimes/48
- GTK_STOCK_FILE, //"gtk-file",
- "gnome-fs-regular", //
- };
-
- if (GtkIconTheme* defaultTheme = gtk_icon_theme_get_default()) //not owned!
- for (auto it = std::begin(mimeFileIcons); it != std::end(mimeFileIcons); ++it)
- if (GdkPixbuf* pixBuf = gtk_icon_theme_load_icon(defaultTheme, *it, IconBuffer::getSize(sz), GTK_ICON_LOOKUP_USE_BUILTIN, nullptr))
- return IconHolder(pixBuf); //pass ownership
- return IconHolder();
-
-#elif defined ZEN_MAC
- try
- {
- return IconHolder(new osx::ImageData(osx::getDefaultFileIcon(IconBuffer::getSize(sz)))); //throw SysError
- }
- catch (zen::SysError&) {}
- return IconHolder();
-#endif
-}
-
-
-IconHolder getGenericDirectoryIcon(IconBuffer::IconSize sz)
-{
-#ifdef ZEN_WIN
- return getIconByAttribute(L"dummy", //Windows 7 doesn't like this parameter to be an empty string!
- FILE_ATTRIBUTE_DIRECTORY, sz);
-#elif defined ZEN_LINUX
- if (GIcon* dirIcon = ::g_content_type_get_icon("inode/directory")) //should contain fallback to GTK_STOCK_DIRECTORY ("gtk-directory")
- return iconHolderFromGicon(dirIcon, sz);
- return IconHolder();
-
-#elif defined ZEN_MAC
- try
- {
- return IconHolder(new osx::ImageData(osx::getDefaultFolderIcon(IconBuffer::getSize(sz)))); //throw SysError
- }
- catch (zen::SysError&) { return IconHolder(); }
-#endif
-}
-
-
-IconHolder getAssociatedIcon(const Zstring& filename, IconBuffer::IconSize sz)
-{
- //1. try to load thumbnails
- switch (sz)
- {
- case IconBuffer::SIZE_SMALL:
- break;
- case IconBuffer::SIZE_MEDIUM:
- case IconBuffer::SIZE_LARGE:
- if (IconHolder ico = getThumbnailIcon(filename, IconBuffer::getSize(sz)))
- return ico;
- //else: fallback to non-thumbnail icon
- break;
- }
-
- warn_static("problem: für folder links ist getThumbnail erfolgreich => SFGAO_LINK nicht gecheckt!")
-
- //2. retrieve file icons
-#ifdef ZEN_WIN
- //perf: optimize fallback case for SIZE_MEDIUM and SIZE_LARGE:
- const Zstring& extension = getFileExtension(filename);
- if (isCheapExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
- return getAssociatedIconByExt(extension, sz);
- //result will not be buffered under extension name, but full filename; this is okay, since we're in SIZE_MEDIUM or SIZE_LARGE context,
- //which means the access to get thumbnail failed: thumbnail failure is not dependent from extension in general!
-
- SHFILEINFO fileInfo = {};
- if (DWORD_PTR imgList = ::SHGetFileInfo(filename.c_str(), //_In_ LPCTSTR pszPath, -> note: ::SHGetFileInfo() can't handle \\?\-prefix!
- 0, //DWORD dwFileAttributes,
- &fileInfo, //_Inout_ SHFILEINFO *psfi,
- sizeof(fileInfo), //UINT cbFileInfo,
- SHGFI_SYSICONINDEX /*| SHGFI_ATTRIBUTES*/)) //UINT uFlags
- {
- (void)imgList;
- //imgList->Release(); //empiric study: crash on XP if we release this! Seems we do not own it... -> also no GDI leak on Win7 -> okay
- //another comment on http://msdn.microsoft.com/en-us/library/bb762179(v=VS.85).aspx describes exact same behavior on Win7/XP
-
- //Quote: "The IImageList pointer type, such as that returned in the ppv parameter, can be cast as an HIMAGELIST as needed;
- // for example, for use in a list view. Conversely, an HIMAGELIST can be cast as a pointer to an IImageList."
- //http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx
-
-#ifdef __MINGW32__ //Shobjidl.h
-#define SFGAO_LINK 0x00010000L // Shortcut (link) or symlinks
-#endif
-
- warn_static("support SFGAO_GHOSTED or hidden?")
- //requires SHGFI_ATTRIBUTES
- //const bool isLink = (fileInfo.dwAttributes & SFGAO_LINK) != 0;
-
- if (getIconByIndex && releaseImageData)
- if (const thumb::ImageData* imgData = getIconByIndex(fileInfo.iIcon, getThumbSizeType(sz)))
- return IconHolder(imgData);
- }
-
-#elif defined ZEN_LINUX
- GFile* file = ::g_file_new_for_path(filename.c_str()); //documented to "never fail"
- ZEN_ON_SCOPE_EXIT(::g_object_unref(file);)
-
- if (GFileInfo* fileInfo = ::g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_ICON, G_FILE_QUERY_INFO_NONE, nullptr, nullptr))
- {
- ZEN_ON_SCOPE_EXIT(::g_object_unref(fileInfo);)
- if (GIcon* gicon = ::g_file_info_get_icon(fileInfo)) //not owned!
- return iconHolderFromGicon(gicon, sz);
- }
- //need fallback: icon lookup may fail because some icons are currently not present on system
-
-#elif defined ZEN_MAC
- try
- {
- return IconHolder(new osx::ImageData(osx::getFileIcon(filename.c_str(), IconBuffer::getSize(sz)))); //throw SysError
- }
- catch (zen::SysError&) { assert(false); }
-#endif
- return ::getGenericFileIcon(sz); //make sure this does not internally call getAssociatedIcon("someDefaultFile.txt")!!! => endless recursion!
-}
-
-//################################################################################################################################################
-
-//---------------------- Shared Data -------------------------
-class WorkLoad
-{
-public:
- Zstring extractNextFile() //context of worker thread, blocking
- {
- assert(boost::this_thread::get_id() != mainThreadId );
- boost::unique_lock<boost::mutex> dummy(lockFiles);
-
- while (filesToLoad.empty())
- conditionNewFiles.timed_wait(dummy, boost::posix_time::milliseconds(50)); //interruption point!
-
- Zstring fileName = filesToLoad.back();
- filesToLoad.pop_back();
- return fileName;
- }
-
- void setWorkload(const std::list<Zstring>& newLoad) //context of main thread
- {
- assert(boost::this_thread::get_id() == mainThreadId );
- {
- boost::lock_guard<boost::mutex> dummy(lockFiles);
- filesToLoad = newLoad;
- }
- conditionNewFiles.notify_all(); //instead of notify_one(); workaround bug: https://svn.boost.org/trac/boost/ticket/7796
- //condition handling, see: http://www.boost.org/doc/libs/1_43_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
- }
-
- void addToWorkload(const Zstring& newEntry) //context of main thread
- {
- assert(boost::this_thread::get_id() == mainThreadId );
- {
- boost::lock_guard<boost::mutex> dummy(lockFiles);
- filesToLoad.push_back(newEntry); //set as next item to retrieve
- }
- conditionNewFiles.notify_all();
- }
-
-private:
- std::list<Zstring> filesToLoad; //processes last elements of vector first!
- boost::mutex lockFiles;
- boost::condition_variable conditionNewFiles; //signal event: data for processing available
-};
-
-
-class Buffer
-{
-public:
- //called by main and worker thread:
- bool hasFileIcon(const Zstring& fileName) const
- {
- boost::lock_guard<boost::mutex> dummy(lockIconList);
- return iconList.find(fileName) != iconList.end();
- }
-
- //must be called by main thread only! => wxBitmap is NOT thread-safe like an int (non-atomic ref-count!!!)
- Opt<wxBitmap> retrieveFileIcon(const Zstring& fileName)
- {
- assert(boost::this_thread::get_id() == mainThreadId);
- boost::lock_guard<boost::mutex> dummy(lockIconList);
- auto it = iconList.find(fileName);
- if (it == iconList.end())
- return NoValue();
-
- IconData& idata = it->second;
- if (idata.iconRaw) //if not yet converted...
- {
- idata.iconFmt = make_unique<wxBitmap>(idata.iconRaw.extractWxBitmap()); //convert in main thread!
- assert(!idata.iconRaw);
- }
- return idata.iconFmt ? *idata.iconFmt : wxNullBitmap; //idata.iconRaw may be inserted as empty from worker thread!
- }
-
- //must be called by main thread only! => ~wxBitmap() is NOT thread-safe!
- //call at an appropriate time, e.g. after Workload::setWorkload()
- void limitBufferSize() //critical because GDI resources are limited (e.g. 10000 on XP per process)
- {
- assert(boost::this_thread::get_id() == mainThreadId);
- boost::lock_guard<boost::mutex> dummy(lockIconList);
- while (iconList.size() > BUFFER_SIZE_MAX)
- {
- iconList.erase(iconSequence.front()); //remove oldest element
- iconSequence.pop();
- }
- }
-
- //called by main and worker thread:
- void moveIntoBuffer(const Zstring& entryName, IconHolder&& icon)
- {
- boost::lock_guard<boost::mutex> dummy(lockIconList);
-
- //thread safety: moving IconHolder is free from side effects, but ~wxBitmap() is NOT! => do NOT delete items from iconList here!
- auto rc = iconList.insert(std::make_pair(entryName, IconData(std::move(icon))));
- if (rc.second) //if insertion took place
- iconSequence.push(entryName); //note: sharing Zstring with IconDB!!!
-
- assert(iconList.size() == iconSequence.size());
- }
-
-private:
- struct IconData
- {
- IconData(IconHolder&& tmp) : iconRaw(std::move(tmp)) {}
- IconData(IconData&& tmp) : iconRaw(std::move(tmp.iconRaw)), iconFmt(std::move(tmp.iconFmt)) {}
-
- IconHolder iconRaw; //native icon representation: may be used by any thread
-
- std::unique_ptr<wxBitmap> iconFmt; //use ONLY from main thread!
- //wxBitmap is NOT thread-safe: non-atomic ref-count just to begin with...
- //- prohibit implicit calls to wxBitmap(const wxBitmap&)
- //- prohibit calls to ~wxBitmap() and transitively ~IconData()
- //- prohibit even wxBitmap() default constructor - better be safe than sorry!
- };
-
- mutable boost::mutex lockIconList;
- std::map<Zstring, IconData, LessFilename> iconList; //shared resource; Zstring is thread-safe like an int
- std::queue<Zstring> iconSequence; //save sequence of buffer entry to delete oldest elements
-};
-
-//################################################################################################################################################
-
-class WorkerThread //lifetime is part of icon buffer
-{
-public:
- WorkerThread(const std::shared_ptr<WorkLoad>& workload,
- const std::shared_ptr<Buffer>& buffer,
- IconBuffer::IconSize st) :
- workload_(workload),
- buffer_(buffer),
- iconSizeType(st) {}
-
- void operator()(); //thread entry
-
-private:
- std::shared_ptr<WorkLoad> workload_; //main/worker thread may access different shared_ptr instances safely (even though they have the same target!)
- std::shared_ptr<Buffer> buffer_; //http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/shared_ptr.htm?sess=8153b05b34d890e02d48730db1ff7ddc#ThreadSafety
- const IconBuffer::IconSize iconSizeType;
-};
-
-
-void WorkerThread::operator()() //thread entry
-{
- //failure to initialize COM for each thread is a source of hard to reproduce bugs: https://sourceforge.net/tracker/?func=detail&aid=3160472&group_id=234430&atid=1093080
-#ifdef ZEN_WIN
- //Prerequisites, see thumbnail.h
-
- //1. Initialize COM
- ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
- ZEN_ON_SCOPE_EXIT(::CoUninitialize());
-
- //2. Initialize system image list
- typedef BOOL (WINAPI* FileIconInitFun)(BOOL fRestoreCache);
- const SysDllFun<FileIconInitFun> fileIconInit(L"Shell32.dll", reinterpret_cast<LPCSTR>(660)); //MS requires and documents this magic number
- assert(fileIconInit);
- if (fileIconInit)
- fileIconInit(false); //TRUE to restore the system image cache from disk; FALSE otherwise.
-#endif
-
- while (true)
- {
- boost::this_thread::interruption_point();
-
- const Zstring fileName = workload_->extractNextFile(); //start work: blocks until next icon to load is retrieved
-
- if (!buffer_->hasFileIcon(fileName)) //perf: workload may contain duplicate entries?
- buffer_->moveIntoBuffer(fileName, getAssociatedIcon(fileName, iconSizeType));
- }
-}
-
-//######################### redirect to impl #####################################################
-
-struct IconBuffer::Pimpl
-{
- Pimpl() :
- workload(std::make_shared<WorkLoad>()),
- buffer (std::make_shared<Buffer>()) {}
-
- std::shared_ptr<WorkLoad> workload;
- std::shared_ptr<Buffer> buffer;
-
- boost::thread worker;
-};
-
-
-IconBuffer::IconBuffer(IconSize sz) : pimpl(make_unique<Pimpl>()),
- iconSizeType(sz),
- genDirIcon (::getGenericDirectoryIcon(sz).extractWxBitmap()),
- genFileIcon(::getGenericFileIcon (sz).extractWxBitmap())
-{
- pimpl->worker = boost::thread(WorkerThread(pimpl->workload, pimpl->buffer, sz));
-}
-
-
-IconBuffer::~IconBuffer()
-{
- setWorkload(std::list<Zstring>()); //make sure interruption point is always reached!
- pimpl->worker.interrupt();
- pimpl->worker.join(); //we assume precondition "worker.joinable()"!!!
-}
-
-
-int IconBuffer::getSize(IconSize icoSize)
-{
- switch (icoSize)
- {
- case IconBuffer::SIZE_SMALL:
-#if defined ZEN_WIN || defined ZEN_MAC
- return 16;
-#elif defined ZEN_LINUX
- return 24;
-#endif
- case IconBuffer::SIZE_MEDIUM:
-#ifdef ZEN_WIN
- if (!wereVistaOrLater) return 32; //48x48 doesn't look sharp on XP
-#endif
- return 48;
-
- case IconBuffer::SIZE_LARGE:
- return 128;
- }
- assert(false);
- return 0;
-}
-
-
-bool IconBuffer::readyForRetrieval(const Zstring& filename)
-{
-#ifdef ZEN_WIN
- if (iconSizeType == IconBuffer::SIZE_SMALL)
- if (isCheapExtension(getFileExtension(filename)))
- return true;
-#endif
- return pimpl->buffer->hasFileIcon(filename);
-}
-
-
-Opt<wxBitmap> IconBuffer::retrieveFileIcon(const Zstring& filename)
-{
-#ifdef ZEN_WIN
- //perf: let's read icons which don't need file access right away! No async delay justified!
- if (iconSizeType == IconBuffer::SIZE_SMALL) //non-thumbnail view, we need file type icons only!
- {
- const Zstring& extension = getFileExtension(filename);
- if (isCheapExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
- {
- if (Opt<wxBitmap> ico = pimpl->buffer->retrieveFileIcon(extension))
- return ico;
-
- //make sure icon is in buffer, even if icon needs not be retrieved!
- pimpl->buffer->moveIntoBuffer(extension, getAssociatedIconByExt(extension, iconSizeType));
-
- Opt<wxBitmap> ico = pimpl->buffer->retrieveFileIcon(extension);
- assert(ico);
- return ico;
- }
- }
-#endif
-
- if (Opt<wxBitmap> ico = pimpl->buffer->retrieveFileIcon(filename))
- return ico;
-
- //since this icon seems important right now, we don't want to wait until next setWorkload() to start retrieving
- pimpl->workload->addToWorkload(filename);
- pimpl->buffer->limitBufferSize();
- return NoValue();
-}
-
-
-void IconBuffer::setWorkload(const std::list<Zstring>& load)
-{
- pimpl->workload->setWorkload(load); //since buffer can only increase due to new workload,
- pimpl->buffer->limitBufferSize(); //this is the place to impose the limit from main thread!
-}
bgstack15