[solang] Added a PixbufMaker with both async and sync capabilities
- From: Debarshi Ray <debarshir src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [solang] Added a PixbufMaker with both async and sync capabilities
- Date: Fri, 25 Dec 2009 10:36:31 +0000 (UTC)
commit 09f0d0bbee4c94e34770285f229f586a8df27445
Author: Debarshi Ray <rishi gnu org>
Date: Tue Dec 8 04:20:20 2009 +0200
Added a PixbufMaker with both async and sync capabilities
Modified the EnlargedRenderer to use the PixbufMaker for asynchronous
loading of Gdk::Pixbufs.
src/common/Makefile.am | 2 +
src/common/pixbuf-maker.cpp | 236 ++++++++++++++++++++++++++++++++++++
src/common/pixbuf-maker.h | 88 +++++++++++++
src/common/types.h | 4 +
src/renderer/enlarged-renderer.cpp | 38 ++++--
src/renderer/enlarged-renderer.h | 5 +
6 files changed, 360 insertions(+), 13 deletions(-)
---
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index aba1033..1041b33 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -38,6 +38,8 @@ libcommon_la_SOURCES = \
photo-search-criteria.h \
plugin.cpp \
plugin.h \
+ pixbuf-maker.cpp \
+ pixbuf-maker.h \
progress-dialog.cpp \
progress-dialog.h \
progress-observer.cpp \
diff --git a/src/common/pixbuf-maker.cpp b/src/common/pixbuf-maker.cpp
new file mode 100644
index 0000000..2703843
--- /dev/null
+++ b/src/common/pixbuf-maker.cpp
@@ -0,0 +1,236 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
+ *
+ * Solang is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Solang is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include <cstdio>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <glib/gstdio.h>
+
+#include "content-type-repo.h"
+#include "photo.h"
+#include "pixbuf-maker.h"
+
+namespace Solang
+{
+
+static const guint CHUNK = 4096;
+
+PixbufMaker::PixbufMaker(bool rotate) throw() :
+ rotate_(rotate),
+ fd_(-1),
+ pixbufLoader_(),
+ signalIO_()
+{
+}
+
+PixbufMaker::~PixbufMaker() throw()
+{
+ stop_async();
+}
+
+PixbufMakerPtr
+PixbufMaker::create(bool rotate) throw()
+{
+ return PixbufMakerPtr(new PixbufMaker(rotate));
+}
+
+gint
+PixbufMaker::create_fd(const std::string & path) const
+ throw(Glib::FileError)
+{
+ const gint fd = g_open(path.c_str(), O_RDONLY);
+
+ if (-1 == fd)
+ {
+ throw Glib::FileError(Glib::FileError::FAILED,
+ Glib::ustring::compose(
+ "%1: Failed to open",
+ path));
+ }
+
+ return fd;
+}
+
+PixbufLoaderPtr
+PixbufMaker::create_pixbuf_loader(const std::string & path) const
+ throw(Gdk::PixbufError)
+{
+ const ContentTypeRepoPtr content_type_repo
+ = ContentTypeRepo::instance();
+ const Glib::ustring content_type
+ = content_type_repo->get_content_type(path);
+
+ if (false == content_type_repo->is_gdk_supported(content_type))
+ {
+ throw Gdk::PixbufError(Gdk::PixbufError::UNKNOWN_TYPE, "");
+ }
+
+ return Gdk::PixbufLoader::create(content_type, true);
+}
+
+void
+PixbufMaker::make_async(const SlotAsyncReady & slot,
+ const PhotoPtr & photo)
+ throw(Gdk::PixbufError, Glib::ConvertError,
+ Glib::FileError)
+{
+ const std::string path = Glib::filename_from_utf8(
+ photo->get_disk_file_path());
+ fd_ = create_fd(path);
+ pixbufLoader_ = create_pixbuf_loader(path);
+
+ signalIO_
+ = Glib::signal_io().connect(
+ sigc::bind(sigc::mem_fun(*this,
+ &PixbufMaker::on_signal_io),
+ slot),
+ fd_,
+ Glib::IO_IN | Glib::IO_HUP,
+ Glib::PRIORITY_DEFAULT_IDLE);
+}
+
+PixbufPtr
+PixbufMaker::make_sync(const PhotoPtr & photo)
+ throw(Gdk::PixbufError, Glib::ConvertError,
+ Glib::FileError)
+{
+ const std::string path = Glib::filename_from_utf8(
+ photo->get_disk_file_path());
+ fd_ = create_fd(path);
+ pixbufLoader_ = create_pixbuf_loader(path);
+ gssize nread;
+ guint8 buffer[CHUNK];
+
+ while (0 < (nread = read(fd_, buffer, sizeof(buffer))))
+ {
+ try
+ {
+ pixbufLoader_->write(buffer, nread);
+ }
+ catch (const Glib::FileError & e)
+ {
+ g_warning("%s", e.what().c_str());
+ break;
+ }
+ catch (const Gdk::PixbufError & e)
+ {
+ g_warning("%s", e.what().c_str());
+ break;
+ }
+ }
+
+ close(fd_);
+ fd_ = -1;
+
+ try
+ {
+ pixbufLoader_->close();
+ }
+ catch (const Glib::FileError & e)
+ {
+ g_warning("%s", e.what().c_str());
+ }
+ catch (const Gdk::PixbufError & e)
+ {
+ g_warning("%s", e.what().c_str());
+ }
+
+ PixbufPtr pixbuf = pixbufLoader_->get_pixbuf();
+ if (0 == pixbuf)
+ {
+ throw Gdk::PixbufError(Gdk::PixbufError::FAILED, "");
+ }
+
+ if (true == rotate_)
+ {
+ pixbuf = Glib::wrap(gdk_pixbuf_apply_embedded_orientation(
+ pixbuf->gobj()), false);
+ }
+
+ return pixbuf;
+}
+
+bool
+PixbufMaker::on_signal_io(Glib::IOCondition condition,
+ const SlotAsyncReady & slot) throw()
+{
+ guint8 buffer[CHUNK];
+ const gssize nread = read(fd_, buffer, sizeof(buffer));
+
+ try
+ {
+ if (0 == nread)
+ {
+ throw 1;
+ }
+ pixbufLoader_->write(buffer, nread);
+ }
+ catch (...)
+ {
+ stop_async();
+ }
+
+ if (-1 == fd_)
+ {
+ PixbufPtr pixbuf = pixbufLoader_->get_pixbuf();
+ if (0 != pixbuf && true == rotate_)
+ {
+ pixbuf = Glib::wrap(gdk_pixbuf_apply_embedded_orientation(
+ pixbuf->gobj()), false);
+ }
+
+ slot(pixbuf);
+ }
+
+ return -1 != fd_;
+}
+
+void
+PixbufMaker::stop_async() throw()
+{
+ if (false == signalIO_)
+ {
+ return;
+ }
+
+ signalIO_.disconnect();
+ close(fd_);
+ fd_ = -1;
+
+ try
+ {
+ pixbufLoader_->close();
+ }
+ catch (const Glib::FileError & e)
+ {
+ g_warning("%s", e.what().c_str());
+ }
+ catch (const Gdk::PixbufError & e)
+ {
+ g_warning("%s", e.what().c_str());
+ }
+}
+
+} // namespace Solang
diff --git a/src/common/pixbuf-maker.h b/src/common/pixbuf-maker.h
new file mode 100644
index 0000000..1e0935f
--- /dev/null
+++ b/src/common/pixbuf-maker.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
+ *
+ * Solang is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Solang is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SOLANG_PIXBUF_MAKER_H
+#define SOLANG_PIXBUF_MAKER_H
+
+#include <gdkmm.h>
+#include <glibmm.h>
+#include <sigc++/sigc++.h>
+
+#include "types.h"
+
+namespace Solang
+{
+
+class PixbufMaker
+{
+ public:
+ typedef sigc::slot<void, const PixbufPtr &> SlotAsyncReady;
+
+ ~PixbufMaker() throw();
+
+ static PixbufMakerPtr
+ create(bool rotate) throw();
+
+ void
+ make_async(const SlotAsyncReady & slot,
+ const PhotoPtr & photo) throw(Gdk::PixbufError,
+ Glib::ConvertError,
+ Glib::FileError);
+
+ PixbufPtr
+ make_sync(const PhotoPtr & photo) throw(Gdk::PixbufError,
+ Glib::ConvertError,
+ Glib::FileError);
+
+ void
+ stop_async() throw();
+
+ protected:
+ PixbufMaker(bool rotate) throw();
+
+ PixbufMaker(const PixbufMaker & source) throw();
+
+ PixbufMaker &
+ operator=(const PixbufMaker & source) throw();
+
+ gint
+ create_fd(const std::string & path) const
+ throw(Glib::FileError);
+
+ PixbufLoaderPtr
+ create_pixbuf_loader(const std::string & path) const
+ throw(Gdk::PixbufError);
+
+ bool
+ on_signal_io(Glib::IOCondition condition,
+ const SlotAsyncReady & slot) throw();
+
+ bool rotate_;
+
+ gint fd_;
+
+ PixbufLoaderPtr pixbufLoader_;
+
+ sigc::connection signalIO_;
+
+ private:
+};
+
+} // namespace Solang
+
+#endif // SOLANG_PIXBUF_MAKER_H
diff --git a/src/common/types.h b/src/common/types.h
index 26d40f2..7cee9d7 100644
--- a/src/common/types.h
+++ b/src/common/types.h
@@ -153,6 +153,10 @@ typedef std::tr1::shared_ptr<PhotoSearchCriteria>
typedef std::vector<PhotoSearchCriteriaPtr> PhotoSearchCriteriaList;
typedef std::map<Glib::ustring,PhotoSearchCriteriaPtr> DragDropCriteriaMap;
+class PixbufMaker;
+typedef std::tr1::shared_ptr<const PixbufMaker> ConstPixbufMakerPtr;
+typedef std::tr1::shared_ptr<PixbufMaker> PixbufMakerPtr;
+
class ProgressDialog;
typedef Glib::RefPtr<const ProgressDialog> ConstProgressDialogPtr;
typedef Glib::RefPtr<ProgressDialog> ProgressDialogPtr;
diff --git a/src/renderer/enlarged-renderer.cpp b/src/renderer/enlarged-renderer.cpp
index 01f83e0..011e855 100644
--- a/src/renderer/enlarged-renderer.cpp
+++ b/src/renderer/enlarged-renderer.cpp
@@ -34,6 +34,7 @@
#include "main-window.h"
#include "photo.h"
#include "photo-search-criteria.h"
+#include "pixbuf-maker.h"
#include "thumbnail.h"
#include "types.h"
@@ -76,6 +77,7 @@ EnlargedRenderer::EnlargedRenderer() throw() :
imageView_(0),
imageScrollWin_(0),
pageNum_(-1),
+ pixbufMaker_(),
signalMainWindowStateEvent_(),
signalSwitchPage_()
{
@@ -125,36 +127,46 @@ EnlargedRenderer::render(const PhotoPtr & photo) throw()
"file");
photo->set_disk_file_path(storage);
- PixbufPtr pixbuf;
- std::string path;
-
- try
+ if (0 == pixbufMaker_)
{
- path = Glib::filename_from_utf8(photo->get_disk_file_path());
+ pixbufMaker_ = PixbufMaker::create(true);
}
- catch (const Glib::ConvertError & e)
+ else
{
- g_warning("%s", e.what().c_str());
- return;
+ pixbufMaker_->stop_async();
}
try
{
- pixbuf = Gdk::Pixbuf::create_from_file(path);
+ pixbufMaker_->make_async(
+ sigc::mem_fun(
+ *this,
+ &EnlargedRenderer::on_pixbuf_maker_async_ready),
+ photo);
+
+ MainWindow & main_window = application_->get_main_window();
+ main_window.set_busy(true);
+ }
+ catch (const Glib::ConvertError & e)
+ {
+ g_warning("%s", e.what().c_str());
}
catch (const Glib::FileError & e)
{
g_warning("%s", e.what().c_str());
- return;
}
catch (const Gdk::PixbufError & e)
{
g_warning("%s", e.what().c_str());
- return;
}
+}
- pixbuf = Glib::wrap(gdk_pixbuf_apply_embedded_orientation(
- pixbuf->gobj()), false);
+void
+EnlargedRenderer::on_pixbuf_maker_async_ready(
+ const PixbufPtr & pixbuf) throw()
+{
+ MainWindow & main_window = application_->get_main_window();
+ main_window.set_busy(false);
if (0 == imageView_)
{
diff --git a/src/renderer/enlarged-renderer.h b/src/renderer/enlarged-renderer.h
index 6c6dc81..e53af0d 100644
--- a/src/renderer/enlarged-renderer.h
+++ b/src/renderer/enlarged-renderer.h
@@ -110,6 +110,9 @@ class EnlargedRenderer :
throw();
void
+ on_pixbuf_maker_async_ready(const PixbufPtr & pixbuf) throw();
+
+ void
on_switch_page(GtkNotebookPage * notebook_page, guint page_num)
throw();
@@ -140,6 +143,8 @@ class EnlargedRenderer :
gint pageNum_;
+ PixbufMakerPtr pixbufMaker_;
+
sigc::connection signalMainWindowStateEvent_;
sigc::connection signalListStoreChangeEnd_;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]