Gtk will temporarily unset my backing pixmap for a GtkDrawingArea when it is packed into a GtkScrolledWindow, is this a necessary behavior?



I have posted a message about using GdkDrawingArea with backing pixmap
to gtk-app-devel-list mailing list yesterday.

After tracing into gtk and gdk for several hours, I think I find where
the problem is.
However, I don't know whether this problem is an undocumented feature or
a bug in gtk.

My attempt is to redraw parts of the contents of the GtkDrawingArea
without using an expose_event signal handler.
That is to say, I want the X Window System to recover the old contents
of the GtkDrawingArea by using the backing pixmap.
Because I want to acquire the max preformance without causing a round
trip between the X Window Server and my own program.

Following is my original question:

==============================================================

I have some problems about the usage of GtkDrawingArea with backing
pixmap when I use it in a GtkScrolledWindow.

You can copy the following code segment into a c++ file (ex: ddd.cpp),
and compile with

g++ 'pkg-config gtkmm-2.0 --cflags --libs' ddd.cpp

and see what will happen.

I have no idea whether this result is the misuse of GtkDrawingArea or a
bug in gtk.

Althought I've implemented the following code segment by using gtkmm
(i.e. C++), but I think it is eqivalent to using gtk (i.e. C).

The container hierarchy is:

GtkWindow -> GtkScrolledWindow -> GtkTable -> GtkDrawingArea

And I use a backing pixmap with GtkDrawingArea to avoid the flicker,
thus I disable the default double buffered behavior with the
GtkDrawingArea.

When I start the program and hit a keystoke, the DrawingArea will be
filled with red. This is OK.

However, when I try to resize the window by using the mouse, X window
seems
not to update the drawing area with its backing pixmap.

Is this  a bug in gtk or the misuse of GtkDrawingArea with backing
pixmap?

============================================================

And I find the problem is:

When I click the scrollbar (vertical or horizontal) in the
GtkScrolledWindow,
the GtkAdjustment will send a change signal to trigger many side
effects.

These side effects include moving the GtkViewport and invalidating the
previous obscure portion in
GtkDrawingArea to trigger the X Window Server to send an expose event to
the GtkDrawingArea.

But the problem is,

before the above side effect occurs, Gtk will first unset the background
pixmap of the GtkDrawingArea
by using XSetWindowBackgroundPixmap(..., ..., NONE). Following are the
calling sequences:

... -> _gdk_window_move_resize_child() -> gdk_window_clip_changed() ->
gdk_window_tmp_unset_bg() -> XSetWindowBackgroundPixmap()

After that, gdk_window_clip_changed() will call
gdk_window_invalidate_region() to trigger the X Window
to send an expose event to the GtkDrawingArea.

However, because of the absence of the background pixmap for the
GtkDrawingArea,
the X Window Server will not redraw the background pixmap for the
GtkDrawingArea.

After that, _gdk_window_move_resize_child() will call
gdk_window_postmove() to reset the background pixmap
for the GtkDrawingArea.

Thus the previous obscure portions of the GtkDrawingArea will not be
covered automatically by the backing pixmap I offered,
and the old contents of that part of the GtkDrawingArea will still be
showed on the screen.

This is not what most programmers want in most situation.

The method to solve this problem is setting up an expose_event signal
handler for the GtkDrawingArea,
and calls some clear_area function or draw_pixmap function to manually
recover the backing pixmap for the GtkDrawingArea.

Thus my question is is this behavour (gdk_window_tmp_unset_bg() &
gdk_window_tmp_reset_bg()) necessary in gtk & gdk?
And can I use a backing pixmap for the GtkDrawingArea when it is packed
into a GtkScrolledWindow or I must to set up an expose_event
signal handler and unset the backing pixmap of the GtkDrawingArea.

Thanks for your help.

============================================================

#include <gtkmm.h>

struct MainWindow : public Gtk::Window
{
  Gtk::ScrolledWindow mScrolledWindow;
  Gtk::DrawingArea mDrawingArea;
  Gtk::Table mTable;
  
  Glib::RefPtr<Gdk::Pixbuf> mpPixbuf;
  Glib::RefPtr<Gdk::Pixmap> mpPixmap;
  
  MainWindow()
  {
    add(mScrolledWindow);
    mScrolledWindow.add(mTable);
    mTable.attach(mDrawingArea, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0,
0);
    
    mDrawingArea.set_double_buffered(false);
    
    mDrawingArea.signal_size_allocate().
      connect(SigC::slot(*this,
&MainWindow::OnDrawingAreaSizeAllocate));
    
    signal_key_press_event().connect_notify(SigC::slot(*this,
&MainWindow::OnKeyPressEvent));
    
    show_all_children();
  }
  
  void
  OnKeyPressEvent(GdkEventKey *event)
  {
    mDrawingArea.set_size_request(400, 500);
  }
  
  void
  OnDrawingAreaSizeAllocate(GtkAllocation *allocate)
  {
    if (true == mDrawingArea.is_realized())
    {
      int width = allocate->width;
      int height = allocate->height;
      
      if (false == mpPixmap.is_null())
      {
        mpPixmap.clear();
      }
      
      if (false == mpPixbuf.is_null())
      {
        mpPixbuf.clear();
      }
      
      mpPixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,
                                     false, // has_alpha
                                     8, // bits_per_sample
                                     width,
                                     height);
      
      mpPixbuf->fill(0xFF000000);
      
      mpPixmap = Gdk::Pixmap::create(mDrawingArea.get_window(),
                                     width,
                                     height, -1);
      
      mpPixmap->draw_pixbuf(Glib::RefPtr<Gdk::GC>(), // an empty GC
                            mpPixbuf,
                            0, 0, // src
                            0, 0, // dest
                            static_cast<int>(width),
                            static_cast<int>(height),
                            Gdk::RGB_DITHER_NONE,
                            0, 0 // dither offset
                            );
      
      mDrawingArea.get_window()->set_back_pixmap(mpPixmap,
                                                 false //
parent_relative
                                                 );
      mDrawingArea.get_window()->clear();
    }
  }
};

int
main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);
  
  MainWindow main_window;
  
  Gtk::Main::run(main_window);
  
  return 0;
}

=========================================================





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