Hi, Today I've got rid of the Gtk frontend's dependency on the xformsImage class. That means that the only xforms-dependence remaining in the Gtk frontend is the placeholder dialogs. It also removes (I think) the last of the X-specific calls apart from Xft.
The image handling is not yet complete: * Only multiple-of-90-degrees rotation is supported * Grayscale and monochrome effects are not yet implemented. That will be fixed in due course. I may soon be tempted to completely rip out all remaining xforms linkage from frontends/gtk, to make things a bit cleaner. John
? glade/tabular.glade Index: ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/gtk/ChangeLog,v retrieving revision 1.142 diff -u -p -r1.142 ChangeLog --- ChangeLog 21 Jan 2006 21:38:32 -0000 1.142 +++ ChangeLog 23 Jan 2006 23:53:28 -0000 @@ -1,3 +1,9 @@ +2006-01-23 John Spray <[EMAIL PROTECTED]> + * LyXGdkImage.[Ch]: replace xforms Image class + * Makefile.am: build LyXGdkImage + * GPainter.C: use new Gdk Image class + * lyx_gui.C: use new Gdk Image class, disable XSynchronize + 2006-01-21 John Spray <[EMAIL PROTECTED]> * GBibItem.[Ch], glade/bibitem.glade: Add the bibitem dialog Index: GPainter.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/gtk/GPainter.C,v retrieving revision 1.17 diff -u -p -r1.17 GPainter.C --- GPainter.C 29 Jan 2005 15:09:14 -0000 1.17 +++ GPainter.C 23 Jan 2006 23:53:28 -0000 @@ -4,6 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Huang Ying + * \author John Spray * * Full author contact details are available in file CREDITS. */ @@ -21,12 +22,12 @@ #include "GPainter.h" #include "debug.h" #include "GWorkArea.h" +#include "LyXGdkImage.h" #include "lyxrc.h" #include "encoding.h" #include "language.h" #include "LColor.h" #include "xftFontLoader.h" -#include "xformsImage.h" #include "frontends/font_metrics.h" #include "codeConvert.h" @@ -186,12 +187,14 @@ void GPainter::arc(int x, int y, unsigne void GPainter::image(int x, int y, int w, int h, graphics::Image const & i) { - graphics::xformsImage const & image = - static_cast<graphics::xformsImage const &>(i); - Pixmap pixmap = GDK_PIXMAP_XID(owner_.getPixmap()->gobj()); - GC gc = GDK_GC_XGC(owner_.getGC()->gobj()); - XCopyArea(owner_.getDisplay(), image.getPixmap(), pixmap, - gc, 0, 0, w, h, x, y); + graphics::LyXGdkImage const & image = + static_cast<graphics::LyXGdkImage const &>(i); + Glib::RefPtr<Gdk::Pixbuf> const & pixbuf = image.pixbuf(); + Glib::RefPtr<Gdk::Pixmap> pixmap = owner_.getPixmap(); + + Glib::RefPtr<Gdk::GC> gc = owner_.getGC(); + pixmap->draw_pixbuf (gc, pixbuf, 0, 0, x, y, w, h, + Gdk::RGB_DITHER_NONE, 0, 0); } Index: GWorkArea.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/gtk/GWorkArea.h,v retrieving revision 1.15 diff -u -p -r1.15 GWorkArea.h --- GWorkArea.h 20 Mar 2005 17:13:17 -0000 1.15 +++ GWorkArea.h 23 Jan 2006 23:53:28 -0000 @@ -103,7 +103,6 @@ private: /// The pixmap overlay on the workarea Glib::RefPtr<Gdk::Pixmap> workAreaPixmap_; Glib::RefPtr<Gdk::GC> workAreaGC_; - /// the xforms-specific painter GPainter painter_; XftDraw * draw_; ColorHandler colorHandler_; Index: LyXGdkImage.C =================================================================== RCS file: LyXGdkImage.C diff -N LyXGdkImage.C --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ LyXGdkImage.C 23 Jan 2006 23:53:28 -0000 @@ -0,0 +1,288 @@ +/** + * \file LyXGdkImage.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming (original Qt version) + * \author John Levon (original Qt version) + * \author John Spray + * + * Full author contact details are available in file CREDITS. + */ + +#include <config.h> + +// Too hard to make concept checks work with this file +#ifdef _GLIBCXX_CONCEPT_CHECKS +#undef _GLIBCXX_CONCEPT_CHECKS +#endif +#ifdef _GLIBCPP_CONCEPT_CHECKS +#undef _GLIBCPP_CONCEPT_CHECKS +#endif + + + +#include "LyXGdkImage.h" + +#include "debug.h" +#include "format.h" + +#include "graphics/GraphicsParams.h" + +#include "support/lstrings.h" // lowercase + +#include <boost/bind.hpp> +#include <boost/tuple/tuple.hpp> + +using lyx::support::lowercase; + +using boost::bind; + +using std::endl; +using std::equal_to; +using std::find_if; +using std::string; + + +namespace lyx { +namespace graphics { + +/// Access to this class is through this static method. +Image::ImagePtr LyXGdkImage::newImage() +{ + ImagePtr ptr; + ptr.reset(new LyXGdkImage); + return ptr; +} + + +/// Return the list of loadable formats. +Image::FormatList LyXGdkImage::loadableFormats() +{ + static FormatList fmts; + + if (!fmts.empty()) + return fmts; + + // The formats recognised by LyX + Formats::const_iterator begin = formats.begin(); + Formats::const_iterator end = formats.end(); + + lyxerr[Debug::GRAPHICS] + << "\nThe image loader can load the following directly:\n"; + + Gdk::Pixbuf::SListHandle_PixbufFormat gdkformats = Gdk::Pixbuf::get_formats(); + Gdk::Pixbuf::SListHandle_PixbufFormat::iterator it = gdkformats.begin(); + Gdk::Pixbuf::SListHandle_PixbufFormat::iterator gdk_end = gdkformats.end(); + + for (; it != gdk_end; ++it) { + Gdk::PixbufFormat thisformat = (*it); + lyxerr[Debug::GRAPHICS] << thisformat.get_name() << endl; + + std::vector<Glib::ustring> extensions = thisformat.get_extensions(); + std::vector<Glib::ustring>::const_iterator ext_end = extensions.end(); + std::vector<Glib::ustring>::iterator ext_it = extensions.begin(); + for (; ext_it != ext_end; ++ext_it) { + std::string ext = lowercase(*ext_it); + Formats::const_iterator fit = + find_if(begin, end, + bind(equal_to<string>(), + bind(&Format::extension, _1), + ext)); + if (fit != end) + fmts.push_back(fit->name()); + } + } + + if (lyxerr.debugging()) { + lyxerr[Debug::GRAPHICS] + << "\nOf these, LyX recognises the following formats:\n"; + + FormatList::const_iterator fbegin = fmts.begin(); + FormatList::const_iterator fend = fmts.end(); + for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) { + if (fit != fbegin) + lyxerr[Debug::GRAPHICS] << ", "; + lyxerr[Debug::GRAPHICS] << *fit; + } + lyxerr[Debug::GRAPHICS] << '\n' << endl; + } + + return fmts; +} + + +LyXGdkImage::LyXGdkImage() + : Image() +{ +} + + +LyXGdkImage::LyXGdkImage(LyXGdkImage const & other) + : Image(other), original_(other.original_), + transformed_(other.transformed_) +{} + + +Image * LyXGdkImage::clone_impl() const +{ + return new LyXGdkImage(*this); +} + + +unsigned int LyXGdkImage::getWidth_impl() const +{ + return transformed_->get_width(); +} + + +unsigned int LyXGdkImage::getHeight_impl() const +{ + return transformed_->get_height(); +} + + +void LyXGdkImage::load_impl(string const & filename) +{ + if (original_) { + lyxerr[Debug::GRAPHICS] + << "Image is loaded already!" << endl; + finishedLoading(false); + return; + } + + original_ = Gdk::Pixbuf::create_from_file(filename); + + if (!original_){ + lyxerr[Debug::GRAPHICS] + << "Unable to open image" << endl; + finishedLoading(false); + return; + } + + transformed_ = original_; + finishedLoading(true); +} + +/* +namespace { + +// This code is taken from KImageEffect::toGray +QImage & toGray(QImage & img) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + int const pixels = img.depth() > 8 ? + img.width() * img.height() : img.numColors(); + + unsigned int * const data = img.depth() > 8 ? + (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + + for(int i = 0; i < pixels; ++i){ + int const val = qGray(data[i]); + data[i] = qRgba(val, val, val, qAlpha(data[i])); + } + return img; +} + +} // namespace anon +*/ + +bool LyXGdkImage::setPixmap_impl(Params const & params) +{ + if (!original_ || params.display == NoDisplay) + return false; + + // TODO: implement grayscale and monochrome + switch (params.display) { + case GrayscaleDisplay: { + //toGray(transformed_); + break; + } + + case MonochromeDisplay: { + //transformed_.convertDepth(transformed_.depth(), Qt::MonoOnly); + break; + } + + default: + break; + } + + return true; +} + + +void LyXGdkImage::clip_impl(Params const & params) +{ + if (!transformed_) + return; + + if (params.bb.empty()) + // No clipping is necessary. + return; + + int const new_width = params.bb.xr - params.bb.xl; + int const new_height = params.bb.yt - params.bb.yb; + + // No need to check if the width, height are > 0 because the + // Bounding Box would be empty() in this case. + if (new_width > original_->get_width() || new_height > original_->get_height()) { + // Bounds are invalid. + return; + } + + if (new_width == original_->get_width() && new_height == original_->get_height()) + return; + + int const xoffset_l = params.bb.xl; + int const yoffset_t = (original_->get_height() > int(params.bb.yt) ? + original_->get_height() - params.bb.yt : 0); + + transformed_ = Gdk::Pixbuf::create_subpixbuf(original_, + xoffset_l, yoffset_t, new_width, new_height); +} + + +void LyXGdkImage::rotate_impl(Params const & params) +{ + if (!transformed_) + return; + + if (!params.angle) + return; + + // TODO: allow free rotation + Gdk::PixbufRotation rotation = Gdk::PIXBUF_ROTATE_NONE; + if (params.angle == 90.0) + rotation = Gdk::PIXBUF_ROTATE_COUNTERCLOCKWISE; + else if (params.angle == 180.0) + rotation = Gdk::PIXBUF_ROTATE_UPSIDEDOWN; + else if (params.angle == 270.0) + rotation = Gdk::PIXBUF_ROTATE_CLOCKWISE; + + + transformed_ = transformed_->rotate_simple(rotation); +} + + +void LyXGdkImage::scale_impl(Params const & params) +{ + if (!transformed_) + return; + + unsigned int width; + unsigned int height; + boost::tie(width, height) = getScaledDimensions(params); + + if (width == getWidth() && height == getHeight()) + return; + + transformed_ = transformed_->scale_simple( + width, height, Gdk::INTERP_BILINEAR); +} + +} // namespace graphics +} // lyx Index: LyXGdkImage.h =================================================================== RCS file: LyXGdkImage.h diff -N LyXGdkImage.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ LyXGdkImage.h 23 Jan 2006 23:53:28 -0000 @@ -0,0 +1,76 @@ +// -*- C++ -*- +/** + * \file GdkImage.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming (original Qt version) + * \author John Levon (original Qt version) + * \author John Spray + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef LYXGDKIMAGE_H +#define LYXGDKIMAGE_H + + +#include "graphics/GraphicsImage.h" + +#include <gdkmm.h> + +namespace lyx { +namespace graphics { + +class LyXGdkImage : public Image { +public: + /// Access to this class is through this static method. + static ImagePtr newImage(); + + /// Return the list of loadable formats. + static FormatList loadableFormats(); + + /// Retrieve the buffered pixmap. + Glib::RefPtr<Gdk::Pixbuf> const & pixbuf() const {return transformed_;} + +private: + /// Create a copy + virtual Image * clone_impl() const; + /// Get the image width + virtual unsigned int getWidth_impl() const; + /// Get the image height + virtual unsigned int getHeight_impl() const; + // FIXME Is the image drawable ? + virtual bool isDrawable_impl() const { return true; } + /** + * Load the image file into memory. + * The process is asynchronous, so this method starts the loading. + * When finished, the Image::finishedLoading signal is emitted. + */ + virtual void load_impl(std::string const & filename); + /** + * Finishes the process of modifying transformed_, using + * \c params to decide on color, grayscale etc. + * \returns true if successful. + */ + virtual bool setPixmap_impl(Params const & params); + /// Clip the image using params. + virtual void clip_impl(Params const & params); + /// Rotate the image using params. + virtual void rotate_impl(Params const & params); + /// Scale the image using params. + virtual void scale_impl(Params const & params); + + /// Access to the class is through newImage() and clone. + LyXGdkImage(); + /// + LyXGdkImage(LyXGdkImage const &); + + Glib::RefPtr<Gdk::Pixbuf> original_; + Glib::RefPtr<Gdk::Pixbuf> transformed_; +}; + +} // namespace graphics +} // namespace lyx + +#endif // LYXGDKIMAGE_H Index: Makefile.am =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/gtk/Makefile.am,v retrieving revision 1.45 diff -u -p -r1.45 Makefile.am --- Makefile.am 21 Jan 2006 20:06:37 -0000 1.45 +++ Makefile.am 23 Jan 2006 23:53:28 -0000 @@ -116,6 +116,8 @@ libgtk_la_SOURCES = \ GtkmmX.h \ IdSc.C \ IdSc.h \ + LyXGdkImage.C \ + LyXGdkImage.h \ LyXKeySymFactory.C \ LyXScreenFactory.C \ WorkAreaFactory.C \ Index: lyx_gui.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/gtk/lyx_gui.C,v retrieving revision 1.27 diff -u -p -r1.27 lyx_gui.C --- lyx_gui.C 25 Jul 2005 13:45:17 -0000 1.27 +++ lyx_gui.C 23 Jan 2006 23:53:28 -0000 @@ -50,7 +50,6 @@ //just for xforms #include "lyx_forms.h" -#include "xformsImage.h" #include "xforms_helpers.h" #include "support/lyxlib.h" @@ -60,6 +59,8 @@ #include <gtkmm.h> +#include "LyXGdkImage.h" + #include <boost/bind.hpp> #include <boost/function.hpp> #include <boost/shared_ptr.hpp> @@ -192,11 +193,6 @@ void parse_init_xforms(int & argc, char XSetErrorHandler(LyX_XErrHandler); - using namespace lyx::graphics; - - // connect the image loader based on the xforms library - Image::newImage = boost::bind(&xformsImage::newImage); - Image::loadableFormats = boost::bind(&xformsImage::loadableFormats); } @@ -206,6 +202,10 @@ void lyx_gui::parse_init(int & argc, cha parse_init_xforms(argc, argv); + using namespace lyx::graphics; + Image::newImage = boost::bind(&LyXGdkImage::newImage); + Image::loadableFormats = boost::bind(&LyXGdkImage::loadableFormats); + locale_init(); // must do this /before/ lyxrc gets read @@ -335,7 +335,7 @@ void lyx_gui::start(string const & batch { start_xforms(); // just for debug - XSynchronize(getDisplay(), true); + //XSynchronize(getDisplay(), true); boost::shared_ptr<GView> view_ptr(new GView); LyX::ref().addLyXView(view_ptr);