/* on double click, zoom in on the clicked point; * also keeps scale in the range 0.1 to 20 */ static gboolean clicked_cb (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { gdouble scale; gfloat click_x, click_y; gfloat click_target_x, click_target_y; guint32 button; /* don't do anything unless there was a double click */ if (clutter_event_get_click_count (event) < 2) return TRUE; /* work out new scale */ button = clutter_event_get_button (event); clutter_actor_get_scale (actor, &scale, NULL); if (button == CLUTTER_BUTTON_PRIMARY) scale *= 1.2; else if (button == CLUTTER_BUTTON_SECONDARY) scale /= 1.2; /* don't do anything if scale is outside bounds */ if (scale < 0.1 || scale > 20.0) return TRUE; /* get the location of the click on the scaled actor */ clutter_event_get_coords (event, &click_x, &click_y); clutter_actor_transform_stage_point (actor, click_x, click_y, &click_target_x, &click_target_y); /* anchor the actor on the clicked point on its surface */ clutter_actor_set_anchor_point (actor, click_target_x, click_target_y); /* set the actor's position to the click coords: it won't move, * because the anchor point is already there; but * the scale will now be centered on these coords (as the * scale center defaults to the anchor point); so the anchor point * on the actor won't move from under the pointer */ clutter_actor_set_position (actor, click_x, click_y); clutter_actor_animate (actor, CLUTTER_LINEAR, 500, "scale-x", scale, "scale-y", scale, NULL); return TRUE; }
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; }
IO_METHOD(IoClutterEvent, getClickCount) { return IONUMBER(clutter_event_get_click_count(IOCEVENT(self))); }
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); }
static gboolean input_cb (ClutterActor *actor, ClutterEvent *event, gpointer data) { ClutterActor *stage = clutter_actor_get_stage (actor); ClutterActor *source_actor = clutter_event_get_source (event); gchar keybuf[128]; switch (event->type) { case CLUTTER_KEY_PRESS: fill_keybuf (keybuf, &event->key); printf ("[%s] KEY PRESS %s", clutter_actor_get_name (source_actor), keybuf); break; case CLUTTER_KEY_RELEASE: fill_keybuf (keybuf, &event->key); printf ("[%s] KEY RELEASE %s", clutter_actor_get_name (source_actor), keybuf); break; case CLUTTER_MOTION: { ClutterMotionEvent *motion = (ClutterMotionEvent *) event; g_print ("[%s] MOTION (%.02f,%.02f)", clutter_actor_get_name (source_actor), motion->x, motion->y); } break; case CLUTTER_ENTER: g_print ("[%s] ENTER (from:%s)", clutter_actor_get_name (source_actor), clutter_event_get_related (event) != NULL ? clutter_actor_get_name (clutter_event_get_related (event)) : "<out of stage>"); break; case CLUTTER_LEAVE: g_print ("[%s] LEAVE (to:%s)", clutter_actor_get_name (source_actor), clutter_event_get_related (event) != NULL ? clutter_actor_get_name (clutter_event_get_related (event)) : "<out of stage>"); break; case CLUTTER_BUTTON_PRESS: g_print ("[%s] BUTTON PRESS (button:%i, click count:%i)", clutter_actor_get_name (source_actor), clutter_event_get_button (event), clutter_event_get_click_count (event)); break; case CLUTTER_BUTTON_RELEASE: g_print ("[%s] BUTTON RELEASE (button:%i, click count:%i)", clutter_actor_get_name (source_actor), clutter_event_get_button (event), clutter_event_get_click_count (event)); if (source_actor == stage) clutter_stage_set_key_focus (CLUTTER_STAGE (stage), NULL); else if (source_actor == actor && clutter_actor_get_parent (actor) == stage) clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor); break; case CLUTTER_SCROLL: g_print ("[%s] BUTTON SCROLL (direction:%s)", clutter_actor_get_name (source_actor), clutter_event_get_scroll_direction (event) == CLUTTER_SCROLL_UP ? "up" : "down"); break; case CLUTTER_STAGE_STATE: g_print ("[%s] STAGE STATE", clutter_actor_get_name (source_actor)); break; case CLUTTER_DESTROY_NOTIFY: g_print ("[%s] DESTROY NOTIFY", clutter_actor_get_name (source_actor)); break; case CLUTTER_CLIENT_MESSAGE: g_print ("[%s] CLIENT MESSAGE", clutter_actor_get_name (source_actor)); break; case CLUTTER_DELETE: g_print ("[%s] DELETE", clutter_actor_get_name (source_actor)); break; case CLUTTER_NOTHING: return FALSE; } if (source_actor == actor) g_print (" *source*"); g_print ("\n"); return FALSE; }