Re: How to redefine button functionality on a GtkTree?

>>>>> "S" == Steven J Hill <> writes:

 S> I am trying to capture button press events within a
 S> GtkTree. However, I notice that if I press the middle mouse button
 S> on a GtkTreeItem that has a subtree and is collapsed, it expands
 S> the subtree. And if I press the right mouse button, it collapses
 S> the subtree. How do I redefine what those events do and how do I
 S> parse the events to see if the middle or right button was pressed?
 S> I looked at the 'gtk_widget_set_events' method, but I am not quite
 S> sure how to make things work yet. Thanks in advance.

As I understand your question, you want to know

 1) How to determine which button was pressed
 2) How to overwrite a default event handler

Now, the first question is easy.  When you get the button_press event,
you also get a GdkEventButton.  This guy has an entry called button,
which tells you exactly which button was pressed.  So you simply
switch on that one.  See the tree_button_press function in the
attached program.

Now, for question you need to know a little more about
signal/event handling.  I quote from the tutorial "20.2 Signal
Emission and Propagation":

  Signal emission is the process wherby GTK+ runs all handlers for a
  specific object and signal.

  First, note that the return value from a signal emission is the
  return value of the last handler executed.  Since event signals are
  all of type GTK_RUN_LAST, this will be the default (GTK+ supplied)
  default handler, unless you connect with gtk_signal_connect_after().

  The way an event (say GTK_BUTTON_PRESS) is handled, is: 

   *  Start with the widget where the event occured. 

   * Emit the generic "event" signal. If that signal handler returns a
     value of TRUE, stop all processing.

   * Otherwise, emit a specific, "button_press_event" signal. If that
     returns TRUE, stop all processing.  Otherwise, go to the widget's
     parent, and repeat the above steps.

   * Contimue until some signal handler returns TRUE, or until the
     top-level widget is reached.

  Some consequences of the above are: 

   * Your handler's return value will have no effect if there is a
     default handler, unless you connect with

   * To prevent the default handler from being run, you need to
     connect with gtk_signal_connect() and use
     gtk_signal_emit_stop_by_name() - the return value only affects
     whether the signal is propagated, not the current emission.

Now, we want to catch the button_press event, but we *don't* want
default handler to get its hands on it. ('cause we don't want all that
expand/collaps stuff).

So we must intall an event handler with gtk_signal_connect, (or
gtk_signal_connect_object) so _we_ get the signal before the default

Then we must stop futher emission of the signal by calling some
variant of gtk_signal_emit_stop.  Try the attached program with and
without emit_stop.

If you want to propagate the event to the parent widget you return
FALSE, otherwise you return TRUE.  You can try both in
tree_button_press in the test program.  Notice however that since the
default button_press handler stops propagation you will only see the
effect of returning FALSE if you also call emit_stop.

Hope this answers your questions


===File ~/tmp/bar.c=========================================
#include <gtk/gtk.h>

static gint
tree_button_press (GtkWidget *tree,
		   GdkEventButton *event)
  g_return_if_fail (tree != NULL);
  g_return_if_fail (GTK_IS_TREE (tree));

  switch (event->button) {
  case 1:
    g_print ("button 1 was pressed\n");
    /* here we just want the usual behaviour */
    return FALSE;		/* we're not done with the signal */

  case 2:
    g_print ("button 2 was pressed\n");
  case 3:
    g_print ("button 3 was pressed\n");

  /* stop further event processing */
  gtk_signal_emit_stop_by_name (GTK_OBJECT (tree), "button_press_event");
  return TRUE;			/* we're done... */

static gint
win_button_press (GtkWidget *w)
  g_print ("window: button pressed\n");
  return FALSE;			/* not done */

main (int argc, char *argv[]) 
  GtkWidget *window;
  GtkWidget *tree;
  GtkWidget *sub_tree;
  GtkWidget *tree_item;

  gint event_mask;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  tree = gtk_tree_new ();
  gtk_widget_set_usize (tree, 200, 200); /* just so I can see it */
  gtk_container_add (GTK_CONTAINER (window), tree);

  /* make a small tree... */
  tree_item = gtk_tree_item_new_with_label ("foo");
  gtk_tree_append (GTK_TREE (tree), tree_item);
  sub_tree = gtk_tree_new ();
  gtk_tree_item_set_subtree (GTK_TREE_ITEM (tree_item), sub_tree);
  tree_item = gtk_tree_item_new_with_label ("bar");
  gtk_widget_show (tree_item);	/* 'cause show_all wont */
  gtk_tree_append (GTK_TREE (sub_tree), tree_item);
  tree_item = gtk_tree_item_new_with_label ("baz");
  gtk_widget_show (tree_item);	/* 'cause show_all wont */
  gtk_tree_append (GTK_TREE (sub_tree), tree_item);

  gtk_signal_connect (GTK_OBJECT (tree), "button_press_event",
		      GTK_SIGNAL_FUNC (tree_button_press), NULL);
  gtk_signal_connect (GTK_OBJECT (sub_tree), "button_press_event",
		      GTK_SIGNAL_FUNC (tree_button_press), NULL);

  event_mask = gtk_widget_get_events (window) | GDK_BUTTON_PRESS_MASK;
  gtk_widget_set_events (window, event_mask);
  gtk_signal_connect (GTK_OBJECT (window), "button_press_event",
		      GTK_SIGNAL_FUNC (win_button_press), NULL);

  gtk_widget_show_all (window);

  gtk_main ();

  return 0;

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