Drawing Area woes: Sample code (Gtk--)





Hi,

the following is a piece of code I've hacked together
in search of enlightenment (no, not the window manager).
It compiles without a hitch but gives a GDK-CRITICAL
error when attemping to size the drawing area
(ie: when attemping to create the backing pixmap).
I've used this specific code in GuiBufferedDrawingArea
for quite a while now without problems and I can't figure
out why it won't work with the example given below.

If any Gtk(--) gurus know the answer to this, I'd be
most appreciative as I've been stuck on this now
for more than a week and still have no clue what
I'm doing wrong ... the actual place where the thing
breaks is in GuiDialogPreview::insertPreview ().

I'm using RH 5.2, Gtk 1.2.1, Gtk-- 1.0.0 (vanilla), egcs 1.1

Thanks a lot
--> Robert

PS: Apologies for the mixture of Gtk-- and Gdk calls ...

------------------ cut here -----------------------
#include <gtk--.h>
#include <gtk/gtk.h>

/*
 *  GuiBufferedDrawingArea: provide an offscreen drawing area which
 *   is refreshes/repaints using an atomic copy operation from the
 *      offscreen pixmap to the on screen window.
 */
class GuiBufferedDrawingArea : public Gtk_DrawingArea
     {
     public:
               GuiBufferedDrawingArea ();
               ~GuiBufferedDrawingArea ();
          void clear (GdkColor *col=NULL);
          void setColors (GdkColor *fg, GdkColor *bg=NULL);
          void      drawRectangle (int x1, int y1,
                 int width, int height, bool filled=TRUE);
          void setUsize (int x, int y);

     private:
          int  handleConfigureEvent (GdkEventConfigure *event);
          int  handleExposeEvent (GdkEventExpose *event);

          GdkPixmap *d_pixmap;     // pixmap buffer for drawing area
          GdkGC     *d_GC;         // graphics content
     };




GuiBufferedDrawingArea::GuiBufferedDrawingArea () : d_pixmap (0)
{
     /* Signals used to handle backing pixmap */
     connect_to_method (expose_event, this, &handleExposeEvent);
     connect_to_method (configure_event, this, &handleConfigureEvent);

     set_events (GDK_EXPOSURE_MASK
          | GDK_LEAVE_NOTIFY_MASK
          | GDK_BUTTON_PRESS_MASK
          | GDK_BUTTON_RELEASE_MASK
          | GDK_POINTER_MOTION_MASK
          | GDK_POINTER_MOTION_HINT_MASK);

     d_GC=GTK_WIDGET (gtkobj())->style->black_gc;
}


GuiBufferedDrawingArea::~GuiBufferedDrawingArea ()
{
     gdk_pixmap_unref (d_pixmap);
}


void GuiBufferedDrawingArea::clear (GdkColor *col)
{
     GdkRectangle update_rect;

     update_rect.x = 0;
     update_rect.y = 0;
     update_rect.width = width();
     update_rect.height = height();

     if (!col)
          gdk_draw_rectangle (d_pixmap,
               GTK_WIDGET(gtkobj())->style->white_gc,
               TRUE, 0, 0, this->width(), this->height());
     else
          {
          setColors (col);
          drawRectangle (0, 0, this->width(), this->height(), TRUE);
          }
}


void GuiBufferedDrawingArea::setUsize (int x, int y)
{
     if (x != width() || y != height())
          {
          if (d_pixmap)
               gdk_pixmap_unref(d_pixmap);
          d_pixmap = gdk_pixmap_new(get_window(), x, y, -1);
          gdk_draw_rectangle (d_pixmap,
               GTK_WIDGET(gtkobj())->style->white_gc,
               TRUE, 0, 0, x, y);
          this->set_usize (x, y);
          }

     this->show ();
}


void GuiBufferedDrawingArea::setColors (GdkColor *fg, GdkColor *bg)
{
     if (fg)
          gdk_gc_set_foreground (GTK_WIDGET (gtkobj())->style->black_gc, fg);
     if (bg)
          gdk_gc_set_foreground (GTK_WIDGET (gtkobj())->style->black_gc, bg);
}


