summaryrefslogtreecommitdiff
path: root/unity-shared
diff options
authorNick Dedekind <nicholas.dedekind@gmail.com>2012-08-02 16:44:07 +0100
committerNick Dedekind <nicholas.dedekind@gmail.com>2012-08-02 16:44:07 +0100
commit9183c4472b00c749244a432b4821a1baedddc137 (patch)
treeefa2b8ad695082cf03696e4864d5a212fbb2a5c0 /unity-shared
parentd860e6560df8e70b2a614ae476c6be1c50cc8b39 (diff)
parentfde2f5ce406aeb7c1b9753393a152c0f313db457 (diff)
Thumbnail Generation for previews.
(bzr r2419.5.2)
Diffstat (limited to 'unity-shared')
-rw-r--r--unity-shared/CMakeLists.txt3
-rw-r--r--unity-shared/CoverArt.cpp301
-rw-r--r--unity-shared/CoverArt.h25
-rw-r--r--unity-shared/DashStyle.cpp8
-rw-r--r--unity-shared/DefaultThumbnailProvider.cpp78
-rw-r--r--unity-shared/DefaultThumbnailProvider.h38
-rw-r--r--unity-shared/IconRenderer.cpp6
-rw-r--r--unity-shared/KeyboardUtil.cpp17
-rw-r--r--unity-shared/KeyboardUtil.h2
-rw-r--r--unity-shared/TextureThumbnailProvider.cpp168
-rw-r--r--unity-shared/TextureThumbnailProvider.h38
-rw-r--r--unity-shared/ThumbnailGenerator.cpp506
-rw-r--r--unity-shared/ThumbnailGenerator.h65
-rw-r--r--unity-shared/UScreen.cpp7
-rw-r--r--unity-shared/UScreen.h7
15 files changed, 1230 insertions, 39 deletions
diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt
index 96cb50ffe..c1927cb65 100644
--- a/unity-shared/CMakeLists.txt
+++ b/unity-shared/CMakeLists.txt
@@ -35,6 +35,7 @@ set (UNITY_SHARED_SOURCES
CoverArt.cpp
BackgroundEffectHelper.cpp
DashStyle.cpp
+ DefaultThumbnailProvider.cpp
FontSettings.cpp
KeyboardUtil.cpp
IMTextEntry.cpp
@@ -55,6 +56,8 @@ set (UNITY_SHARED_SOURCES
SearchBarSpinner.cpp
StaticCairoText.cpp
TextureCache.cpp
+ TextureThumbnailProvider.cpp
+ ThumbnailGenerator.cpp
Timer.cpp
UBusWrapper.cpp
UScreen.cpp
diff --git a/unity-shared/CoverArt.cpp b/unity-shared/CoverArt.cpp
index c5c2caa53..010f86f02 100644
--- a/unity-shared/CoverArt.cpp
+++ b/unity-shared/CoverArt.cpp
@@ -25,6 +25,9 @@
#include "unity-shared/IntrospectableWrappers.h"
#include <NuxCore/Logger.h>
#include <Nux/VLayout.h>
+#include "ThumbnailGenerator.h"
+#include "DashStyle.h"
+#include "IconLoader.h"
namespace unity
{
@@ -43,30 +46,189 @@ NUX_IMPLEMENT_OBJECT_TYPE(CoverArt);
CoverArt::CoverArt()
: View(NUX_TRACKER_LOCATION)
, overlay_text_(nullptr)
+ , thumb_handle_(0)
+ , slot_handle_(0)
+ , stretch_image_(false)
+ , waiting_(false)
+ , rotation_(0.0)
{
SetupViews();
+
+ ThumbnailGenerator::Instance().ready.connect(sigc::mem_fun(this, &CoverArt::OnThumbnailGenerated));
+ ThumbnailGenerator::Instance().error.connect(sigc::mem_fun(this, &CoverArt::OnThumbnailError));
}
CoverArt::~CoverArt()
{
if (overlay_text_)
overlay_text_->UnReference();
+
+ if (slot_handle_ > 0)
+ {
+ IconLoader::GetDefault().DisconnectHandle(slot_handle_);
+ slot_handle_ = 0;
+ }
}
void CoverArt::SetImage(std::string const& image_hint)
{
- if (overlay_text_ && GetLayout())
+ if (slot_handle_ > 0)
+ {
+ IconLoader::GetDefault().DisconnectHandle(slot_handle_);
+ slot_handle_ = 0;
+ }
+
+ if (GetLayout())
GetLayout()->RemoveChildObject(overlay_text_);
- texture_screenshot_.Adopt(nux::CreateTexture2DFromFile(image_hint.c_str(), -1, true));
+ GIcon* icon = g_icon_new_for_string(image_hint.c_str(), NULL);
- if (!texture_screenshot_ && GetLayout())
+ if (g_strrstr(image_hint.c_str(), "://"))
{
- GetLayout()->AddView(overlay_text_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL, 100.0, nux::LayoutPosition(1));
+ // for files on disk, we stretch to maximum aspect ratio.
+ stretch_image_ = true;
+ spinner_timeout_.reset();
+ waiting_ = false;
+
+ GFileInputStream *stream;
+ GError *error = NULL;
+ GFile *file;
+
+ /* try to open the source file for reading */
+ file = g_file_new_for_uri (image_hint.c_str());
+ stream = g_file_read (file, NULL, &error);
+ g_object_unref (file);
+
+ if (error != NULL)
+ {
+ g_error_free (error);
+ QueueDraw();
+ return;
+ }
+
+ /* stream image into pixel-buffer. */
+ glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &error));
+ g_object_unref (stream);
+
+ texture_screenshot_.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true));
+ g_object_unref(pixbuf);
+
+ if (!texture_screenshot_ && GetLayout())
+ {
+ GetLayout()->AddView(overlay_text_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL, 100.0, nux::LayoutPosition(1));
+ ComputeContentSize();
+ }
+ QueueDraw();
+ }
+ else
+ {
+ GFile *file = g_file_new_for_path (image_hint.c_str());
+ if (g_file_query_exists(file, NULL))
+ {
+ // for files on disk, we stretch to maximum aspect ratio.
+ stretch_image_ = true;
+ spinner_timeout_.reset();
+ waiting_ = false;
+
+ GFileInputStream *stream;
+ GError *error = NULL;
+
+ /* try to open the source file for reading */
+ stream = g_file_read (file, NULL, &error);
+ g_object_unref (file);
+
+ if (error != NULL)
+ {
+ g_error_free (error);
+ QueueDraw();
+ return;
+ }
+
+ /* stream image into pixel-buffer. */
+ glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream), NULL, &error));
+ g_object_unref (stream);
+
+ texture_screenshot_.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true));
+
+ if (!texture_screenshot_ && GetLayout())
+ {
+ GetLayout()->AddView(overlay_text_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL, 100.0, nux::LayoutPosition(1));
+ ComputeContentSize();
+ }
+ QueueDraw();
+ }
+ else if (G_IS_ICON(icon))
+ {
+ StartWaiting();
+ slot_handle_ = IconLoader::GetDefault().LoadFromGIconString(image_hint, 128, sigc::mem_fun(this, &CoverArt::IconLoaded));
+ }
+ else
+ {
+ StartWaiting();
+ slot_handle_ = IconLoader::GetDefault().LoadFromIconName(image_hint, 128, sigc::mem_fun(this, &CoverArt::IconLoaded));
+ }
}
+
+ if (icon != NULL)
+ g_object_unref(icon);
+}
+
+void CoverArt::GenerateImage(std::string const& uri)
+{
+ StartWaiting();
+ thumb_handle_ = ThumbnailGenerator::Instance().GetThumbnail(uri, 512);
+}
+
+void CoverArt::StartWaiting()
+{
+ waiting_ = true;
+
+ rotate_matrix_.Rotate_z(0.0f);
+ rotation_ = 0.0f;
+
+ spinner_timeout_.reset(new glib::TimeoutSeconds(5, [&]
+ {
+ texture_screenshot_.Release();
+ waiting_ = false;
+
+ if (GetLayout())
+ {
+ GetLayout()->RemoveChildObject(overlay_text_);
+ GetLayout()->AddView(overlay_text_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL, 100.0, nux::LayoutPosition(1));
+ ComputeContentSize();
+ }
+
+ QueueDraw();
+ return false;
+ }));
+
QueueDraw();
}
+void CoverArt::IconLoaded(std::string const& texid, unsigned size, glib::Object<GdkPixbuf> const& pixbuf)
+{
+ if (GetLayout())
+ GetLayout()->RemoveChildObject(overlay_text_);
+
+ slot_handle_ = 0;
+ stretch_image_ = false;
+ texture_screenshot_.Release();
+ waiting_ = false;
+ spinner_timeout_.reset();
+
+ if (pixbuf)
+ {
+ texture_screenshot_.Adopt(nux::CreateTextureFromPixbuf(pixbuf));
+
+ QueueDraw();
+ }
+ else if (GetLayout())
+ {
+ GetLayout()->AddView(overlay_text_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL, 100.0, nux::LayoutPosition(1));
+ ComputeContentSize();
+ }
+}
+
void CoverArt::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw)
{
nux::Geometry const& base = GetGeometry();
@@ -79,26 +241,32 @@ void CoverArt::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw)
nux::Geometry imageDest = base;
nux::TexCoordXForm texxform;
- float base_apsect = float(base.GetWidth()) / base.GetHeight();
- float image_aspect = float(texture_screenshot_->GetWidth()) / texture_screenshot_->GetHeight();
-
- if (image_aspect > base_apsect)
- {
- imageDest.SetHeight(float(imageDest.GetWidth())/image_aspect);
- }
- if (image_aspect < base_apsect)
- {
- imageDest.SetWidth(image_aspect*imageDest.GetHeight());
- }
-
- int border_width = 1;
-
gfx_engine.QRP_Color(base.x,
base.y,
base.GetWidth(),
base.GetHeight(),
nux::Color(0.03f, 0.03f, 0.03f, 0.0f));
+ if (stretch_image_ || base.GetWidth() < texture_screenshot_->GetWidth() || base.height < texture_screenshot_->GetHeight())
+ {
+ float base_apsect = float(base.GetWidth()) / base.GetHeight();
+ float image_aspect = float(texture_screenshot_->GetWidth()) / texture_screenshot_->GetHeight();
+
+ if (image_aspect > base_apsect)
+ {
+ imageDest.SetHeight(float(imageDest.GetWidth()) / image_aspect);
+ }
+ if (image_aspect < base_apsect)
+ {
+ imageDest.SetWidth(image_aspect * imageDest.GetHeight());
+ }
+ }
+ else
+ {
+ imageDest = nux::Geometry(0, 0, texture_screenshot_->GetWidth(), texture_screenshot_->GetHeight());
+ }
+
+
texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_SCALE_COORD);
texxform.SetWrap(nux::TEXWRAP_CLAMP_TO_BORDER, nux::TEXWRAP_CLAMP_TO_BORDER);
texxform.SetFilter(nux::TEXFILTER_LINEAR, nux::TEXFILTER_LINEAR);
@@ -108,8 +276,9 @@ void CoverArt::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw)
texxform.u1 = imageDest.width;
texxform.v1 = imageDest.height;
- gfx_engine.QRP_1Tex(imageDest.x + (float(base.GetWidth() - imageDest.GetWidth()) / 2) + border_width,
- imageDest.y + (float(base.GetHeight() - imageDest.GetHeight()) / 2) + border_width,
+ int border_width = 1;
+ gfx_engine.QRP_1Tex(base.x + (float(base.GetWidth() - imageDest.GetWidth()) / 2) + border_width,
+ base.y + (float(base.GetHeight() - imageDest.GetHeight()) / 2) + border_width,
imageDest.width - (border_width * 2),
imageDest.height - (border_width * 2),
texture_screenshot_.GetPointer()->GetDeviceTexture(),
@@ -135,6 +304,48 @@ void CoverArt::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw)
base.GetHeight(),
nux::Color(0.5f, 0.5, 0.5, 0.15f));
+ if (waiting_)
+ {
+ nux::TexCoordXForm texxform;
+ texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
+ texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT);
+ texxform.min_filter = nux::TEXFILTER_LINEAR;
+ texxform.mag_filter = nux::TEXFILTER_LINEAR;
+
+ nux::Geometry spin_geo(base.x + ((base.width - spin_->GetWidth()) / 2),
+ base.y + ((base.height - spin_->GetHeight()) / 2),
+ spin_->GetWidth(),
+ spin_->GetHeight());
+ // Geometry (== Rect) uses integers which were rounded above,
+ // hence an extra 0.5 offset for odd sizes is needed
+ // because pure floating point is not being used.
+ int spin_offset_w = !(base.width % 2) ? 0 : 1;
+ int spin_offset_h = !(base.height % 2) ? 0 : 1;
+
+ gfx_engine.PushModelViewMatrix(nux::Matrix4::TRANSLATE(-spin_geo.x - (spin_geo.width + spin_offset_w) / 2.0f,
+ -spin_geo.y - (spin_geo.height + spin_offset_h) / 2.0f, 0));
+ gfx_engine.PushModelViewMatrix(rotate_matrix_);
+ gfx_engine.PushModelViewMatrix(nux::Matrix4::TRANSLATE(spin_geo.x + (spin_geo.width + spin_offset_w) / 2.0f,
+ spin_geo.y + (spin_geo.height + spin_offset_h) / 2.0f, 0));
+
+ gfx_engine.QRP_1Tex(spin_geo.x,
+ spin_geo.y,
+ spin_geo.width,
+ spin_geo.height,
+ spin_->GetDeviceTexture(),
+ texxform,
+ nux::color::White);
+
+ gfx_engine.PopModelViewMatrix();
+ gfx_engine.PopModelViewMatrix();
+ gfx_engine.PopModelViewMatrix();
+
+ if (!frame_timeout_)
+ {
+ frame_timeout_.reset(new glib::Timeout(22, sigc::mem_fun(this, &CoverArt::OnFrameTimeout)));
+ }
+ }
+
gfx_engine.GetRenderStates().SetBlend(alpha, src, dest);
}
@@ -170,6 +381,13 @@ void CoverArt::SetupViews()
overlay_text_->SetFont("Ubuntu 14");
overlay_text_->SetLines(-3);
overlay_text_->SetText("No Image Available");
+
+ dash::Style& style = dash::Style::Instance();
+ spin_ = style.GetSearchSpinIcon();
+
+ rotate_matrix_.Identity();
+ rotate_matrix_.Rotate_z(0.0);
+
}
void CoverArt::SetFont(std::string const& font)
@@ -177,6 +395,49 @@ void CoverArt::SetFont(std::string const& font)
overlay_text_->SetFont(font);
}
+void CoverArt::OnThumbnailGenerated(unsigned int thumb_handle, std::string const& uri)
+{
+ if (thumb_handle_ != thumb_handle)
+ return;
+
+ SetImage(uri);
+}
+
+void CoverArt::OnThumbnailError(unsigned int thumb_handle, std::string const& error_hint)
+{
+ if (thumb_handle_ != thumb_handle)
+ return;
+
+ LOG_WARNING(logger) << "Failed to generate thumbnail: " << error_hint;
+ spinner_timeout_.reset();
+ frame_timeout_.reset();
+ waiting_ = false;
+
+ texture_screenshot_.Release();
+ if (GetLayout())
+ {
+ GetLayout()->RemoveChildObject(overlay_text_);
+ GetLayout()->AddView(overlay_text_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL, 100.0, nux::LayoutPosition(1));
+ ComputeContentSize();
+ }
+ QueueDraw();
+}
+
+
+bool CoverArt::OnFrameTimeout()
+{
+ rotation_ += 0.1f;
+
+ if (rotation_ >= 360.0f)
+ rotation_ = 0.0f;
+
+ rotate_matrix_.Rotate_z(rotation_);
+ QueueDraw();
+
+ frame_timeout_.reset();
+ return false;
+}
+
}
}
} \ No newline at end of file
diff --git a/unity-shared/CoverArt.h b/unity-shared/CoverArt.h
index dad9969ae..792655a8f 100644
--- a/unity-shared/CoverArt.h
+++ b/unity-shared/CoverArt.h
@@ -27,6 +27,7 @@
#include <Nux/Nux.h>
#include <Nux/View.h>
#include <UnityCore/ApplicationPreview.h>
+#include <UnityCore/GLibSource.h>
#include "unity-shared/StaticCairoText.h"
#include <NuxCore/ObjectPtr.h>
@@ -46,7 +47,10 @@ public:
CoverArt();
virtual ~CoverArt();
+ // Use for setting an image which is already an image (path to iamge, gicon).
void SetImage(std::string const& image_hint);
+ // Use for generating an image for a uri which is not necessarily an image.
+ void GenerateImage(std::string const& uri);
// From debug::Introspectable
std::string GetName() const;
@@ -59,9 +63,30 @@ protected:
void SetupViews();
+ void OnThumbnailGenerated(unsigned int thumb_handle, std::string const& uri);
+ void OnThumbnailError(unsigned int thumb_handle, std::string const& error_hint);
+ bool OnFrameTimeout();
+
+ void IconLoaded(std::string const& texid, unsigned size, glib::Object<GdkPixbuf> const& pixbuf);
+
+ void StartWaiting();
+
private:
nux::ObjectPtr<nux::BaseTexture> texture_screenshot_;
nux::StaticCairoText* overlay_text_;
+
+ std::string image_hint_;
+ unsigned int thumb_handle_;
+ int slot_handle_;
+ bool stretch_image_;
+
+ // Spinner
+ bool waiting_;
+ nux::BaseTexture* spin_;
+ glib::Source::UniquePtr spinner_timeout_;
+ glib::Source::UniquePtr frame_timeout_;
+ nux::Matrix4 rotate_matrix_;
+ float rotation_;
};
}
diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp
index 2b323a531..4676b02a6 100644
--- a/unity-shared/DashStyle.cpp
+++ b/unity-shared/DashStyle.cpp
@@ -1363,10 +1363,6 @@ void Style::Impl::Text(cairo_t* cr,
PangoWeight weight;
switch (regular_text_weight_)
{
- case FontWeight::REGULAR:
- weight = PANGO_WEIGHT_NORMAL;
- break;
-
case FontWeight::LIGHT:
weight = PANGO_WEIGHT_LIGHT;
break;
@@ -1374,6 +1370,10 @@ void Style::Impl::Text(cairo_t* cr,
case FontWeight::BOLD:
weight = PANGO_WEIGHT_BOLD;
break;
+
+ case FontWeight::REGULAR:
+ default:
+ weight = PANGO_WEIGHT_NORMAL;
}
pango_font_description_set_weight(desc, weight);
diff --git a/unity-shared/DefaultThumbnailProvider.cpp b/unity-shared/DefaultThumbnailProvider.cpp
new file mode 100644
index 000000000..2c6210f66
--- /dev/null
+++ b/unity-shared/DefaultThumbnailProvider.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ **
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#include <Nux/Nux.h>
+#include "ThumbnailGenerator.h"
+#include "UnityCore/GLibWrapper.h"
+#include "DefaultThumbnailProvider.h"
+
+namespace unity
+{
+
+namespace DefaultThumbnailProvider
+{
+
+class DefaultThumbnailer : public Thumbnailer
+{
+public:
+ DefaultThumbnailer(std::string const& name)
+ : name(name)
+ {}
+
+ std::string name;
+
+ virtual std::string GetName() const { return name; }
+
+ virtual bool Run(int size, std::string const& input_file, std::string& output_file, std::string& error_hint);
+};
+
+
+bool DefaultThumbnailer::Run(int size, std::string const& input_file, std::string& output_file, std::string& error_hint)
+{
+ glib::Object<GFile> file(::g_file_new_for_uri(input_file.c_str()));
+
+ GError *err = NULL;
+ glib::Object<GFileInfo> file_info(g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_ICON, G_FILE_QUERY_INFO_NONE, NULL, &err));
+ if (err != NULL)
+ {
+ error_hint = err->message;
+ g_error_free (err);
+ return "";
+ }
+
+ glib::Object<GIcon> icon(g_file_info_get_icon(file_info));
+ output_file = g_icon_to_string(icon);
+
+ return true;
+}
+
+void Initialise()
+{
+ Thumbnailer::Ptr thumbnailer(new DefaultThumbnailer("default"));
+ std::list<std::string> mime_types;
+ mime_types.push_back("*");
+ ThumbnailGenerator::RegisterThumbnailer(mime_types, thumbnailer);
+}
+
+} // namespace DefaultThumbnailProvider
+} // namespace unity
+
+
diff --git a/unity-shared/DefaultThumbnailProvider.h b/unity-shared/DefaultThumbnailProvider.h
new file mode 100644
index 000000000..3c7707b14
--- /dev/null
+++ b/unity-shared/DefaultThumbnailProvider.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ **
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#ifndef UNITYSHARED_DEFAULTTHUMBNAILPROVIDER_H
+#define UNITYSHARED_DEFAULTTHUMBNAILPROVIDER_H
+
+#include <Nux/Nux.h>
+
+namespace unity
+{
+
+namespace DefaultThumbnailProvider
+{
+ void Initialise();
+};
+
+} // namespace unity
+
+#endif // UNITYSHARED_DEFAULTTHUMBNAILPROVIDER_H
+
diff --git a/unity-shared/IconRenderer.cpp b/unity-shared/IconRenderer.cpp
index 7e87f9425..f8bbbba66 100644
--- a/unity-shared/IconRenderer.cpp
+++ b/unity-shared/IconRenderer.cpp
@@ -760,9 +760,9 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext,
int TextureObjectLocation;
int VertexLocation;
int TextureCoord0Location;
- int FragmentColor;
- int ColorifyColor;
- int DesatFactor;
+ int FragmentColor = 0;
+ int ColorifyColor = 0;
+ int DesatFactor = 0;
if (nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath())
{
diff --git a/unity-shared/KeyboardUtil.cpp b/unity-shared/KeyboardUtil.cpp
index b65fbc15a..90806d5e0 100644
--- a/unity-shared/KeyboardUtil.cpp
+++ b/unity-shared/KeyboardUtil.cpp
@@ -25,17 +25,18 @@
namespace unity {
namespace ui {
+namespace {
+ const unsigned int FETCH_MASK = XkbGBN_KeyNamesMask | XkbGBN_ClientSymbolsMask | XkbGBN_GeometryMask;
+}
KeyboardUtil::KeyboardUtil(Display *display)
: display_(display)
-{
- unsigned int fetch_mask = XkbGBN_KeyNamesMask | XkbGBN_ClientSymbolsMask | XkbGBN_GeometryMask;
- keyboard_ = XkbGetKeyboard (display, fetch_mask, XkbUseCoreKbd);
-}
+ , keyboard_(XkbGetKeyboard(display_, FETCH_MASK, XkbUseCoreKbd))
+{}
KeyboardUtil::~KeyboardUtil()
{
- XkbFreeKeyboard (keyboard_, 0, True);
+ XkbFreeKeyboard(keyboard_, 0, True);
}
bool KeyboardUtil::FindKeyInGeometry(XkbGeometryPtr geo, char *key_name, int& res_section, XkbBoundsRec& res_bounds) const
@@ -86,6 +87,9 @@ bool KeyboardUtil::CompareOffsets(int current_x, int current_y, int best_x, int
guint KeyboardUtil::ConvertKeyToKeycode(XkbKeyPtr key) const
{
+ if (!keyboard_)
+ return 0;
+
int min_code = keyboard_->min_key_code;
int max_code = keyboard_->max_key_code;
@@ -94,6 +98,7 @@ guint KeyboardUtil::ConvertKeyToKeycode(XkbKeyPtr key) const
if (!strncmp(key->name.name, keyboard_->names->keys[i].name, XkbKeyNameLength))
return i;
}
+
return 0;
}
@@ -186,7 +191,7 @@ guint KeyboardUtil::GetKeycodeAboveKeySymbol(KeySym key_symbol) const
int code = XKeysymToKeycode(display_, key_symbol);
- if (!code)
+ if (!code || !keyboard_)
return result;
if (keyboard_->min_key_code > code || keyboard_->max_key_code < code)
diff --git a/unity-shared/KeyboardUtil.h b/unity-shared/KeyboardUtil.h
index 0df116299..b5ee98146 100644
--- a/unity-shared/KeyboardUtil.h
+++ b/unity-shared/KeyboardUtil.h
@@ -51,8 +51,8 @@ private:
XkbBoundsRec GetAbsoluteKeyBounds (XkbKeyPtr key, XkbRowPtr row, XkbSectionPtr section, XkbGeometryPtr geo) const;
- XkbDescPtr keyboard_;
Display *display_;
+ XkbDescPtr keyboard_;
};
}
diff --git a/unity-shared/TextureThumbnailProvider.cpp b/unity-shared/TextureThumbnailProvider.cpp
new file mode 100644
index 000000000..a32b8cd92
--- /dev/null
+++ b/unity-shared/TextureThumbnailProvider.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2011 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ **
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#include <Nux/Nux.h>
+#include "ThumbnailGenerator.h"
+#include "UnityCore/GLibWrapper.h"
+#include "TextureThumbnailProvider.h"
+
+namespace unity
+{
+
+namespace TextureThumbnailProvider
+{
+
+class GdkTextureThumbnailer : public Thumbnailer
+{
+public:
+ GdkTextureThumbnailer(std::string const& name)
+ : name(name)
+ {}
+
+ std::string name;
+
+ virtual std::string GetName() const { return name; }
+
+ virtual bool Run(int size, std::string const& input_file, std::string& output_file, std::string& error_hint);
+};
+
+
+bool GdkTextureThumbnailer::Run(int size, std::string const& input_file, std::string& output_file, std::string& error_hint)
+{
+ GFileInputStream *stream;
+ GError *error = NULL;
+ GFile *file;
+
+ /* try to open the source file for reading */
+ file = g_file_new_for_uri (input_file.c_str());
+ stream = g_file_read (file, NULL, &error);
+ g_object_unref (file);
+
+ if (error != NULL)
+ {
+ error_hint = error->message;
+ g_error_free (error);
+ return false;
+ }
+
+ glib::Object<GdkPixbuf> source_pixbuf(gdk_pixbuf_new_from_stream (G_INPUT_STREAM (stream),
+ NULL, &error));
+ g_object_unref (stream);
+
+ if (error != NULL)
+ {
+ error_hint = error->message;
+ g_error_free (error);
+ return false;
+ }
+
+ /**************************
+ * Generate Scaled buffer *
+ **************************/
+
+ gdouble hratio;
+ gdouble wratio;
+ gint dest_width = size;
+ gint dest_height = size;
+ gint source_width;
+ gint source_height;
+
+ /* determine the source pixbuf dimensions */
+ source_width = gdk_pixbuf_get_width (source_pixbuf);
+ source_height = gdk_pixbuf_get_height (source_pixbuf);
+
+ /* return the same pixbuf if no scaling is required */
+ if (source_width <= dest_width && source_height <= dest_height)
+ {
+ gdk_pixbuf_save(source_pixbuf, output_file.c_str(), "png", &error, NULL);
+ if (error != NULL)
+ {
+ error_hint = error->message;
+ g_error_free (error);
+ return false;
+ }
+ }
+
+ /* determine which axis needs to be scaled down more */
+ wratio = (gdouble) source_width / (gdouble) dest_width;
+ hratio = (gdouble) source_height / (gdouble) dest_height;
+
+ /* adjust the other axis */
+ if (hratio > wratio)
+ dest_width = rint (source_width / hratio);
+ else
+ dest_height = rint (source_height / wratio);
+
+
+ /* scale the pixbuf down to the desired size */
+ glib::Object<GdkPixbuf> thumbnail_buffer(gdk_pixbuf_scale_simple (source_pixbuf,
+ MAX (dest_width, 1), MAX (dest_height, 1),
+ GDK_INTERP_BILINEAR));
+
+ gdk_pixbuf_save(thumbnail_buffer, output_file.c_str(), "png", &error, NULL);
+ if (error != NULL)
+ {
+ error_hint = error->message;
+ g_error_free (error);
+ return false;
+ }
+ return true;
+}
+
+void Initialise()
+{
+ GSList *formats;
+ GSList *fp;
+ GStrv format_types;
+ guint n;
+ std::list<std::string> mime_types;
+
+ /* get a list of all formats supported by GdkPixbuf */
+ formats = gdk_pixbuf_get_formats ();
+
+ /* iterate over all formats */
+ for (fp = formats; fp != NULL; fp = fp->next)
+ {
+ /* ignore the disabled ones */
+ if (!gdk_pixbuf_format_is_disabled ((GdkPixbufFormat*)fp->data))
+ {
+ /* get a list of MIME types supported by this format */
+ format_types = gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat*)fp->data);
+
+ /* put them all in the unqiue MIME type hash table */
+ for (n = 0; format_types != NULL && format_types[n] != NULL; ++n)
+ {
+ mime_types.push_back(format_types[n]);
+ }
+
+ /* free the string array */
+ g_strfreev (format_types);
+ }
+ }
+
+
+ Thumbnailer::Ptr thumbnailer(new GdkTextureThumbnailer("gdk_pixelbuffer"));
+ ThumbnailGenerator::RegisterThumbnailer(mime_types, thumbnailer);
+}
+
+} // namespace TextureThumbnailProvider
+} // namespace unity
+
diff --git a/unity-shared/TextureThumbnailProvider.h b/unity-shared/TextureThumbnailProvider.h
new file mode 100644
index 000000000..3d16fddc0
--- /dev/null
+++ b/unity-shared/TextureThumbnailProvider.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ **
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#ifndef UNITYSHARED_TEXTURETHUMBNAILPROVIDER_H
+#define UNITYSHARED_TEXTURETHUMBNAILPROVIDER_H
+
+#include <Nux/Nux.h>
+
+namespace unity
+{
+
+namespace TextureThumbnailProvider
+{
+ void Initialise();
+};
+
+} // namespace unity
+
+#endif // UNITYSHARED_TEXTURETHUMBNAILPROVIDER_H
+
diff --git a/unity-shared/ThumbnailGenerator.cpp b/unity-shared/ThumbnailGenerator.cpp
new file mode 100644
index 000000000..04a502c6e
--- /dev/null
+++ b/unity-shared/ThumbnailGenerator.cpp
@@ -0,0 +1,506 @@
+/*
+ * Copyright 2011 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ **
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#include <pthread.h>
+#include <NuxCore/Logger.h>
+#include "UnityCore/GLibSource.h"
+#include "UnityCore/GLibWrapper.h"
+#include "ThumbnailGenerator.h"
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "TextureThumbnailProvider.h"
+#include "DefaultThumbnailProvider.h"
+
+namespace unity
+{
+
+namespace
+{
+ nux::logging::Logger logger("unity.thumbnailgenerator");
+ ThumbnailGenerator* thumbnail_instance = nullptr;
+ static unsigned int last_handle = 1;
+
+ class ThumbnailerProcess : public Thumbnailer
+ {
+ public:
+ ThumbnailerProcess(std::string const& name, std::string const& command_line)
+ : name(name)
+ , command_line(command_line)
+ {}
+
+ std::string name;
+ std::string command_line;
+
+ virtual std::string GetName() const { return name; }
+
+ virtual bool Run(int size, std::string const& input_file, std::string& output_file, std::string& error_hint);
+ };
+ static std::map<std::string, std::string> thumbnail_content_map;
+ static std::map<std::string, Thumbnailer::Ptr> thumbnailers_;
+ static bool all_thumbnailers_initialized = false;
+
+ pthread_mutex_t thumbnailers_mutex_ = PTHREAD_MUTEX_INITIALIZER;
+}
+
+class Thumbnail
+{
+public:
+ typedef std::shared_ptr<Thumbnail> Ptr;
+
+ Thumbnail(std::string const& uri, unsigned int size);
+
+ virtual ~Thumbnail();
+
+ std::string Generate(std::string& error_hint);
+
+ unsigned int GetHandle() const;
+
+protected:
+ std::string const uri_;
+ unsigned int size_;
+ const unsigned int handle_;
+};
+
+class ThumbnailGeneratorImpl
+{
+public:
+ ThumbnailGeneratorImpl(ThumbnailGenerator* parent)
+ : parent_(parent)
+ , thumbnails_mutex_(PTHREAD_MUTEX_INITIALIZER)
+ , thumbnail_thread_is_running_(false)
+ {}
+
+ ~ThumbnailGeneratorImpl()
+ {
+ pthread_join(thumbnail_thread_, NULL);
+ }
+
+ void Run_();
+
+ unsigned int GetThumbnail(std::string const& uri, int size);
+
+ bool OnThumbnailComplete();
+
+ static void LoadThumbnailers();
+ static Thumbnailer::Ptr GetThumbnailer(std::string const& content_type, std::string& error_hint);
+
+protected:
+ ThumbnailGenerator* parent_;
+
+ glib::Source::UniquePtr idle_;
+ glib::Source::UniquePtr idle_return_;
+
+ /* Our mutex used when accessing data shared between the main thread and the
+ thumbnail thread, i.e. the thumbnail_thread_is_running flag and the
+ thumbnails_to_make list. */
+ pthread_mutex_t thumbnails_mutex_;
+
+ /* A flag to indicate whether a thumbnail thread is running, so we don't
+ start more than one. Lock thumbnails_mutex when accessing this. */
+ volatile bool thumbnail_thread_is_running_;
+ pthread_t thumbnail_thread_;
+
+ std::queue<Thumbnail::Ptr> thumbnails_;
+
+ struct CompleteThumbnail
+ {
+ unsigned int handle;
+ std::string thubnail_uri;
+ std::string error_hint;
+ };
+ std::list<CompleteThumbnail> complete_thumbnails_;
+};
+
+static void*
+thumbnail_thread_start (void* data)
+{
+ ((ThumbnailGeneratorImpl*)data)->Run_();
+ return NULL;
+}
+
+unsigned int ThumbnailGeneratorImpl::GetThumbnail(std::string const& uri, int size)
+{
+ pthread_mutex_lock (&thumbnails_mutex_);
+ /*********************************
+ * MUTEX LOCKED
+ *********************************/
+
+ if (!idle_ && thumbnail_thread_is_running_ == false)
+ {
+ idle_.reset(new glib::Idle([&]()
+ {
+
+ thumbnail_thread_is_running_ = true;
+ pthread_create (&thumbnail_thread_, NULL, thumbnail_thread_start, this);
+ idle_.reset();
+ return false;
+ }, glib::Source::Priority::LOW));
+ }
+
+ Thumbnail::Ptr thumb(new Thumbnail(uri, size));
+ thumbnails_.push(thumb);
+ unsigned int handle = thumb->GetHandle();
+
+ pthread_mutex_unlock (&thumbnails_mutex_);
+ /*********************************
+ * MUTEX UNLOCKED
+ *********************************/
+ return handle;
+}
+
+
+void ThumbnailGeneratorImpl::Run_()
+{
+ for (;;)
+ {
+ /*********************************
+ * MUTEX LOCKED
+ *********************************/
+ pthread_mutex_lock (&thumbnails_mutex_);
+
+ if (thumbnails_.size() == 0)
+ {
+ thumbnail_thread_is_running_ = FALSE;
+ pthread_mutex_unlock (&thumbnails_mutex_);
+ pthread_exit (NULL);
+ }
+
+ pthread_mutex_unlock (&thumbnails_mutex_);
+ /*********************************
+ * MUTEX UNLOCKED
+ *********************************/
+
+ Thumbnail::Ptr thumb(thumbnails_.front());
+ std::string error_hint;
+ std::string uri_result = thumb->Generate(error_hint);
+ thumbnails_.pop();
+
+
+ /*********************************
+ * MUTEX LOCKED
+ *********************************/
+ pthread_mutex_lock (&thumbnails_mutex_);
+
+ CompleteThumbnail complete_thumb;
+ complete_thumb.handle = thumb->GetHandle();
+ complete_thumb.thubnail_uri = uri_result;
+ complete_thumb.error_hint = error_hint;
+
+ complete_thumbnails_.push_back(complete_thumb);
+
+ if (!idle_return_)
+ {
+ idle_return_.reset(new glib::Idle(sigc::mem_fun(this, &ThumbnailGeneratorImpl::OnThumbnailComplete), glib::Source::Priority::LOW));
+ }
+
+ pthread_mutex_unlock (&thumbnails_mutex_);
+ /*********************************
+ * MUTEX UNLOCKED
+ *********************************/
+ }
+}
+
+bool ThumbnailGeneratorImpl::OnThumbnailComplete()
+{
+ for (;;)
+ {
+ pthread_mutex_lock (&thumbnails_mutex_);
+
+ if (complete_thumbnails_.size() == 0)
+ {
+ idle_return_.reset();
+ pthread_mutex_unlock (&thumbnails_mutex_);
+ return false;
+ }
+ CompleteThumbnail complete_thumbnail = complete_thumbnails_.front();
+ complete_thumbnails_.pop_front();
+
+ pthread_mutex_unlock (&thumbnails_mutex_);
+
+ if (complete_thumbnail.error_hint == "")
+ parent_->ready.emit(complete_thumbnail.handle, complete_thumbnail.thubnail_uri);
+ else
+ parent_->error.emit(complete_thumbnail.handle, complete_thumbnail.error_hint);
+ }
+ return false;
+}
+
+void ThumbnailGeneratorImpl::LoadThumbnailers()
+{
+ if (all_thumbnailers_initialized)
+ return;
+
+ GError* err = NULL;
+ GDir* thumbnailer_dir = g_dir_open("/usr/share/thumbnailers", 0, &err);
+ if (err != NULL)
+ return;
+
+ const gchar* file;
+ while((file = g_dir_read_name(thumbnailer_dir)) != NULL)
+ {
+ std::string file_name(file);
+ if (file_name == "." || file_name == "..")
+ continue;
+
+ pthread_mutex_lock (&thumbnailers_mutex_);
+ // Already have this one?
+ if (thumbnailers_.find(file_name) != thumbnailers_.end())
+ {
+ pthread_mutex_unlock (&thumbnailers_mutex_);
+ continue;
+ }
+ pthread_mutex_unlock (&thumbnailers_mutex_);
+
+ /*********************************
+ * READ SETTINGS
+ *********************************/
+
+ GKeyFile* key_file = g_key_file_new();
+
+ err=NULL;
+ if (!g_key_file_load_from_file (key_file, (std::string("/usr/share/thumbnailers/") + file_name).c_str(), G_KEY_FILE_NONE, &err))
+ {
+ g_key_file_free(key_file);
+ g_error_free(err);
+ continue;
+ }
+
+ err=NULL;
+ glib::String command_line(g_key_file_get_string (key_file, "Thumbnailer Entry", "Exec", &err));
+ if (err != NULL)
+ {
+ g_key_file_free(key_file);
+ g_error_free(err);
+ continue;
+ }
+
+ err=NULL;
+ gsize mime_count = 0;
+ gchar** mime_types = g_key_file_get_string_list (key_file, "Thumbnailer Entry", "MimeType", &mime_count, &err);
+ if (err != NULL)
+ {
+ g_key_file_free(key_file);
+ g_error_free(err);
+ continue;
+ }
+
+ Thumbnailer::Ptr thumbnailer(new ThumbnailerProcess(file_name, command_line.Value()));
+ std::list<std::string> mime_type_list;
+ for (gsize i = 0; i < mime_count && mime_types[i] != NULL; i++)
+ {
+ mime_type_list.push_front(mime_types[i]);
+ }
+
+ ThumbnailGenerator::RegisterThumbnailer(mime_type_list, thumbnailer);
+
+ g_strfreev(mime_types);
+ g_key_file_free(key_file);
+ }
+
+ all_thumbnailers_initialized = true;
+ g_dir_close(thumbnailer_dir);
+}
+
+Thumbnailer::Ptr ThumbnailGeneratorImpl::GetThumbnailer(std::string const& content_type, std::string& error_hint)
+{
+ LoadThumbnailers();
+
+ gchar** content_split = g_strsplit(content_type.c_str(), "/", -1);
+
+ std::vector<std::string> content_list;
+ int i = 0;
+ while(content_split[i] != NULL)
+ {
+ if (g_strcmp0(content_split[i], "") != 0)
+ content_list.push_back(content_split[i]);
+ i++;
+ }
+
+ unsigned int content_last = content_list.size();
+ for (unsigned int i = 0; i < content_list.size()+1; ++i)
+ {
+ std::stringstream ss_content_type;
+ for (unsigned int j = 0; j < content_last; ++j)
+ {
+ ss_content_type << content_list[j];
+ if (j < content_last-1)
+ ss_content_type << "/";
+ }
+
+ if (content_last == 0)
+ ss_content_type << "*";
+ else if (content_last < content_list.size())
+ ss_content_type << "/*";
+
+ content_last--;
+
+ /*********************************
+ * FIND THUMBNAILER
+ *********************************/
+
+ pthread_mutex_lock (&thumbnailers_mutex_);
+
+ // have already got this content type?
+ auto iter_content = thumbnail_content_map.find(ss_content_type.str());
+ if (iter_content != thumbnail_content_map.end())
+ {
+ pthread_mutex_unlock (&thumbnailers_mutex_);
+
+ // find the thumbnailer.
+ auto iter_tumbnailers = thumbnailers_.find(iter_content->second);
+ if (iter_tumbnailers != thumbnailers_.end())
+ return iter_tumbnailers->second;
+ }
+ pthread_mutex_unlock (&thumbnailers_mutex_);
+ }
+
+ error_hint = "thumbnailer not found.";
+ return NULL;
+}
+
+ThumbnailGenerator::ThumbnailGenerator()
+: pimpl(new ThumbnailGeneratorImpl(this))
+{
+ if (thumbnail_instance)
+ {
+ LOG_ERROR(logger) << "More than one thumbnail generator created.";
+ }
+ else
+ {
+ thumbnail_instance = this;
+
+ TextureThumbnailProvider::Initialise();
+ DefaultThumbnailProvider::Initialise();
+ }
+
+}
+
+ThumbnailGenerator::~ThumbnailGenerator()
+{
+
+}
+
+ThumbnailGenerator& ThumbnailGenerator::Instance()
+{
+ if (!thumbnail_instance)
+ {
+ LOG_ERROR(logger) << "No panel::Style created yet.";
+ }
+
+ return *thumbnail_instance;
+}
+
+unsigned int ThumbnailGenerator::GetThumbnail(std::string const& uri, int size)
+{
+ return pimpl->GetThumbnail(uri, size);
+}
+
+void ThumbnailGenerator::RegisterThumbnailer(std::list<std::string> mime_types, Thumbnailer::Ptr thumbnailer)
+{
+ pthread_mutex_lock (&thumbnailers_mutex_);
+
+ thumbnailers_[thumbnailer->GetName()] = thumbnailer;
+
+ for (std::string mime_type : mime_types)
+ {
+ thumbnail_content_map[mime_type] = thumbnailer->GetName();
+ }
+
+ pthread_mutex_unlock (&thumbnailers_mutex_);
+}
+
+Thumbnail::Thumbnail(std::string const& uri, unsigned int size)
+: uri_(uri)
+, size_(size)
+, handle_(last_handle++)
+{
+}
+
+Thumbnail::~Thumbnail()
+{
+}
+
+std::string Thumbnail::Generate(std::string& error_hint)
+{
+ std::string output_file;
+
+ glib::Object<GFile> file(::g_file_new_for_uri(uri_.c_str()));
+
+ GError *err = NULL;
+ glib::Object<GFileInfo> file_info(g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &err));
+ if (err != NULL)
+ {
+ error_hint = err->message;
+ g_error_free (err);
+ return "";
+ }
+
+ std::string file_type = g_file_info_get_attribute_string(file_info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
+
+ Thumbnailer::Ptr thumbnailer = ThumbnailGeneratorImpl::GetThumbnailer(file_type, error_hint);
+ if (!thumbnailer)
+ return "";
+
+ std::hash<std::string> hash_fn;
+ std::stringstream ss_output; ss_output << "/home/nick/test_thumbnails/" << hash_fn(uri_) << ".png";
+ output_file = ss_output.str();
+
+ if (!thumbnailer->Run(size_, uri_, output_file, error_hint))
+ {
+ return "";
+ }
+
+ return output_file;
+}
+
+unsigned int Thumbnail::GetHandle() const
+{
+ return handle_;
+}
+
+bool ThumbnailerProcess::Run(int size, std::string const& input_file, std::string& output_file, std::string& error_hint)
+{
+ std::string tmp_command_line = command_line;
+
+ size_t pos = tmp_command_line.find("%s");
+ std::stringstream ss; ss << size;
+ if (pos != std::string::npos) { tmp_command_line.replace(pos, 2, ss.str()); }
+
+ pos = tmp_command_line.find("%u");
+ if (pos != std::string::npos) { tmp_command_line.replace(pos, 2, input_file); }
+
+ pos = tmp_command_line.find("%o");
+ if (pos != std::string::npos) { tmp_command_line.replace(pos, 2, output_file); }
+
+ gint exit_status = 0;
+ GError* err = NULL;
+ g_spawn_command_line_sync(tmp_command_line.c_str(), NULL, NULL, &exit_status, &err);
+ if (err != NULL)
+ {
+ error_hint = err->message;
+ g_error_free (err);
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace unity \ No newline at end of file
diff --git a/unity-shared/ThumbnailGenerator.h b/unity-shared/ThumbnailGenerator.h
new file mode 100644
index 000000000..7ea5c348e
--- /dev/null
+++ b/unity-shared/ThumbnailGenerator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ **
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#ifndef UNITYSHARED_THUMBNAILGENERATOR_H
+#define UNITYSHARED_THUMBNAILGENERATOR_H
+
+#include <Nux/Nux.h>
+
+namespace unity
+{
+
+class Thumbnailer
+{
+public:
+ typedef std::shared_ptr<Thumbnailer> Ptr;
+
+ virtual std::string GetName() const = 0;
+
+ virtual bool Run(int size, std::string const& input_file, std::string& output_file, std::string& error_hint) = 0;
+};
+
+class ThumbnailGeneratorImpl;
+class ThumbnailGenerator
+{
+public:
+ ThumbnailGenerator();
+ virtual ~ThumbnailGenerator();
+
+ static ThumbnailGenerator& Instance();
+
+ static void RegisterThumbnailer(std::list<std::string> mime_types, Thumbnailer::Ptr thumbnailer);
+
+ unsigned int GetThumbnail(std::string const& uri, int size);
+
+ sigc::signal<void, unsigned int, std::string> ready;
+ sigc::signal<void, unsigned int, std::string> error;
+
+protected:
+ std::unique_ptr<ThumbnailGeneratorImpl> pimpl;
+
+ friend class Thumbnail;
+};
+
+} // namespace unity
+
+#endif // UNITYSHARED_THUMBNAILGENERATOR_H
+
diff --git a/unity-shared/UScreen.cpp b/unity-shared/UScreen.cpp
index e33508e30..3b643382d 100644
--- a/unity-shared/UScreen.cpp
+++ b/unity-shared/UScreen.cpp
@@ -24,17 +24,18 @@ namespace unity
namespace
{
-static UScreen* default_screen_ = nullptr;
nux::logging::Logger logger("unity.screen");
}
+UScreen* UScreen::default_screen_ = nullptr;
+
UScreen::UScreen()
- : screen_(gdk_screen_get_default(), glib::AddRef())
+ : primary_(0)
+ , screen_(gdk_screen_get_default(), glib::AddRef())
, proxy_("org.freedesktop.UPower",
"/org/freedesktop/UPower",
"org.freedesktop.UPower",
G_BUS_TYPE_SYSTEM)
- , primary_(0)
{
size_changed_signal_.Connect(screen_, "size-changed", sigc::mem_fun(this, &UScreen::Changed));
monitors_changed_signal_.Connect(screen_, "monitors-changed", sigc::mem_fun(this, &UScreen::Changed));
diff --git a/unity-shared/UScreen.h b/unity-shared/UScreen.h
index 3e44dfeea..f66e07d7a 100644
--- a/unity-shared/UScreen.h
+++ b/unity-shared/UScreen.h
@@ -55,14 +55,17 @@ private:
void Changed(GdkScreen* screen);
void Refresh();
-private:
+protected:
+ static UScreen* default_screen_;
std::vector<nux::Geometry> monitors_;
+ int primary_;
+
+private:
glib::Object<GdkScreen> screen_;
glib::DBusProxy proxy_;
glib::Signal<void, GdkScreen*> size_changed_signal_;
glib::Signal<void, GdkScreen*> monitors_changed_signal_;
glib::Source::UniquePtr refresh_idle_;
- int primary_;
};
} // Namespace