XORing the GC

I'm testing out Gtk+ on the VMS environment.  The source code was
recently ported to VMS and I've been messing around with the example
programs.  I took the simple-scribble.c program and modified it to
perform rubberbanding, however I'm having trouble with XORing the
results. I want to eliminate the artifacts that result from simply
negating the old line with the background color and rather flip it back
to whatever it was originally.

My basic problem is -- "I don't know when and where I should get the
"Graphic Context" function to XOR.  Do I do it once in the main routine
or when I configure the drawable.  Also, the syntax is giving me
trouble.  I'm using Havoc Pennington's good reference book "GTK+/Gnome
Application Development" as a reference.


Donald G Plugge

Notice the main routine where I play with GtkGC.  The XOR does nothing
at this point, but the code works to rubberband.
Code is as follows:

#include <gtk/gtk.h>

/* Current rubber line coordinates */
  struct {
    gint orig_x;
    gint orig_y;
    gint base_x;
    gint base_y;
    gint dyn_x;
    gint dyn_y;
  } update_line;

/* Phase of selection process*/
  gint phase = 0;

/* Backing pixmap for drawing area */
static GdkPixmap *pixmap = NULL;

/* Create a new backing pixmap of the appropriate size */
static gint configure_event( GtkWidget         *widget,
                             GdkEventConfigure *event )
  g_print ("configure_event\n");
  if (pixmap)

  pixmap = gdk_pixmap_new(widget->window,

  gdk_draw_rectangle (pixmap,
                      widget->style->bg_gc[GTK_WIDGET_STATE (widget)],
                      0, 0,

  return TRUE;

/* Redraw the screen from the backing pixmap */
static gint expose_event( GtkWidget      *widget,
                          GdkEventExpose *event )
  g_print ("expose_event\n");
                  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                  event->area.x, event->area.y,
                  event->area.x, event->area.y,
                  event->area.width, event->area.height);

  return FALSE;

/* Draw a rubber line on the screen using a base position */
static gint rubber_line( GtkWidget *widget,
                        gdouble    x,
                        gdouble    y)
  gdk_draw_line (widget->window,
                      widget->style->bg_gc[GTK_WIDGET_STATE (widget)],
                      update_line.base_x, update_line.base_y,
                      update_line.dyn_x, update_line.dyn_y);
  update_line.dyn_x = x;
  update_line.dyn_y = y;
  gdk_draw_line (widget->window,
                      widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                      update_line.base_x, update_line.base_y,
                      update_line.dyn_x, update_line.dyn_y);

  return FALSE;

static gint button_press_event( GtkWidget      *widget,
                                GdkEventButton *event )
  g_print ("button_press_event\n");
  if (event->button == 1 && pixmap != NULL) {
    if (phase == 0) {
      update_line.orig_x = event->x;
      update_line.orig_y = event->y;
    update_line.base_x = event->x;
    update_line.base_y = event->y;
    phase = 1;
  if (event->button == 3 && pixmap != NULL) {
    update_line.base_x = update_line.orig_x;
    update_line.base_y = update_line.orig_y;
    phase = 2;
  return TRUE;

static gint motion_notify_event( GtkWidget *widget,
                                 GdkEventMotion *event )
  int x, y;
  GdkModifierType state;

  if (event->is_hint) 
    gdk_window_get_pointer (event->window, &x, &y, &state);
      x = event->x;
      y = event->y;
      state = event->state;
  if (phase == 1 && pixmap != NULL)
    rubber_line (widget, x, y);
  return TRUE;

void quit ()
  gtk_exit (0);

int main( int   argc, 
          char *argv[] )
  GtkWidget *window;
  GtkWidget *drawing_area;
  GtkWidget *vbox;
  GdkGC     *gc;

  GtkWidget *button;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_name (window, "Test Input");

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), vbox);
  gtk_widget_show (vbox);

  gtk_signal_connect (GTK_OBJECT (window), "destroy",
                      GTK_SIGNAL_FUNC (quit), NULL);

  /* Create the drawing area */

  drawing_area = gtk_drawing_area_new ();
  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);

  GdkGCValues values;
  values.foreground = window->style->white.pixel ?
    window->style->white : window->style->black;
  values.function = GDK_XOR;
  gc = gdk_gc_new_with_values (GTK_LAYOUT (window),
                               GDK_GC_FOREGROUND | GDK_GC_FUNCTION);

  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);

  gtk_widget_show (drawing_area);

  /* Signals used to handle backing pixmap */

  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
                      (GtkSignalFunc) expose_event, NULL);
  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
                      (GtkSignalFunc) configure_event, NULL);

  /* Event signals */

  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
                      (GtkSignalFunc) motion_notify_event, NULL);
  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
                      (GtkSignalFunc) button_press_event, NULL);

  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
                         | GDK_LEAVE_NOTIFY_MASK
                         | GDK_BUTTON_PRESS_MASK
                         | GDK_POINTER_MOTION_MASK
                         | GDK_POINTER_MOTION_HINT_MASK);

  /* .. And a quit button */
  button = gtk_button_new_with_label ("Quit");
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);

  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                             GTK_SIGNAL_FUNC (gtk_widget_destroy),
                             GTK_OBJECT (window));
  gtk_widget_show (button);

  gtk_widget_show (window);

  gtk_main ();

  return 0;
/* example-end */

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