int GuiBufferedDrawingArea::handleConfigureEvent (GdkEventConfigure *event)
{
     //GtkWidget    *widget = GTK_WIDGET(gtkobj());
     if (event);              // silence compiler warning

     if (d_pixmap)
          gdk_pixmap_unref(d_pixmap);

     d_pixmap = gdk_pixmap_new(get_window(),  width(), height(), -1);
     gdk_draw_rectangle (d_pixmap,
          GTK_WIDGET(gtkobj())->style->white_gc,
          TRUE, 0, 0, width(), height());

     return TRUE;
}


int GuiBufferedDrawingArea::handleExposeEvent (GdkEventExpose *event)
{
     gdk_draw_pixmap(get_window(),
         GTK_WIDGET (gtkobj())->style->fg_gc[GTK_WIDGET_STATE
(GTK_WIDGET(gtkobj()))],
         d_pixmap,
         event->area.x, event->area.y,
         event->area.x, event->area.y,
         event->area.width, event->area.height);
     return FALSE;
}


void GuiBufferedDrawingArea::drawRectangle (int x1, int y1,
                             int width, int height,
                             bool filled)
{
     GdkRectangle update_rect;

     update_rect.x = x1;
     update_rect.y = y1;
     update_rect.width = width;
     update_rect.height = height;
     gdk_draw_rectangle (d_pixmap,
          GTK_WIDGET (gtkobj())->style->black_gc,
          filled,
          update_rect.x, update_rect.y,
          update_rect.width, update_rect.height);
}


class GuiDialogPreview : public Gtk_Dialog
     {
     public:
                         GuiDialogPreview (char *winTitle, char *frameTitle,
                                     int tableX, int tableY);
                         ~GuiDialogPreview ();

     protected:
          void           insertPreview ();
          void           clearPreview ();
          void           setupVBox ();
          virtual void        fillVBox ();
          virtual void        fillActionArea ();
          virtual void        buildDialogWindow ();
          virtual void        buttonCallbackOK ();
          virtual void        buttonCallbackApply ();
          virtual void        buttonCallbackCancel ();
          virtual void        checkboxCallbackPreview ();
          virtual gint        delete_event_impl (GdkEventAny *);

          int            d_size,
                         d_frameBorder;
          Gtk_VBox       d_vBoxPreview;
          Gtk_Button          d_btnOK,
                         d_btnApply,
                         d_btnCancel;
          Gtk_CheckButton          d_cbUsePreview;
          Gtk_Frame      *d_baseFrame,
                         *d_previewFrame,
                         *d_previewGroupFrame;
          Gtk_Preview         *d_preview;
          GuiBufferedDrawingArea   *d_drawArea;
          Gtk_Table      *d_table;
          char           *d_winTitle,
                         *d_frameTitle;
          bool           d_applyHit;
     };



GuiDialogPreview::GuiDialogPreview (char *winTitle, char *frameTitle,
                        int tableX, int tableY) :
            d_vBoxPreview (FALSE, 0),
            d_btnOK ("OK"),
            d_btnApply ("Apply"),
            d_btnCancel ("Cancel"),
            d_cbUsePreview ("Use Preview")
{
     d_winTitle = strdup (winTitle);
     d_frameTitle = strdup (frameTitle);

     d_baseFrame = d_previewFrame = d_previewGroupFrame = NULL;
     d_preview = NULL;
     d_drawArea = NULL;
     d_size = 100;
     d_frameBorder = 4;

     d_table = new Gtk_Table (tableX, tableY, FALSE);
     d_applyHit = FALSE;

        this->set_position (GTK_WIN_POS_MOUSE);
     buildDialogWindow ();
}


GuiDialogPreview::~GuiDialogPreview ()
{
     if (d_winTitle) free (d_winTitle);  // c-type alloc from strdup
     if (d_frameTitle) free (d_frameTitle);   // c-type alloc from strdup
     if (d_baseFrame) delete d_baseFrame;
     if (d_previewFrame) delete d_previewFrame;
     if (d_preview) delete d_preview;
     if (d_table) delete d_table;
}


void GuiDialogPreview::buildDialogWindow ()
{
     this->set_usize (300, 250);
     this->set_title (d_winTitle);

     this->get_vbox()->set_border_width (2);

     setupVBox ();
     insertPreview ();
     fillVBox ();
     fillActionArea ();

     if (d_baseFrame)
          d_baseFrame->show ();
     this->show ();
}


