mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-05 18:40:37 +00:00
Add the thumbnailer COM server for Windows
Note: Moved the desktop integration for Linux to src/desktop/linux
This commit is contained in:
parent
80744eb80e
commit
1898ce2886
@ -448,10 +448,6 @@ if(APPLE)
|
||||
endif(COMPILER_GCC)
|
||||
endif(APPLE)
|
||||
|
||||
if(WITH_DESKTOP_INTEGRATION)
|
||||
add_subdirectory(desktop)
|
||||
endif()
|
||||
|
||||
# Third parties
|
||||
add_subdirectory(third_party)
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
# Aseprite Desktop Integration Module
|
||||
# Copyright (C) 2016 Gabriel Rauter
|
||||
# Copyright (C) 2016 David Capello
|
||||
#
|
||||
# Licensed under the the MIT License (https://opensource.org/licenses/MIT).
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
# Desktop shortcut
|
||||
install(FILES aseprite.desktop
|
||||
DESTINATION share/applications)
|
||||
|
||||
# GNOME Thumbnailer
|
||||
install(FILES mime/aseprite.xml
|
||||
DESTINATION share/mime/packages)
|
||||
install(PROGRAMS aseprite-thumbnailer
|
||||
DESTINATION bin)
|
||||
install(FILES gnome/aseprite.thumbnailer
|
||||
DESTINATION share/thumbnailers)
|
||||
|
||||
# Qt Thumbnailer
|
||||
if(WITH_QT_THUMBNAILER)
|
||||
add_subdirectory(kde)
|
||||
endif()
|
||||
endif()
|
@ -117,6 +117,10 @@ if(ENABLE_STEAM)
|
||||
add_subdirectory(steam)
|
||||
endif()
|
||||
|
||||
if(WITH_DESKTOP_INTEGRATION)
|
||||
add_subdirectory(desktop)
|
||||
endif()
|
||||
|
||||
add_subdirectory(app)
|
||||
|
||||
######################################################################
|
||||
|
@ -55,6 +55,7 @@ because they don't depend on any other component.
|
||||
## Level 6
|
||||
|
||||
* [main](main/) (app, base, she, ui)
|
||||
* [desktop](desktop/) (base, doc, dio, render): Integration with the desktop (Windows Explorer, Finder, GNOME, KDE, etc.)
|
||||
|
||||
# Debugging Tricks
|
||||
|
||||
|
12
src/desktop/CMakeLists.txt
Normal file
12
src/desktop/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# Desktop Integration
|
||||
# Copyright (C) 2017-2018 David Capello
|
||||
|
||||
# Windows
|
||||
if(WIN32)
|
||||
add_subdirectory(win)
|
||||
endif()
|
||||
|
||||
# Linux-like
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_subdirectory(linux)
|
||||
endif()
|
20
src/desktop/LICENSE.txt
Normal file
20
src/desktop/LICENSE.txt
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (C) 2017-2018 David Capello
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
4
src/desktop/README.md
Normal file
4
src/desktop/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Desktop Integration
|
||||
*Copyright (C) 2017-2018 David Capello*
|
||||
|
||||
> Distributed under [MIT license](LICENSE.txt)
|
15
src/desktop/linux/CMakeLists.txt
Normal file
15
src/desktop/linux/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Desktop Integration
|
||||
# Copyright (C) 2016 Gabriel Rauter
|
||||
|
||||
# Desktop shortcut
|
||||
install(FILES aseprite.desktop DESTINATION share/applications)
|
||||
|
||||
# GNOME Thumbnailer
|
||||
install(FILES mime/aseprite.xml DESTINATION share/mime/packages)
|
||||
install(PROGRAMS aseprite-thumbnailer DESTINATION bin)
|
||||
install(FILES gnome/aseprite.thumbnailer DESTINATION share/thumbnailers)
|
||||
|
||||
# Qt Thumbnailer
|
||||
if(WITH_QT_THUMBNAILER)
|
||||
add_subdirectory(kde)
|
||||
endif()
|
0
desktop/aseprite-thumbnailer → src/desktop/linux/aseprite-thumbnailer
Executable file → Normal file
0
desktop/aseprite-thumbnailer → src/desktop/linux/aseprite-thumbnailer
Executable file → Normal file
13
src/desktop/win/CMakeLists.txt
Normal file
13
src/desktop/win/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Desktop Integration
|
||||
# Copyright (C) 2017-2018 David Capello
|
||||
|
||||
add_library(aseprite-thumbnailer SHARED
|
||||
dllmain.cpp
|
||||
exports.def
|
||||
thumbnail_handler.cpp)
|
||||
|
||||
target_link_libraries(aseprite-thumbnailer
|
||||
laf-base
|
||||
dio-lib
|
||||
render-lib
|
||||
shlwapi)
|
77
src/desktop/win/class_factory.h
Normal file
77
src/desktop/win/class_factory.h
Normal file
@ -0,0 +1,77 @@
|
||||
// Desktop Integration
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DESKTOP_CLASS_FACTORY_H_INCLUDED
|
||||
#define DESKTOP_CLASS_FACTORY_H_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <objbase.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
namespace desktop {
|
||||
|
||||
class ClassFactoryDelegate {
|
||||
public:
|
||||
virtual ~ClassFactoryDelegate() { }
|
||||
virtual HRESULT lockServer(const bool lock) = 0;
|
||||
virtual HRESULT createInstance(REFIID riid, void** ppvObject) = 0;
|
||||
};
|
||||
|
||||
class ClassFactory : public IClassFactory {
|
||||
public:
|
||||
ClassFactory(ClassFactoryDelegate* delegate)
|
||||
: m_ref(1)
|
||||
, m_delegate(delegate) {
|
||||
assert(m_delegate);
|
||||
m_delegate->lockServer(true);
|
||||
}
|
||||
|
||||
~ClassFactory() {
|
||||
m_delegate->lockServer(false);
|
||||
delete m_delegate;
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) {
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(ClassFactory, IClassFactory),
|
||||
{ 0 }
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef() {
|
||||
return InterlockedIncrement(&m_ref);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release() {
|
||||
long ref = InterlockedDecrement(&m_ref);
|
||||
if (ref == 0)
|
||||
delete this;
|
||||
return ref;
|
||||
}
|
||||
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv) {
|
||||
if (punkOuter)
|
||||
return CLASS_E_NOAGGREGATION;
|
||||
else
|
||||
return m_delegate->createInstance(riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP LockServer(BOOL lock) {
|
||||
return m_delegate->lockServer(lock ? true: false);
|
||||
}
|
||||
|
||||
private:
|
||||
long m_ref;
|
||||
ClassFactoryDelegate* m_delegate;
|
||||
};
|
||||
|
||||
} // namespace desktop
|
||||
|
||||
#endif
|
131
src/desktop/win/dllmain.cpp
Normal file
131
src/desktop/win/dllmain.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
// Desktop Integration
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "base/string.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/win32_exception.h"
|
||||
#include "desktop/win/class_factory.h"
|
||||
#include "desktop/win/thumbnail_handler.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
// This CLSID is defined by Windows for IThumbnailProvider implementations.
|
||||
#define THUMBNAILHANDLER_SHELL_EXTENSION_CLSID "{E357FCCD-A995-4576-B01F-234630154E96}"
|
||||
|
||||
// This CLSID is defined by us, and can be used to create class factory for ThumbnailHandler instances.
|
||||
#define THUMBNAILHANDLER_CLSID_STRING "{A5E9417E-6E7A-4B2D-85A4-84E114D7A960}"
|
||||
#define THUMBNAILHANDLER_NAME_STRING "Aseprite Thumbnail Handler"
|
||||
|
||||
using namespace desktop;
|
||||
|
||||
namespace {
|
||||
|
||||
namespace Global {
|
||||
long refCount = 0;
|
||||
HINSTANCE hInstance = nullptr;
|
||||
CLSID clsidThumbnailHandler;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class ClassFactoryDelegateImpl : public ClassFactoryDelegate {
|
||||
public:
|
||||
HRESULT lockServer(const bool lock) override {
|
||||
if (lock)
|
||||
InterlockedIncrement(&Global::refCount);
|
||||
else
|
||||
InterlockedDecrement(&Global::refCount);
|
||||
return S_OK;
|
||||
}
|
||||
HRESULT createInstance(REFIID riid, void** ppvObject) override {
|
||||
return T::CreateInstance(riid, ppvObject);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void*)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH) {
|
||||
CLSIDFromString(
|
||||
base::from_utf8(THUMBNAILHANDLER_CLSID_STRING).c_str(),
|
||||
&Global::clsidThumbnailHandler);
|
||||
|
||||
Global::hInstance = hInstance;
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STDAPI DllCanUnloadNow()
|
||||
{
|
||||
return (Global::refCount == 0) ? S_OK: S_FALSE;
|
||||
}
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void** ppv)
|
||||
{
|
||||
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
|
||||
|
||||
if (IsEqualCLSID(clsid, Global::clsidThumbnailHandler)) {
|
||||
ClassFactoryDelegate* delegate = new (std::nothrow)ClassFactoryDelegateImpl<ThumbnailHandler>;
|
||||
if (!delegate)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
IClassFactory* classFactory = new (std::nothrow)ClassFactory(delegate);
|
||||
if (!classFactory) {
|
||||
delete delegate;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
hr = classFactory->QueryInterface(riid, ppv);
|
||||
classFactory->Release();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDAPI DllRegisterServer()
|
||||
{
|
||||
WCHAR dllPath[MAX_PATH];
|
||||
if (!GetModuleFileNameW(Global::hInstance, dllPath, sizeof(dllPath)/sizeof(dllPath[0])))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
auto hkcu = base::hkey::current_user();
|
||||
auto k = hkcu.create("Software\\Classes\\CLSID\\" THUMBNAILHANDLER_CLSID_STRING);
|
||||
k.string("", THUMBNAILHANDLER_NAME_STRING);
|
||||
k = k.create("InProcServer32");
|
||||
k.string("", base::to_utf8(dllPath));
|
||||
k.string("ThreadingModel", "Apartment");
|
||||
|
||||
k = hkcu.create("Software\\Classes\\AsepriteFile");
|
||||
k.create("ShellEx\\" THUMBNAILHANDLER_SHELL_EXTENSION_CLSID).string("", THUMBNAILHANDLER_CLSID_STRING);
|
||||
|
||||
// TypeOverlay = empty string = don't show the app icon overlay in the thumbnail
|
||||
k.string("TypeOverlay", "");
|
||||
|
||||
// Treatment = 2 = photo border
|
||||
k.dword("Treatment", 2);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDAPI DllUnregisterServer()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
auto hkcu = base::hkey::current_user();
|
||||
try {
|
||||
hkcu.delete_tree("Software\\Classes\\AsepriteFile\\ShellEx\\" THUMBNAILHANDLER_SHELL_EXTENSION_CLSID);
|
||||
}
|
||||
catch (const base::Win32Exception& ex) {
|
||||
hr = HRESULT_FROM_WIN32(ex.errorCode());
|
||||
}
|
||||
try {
|
||||
hkcu.delete_tree("Software\\Classes\\CLSID\\" THUMBNAILHANDLER_CLSID_STRING);
|
||||
}
|
||||
catch (const base::Win32Exception& ex) {
|
||||
hr = HRESULT_FROM_WIN32(ex.errorCode());
|
||||
}
|
||||
return hr;
|
||||
}
|
6
src/desktop/win/exports.def
Normal file
6
src/desktop/win/exports.def
Normal file
@ -0,0 +1,6 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
DllMain PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
235
src/desktop/win/thumbnail_handler.cpp
Normal file
235
src/desktop/win/thumbnail_handler.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
// Desktop Integration
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "base/base.h"
|
||||
#include "dio/decode_delegate.h"
|
||||
#include "dio/decode_file.h"
|
||||
#include "dio/file_interface.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/document.h"
|
||||
#include "doc/image_ref.h"
|
||||
#include "doc/image_traits.h"
|
||||
#include "doc/pixel_format.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "render/render.h"
|
||||
|
||||
#include "desktop/win/thumbnail_handler.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
|
||||
#include <objbase.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
namespace desktop {
|
||||
|
||||
namespace {
|
||||
|
||||
class DecodeDelegate : public dio::DecodeDelegate {
|
||||
public:
|
||||
DecodeDelegate() : m_sprite(nullptr) { }
|
||||
~DecodeDelegate() { delete m_sprite; }
|
||||
|
||||
bool decodeOneFrame() override { return true; }
|
||||
void onSprite(doc::Sprite* sprite) override {
|
||||
m_sprite = sprite;
|
||||
}
|
||||
|
||||
doc::Sprite* sprite() { return m_sprite; }
|
||||
|
||||
private:
|
||||
doc::Sprite* m_sprite;
|
||||
};
|
||||
|
||||
class StreamAdaptor : public dio::FileInterface {
|
||||
public:
|
||||
StreamAdaptor(IStream* stream)
|
||||
: m_stream(stream)
|
||||
, m_ok(m_stream != nullptr) {
|
||||
}
|
||||
|
||||
bool ok() const {
|
||||
return m_ok;
|
||||
}
|
||||
|
||||
size_t tell() {
|
||||
LARGE_INTEGER delta;
|
||||
delta.QuadPart = 0;
|
||||
|
||||
ULARGE_INTEGER newPos;
|
||||
HRESULT hr = m_stream->Seek(delta, STREAM_SEEK_CUR, &newPos);
|
||||
if (FAILED(hr)) {
|
||||
m_ok = false;
|
||||
return 0;
|
||||
}
|
||||
return newPos.QuadPart;
|
||||
}
|
||||
|
||||
void seek(size_t absPos) {
|
||||
LARGE_INTEGER pos;
|
||||
pos.QuadPart = absPos;
|
||||
|
||||
ULARGE_INTEGER newPos;
|
||||
HRESULT hr = m_stream->Seek(pos, STREAM_SEEK_SET, &newPos);
|
||||
if (FAILED(hr))
|
||||
m_ok = false;
|
||||
}
|
||||
|
||||
uint8_t read8() {
|
||||
if (!m_ok)
|
||||
return 0;
|
||||
|
||||
unsigned char byte = 0;
|
||||
ULONG count;
|
||||
HRESULT hr = m_stream->Read((void*)&byte, 1, &count);
|
||||
if (FAILED(hr) || count != 1) {
|
||||
m_ok = false;
|
||||
return 0;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
size_t readBytes(uint8_t* buf, size_t n) {
|
||||
if (!m_ok)
|
||||
return 0;
|
||||
|
||||
ULONG count;
|
||||
HRESULT hr = m_stream->Read((void*)buf, (ULONG)n, &count);
|
||||
if (FAILED(hr) || count != n)
|
||||
m_ok = false;
|
||||
return count;
|
||||
}
|
||||
|
||||
void write8(uint8_t value) {
|
||||
// Do nothing, we don't write in the file
|
||||
}
|
||||
|
||||
IStream* m_stream;
|
||||
bool m_ok;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// static
|
||||
HRESULT ThumbnailHandler::CreateInstance(REFIID riid, void** ppv)
|
||||
{
|
||||
*ppv = nullptr;
|
||||
|
||||
ThumbnailHandler* obj = new (std::nothrow)ThumbnailHandler;
|
||||
if (!obj)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
HRESULT hr = obj->QueryInterface(riid, ppv);
|
||||
obj->Release();
|
||||
return hr;
|
||||
}
|
||||
|
||||
ThumbnailHandler::ThumbnailHandler()
|
||||
: m_ref(1)
|
||||
{
|
||||
}
|
||||
|
||||
ThumbnailHandler::~ThumbnailHandler()
|
||||
{
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
HRESULT ThumbnailHandler::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
*ppv = nullptr;
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(ThumbnailHandler, IInitializeWithStream),
|
||||
QITABENT(ThumbnailHandler, IThumbnailProvider),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
ULONG ThumbnailHandler::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_ref);
|
||||
}
|
||||
|
||||
ULONG ThumbnailHandler::Release()
|
||||
{
|
||||
ULONG ref = InterlockedDecrement(&m_ref);
|
||||
if (!ref)
|
||||
delete this;
|
||||
return ref;
|
||||
}
|
||||
|
||||
// IInitializeWithStream
|
||||
HRESULT ThumbnailHandler::Initialize(IStream* pStream, DWORD grfMode)
|
||||
{
|
||||
if (!pStream)
|
||||
return E_INVALIDARG;
|
||||
|
||||
m_stream.reset();
|
||||
return pStream->QueryInterface(IID_IStream, (void**)&m_stream);
|
||||
}
|
||||
|
||||
// IThumbnailProvider
|
||||
HRESULT ThumbnailHandler::GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
|
||||
{
|
||||
if (!m_stream.get())
|
||||
return E_FAIL;
|
||||
|
||||
doc::ImageRef image;
|
||||
int w, h;
|
||||
|
||||
try {
|
||||
DecodeDelegate delegate;
|
||||
StreamAdaptor adaptor(m_stream.get());
|
||||
if (!dio::decode_file(&delegate, &adaptor))
|
||||
return E_FAIL;
|
||||
|
||||
doc::Sprite* spr = delegate.sprite();
|
||||
w = spr->width();
|
||||
h = spr->height();
|
||||
|
||||
image.reset(doc::Image::create(doc::IMAGE_RGB, w, h));
|
||||
|
||||
#undef TRANSPARENT // Windows defines TRANSPARENT macro
|
||||
render::Render render;
|
||||
render.setBgType(render::BgType::TRANSPARENT);
|
||||
render.renderSprite(image.get(), spr, 0);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
// TODO convert exception into a HRESULT
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
BITMAPINFO bi;
|
||||
ZeroMemory(&bi, sizeof(bi));
|
||||
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
|
||||
bi.bmiHeader.biWidth = w;
|
||||
bi.bmiHeader.biHeight = -h;
|
||||
bi.bmiHeader.biPlanes = 1;
|
||||
bi.bmiHeader.biBitCount = 32;
|
||||
bi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
unsigned char* data = nullptr;
|
||||
*phbmp = CreateDIBSection(nullptr, &bi, DIB_RGB_COLORS, (void**)&data, nullptr, 0);
|
||||
if (!*phbmp)
|
||||
return E_FAIL;
|
||||
|
||||
for (int y=0; y<h; ++y) {
|
||||
doc::RgbTraits::address_t row =
|
||||
(doc::RgbTraits::address_t)image->getPixelAddress(0, y);
|
||||
for (int x=0; x<w; ++x, ++row) {
|
||||
doc::color_t c = *row;
|
||||
*(data++) = doc::rgba_getb(c);
|
||||
*(data++) = doc::rgba_getg(c);
|
||||
*(data++) = doc::rgba_getr(c);
|
||||
*(data++) = doc::rgba_geta(c);
|
||||
}
|
||||
}
|
||||
|
||||
*pdwAlpha = WTSAT_ARGB;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
} // namespace desktop
|
43
src/desktop/win/thumbnail_handler.h
Normal file
43
src/desktop/win/thumbnail_handler.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Desktop Integration
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DESKTOP_THUMBNAIL_HANDLER_H_INCLUDED
|
||||
#define DESKTOP_THUMBNAIL_HANDLER_H_INCLUDED
|
||||
|
||||
#include "base/win/comptr.h"
|
||||
|
||||
#include <propsys.h>
|
||||
#include <thumbcache.h>
|
||||
|
||||
namespace desktop {
|
||||
|
||||
class ThumbnailHandler : public IInitializeWithStream,
|
||||
public IThumbnailProvider {
|
||||
public:
|
||||
static HRESULT CreateInstance(REFIID riid, void** ppvObject);
|
||||
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IInitializeWithStream
|
||||
IFACEMETHODIMP Initialize(IStream* pStream, DWORD grfMode);
|
||||
|
||||
// IThumbnailProvider
|
||||
IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);
|
||||
|
||||
private:
|
||||
ThumbnailHandler();
|
||||
virtual ~ThumbnailHandler();
|
||||
|
||||
long m_ref;
|
||||
base::ComPtr<IStream> m_stream;
|
||||
};
|
||||
|
||||
} // namespace desktop
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user