static gboolean handle_capture_event_cb (ClutterActor *trough, ClutterEvent *event, StScrollBar *bar) { if (clutter_event_type (event) == CLUTTER_MOTION) { move_slider (bar, ((ClutterMotionEvent*) event)->x, ((ClutterMotionEvent*) event)->y); } else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE && ((ClutterButtonEvent*) event)->button == 1) { ClutterActor *stage, *target; stop_scrolling (bar); /* check if the mouse pointer has left the handle during the drag and * remove the hover state if it has */ stage = clutter_actor_get_stage (bar->priv->trough); target = clutter_stage_get_actor_at_pos ((ClutterStage*) stage, CLUTTER_PICK_REACTIVE, ((ClutterButtonEvent*) event)->x, ((ClutterButtonEvent*) event)->y); if (target != bar->priv->handle) { st_widget_remove_style_pseudo_class ((StWidget*) bar->priv->handle, "hover"); } } return TRUE; }
/* Action signal to move selection was emitted */ static gboolean _xfdashboard_focusable_selection_move_to_direction(XfdashboardFocusable *self, XfdashboardFocusable *inSource, const gchar *inAction, ClutterEvent *inEvent, XfdashboardSelectionTarget inDirection) { ClutterActor *currentSelection; ClutterActor *newSelection; g_return_val_if_fail(XFDASHBOARD_IS_FOCUSABLE(self), CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(inEvent, CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(inDirection<=XFDASHBOARD_SELECTION_TARGET_NEXT, CLUTTER_EVENT_PROPAGATE); /* Check for key press or release event */ if(clutter_event_type(inEvent)!=CLUTTER_KEY_PRESS && clutter_event_type(inEvent)!=CLUTTER_KEY_RELEASE) { return(CLUTTER_EVENT_PROPAGATE); } /* If focusable actor does not support selections return here with event unhandled */ if(!xfdashboard_focusable_supports_selection(self)) return(CLUTTER_EVENT_PROPAGATE); /* Find new selection */ currentSelection=xfdashboard_focusable_get_selection(self); newSelection=xfdashboard_focusable_find_selection(self, currentSelection, inDirection); /* Set new selection */ xfdashboard_focusable_set_selection(self, newSelection); /* All done so return and stop further processing of this action */ return(CLUTTER_EVENT_STOP); }
static gboolean actor_captured_event_cb (ClutterActor *actor, ClutterEvent *event, ClutterGestureAction *action) { ClutterGestureActionPrivate *priv = action->priv; GesturePoint *point G_GNUC_UNUSED; if ((clutter_event_type (event) != CLUTTER_BUTTON_PRESS) && (clutter_event_type (event) != CLUTTER_TOUCH_BEGIN)) return CLUTTER_EVENT_PROPAGATE; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) return CLUTTER_EVENT_PROPAGATE; point = gesture_register_point (action, event); if (priv->stage == NULL) priv->stage = clutter_actor_get_stage (actor); if (priv->stage_capture_id == 0) priv->stage_capture_id = g_signal_connect_after (priv->stage, "captured-event", G_CALLBACK (stage_captured_event_cb), action); /* Start the gesture immediately if the gesture has no * _TRIGGER_EDGE_AFTER drag threshold. */ if ((priv->points->len >= priv->requested_nb_points) && (priv->edge != CLUTTER_GESTURE_TRIGGER_EDGE_AFTER)) begin_gesture (action, actor); return CLUTTER_EVENT_PROPAGATE; }
static gboolean on_handle_capture_event (ClutterActor *trough, ClutterEvent *event, MxSlider *bar) { MxSliderPrivate *priv = bar->priv; if (clutter_event_type (event) == CLUTTER_MOTION) { drag_handle (bar, ((ClutterMotionEvent*)event)->x, ((ClutterMotionEvent*)event)->y); } else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE && ((ClutterButtonEvent*)event)->button == 1) { ClutterActor *stage, *target; stage = clutter_actor_get_stage(priv->trough); if (priv->capture_handler) { g_signal_handler_disconnect (stage, priv->capture_handler); priv->capture_handler = 0; /* update the handle position */ mx_slider_allocate_fill_handle (bar, NULL, 0); clutter_actor_queue_redraw (CLUTTER_ACTOR (bar)); } clutter_stage_set_motion_events_enabled (CLUTTER_STAGE (stage), TRUE); /* check if the mouse pointer has left the handle during the drag and * remove the hover state if it has */ target = clutter_stage_get_actor_at_pos ((ClutterStage*) stage, CLUTTER_PICK_REACTIVE, ((ClutterButtonEvent*) event)->x, ((ClutterButtonEvent*) event)->y); if (target != priv->handle) { mx_stylable_set_style_pseudo_class (MX_STYLABLE (priv->handle), NULL); } /* emit the stop signal */ g_signal_emit (bar, signals[SLIDE_STOP], 0); } return FALSE; }
/* An event after a tooltip was shown so check if tooltip should be hidden again */ static gboolean _xfdashboard_tooltip_action_on_captured_event_after_tooltip(XfdashboardTooltipAction *self, ClutterEvent *inEvent, gpointer inUserData) { gboolean doHide; g_return_val_if_fail(XFDASHBOARD_IS_TOOLTIP_ACTION(self), CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(XFDASHBOARD_IS_STAGE(inUserData), CLUTTER_EVENT_PROPAGATE); /* Check if tooltip should be hidden depending on event type */ switch(clutter_event_type(inEvent)) { case CLUTTER_NOTHING: case CLUTTER_MOTION: doHide=FALSE; break; default: doHide=TRUE; break; } /* Hide tooltip if requested */ if(doHide) { _xfdashboard_tooltip_action_on_leave_event(self, inEvent, inUserData); } return(CLUTTER_EVENT_PROPAGATE); }
static GesturePoint * gesture_find_point (ClutterGestureAction *action, ClutterEvent *event, gint *position) { ClutterGestureActionPrivate *priv = action->priv; GesturePoint *point = NULL; ClutterEventType type = clutter_event_type (event); ClutterInputDevice *device = clutter_event_get_device (event); ClutterEventSequence *sequence = NULL; gint i; if ((type != CLUTTER_BUTTON_PRESS) && (type != CLUTTER_BUTTON_RELEASE) && (type != CLUTTER_MOTION)) sequence = clutter_event_get_event_sequence (event); for (i = 0; i < priv->points->len; i++) { if ((g_array_index (priv->points, GesturePoint, i).device == device) && (g_array_index (priv->points, GesturePoint, i).sequence == sequence)) { if (position != NULL) *position = i; point = &g_array_index (priv->points, GesturePoint, i); break; } } return point; }
static void drag_grab_button (MetaWaylandPointerGrab *grab, const ClutterEvent *event) { MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; MetaWaylandSeat *seat = drag_grab->seat; ClutterEventType event_type = clutter_event_type (event); if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) && event_type == CLUTTER_BUTTON_RELEASE) { gboolean success = FALSE; if (drag_grab->drag_focus_data_device && drag_grab->drag_data_source->has_target) { wl_data_device_send_drop (drag_grab->drag_focus_data_device); success = TRUE; } /* Finish drag and let actor self-destruct */ meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor), success); drag_grab->feedback_actor = NULL; } if (seat->pointer.button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE) data_device_end_drag_grab (drag_grab); }
static GesturePoint * gesture_register_point (ClutterGestureAction *action, ClutterEvent *event) { ClutterGestureActionPrivate *priv = action->priv; GesturePoint *point = NULL; if (priv->points->len >= MAX_GESTURE_POINTS) return NULL; g_array_set_size (priv->points, priv->points->len + 1); point = &g_array_index (priv->points, GesturePoint, priv->points->len - 1); point->last_event = clutter_event_copy (event); point->device = clutter_event_get_device (event); clutter_event_get_coords (event, &point->press_x, &point->press_y); point->last_motion_x = point->press_x; point->last_motion_y = point->press_y; point->last_motion_time = clutter_event_get_time (event); point->last_delta_x = point->last_delta_y = 0; point->last_delta_time = 0; if (clutter_event_type (event) != CLUTTER_BUTTON_PRESS) point->sequence = clutter_event_get_event_sequence (event); else point->sequence = NULL; return point; }
static gboolean handle_capture_event_cb (ClutterActor *trough, ClutterEvent *event, MxScrollBar *bar) { if (clutter_event_type (event) == CLUTTER_MOTION) { move_slider (bar, ((ClutterMotionEvent*) event)->x, ((ClutterMotionEvent*) event)->y); } else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE && ((ClutterButtonEvent*) event)->button == 1) { ClutterActor *stage, *target; stage = clutter_actor_get_stage(bar->priv->trough); if (bar->priv->capture_handler) { g_signal_handler_disconnect (stage, bar->priv->capture_handler); bar->priv->capture_handler = 0; } clutter_set_motion_events_enabled (TRUE); g_signal_emit (bar, signals[SCROLL_STOP], 0); /* check if the mouse pointer has left the handle during the drag and * remove the hover state if it has */ target = clutter_stage_get_actor_at_pos ((ClutterStage*) stage, CLUTTER_PICK_REACTIVE, ((ClutterButtonEvent*) event)->x, ((ClutterButtonEvent*) event)->y); if (target != bar->priv->handle) { mx_stylable_set_style_pseudo_class (MX_STYLABLE (bar->priv->handle), NULL); } else { /* allow the release event to continue to the handle for processing */ return FALSE; } } return TRUE; }
gboolean Animation::handleTouchEvents(ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterEventType eventType = clutter_event_type(event); // if (eventType == CLUTTER_TOUCH_END) { // // printf("Touch end!\n"); // // } else if (eventType == CLUTTER_TOUCH_UPDATE || eventType == CLUTTER_MOTION) { // Rebuild the struct from the pointer we handed in: // TouchData *data; // data = (TouchData *) user_data; gfloat stage_x, stage_y; gfloat actor_x = 0, actor_y = 0; clutter_event_get_coords(event, &stage_x, &stage_y); clutter_actor_transform_stage_point(actor, stage_x, stage_y, &actor_x, &actor_y); // printf("Touch Move!!\nx: %f\ny: %f\n\n", actor_x, actor_y ); // Now we have some x,y coordinates we can throw back at those animations! // but we should probably scale them now since we have all the stuff we need // to do so in this block... // // This will scale both to 0.0 <-> 255.0: //actor_x = actor_x / clutter_actor_get_width(actor) * 255; //actor_y = actor_y / clutter_actor_get_height(actor) * 255; // This will scale both to the actual on screen pixel size: actor_x = actor_x * osd_scale; actor_y = actor_y * osd_scale; // We only want integers: temp_x = static_cast<int>(actor_x); temp_y = static_cast<int>(actor_y); // And this will map the values around so that we can use the full range even though // the edges of the touchscreen are not really touchable: input_x = map(temp_x, 0, WIDTH*osd_scale, 0, WIDTH*osd_scale+(WIDTH*osd_scale-150)); input_y = map(temp_y, 0, HEIGHT*osd_scale, 0-50, HEIGHT*osd_scale+(HEIGHT*osd_scale-750)); // input_x = temp_x; // input_y = temp_y; // printf("Touch Move!!\nx: %i\ny: %i\n\n", input_x, input_y ); } // else { // // printf("Some other touch event %i\n", eventType); // } return CLUTTER_EVENT_STOP; }
static gboolean on_captured_event (ClutterActor *stage, ClutterEvent *event, ClutterDragAction *action) { ClutterDragActionPrivate *priv = action->priv; ClutterActor *actor; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); if (!priv->in_drag) return FALSE; switch (clutter_event_type (event)) { case CLUTTER_MOTION: { ClutterModifierType mods = clutter_event_get_state (event); /* we might miss a button-release event in case of grabs, * so we need to check whether the button is still down * during a motion event */ if (mods & CLUTTER_BUTTON1_MASK) emit_drag_motion (action, actor, event); else emit_drag_end (action, actor, event); } break; case CLUTTER_BUTTON_RELEASE: if (priv->in_drag) emit_drag_end (action, actor, event); break; case CLUTTER_ENTER: case CLUTTER_LEAVE: if (priv->in_drag) return TRUE; break; default: break; } return FALSE; }
static gboolean button_event_cb (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { gfloat x, y; gchar *event_type; guint button_pressed; ClutterModifierType state; gchar *ctrl_pressed; guint32 click_count; /* where the pointer was when the button event occurred */ clutter_event_get_coords (event, &x, &y); /* check whether it was a press or release event */ event_type = "released"; if (clutter_event_type (event) == CLUTTER_BUTTON_PRESS) event_type = "pressed"; /* which button triggered the event */ button_pressed = clutter_event_get_button (event); /* keys down when the button was pressed */ state = clutter_event_get_state (event); ctrl_pressed = "ctrl not pressed"; if (state & CLUTTER_CONTROL_MASK) ctrl_pressed = "ctrl pressed"; /* click count */ click_count = clutter_event_get_click_count (event); g_debug ("button %d %s at %.0f,%.0f; %s; click count %d", button_pressed, event_type, x, y, ctrl_pressed, click_count); return TRUE; }
static gboolean st_im_text_captured_event (ClutterActor *actor, ClutterEvent *event) { StIMText *self = ST_IM_TEXT (actor); StIMTextPrivate *priv = self->priv; ClutterText *clutter_text = CLUTTER_TEXT (actor); ClutterEventType type = clutter_event_type (event); gboolean result = FALSE; int old_position; if (type != CLUTTER_KEY_PRESS && type != CLUTTER_KEY_RELEASE) return FALSE; if (clutter_text_get_editable (clutter_text)) { GdkEventKey *event_gdk = key_event_to_gdk ((ClutterKeyEvent *)event); if (gtk_im_context_filter_keypress (priv->im_context, event_gdk)) { priv->need_im_reset = TRUE; result = TRUE; } gdk_event_free ((GdkEvent *)event_gdk); } old_position = clutter_text_get_cursor_position (clutter_text); if (!result && CLUTTER_ACTOR_CLASS (st_im_text_parent_class)->captured_event) result = CLUTTER_ACTOR_CLASS (st_im_text_parent_class)->captured_event (actor, event); if (type == CLUTTER_KEY_PRESS && clutter_text_get_cursor_position (clutter_text) != old_position) reset_im_context (self); return result; }
/* input handler */ static gboolean input_cb (ClutterStage *stage, ClutterEvent *event, gpointer data) { ClutterEventType event_type = clutter_event_type (event); SuperOH *oh = data; if (event_type == CLUTTER_BUTTON_PRESS) { ClutterActor *a; gfloat x, y; clutter_event_get_coords (event, &x, &y); a = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, x, y); if (a != NULL && (CLUTTER_IS_TEXTURE (a) || CLUTTER_IS_CLONE (a))) clutter_actor_hide (a); } else if (event->type == CLUTTER_KEY_PRESS) { g_print ("*** key press event (key:%c) ***\n", clutter_event_get_key_symbol (event)); if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_q) gtk_main_quit (); else if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_r) { int i; for (i = 0; i < NHANDS; i++) clutter_actor_show (oh->hand[i]); } } return TRUE; }
IO_METHOD(IoClutterEvent, eventType) { return IONUMBER(clutter_event_type(IOCEVENT(self))); }
/** * cinnamon_tray_icon_click: * @icon: a #CinnamonTrayIcon * @event: the #ClutterEvent triggering the fake click * * Fakes a press and release on @icon. @event must be a * %CLUTTER_BUTTON_RELEASE event. Its relevant details will be passed * on to the icon, but its coordinates will be ignored; the click is * always made on the center of @icon. */ void cinnamon_tray_icon_click (CinnamonTrayIcon *icon, ClutterEvent *event) { XButtonEvent xbevent; XCrossingEvent xcevent; GdkWindow *remote_window; GdkScreen *screen; int x_root, y_root; Display *xdisplay; Window xwindow, xrootwindow; g_return_if_fail (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE); gdk_error_trap_push (); remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); if (remote_window == NULL) { g_warning ("cinnamon tray: plug window is gone"); gdk_error_trap_pop_ignored (); return; } xwindow = GDK_WINDOW_XID (remote_window); xdisplay = GDK_WINDOW_XDISPLAY (remote_window); screen = gdk_window_get_screen (remote_window); xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); gdk_window_get_origin (remote_window, &x_root, &y_root); /* First make the icon believe the pointer is inside it */ xcevent.type = EnterNotify; xcevent.window = xwindow; xcevent.root = xrootwindow; xcevent.subwindow = None; xcevent.time = clutter_event_get_time (event); xcevent.x = gdk_window_get_width (remote_window) / 2; xcevent.y = gdk_window_get_height (remote_window) / 2; xcevent.x_root = x_root + xcevent.x; xcevent.y_root = y_root + xcevent.y; xcevent.mode = NotifyNormal; xcevent.detail = NotifyNonlinear; xcevent.same_screen = True; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); /* Now do the click */ xbevent.type = ButtonPress; xbevent.window = xwindow; xbevent.root = xrootwindow; xbevent.subwindow = None; xbevent.time = xcevent.time; xbevent.x = xcevent.x; xbevent.y = xcevent.y; xbevent.x_root = xcevent.x_root; xbevent.y_root = xcevent.y_root; xbevent.state = clutter_event_get_state (event); xbevent.button = clutter_event_get_button (event); xbevent.same_screen = True; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); xbevent.type = ButtonRelease; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); /* And move the pointer back out */ xcevent.type = LeaveNotify; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); gdk_error_trap_pop_ignored (); }
/* Handle key event (it is either key-press or key-release) by focusable actor * which has the focus or by specified actor. */ gboolean xfdashboard_focus_manager_handle_key_event(XfdashboardFocusManager *self, const ClutterEvent *inEvent, XfdashboardFocusable *inFocusable) { XfdashboardFocusManagerPrivate *priv; g_return_val_if_fail(XFDASHBOARD_IS_FOCUS_MANAGER(self), CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(inEvent, CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(clutter_event_type(inEvent)==CLUTTER_KEY_PRESS || clutter_event_type(inEvent)==CLUTTER_KEY_RELEASE, CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(!inFocusable || XFDASHBOARD_IS_FOCUSABLE(inFocusable), CLUTTER_EVENT_PROPAGATE); priv=self->priv; /* If no focusable actor was specified then use current focused actor */ if(!inFocusable) { inFocusable=priv->currentFocus; /* If still no focusable actor is available we cannot handle event * so let the others try it by propagating event. */ if(!inFocusable) return(CLUTTER_EVENT_PROPAGATE); } /* Synthesize event for specified focusable actor */ if(inFocusable) { XfdashboardBindingsPool *bindings; const XfdashboardBinding *binding; gboolean eventStatus; /* Take reference on ourselve and the focusable actor to keep them alive when handling event */ g_object_ref(self); g_object_ref(inFocusable); /* Lookup action for event and emit action if a binding was found * for this event. */ eventStatus=CLUTTER_EVENT_PROPAGATE; bindings=xfdashboard_bindings_pool_get_default(); binding=xfdashboard_bindings_pool_find_for_event(bindings, CLUTTER_ACTOR(inFocusable), inEvent); if(binding) { const gchar *target; const gchar *action; GSList *targetFocusables; GSList *iter; GSignalQuery signalData={ 0, }; /* Get action of binding */ action=xfdashboard_binding_get_action(binding); /* Build up list of targets which is either the requested focusable actor, * the current focused actor or focusable actors of a specific type */ targetFocusables=NULL; target=xfdashboard_binding_get_target(binding); if(target) { /* Target class name is specified so build up a list of targets */ targetFocusables=_xfdashboard_focus_manager_get_targets_for_binding(self, binding); } else { /* No target class name was specified so add requested focusable * actor to list of target. */ targetFocusables=g_slist_append(targetFocusables, g_object_ref(inFocusable)); } g_debug("Target list for action '%s' has %d actors", action, g_slist_length(targetFocusables)); /* Emit action of binding to each actor in target list just build up */ for(iter=targetFocusables; iter; iter=g_slist_next(iter)) { GObject *targetObject; guint signalID; /* Get target to emit action signal at */ targetObject=G_OBJECT(iter->data); /* Check if target provides action requested as signal */ signalID=g_signal_lookup(action, G_OBJECT_TYPE(targetObject)); if(!signalID) { g_warning(_("Object type %s does not provide action '%s'"), G_OBJECT_TYPE_NAME(targetObject), action); continue; } /* Query signal for detailed data */ g_signal_query(signalID, &signalData); /* Check if signal is an action signal */ if(!(signalData.signal_flags & G_SIGNAL_ACTION)) { g_warning(_("Action '%s' at object type %s is not an action signal."), action, G_OBJECT_TYPE_NAME(targetObject)); continue; } #if DEBUG /* In debug mode also check if signal has right signature * to be able to handle this action properly. */ if(signalID) { GType returnValueType=G_TYPE_BOOLEAN; GType parameterTypes[]={ XFDASHBOARD_TYPE_FOCUSABLE, G_TYPE_STRING, CLUTTER_TYPE_EVENT }; guint parameterCount; guint i; /* Check if signal wants the right type of return value */ if(signalData.return_type!=returnValueType) { g_critical(_("Action '%s' at object type %s wants return value of type %s but expected is %s."), action, G_OBJECT_TYPE_NAME(targetObject), g_type_name(signalData.return_type), g_type_name(returnValueType)); } /* Check if signals wants the right number and types of parameters */ parameterCount=sizeof(parameterTypes)/sizeof(GType); if(signalData.n_params!=parameterCount) { g_critical(_("Action '%s' at object type %s wants %u parameters but expected are %u."), action, G_OBJECT_TYPE_NAME(targetObject), signalData.n_params, parameterCount); } for(i=0; i<(parameterCount<signalData.n_params ? parameterCount : signalData.n_params); i++) { if(signalData.param_types[i]!=parameterTypes[i]) { g_critical(_("Action '%s' at object type %s wants type %s at parameter %u but type %s is expected."), action, G_OBJECT_TYPE_NAME(targetObject), g_type_name(signalData.param_types[i]), i+1, g_type_name(parameterTypes[i])); } } } #endif /* Emit action signal at target */ g_debug("Emitting action signal '%s' at focusable actor %s", action, G_OBJECT_TYPE_NAME(targetObject)); g_signal_emit_by_name(targetObject, action, inFocusable, action, inEvent, &eventStatus); g_debug("Action signal '%s' was %s by focusable actor %s", action, eventStatus==CLUTTER_EVENT_STOP ? "handled" : "not handled", G_OBJECT_TYPE_NAME(targetObject)); } /* Release allocated resources */ g_slist_free_full(targetFocusables, g_object_unref); } g_object_unref(bindings); /* Release reference on ourselve and the focusable actor to took to keep them alive */ g_object_unref(inFocusable); g_object_unref(self); if(eventStatus==CLUTTER_EVENT_STOP) return(CLUTTER_EVENT_STOP); } /* Event was not handled so synthesize event to specified focusable actor */ return(clutter_actor_event(CLUTTER_ACTOR(inFocusable), inEvent, FALSE)); }
static gboolean on_captured_event (ClutterActor *stage, ClutterEvent *event, ClutterClickAction *action) { ClutterClickActionPrivate *priv = action->priv; ClutterActor *actor; ClutterModifierType modifier_state; gboolean has_button = TRUE; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); switch (clutter_event_type (event)) { case CLUTTER_TOUCH_END: has_button = FALSE; case CLUTTER_BUTTON_RELEASE: if (!priv->is_held) return CLUTTER_EVENT_STOP; if ((has_button && clutter_event_get_button (event) != priv->press_button) || (has_button && clutter_event_get_click_count (event) != 1) || clutter_event_get_device_id (event) != priv->press_device_id || clutter_event_get_event_sequence (event) != priv->press_sequence) return CLUTTER_EVENT_PROPAGATE; click_action_set_held (action, FALSE); click_action_cancel_long_press (action); /* disconnect the capture */ if (priv->capture_id != 0) { g_signal_handler_disconnect (priv->stage, priv->capture_id); priv->capture_id = 0; } if (priv->long_press_id != 0) { g_source_remove (priv->long_press_id); priv->long_press_id = 0; } if (!clutter_actor_contains (actor, clutter_event_get_source (event))) return CLUTTER_EVENT_PROPAGATE; /* exclude any button-mask so that we can compare * the press and release states properly */ modifier_state = clutter_event_get_state (event) & ~(CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK | CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK); /* if press and release states don't match we * simply ignore modifier keys. i.e. modifier keys * are expected to be pressed throughout the whole * click */ if (modifier_state != priv->modifier_state) priv->modifier_state = 0; click_action_set_pressed (action, FALSE); g_signal_emit (action, click_signals[CLICKED], 0, actor); break; case CLUTTER_MOTION: case CLUTTER_TOUCH_UPDATE: { gfloat motion_x, motion_y; gfloat delta_x, delta_y; if (!priv->is_held) return CLUTTER_EVENT_PROPAGATE; clutter_event_get_coords (event, &motion_x, &motion_y); delta_x = ABS (motion_x - priv->press_x); delta_y = ABS (motion_y - priv->press_y); if (delta_x > priv->drag_threshold || delta_y > priv->drag_threshold) click_action_cancel_long_press (action); } break; default: break; } return CLUTTER_EVENT_STOP; }
static gboolean on_event (ClutterActor *actor, ClutterEvent *event, ClutterClickAction *action) { ClutterClickActionPrivate *priv = action->priv; gboolean has_button = TRUE; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) return CLUTTER_EVENT_PROPAGATE; switch (clutter_event_type (event)) { case CLUTTER_TOUCH_BEGIN: has_button = FALSE; case CLUTTER_BUTTON_PRESS: if (has_button && clutter_event_get_click_count (event) != 1) return CLUTTER_EVENT_PROPAGATE; if (priv->is_held) return CLUTTER_EVENT_STOP; if (!clutter_actor_contains (actor, clutter_event_get_source (event))) return CLUTTER_EVENT_PROPAGATE; priv->press_button = has_button ? clutter_event_get_button (event) : 0; priv->press_device_id = clutter_event_get_device_id (event); priv->press_sequence = clutter_event_get_event_sequence (event); priv->modifier_state = clutter_event_get_state (event); clutter_event_get_coords (event, &priv->press_x, &priv->press_y); if (priv->long_press_threshold < 0) { ClutterSettings *settings = clutter_settings_get_default (); g_object_get (settings, "dnd-drag-threshold", &priv->drag_threshold, NULL); } else priv->drag_threshold = priv->long_press_threshold; if (priv->stage == NULL) priv->stage = clutter_actor_get_stage (actor); priv->capture_id = g_signal_connect_after (priv->stage, "captured-event", G_CALLBACK (on_captured_event), action); click_action_set_pressed (action, TRUE); click_action_set_held (action, TRUE); click_action_query_long_press (action); break; case CLUTTER_ENTER: click_action_set_pressed (action, priv->is_held); break; case CLUTTER_LEAVE: click_action_set_pressed (action, priv->is_held); click_action_cancel_long_press (action); break; default: break; } return CLUTTER_EVENT_PROPAGATE; }
/* An event was received */ static gboolean _xfdashboard_click_action_on_event(XfdashboardClickAction *self, ClutterEvent *inEvent, gpointer inUserData) { XfdashboardClickActionPrivate *priv; gboolean hasButton; ClutterActor *actor; g_return_val_if_fail(XFDASHBOARD_IS_CLICK_ACTION(self), CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(CLUTTER_IS_ACTOR(inUserData), CLUTTER_EVENT_PROPAGATE); priv=self->priv; hasButton=TRUE; actor=CLUTTER_ACTOR(inUserData); /* Check if actor is enabled to handle events */ if(!clutter_actor_meta_get_enabled(CLUTTER_ACTOR_META(self))) return(CLUTTER_EVENT_PROPAGATE); /* Handle event */ switch(clutter_event_type(inEvent)) { case CLUTTER_TOUCH_BEGIN: hasButton=FALSE; case CLUTTER_BUTTON_PRESS: /* We only handle single clicks if it is pointer device */ if(hasButton && clutter_event_get_click_count(inEvent)!=1) { return(CLUTTER_EVENT_PROPAGATE); } /* Do we already held the press? */ if(priv->isHeld) return(CLUTTER_EVENT_STOP); /* Is the source of event a child of this actor. If not do * not handle this event but any other. */ if(!clutter_actor_contains(actor, clutter_event_get_source(inEvent))) { return(CLUTTER_EVENT_PROPAGATE); } /* Remember event data */ priv->pressButton=hasButton ? clutter_event_get_button(inEvent) : 0; priv->pressDeviceID=clutter_event_get_device_id(inEvent); priv->pressSequence=clutter_event_get_event_sequence(inEvent); priv->modifierState=clutter_event_get_state(inEvent); clutter_event_get_coords(inEvent, &priv->pressX, &priv->pressY); if(priv->longPressThreshold<0) { ClutterSettings *settings=clutter_settings_get_default(); g_object_get(settings, "dnd-drag-threshold", &priv->dragThreshold, NULL); } else priv->dragThreshold=priv->longPressThreshold; if(priv->stage==NULL) priv->stage=clutter_actor_get_stage(actor); /* Connect signals */ priv->captureID=g_signal_connect_object(priv->stage, "captured-event", G_CALLBACK(_xfdashboard_click_action_on_captured_event), self, G_CONNECT_AFTER | G_CONNECT_SWAPPED); /* Set state of this action */ _xfdashboard_click_action_set_pressed(self, TRUE); _xfdashboard_click_action_set_held(self, TRUE); _xfdashboard_click_action_query_long_press(self); break; case CLUTTER_ENTER: _xfdashboard_click_action_set_pressed(self, priv->isHeld); break; case CLUTTER_LEAVE: _xfdashboard_click_action_set_pressed(self, priv->isHeld); _xfdashboard_click_action_cancel_long_press(self); break; default: break; } return(CLUTTER_EVENT_PROPAGATE); }
/* An event was captured */ static gboolean _xfdashboard_click_action_on_captured_event(XfdashboardClickAction *self, ClutterEvent *inEvent, gpointer inUserData) { XfdashboardClickActionPrivate *priv; ClutterActor *stage G_GNUC_UNUSED; ClutterActor *actor; ClutterModifierType modifierState; gboolean hasButton; g_return_val_if_fail(XFDASHBOARD_IS_CLICK_ACTION(self), CLUTTER_EVENT_PROPAGATE); g_return_val_if_fail(CLUTTER_IS_ACTOR(inUserData), CLUTTER_EVENT_PROPAGATE); priv=self->priv; stage=CLUTTER_ACTOR(inUserData); hasButton=TRUE; /* Handle captured event */ actor=clutter_actor_meta_get_actor(CLUTTER_ACTOR_META(self)); switch(clutter_event_type(inEvent)) { case CLUTTER_TOUCH_END: hasButton=FALSE; case CLUTTER_BUTTON_RELEASE: if(!priv->isHeld) return(CLUTTER_EVENT_STOP); if((hasButton && clutter_event_get_button(inEvent)!=priv->pressButton) || (hasButton && clutter_event_get_click_count(inEvent)!=1) || clutter_event_get_device_id(inEvent)!=priv->pressDeviceID || clutter_event_get_event_sequence(inEvent)!=priv->pressSequence) { return(CLUTTER_EVENT_PROPAGATE); } _xfdashboard_click_action_set_held(self, FALSE); _xfdashboard_click_action_cancel_long_press(self); /* Disconnect the capture */ if(priv->captureID!=0) { g_signal_handler_disconnect(priv->stage, priv->captureID); priv->captureID = 0; } if(priv->longPressID!=0) { g_source_remove(priv->longPressID); priv->longPressID=0; } if(!clutter_actor_contains(actor, clutter_event_get_source(inEvent))) { return(CLUTTER_EVENT_PROPAGATE); } /* Exclude any button-mask so that we can compare * the press and release states properly */ modifierState=clutter_event_get_state(inEvent) & ~(CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK | CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK); /* If press and release states don't match we simply ignore * modifier keys. i.e. modifier keys are expected to be pressed * throughout the whole click */ if(modifierState!=priv->modifierState) priv->modifierState=0; _xfdashboard_click_action_set_pressed(self, FALSE); g_signal_emit(self, XfdashboardClickActionSignals[SIGNAL_CLICKED], 0, actor); break; case CLUTTER_MOTION: case CLUTTER_TOUCH_UPDATE: { gfloat motionX, motionY; gfloat deltaX, deltaY; if(!priv->isHeld) return(CLUTTER_EVENT_PROPAGATE); clutter_event_get_coords (inEvent, &motionX, &motionY); deltaX=ABS(motionX-priv->pressX); deltaY=ABS(motionY-priv->pressY); if(deltaX>priv->dragThreshold || deltaY>priv->dragThreshold) { _xfdashboard_click_action_cancel_long_press(self); } } break; default: break; } /* This is line changed in returning CLUTTER_EVENT_PROPAGATE * instead of CLUTTER_EVENT_STOP */ return(CLUTTER_EVENT_PROPAGATE); }
/* Dragged actor moved */ static void _xfdashboard_drag_action_drag_motion(ClutterDragAction *inAction, ClutterActor *inActor, gfloat inDeltaX, gfloat inDeltaY) { XfdashboardDragAction *self; XfdashboardDragActionPrivate *priv; ClutterDragActionClass *dragActionClass; gfloat stageX, stageY; XfdashboardDropAction *dropTarget; gfloat dropX, dropY; const ClutterEvent *event; g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inAction)); self=XFDASHBOARD_DRAG_ACTION(inAction); priv=self->priv; dragActionClass=CLUTTER_DRAG_ACTION_CLASS(xfdashboard_drag_action_parent_class); /* Call parent's class method */ if(dragActionClass->drag_motion) dragActionClass->drag_motion(inAction, inActor, inDeltaX, inDeltaY); /* Remember motion delta coordinates */ priv->lastDeltaX=inDeltaX; priv->lastDeltaY=inDeltaY; /* Get event coordinates relative to stage */ clutter_drag_action_get_motion_coords(inAction, &stageX, &stageY); /* Find drop target at stage coordinate */ dropTarget=_xfdashboard_drag_action_find_drop_traget_at_coord(self, stageX, stageY); /* If found drop target is not the same as the last one emit "drag-leave" * signal at last drop target and "drag-enter" in new drop target */ if(priv->lastDropTarget!=dropTarget) { /* Emit "drag-leave" signal on last drop target */ if(priv->lastDropTarget) { g_signal_emit_by_name(priv->lastDropTarget, "drag-leave", self, NULL); priv->lastDropTarget=NULL; } /* Check if new drop target is active and emit "drag-enter" signal */ if(dropTarget) { ClutterActorMeta *actorMeta=CLUTTER_ACTOR_META(dropTarget); ClutterActor *dropActor=clutter_actor_meta_get_actor(actorMeta); if(clutter_actor_meta_get_enabled(actorMeta) && clutter_actor_is_visible(dropActor) && clutter_actor_get_reactive(dropActor)) { g_signal_emit_by_name(dropTarget, "drag-enter", self, NULL); priv->lastDropTarget=dropTarget; } } } /* Transform event coordinates relative to last drop target which * should be the drop target under pointer device if it is active * and emit "drag-motion" signal */ if(priv->lastDropTarget) { dropX=dropY=0.0f; _xfdashboard_drag_action_transform_stage_point(priv->lastDropTarget, stageX, stageY, &dropX, &dropY); g_signal_emit_by_name(priv->lastDropTarget, "drag-motion", self, dropX, dropY, NULL); } /* We are derived from ClutterDragAction and this one disables stage motion * so no "enter-event", "motion-event" and "leave-event" will be emitted while * dragging. We need to do it on our own. */ event=clutter_get_current_event(); if(event && clutter_event_type(event)==CLUTTER_MOTION) { GSList *list, *next; ClutterStage *stage; ClutterActor *motionActor; gboolean newMotionActor; ClutterActor *actor; gfloat x, y, w, h; gboolean result; ClutterEvent *actorEvent; /* Get stage where event happened */ stage=clutter_event_get_stage(event); if(stage) { /* Get actor under pointer */ newMotionActor=TRUE; motionActor=clutter_stage_get_actor_at_pos(stage, CLUTTER_PICK_REACTIVE, stageX, stageY); /* Iterate through list of crossed actors so far and check if pointer * is still inside. If pointer is outside of an actor emit "leave-event". * For each actor the pointer is still inside emit this "motion-event". * Also check if actor under pointer is already is list to prevent * "enter-event" to be emitted more than once. */ list=priv->lastMotionActors; while(list) { /* Get next entry now as this entry might get deleted */ next=g_slist_next(list); /* Get actor from entry */ actor=CLUTTER_ACTOR(list->data); /* Actor must be one same stage where event happened */ if(clutter_actor_get_stage(actor)!=CLUTTER_ACTOR(stage)) continue; /* Get position and size of actor in stage coordinates */ clutter_actor_get_transformed_position(actor, &x, &y); clutter_actor_get_transformed_size(actor, &w, &h); /* Check if pointer is still inside actor */ if(stageX>=x && stageX<(x+w) && stageY>=y && stageY<(y+h)) { /* Check if actor is the "new" motion actor. If so set flag. */ if(actor==motionActor) newMotionActor=FALSE; /* Emit "motion-event" */ actorEvent=clutter_event_copy(event); actorEvent->motion.source=actor; g_signal_emit_by_name(actor, "motion-event", actorEvent, &result); clutter_event_free(actorEvent); } /* Pointer is not inside actor anymore so remove actor from list * of last known "motion actors" and send "leave-event" */ else { /* Disconnect signal */ g_signal_handlers_disconnect_by_func(actor, G_CALLBACK(_xfdashboard_drag_action_on_motion_actor_destroyed), self); /* Remove from list */ priv->lastMotionActors=g_slist_remove_link(priv->lastMotionActors, list); g_slist_free_1(list); /* Create and emit "leave-event" */ actorEvent=clutter_event_new(CLUTTER_LEAVE); actorEvent->crossing.time=event->motion.time; actorEvent->crossing.flags=event->motion.flags; actorEvent->crossing.stage=event->motion.stage; actorEvent->crossing.source=actor; actorEvent->crossing.x=event->motion.x; actorEvent->crossing.y=event->motion.y; actorEvent->crossing.device=event->motion.device; actorEvent->crossing.related=event->motion.source; g_signal_emit_by_name(actor, "leave-event", actorEvent, &result); clutter_event_free(actorEvent); } /* Proceed with next actor */ list=next; } /* We have an actor under pointer and was not seen while iterating * through list of all last known "motion actors" then add this actor * to list and emit "enter-event" and also all parent actors because * if pointer is inside their child then it is also inside them. */ if(motionActor && newMotionActor) { while(motionActor) { /* Avoid duplicates */ if(!g_slist_find(priv->lastMotionActors, motionActor)) { /* Add to list */ priv->lastMotionActors=g_slist_append(priv->lastMotionActors, motionActor); /* Create and emit "enter-event" */ actorEvent=clutter_event_new(CLUTTER_ENTER); actorEvent->crossing.time=event->motion.time; actorEvent->crossing.flags=event->motion.flags; actorEvent->crossing.stage=event->motion.stage; actorEvent->crossing.source=event->motion.source; actorEvent->crossing.x=event->motion.x; actorEvent->crossing.y=event->motion.y; actorEvent->crossing.device=event->motion.device; actorEvent->crossing.related=motionActor; g_signal_emit_by_name(motionActor, "enter-event", actorEvent, &result); clutter_event_free(actorEvent); /* To prevent emiting these motion events on actors being * destroyed while drag is in progress we connect to 'destroy' * signal of each "motion actor" added to list. The signal * handler will be removed either on actor's destruction by * signal handler's callback, when pointer leaves actor or on * end of drag. */ g_signal_connect(motionActor, "destroy", G_CALLBACK(_xfdashboard_drag_action_on_motion_actor_destroyed), self); } /* Get parent */ motionActor=clutter_actor_get_parent(motionActor); } } } } }
static gboolean stage_captured_event_cb (ClutterActor *stage, ClutterEvent *event, ClutterGestureAction *action) { ClutterGestureActionPrivate *priv = action->priv; ClutterActor *actor; gint position; float threshold_x, threshold_y; gboolean return_value; GesturePoint *point; ClutterEventType event_type; event_type = clutter_event_type (event); if (event_type != CLUTTER_TOUCH_CANCEL && event_type != CLUTTER_TOUCH_UPDATE && event_type != CLUTTER_TOUCH_END && event_type != CLUTTER_MOTION && event_type != CLUTTER_BUTTON_RELEASE) return CLUTTER_EVENT_PROPAGATE; if ((point = gesture_find_point (action, event, &position)) == NULL) return CLUTTER_EVENT_PROPAGATE; actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); switch (clutter_event_type (event)) { case CLUTTER_MOTION: { ClutterModifierType mods = clutter_event_get_state (event); /* we might miss a button-release event in case of grabs, * so we need to check whether the button is still down * during a motion event */ if (!(mods & CLUTTER_BUTTON1_MASK)) { cancel_gesture (action); return CLUTTER_EVENT_PROPAGATE; } } /* Follow same code path as a touch event update */ case CLUTTER_TOUCH_UPDATE: if (!priv->in_gesture) { if (priv->points->len < priv->requested_nb_points) { gesture_update_motion_point (point, event); return CLUTTER_EVENT_PROPAGATE; } /* Wait until the drag threshold has been exceeded * before starting _TRIGGER_EDGE_AFTER gestures. */ if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER && gesture_point_pass_threshold (action, point, event)) { gesture_update_motion_point (point, event); return CLUTTER_EVENT_PROPAGATE; } if (!begin_gesture (action, actor)) { if ((point = gesture_find_point (action, event, &position)) != NULL) gesture_update_motion_point (point, event); return CLUTTER_EVENT_PROPAGATE; } if ((point = gesture_find_point (action, event, &position)) == NULL) return CLUTTER_EVENT_PROPAGATE; } gesture_update_motion_point (point, event); g_signal_emit (action, gesture_signals[GESTURE_PROGRESS], 0, actor, &return_value); if (!return_value) { cancel_gesture (action); return CLUTTER_EVENT_PROPAGATE; } /* Check if a _TRIGGER_EDGE_BEFORE gesture needs to be cancelled because * the drag threshold has been exceeded. */ clutter_gesture_action_get_threshold_trigger_distance (action, &threshold_x, &threshold_y); if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE && ((fabsf (point->press_y - point->last_motion_y) > threshold_y) || (fabsf (point->press_x - point->last_motion_x) > threshold_x))) { cancel_gesture (action); return CLUTTER_EVENT_PROPAGATE; } break; case CLUTTER_BUTTON_RELEASE: case CLUTTER_TOUCH_END: { gesture_update_release_point (point, event); if (priv->in_gesture && ((priv->points->len - 1) < priv->requested_nb_points)) { priv->in_gesture = FALSE; g_signal_emit (action, gesture_signals[GESTURE_END], 0, actor); } gesture_unregister_point (action, position); } break; case CLUTTER_TOUCH_CANCEL: { gesture_update_release_point (point, event); if (priv->in_gesture) { priv->in_gesture = FALSE; cancel_gesture (action); } gesture_unregister_point (action, position); } break; default: break; } if (priv->points->len == 0 && priv->stage_capture_id) { g_signal_handler_disconnect (priv->stage, priv->stage_capture_id); priv->stage_capture_id = 0; } return CLUTTER_EVENT_PROPAGATE; }
/** * shell_tray_icon_click: * @icon: a #ShellTrayIcon * @event: the #ClutterEvent triggering the fake click * * Fakes a press and release on @icon. @event must be a * %CLUTTER_BUTTON_RELEASE, %CLUTTER_KEY_PRESS or %CLUTTER_KEY_RELEASE event. * Its relevant details will be passed on to the icon, but its * coordinates will be ignored; the click is * always made on the center of @icon. */ void shell_tray_icon_click (ShellTrayIcon *icon, ClutterEvent *event) { XKeyEvent xkevent; XButtonEvent xbevent; XCrossingEvent xcevent; GdkWindow *remote_window; GdkScreen *screen; int x_root, y_root; Display *xdisplay; Window xwindow, xrootwindow; ClutterEventType event_type = clutter_event_type (event); g_return_if_fail (event_type == CLUTTER_BUTTON_RELEASE || event_type == CLUTTER_KEY_PRESS || event_type == CLUTTER_KEY_RELEASE); gdk_error_trap_push (); remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); xwindow = GDK_WINDOW_XID (remote_window); xdisplay = GDK_WINDOW_XDISPLAY (remote_window); screen = gdk_window_get_screen (remote_window); xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); gdk_window_get_origin (remote_window, &x_root, &y_root); /* First make the icon believe the pointer is inside it */ xcevent.type = EnterNotify; xcevent.window = xwindow; xcevent.root = xrootwindow; xcevent.subwindow = None; xcevent.time = clutter_event_get_time (event); xcevent.x = gdk_window_get_width (remote_window) / 2; xcevent.y = gdk_window_get_height (remote_window) / 2; xcevent.x_root = x_root + xcevent.x; xcevent.y_root = y_root + xcevent.y; xcevent.mode = NotifyNormal; xcevent.detail = NotifyNonlinear; xcevent.same_screen = True; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); /* Now do the click */ if (event_type == CLUTTER_BUTTON_RELEASE) { xbevent.window = xwindow; xbevent.root = xrootwindow; xbevent.subwindow = None; xbevent.time = xcevent.time; xbevent.x = xcevent.x; xbevent.y = xcevent.y; xbevent.x_root = xcevent.x_root; xbevent.y_root = xcevent.y_root; xbevent.state = clutter_event_get_state (event); xbevent.same_screen = True; xbevent.type = ButtonPress; xbevent.button = clutter_event_get_button (event); XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); xbevent.type = ButtonRelease; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); } else { xkevent.window = xwindow; xkevent.root = xrootwindow; xkevent.subwindow = None; xkevent.time = xcevent.time; xkevent.x = xcevent.x; xkevent.y = xcevent.y; xkevent.x_root = xcevent.x_root; xkevent.y_root = xcevent.y_root; xkevent.state = clutter_event_get_state (event); xkevent.same_screen = True; xkevent.keycode = clutter_event_get_key_code (event); xkevent.type = KeyPress; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xkevent); if (event_type == CLUTTER_KEY_RELEASE) { /* If the application takes a grab on KeyPress, we don't * want to send it a KeyRelease. There's no good way of * knowing whether a tray icon will take a grab, so just * assume it does, and don't send the KeyRelease. That might * make the tracking for key events messed up if it doesn't take * a grab, but the tray icon won't get key focus in normal cases, * so let's hope this isn't too damaging... */ xkevent.type = KeyRelease; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xkevent); } } /* And move the pointer back out */ xcevent.type = LeaveNotify; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); gdk_error_trap_pop_ignored (); }