Play find the memory leak! (Gtk--)



Hi all:

I'm working on some small apps to get my Gtk-- chops up, which is a bit
of an uphill climb, since the documentation can be fairly sparse at
(all) times.  In any case, I'm working on a simple app used to view
images via Gdk_Imlib.

To help you grok the source more easily, here's the basic idea:  class
PicView is implemented with a mixin from class Observer, and class
ImgModel is derived from abstract class Subject.  The abstract Observer
and Subject classes are your basic implementation of the Observer design
pattern, where an Observer "subscribes" to a Subject, and the Subject
notifies all subscribed Observers when its state changes so they can
update themselves.  ImgModel uses Gdk_Imlib::Image to read and render
the file on disk to (ultimately) a Gtk_Pixmap, which is added to a
Gtk_ScrolledWindow contained in PicView.  PicView is a friend class of
ImgModel.

Whew.

Anyway, I've come across a major and a minor problem that I've been
unable to solve:
1) Major -- huge memory leak here somewhere, and I can't figure out
where it is.
2) Minor -- I get the following message when the Update() method is
called on the PicView object:

Gtk-CRITICAL **: file gtkscrolledwindow.c: line 951
(gtk_scrolled_window_add_with_viewport): assertion 'child->parent ==
NULL' failed.

OK, whew again.  Here are the important parts of the source:

/////////////////////////////////////////////////////////////////
// PicView.C starts here
/////////////////////////////////////////////////////////////////

... a few #includes ...

using namespace std;

PicView::PicView(ImgModel* img)
 :  Gtk_Frame( img->get_filename() ), _subject(img), pScreen(0)
{
 set_label_align( 0.5, 0.5 );

 pScreen = new Gtk_ScrolledWindow();
 pScreen->add_with_viewport( _subject->_gtk_pixmap );
 add(pScreen);

 _subject->Attach(this);    // subscribe to ImgModel img to be notified
of updates

 show_all();
}

PicView::~PicView()
{
 _subject->Detach(this);
 delete pScreen;
}



void PicView::Update(Subject* changedSubject)
{
 if (_subject == changedSubject)
 {
      hide_all();

      // Possible leak here?  Shouldn't be -- the "old" _gtk_pixmap was
replaced by
      // the new one using Gtk_Pixmap::set(...) -- not dynamically
allocated.  Also
      // tried destroying pScreen completely and creating a new one here
to no avail.
      pScreen->add_with_viewport( _subject->_gtk_pixmap );

      set_label( _subject->get_filename() );
      show_all();
 }
}

void PicView::Warn_Detach(Subject* detachingSubject)
{
 _subject = 0;    // subject is now null -- don't point to subjects that
may have
        // been destructed!
}

////////////////////////////////////////////////////////////
// End of PicView.C

/////////////////////////////////////////////////////////////
// Start ImgModel.C
/////////////////////////////////////////////////////////////

// ImgModel.C
//
// This model is derived from Subject, which means it can register and
notify observers of changes.

#include "ImgModel.h"

#include <iostream>
#include <string>
#include <gdk--/extra/imlib.h>
#include <gtk--.h>
#include <gdk--.h>

using namespace std;

ImgModel::ImgModel(const string& fname)
 :  _filename(fname), p_imlib_image(0), _gtk_pixmap(),
  p_pixmap(0), p_bitmap(0)
{
 load_file( _filename );
}

ImgModel::~ImgModel()
{
 // observer detachment taken care of in Subject's virtual destructor
 delete p_imlib_image;
 delete p_pixmap;
 delete p_bitmap;
}

const string ImgModel::get_filename() const
{
 return _filename;
}

void ImgModel::load_file(const string& fname)
{
     // nuke the old image and create a new one
     delete p_imlib_image;
     p_imlib_image = new Gdk_Imlib::Image(fname);
     p_imlib_image->render(p_imlib_image->rgb_width(),
p_imlib_image->rgb_height());

     // nuke the Gdk_Pixmap and create a new one from the newly rendered
image
     delete p_pixmap;
     p_pixmap = new Gdk_Pixmap( p_imlib_image->copy_image());

     // same for the Gdk_Bitmap
     delete p_bitmap;
     p_bitmap = new Gdk_Bitmap( p_imlib_image->copy_mask() );

     _gtk_pixmap.set( *p_pixmap, *p_bitmap );        // possible source
of leak, if

//  Gtk_Pixmap needs an explicit

//  instruction to destroy any local

//  copies of these it might hold
     _filename = fname;

     Notify();            // calls Update(this) on all registered
PicView observers
}

//////////////////////////////////
// End ImgModel.C

/////////////////////////////////////
// This is the little driver prog I'm using to test these classes out
//

#include <gtk--.h>
#include <gdk/gdk.h>
#include <gdk--/extra/imlib.h>
#include <gdk_imlib.h>
#include <iostream>
#include "ImgModel.h"
#include "PicView.h"

using namespace std;

void NextPic(ImgModel*);

int main(int argc, char *argv[])
{
 Gtk_Main mw(&argc, &argv);

 Gdk_Imlib imlib;
 imlib.set_render_type(5);

 ImgModel *img = new ImgModel("pic1.jpg");
 PicView *pv = new PicView(img);

 Gtk_Window win( GTK_WINDOW_TOPLEVEL );
 Gtk_VBox box;
 Gtk_Button btnNext("Next Image");

 box.pack_start(*pv);
 box.pack_start(btnNext);
 connect_to_function(btnNext.clicked, &NextPic, img);

 win.add(&box);
 win.set_usize(300,300);
 win.show_all();

 mw.run();

 return 0;
}

void NextPic(ImgModel* img) {    // simply alternates between two pics
to load when
                                               // button "Next Pic" is
clicked.
 static int timesCalled = 0;

 if (++timesCalled % 2)
      img->load_file("pic2.jpg");
 else
      img->load_file("pic3.jpg");
}

//////////////////////////////////////////////////////////////

Sorry this message is so long...  I'd post less code if I knew
approximately where the memory leak is coming from, but I don't.  I've
tried rewriting it a few times, changing the way I allocate/deallocate
the images and pixmaps, but I always run into the same problem.

Thanks to any gurus who can help out here...

Dave Brown
DrDave@POBoxes.com




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]