void GuiDialogPreview::setupVBox ()
{
     d_baseFrame = new Gtk_Frame (d_frameTitle);
     d_baseFrame->set_shadow_type (GTK_SHADOW_ETCHED_IN);
     d_baseFrame->set_border_width (0);
     this->get_vbox()->pack_start (*d_baseFrame, TRUE, TRUE, 0);
     d_baseFrame->show ();
     this->get_vbox()->show ();
}


void GuiDialogPreview::insertPreview ()
{
     // add main table
     d_baseFrame->add (*d_table);

     // add bounding frame + main preview vbox
     d_previewGroupFrame = new Gtk_Frame ("Preview");
     d_previewGroupFrame->set_border_width (d_frameBorder);
     // add main VBox
     d_previewGroupFrame->add (d_vBoxPreview);
     d_previewGroupFrame->show ();

     // add preview frame to table
     d_table->attach (*d_previewGroupFrame, 1, 3, 1, 4);

     // build preview Frame and add it to preview vbox
     d_previewFrame = new Gtk_Frame ();
     d_previewFrame->set_shadow_type (GTK_SHADOW_ETCHED_IN);
     d_previewFrame->set_border_width (2);
     d_vBoxPreview.pack_start (*d_previewFrame, FALSE, FALSE, 0);
     d_previewFrame->show ();

     // setup checkbutton
     d_cbUsePreview.set_active (TRUE);
     connect_to_method (d_cbUsePreview.clicked, this, &checkboxCallbackPreview);
     d_vBoxPreview.pack_start (d_cbUsePreview, FALSE, FALSE, 0);
     d_cbUsePreview.show ();

     d_vBoxPreview.show ();
     d_table->show ();

     // add drawing area
     d_drawArea = new GuiBufferedDrawingArea ();
     d_previewFrame->add (*d_drawArea);
     d_drawArea->show ();

     printf ("F\n"); fflush (stdout);
     // GDK ERROR is here
     d_drawArea->setUsize (d_size, d_size);
     printf ("G\n"); fflush (stdout);
}


void GuiDialogPreview::clearPreview ()
{
     guchar    *row = new unsigned char [3*d_size];

     for (int i=0; i<d_size; i++)
        for (int j=0; j<d_size; j++)
          {
          row[j*3]=(int) (255.0/d_size*i);
          row[j*3+1]=(int) (255.0/d_size*i);
          row[j*3+2]=(int) (255.0/d_size*i);
          d_preview->draw_row (row, 0, i, d_size);
          }

     delete [] row;
}


void GuiDialogPreview::fillVBox ()
{
}


void GuiDialogPreview::fillActionArea ()
{
     connect_to_method (d_btnOK.clicked, this, &buttonCallbackOK);
     this->get_action_area()->pack_start (d_btnOK, TRUE, TRUE, 0);
     d_btnOK.show ();

     connect_to_method (d_btnApply.clicked, this, &buttonCallbackApply);
     this->get_action_area()->pack_start (d_btnApply, TRUE, TRUE, 0);
     d_btnApply.show ();

     connect_to_method (d_btnCancel.clicked, this, &buttonCallbackCancel);
     this->get_action_area()->pack_start (d_btnCancel, TRUE, TRUE, 0);
     d_btnCancel.show ();
}


void GuiDialogPreview::buttonCallbackOK ()
{
     cout << "GuiDialogPreview: Default Callback OK\n";
     d_applyHit = FALSE;
}


void GuiDialogPreview::buttonCallbackApply ()
{
     cout << "GuiDialogPreview: Default Callback Apply\n";
     d_applyHit = TRUE;
}


void GuiDialogPreview::buttonCallbackCancel ()
{
     this->hide ();
     d_applyHit = FALSE;
}


void GuiDialogPreview::checkboxCallbackPreview ()
{
     if (!d_cbUsePreview.get_active())
          d_previewFrame->set_sensitive (FALSE);
     else
          d_previewFrame->set_sensitive (TRUE);
}


gint GuiDialogPreview::delete_event_impl (GdkEventAny *)
{
     this->hide ();
     return (0);
}



int main (int argc, char *argv[])
{
     GuiDialogPreview    *dp;
     Gtk_Main       dork (&argc, &argv);

     dp = new GuiDialogPreview ("test", "preview", 4, 4);
     dp->show();

     dork.run();

     return 0;
}




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