Re: Get clicks OUTSIDE the window



Havoc Pennington wrote:

> You have to gdk_grab_pointer() and gtk_grab_add() during the time that
> the modal window is active.
I realized that (and the modal window too, or I couldn't gdk_grab
modalwin->window ... :-) ). The Gtk source was useful. But not
sufficient.
The situation is: I have a GtkEntry. When the user right-clicks it, the
modal window (containing two spinbuttons and two buttons) pops up over
it.
In the best case, the "button_press_event" for the entry stays active
for two clicks (the second when the popup is already displayed!), in the
worst case "event" handler for the popup window is never called (so I
have to switch to a terminal and kill the app).
In the Gtk sources (in gtkcombo.c) I saw a comment regarding not
explicitly grabbing button presses, but couldn't understand it...
The other strange thing is that when the cursor is over the spinbutton
entries, it changes (this means that spinbuttons are getting some
events, IIUC), but the buttons won't PRELIGHT when it's over them (so
they don't get some events, apparently).
I tried grabbing a lot of different events (button presses, mouse
movements, etc) - at most I got an X error saying "invalid value" when
using GDK_ALL_EVENTS_MASK .

The relevant code is:

static gboolean _popup_event(GtkWidget *widget, GdkEvent *event,
							 gpointer user_data)
{
  gboolean rv=FALSE;
  switch(event->type) {
    case GDK_DESTROY:
      gdk_pointer_ungrab(GDK_CURRENT_TIME);
      gdk_keyboard_ungrab(GDK_CURRENT_TIME);
      gtk_grab_remove(widget);
      break;
    case GDK_BUTTON_PRESS: {
      // Close window if click is outside
      GdkEventButton *e=(GdkEventButton*)event;
      GtkRequisition req;
      gtk_widget_size_request(widget, &req);
      if(0>e->x || 0>e->y || e->x > req.width || e->y > req.height) {
        gtk_widget_destroy(widget);
        rv=TRUE;
      }
      } break;
    default:
      break;
  }
  return rv;
}

static void gtk_widget_pop_on(GtkWidget *popup, GtkWidget *ref, gboolean
over,
							  gboolean exp_x, gboolean exp_y)
{
  gint x, y, maxx=gdk_screen_width(), maxy=gdk_screen_height(), w, h;
  GtkRequisition req;

  g_assert(popup!=NULL);
  g_assert(ref!=NULL);
  g_assert(GTK_IS_WINDOW(popup));

  // avoid NULL==popup->window
  if(!GTK_WIDGET_REALIZED(popup)) gtk_widget_realize(popup);
  gdk_window_get_origin(ref->window, &x, &y);
  if(!over) {
    // Upper left corner just under 'ref' widget
    gtk_widget_size_request(ref, &req);
    y+=req.height;
  }
  // Anyway, it must stay on screen
  gtk_widget_size_request(popup, &req);
  w=req.width;
  h=req.height;
  x=MIN(x, MAX(0, maxx-w));
  y=MIN(y, MAX(0, maxy-h));
  gtk_widget_popup(popup, x, y);

  if(exp_x)
    w=maxx-x;
  if(exp_y)
    h=maxy-y;

  gtk_widget_set_usize(popup, w, h);
  gtk_object_set_data(GTK_OBJECT(popup), "master", ref);
  gdk_pointer_grab(popup->window, FALSE, GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
| GDK_POINTER_MOTION_MASK, NULL, NULL, GDK_CURRENT_TIME);
  gdk_keyboard_grab(popup->window, TRUE, GDK_CURRENT_TIME);
  gtk_grab_add(popup);

  gtk_signal_connect(GTK_OBJECT(popup), "event", _popup_event, NULL);
}

gboolean
on_search_res_date_button_press_event  (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	gboolean rv=FALSE;
	if(event->button==3) {
		gtk_widget_pop_on(create_date_edit(), widget, TRUE, FALSE, FALSE);
		rv=TRUE;
	}
	return rv;
}

I tried propagating event->time, too, but it didn't work :-(
I bet it's something obvious, once understood...

Tks.

BYtE,
 Diego.



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