static void switch_workspace (MetaPlugin *plugin, gint from, gint to, MetaMotionDirection direction) { MetaScreen *screen; MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; GList *l; ClutterActor *workspace0 = clutter_group_new (); ClutterActor *workspace1 = clutter_group_new (); ClutterActor *stage; int screen_width, screen_height; ClutterAnimation *animation; screen = meta_plugin_get_screen (plugin); stage = meta_get_stage_for_screen (screen); meta_screen_get_size (screen, &screen_width, &screen_height); clutter_actor_set_anchor_point (workspace1, screen_width, screen_height); clutter_actor_set_position (workspace1, screen_width, screen_height); clutter_actor_set_scale (workspace1, 0.0, 0.0); clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace1); clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace0); if (from == to) { meta_plugin_switch_workspace_completed (plugin); return; } l = g_list_last (meta_get_window_actors (screen)); while (l) { MetaWindowActor *window_actor = l->data; ActorPrivate *apriv = get_actor_private (window_actor); ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWorkspace *workspace; gint win_workspace; workspace = meta_window_get_workspace (meta_window_actor_get_meta_window (window_actor)); win_workspace = meta_workspace_index (workspace); if (win_workspace == to || win_workspace == from) { apriv->orig_parent = clutter_actor_get_parent (actor); clutter_actor_reparent (actor, win_workspace == to ? workspace1 : workspace0); clutter_actor_show_all (actor); clutter_actor_raise_top (actor); } else if (win_workspace < 0) { /* Sticky window */ apriv->orig_parent = NULL; } else { /* Window on some other desktop */ clutter_actor_hide (actor); apriv->orig_parent = NULL; } l = l->prev; } priv->desktop1 = workspace0; priv->desktop2 = workspace1; animation = clutter_actor_animate (workspace0, CLUTTER_EASE_IN_SINE, SWITCH_TIMEOUT, "scale-x", 1.0, "scale-y", 1.0, NULL); priv->tml_switch_workspace1 = clutter_animation_get_timeline (animation); g_signal_connect (priv->tml_switch_workspace1, "completed", G_CALLBACK (on_switch_workspace_effect_complete), plugin); animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE, SWITCH_TIMEOUT, "scale-x", 0.0, "scale-y", 0.0, NULL); priv->tml_switch_workspace2 = clutter_animation_get_timeline (animation); }
/* snap size, as affected by resizing lower right corner, * will need extension if other corners are to be supported, * it seems possible to do all needed alignments through * simple workarounds when only snapping for lower right). */ static void snap_size (ClutterActor *actor, gfloat in_width, gfloat in_height, gfloat *out_width, gfloat *out_height) { *out_width = in_width; *out_height = in_height; ClutterActor *parent; parent = clutter_actor_get_parent (actor); if (CLUTTER_IS_CONTAINER (parent)) { gfloat in_x = clutter_actor_get_x (actor); gfloat in_y = clutter_actor_get_y (actor); gfloat in_end_x = in_x + in_width; gfloat in_end_y = in_y + in_height; gfloat best_x = 0; gfloat best_x_diff = 4096; gfloat best_y = 0; gfloat best_y_diff = 4096; GList *children, *c; children = clutter_container_get_children (CLUTTER_CONTAINER (parent)); hor_pos = 0; ver_pos = 0; /* We only search our siblings for snapping... * perhaps we should search more. */ for (c=children; c; c = c->next) { gfloat this_x = clutter_actor_get_x (c->data); gfloat this_width = clutter_actor_get_width (c->data); gfloat this_height = clutter_actor_get_height (c->data); gfloat this_end_x = this_x + this_width; gfloat this_y = clutter_actor_get_y (c->data); gfloat this_end_y = this_y + this_height; /* skip self */ if (c->data == actor) continue; /* end aligned with start this_x this_mid_x this_end_x in_x in_mid_x in_end_x */ if (abs (this_x - in_end_x) < best_x_diff) { best_x_diff = abs (this_x - in_end_x); best_x = this_x; hor_pos=3; } if (abs (this_y - in_end_y) < best_y_diff) { best_y_diff = abs (this_y - in_end_y); best_y = this_y; ver_pos=3; } /* ends aligned this_x this_mid_x this_end_x in_x in_mid_x in_end_x */ if (abs (this_end_x - in_end_x) < best_x_diff) { best_x_diff = abs (this_end_x - in_end_x); best_x = this_end_x; hor_pos=3; } if (abs (this_end_y - in_end_y) < best_y_diff) { best_y_diff = abs (this_end_y - in_end_y); best_y = this_end_y; ver_pos=3; } } { if (best_x_diff < SNAP_THRESHOLD) { *out_width = best_x-in_x; } else { hor_pos = 0; } if (best_y_diff < SNAP_THRESHOLD) { *out_height = best_y-in_y; } else { ver_pos = 0; } } } }
/* Get minimum and natural size of all visible children */ static void _xfdashboard_fill_box_layout_get_sizes_for_all(XfdashboardFillBoxLayout *self, ClutterContainer *inContainer, gfloat *outMinWidth, gfloat *outNaturalWidth, gfloat *outMinHeight, gfloat *outNaturalHeight) { XfdashboardFillBoxLayoutPrivate *priv; ClutterActor *child; ClutterActorIter iter; gint numberChildren; gfloat minWidth, naturalWidth; gfloat minHeight, naturalHeight; gfloat childMinWidth, childNaturalWidth; gfloat childMinHeight, childNaturalHeight; ClutterActor *parent; gfloat parentWidth, parentHeight; gfloat aspectRatio; g_return_if_fail(XFDASHBOARD_IS_FILL_BOX_LAYOUT(self)); g_return_if_fail(CLUTTER_IS_CONTAINER(inContainer)); g_return_if_fail(CLUTTER_IS_ACTOR(inContainer)); priv=self->priv; /* Initialize return values */ numberChildren=0; minWidth=naturalWidth=minHeight=naturalHeight=0.0f; /* If not homogeneous then iterate through all children and determine sizes ... */ if(priv->isHomogeneous==FALSE) { /* Iterate through children and calculate sizes */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(inContainer)); while(clutter_actor_iter_next(&iter, &child)) { /* Only get sizes of visible children */ if(!clutter_actor_is_visible(child)) continue; /* Count visible children */ numberChildren++; /* Determine sizes of visible child */ clutter_actor_get_preferred_size(child, &childMinWidth, &childNaturalWidth, &childMinHeight, &childNaturalHeight); if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) { minWidth+=childMinWidth; naturalWidth+=childNaturalWidth; if(childMinHeight>minHeight) minHeight=childMinHeight; if(childNaturalHeight>naturalHeight) naturalHeight=childNaturalHeight; } else { minHeight+=childMinHeight; naturalHeight+=childNaturalHeight; if(childMinWidth>naturalWidth) minWidth=naturalWidth; if(childNaturalWidth>naturalHeight) naturalHeight=childNaturalWidth; } } } /* ... otherwise get largest minimum and natural size and add spacing */ else { /* Get number of visible children and also largest minimum * and natural size */ numberChildren=_xfdashboard_fill_box_layout_get_largest_sizes(self, inContainer, &childMinWidth, &childNaturalWidth, &childMinHeight, &childNaturalHeight); /* Multiply largest sizes with number visible children */ if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) { minWidth=(numberChildren*childMinWidth); naturalWidth=(numberChildren*childNaturalWidth); minHeight=childMinHeight; naturalHeight=childNaturalHeight; } else { minWidth=childMinWidth; naturalWidth=childNaturalWidth; minHeight=(numberChildren*childMinHeight); naturalHeight=(numberChildren*childNaturalHeight); } } /* Add spacing */ if(numberChildren>0) { numberChildren--; if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) { minWidth+=numberChildren*priv->spacing; naturalWidth+=numberChildren*priv->spacing; } else { minHeight+=numberChildren*priv->spacing; naturalHeight+=numberChildren*priv->spacing; } } /* Depending on orientation set sizes to fit into parent actor */ parent=clutter_actor_get_parent(CLUTTER_ACTOR(inContainer)); if(parent) { aspectRatio=1.0f; clutter_actor_get_size(CLUTTER_ACTOR(parent), &parentWidth, &parentHeight); if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) { if(priv->keepAspect==TRUE) { aspectRatio=minWidth/minHeight; minHeight=parentHeight; minWidth=minHeight*aspectRatio; aspectRatio=naturalWidth/naturalHeight; naturalHeight=parentHeight; naturalWidth=naturalHeight*aspectRatio; } else { minHeight=parentHeight; naturalHeight=parentHeight; } } else { if(priv->keepAspect==TRUE) { aspectRatio=minHeight/minWidth; minWidth=parentWidth; minHeight=minWidth*aspectRatio; aspectRatio=naturalHeight/naturalWidth; naturalWidth=parentWidth; naturalHeight=naturalWidth*aspectRatio; } else { minWidth=parentWidth; naturalWidth=parentWidth; } } } /* Set return values */ if(outMinWidth) *outMinWidth=minWidth; if(outNaturalWidth) *outNaturalWidth=naturalWidth; if(outMinHeight) *outMinHeight=minHeight; if(outNaturalHeight) *outNaturalHeight=naturalHeight; }
/* Get largest minimum and natural size of all visible children * for calculation of one child and returns the number of visible ones */ static gint _xfdashboard_fill_box_layout_get_largest_sizes(XfdashboardFillBoxLayout *self, ClutterContainer *inContainer, gfloat *outMinWidth, gfloat *outNaturalWidth, gfloat *outMinHeight, gfloat *outNaturalHeight) { XfdashboardFillBoxLayoutPrivate *priv; ClutterActor *child; ClutterActorIter iter; gint numberChildren; gfloat largestMinWidth, largestNaturalWidth; gfloat largestMinHeight, largestNaturalHeight; gfloat childMinWidth, childNaturalWidth; gfloat childMinHeight, childNaturalHeight; ClutterActor *parent; gfloat parentWidth, parentHeight; gfloat aspectRatio; g_return_val_if_fail(XFDASHBOARD_IS_FILL_BOX_LAYOUT(self), 0); g_return_val_if_fail(CLUTTER_IS_CONTAINER(inContainer), 0); g_return_val_if_fail(CLUTTER_IS_ACTOR(inContainer), 0); priv=self->priv; /* Iterate through all children and determine sizes */ numberChildren=0; largestMinWidth=largestNaturalWidth=largestMinHeight=largestNaturalHeight=0.0f; clutter_actor_iter_init(&iter, CLUTTER_ACTOR(inContainer)); while(clutter_actor_iter_next(&iter, &child)) { /* Only check visible children */ if(!clutter_actor_is_visible(child)) continue; /* Check for largest size */ clutter_actor_get_preferred_size(child, &childMinWidth, &childNaturalWidth, &childMinHeight, &childNaturalHeight); if(childMinWidth>largestMinWidth) largestMinWidth=childMinWidth; if(childNaturalWidth>largestNaturalWidth) largestNaturalWidth=childNaturalWidth; if(childMinHeight>largestMinHeight) largestMinHeight=childMinHeight; if(childNaturalHeight>largestNaturalHeight) largestNaturalHeight=childNaturalHeight; /* Count visible children */ numberChildren++; } /* Depending on orientation set sizes to fit into parent actor */ parent=clutter_actor_get_parent(CLUTTER_ACTOR(inContainer)); if(parent) { aspectRatio=1.0f; clutter_actor_get_size(CLUTTER_ACTOR(parent), &parentWidth, &parentHeight); if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) { if(priv->keepAspect==TRUE) { aspectRatio=largestMinWidth/largestMinHeight; largestMinHeight=parentHeight; largestMinWidth=largestMinHeight*aspectRatio; aspectRatio=largestNaturalWidth/largestNaturalHeight; largestNaturalHeight=parentHeight; largestNaturalWidth=largestNaturalHeight*aspectRatio; } else { largestMinHeight=parentHeight; largestNaturalHeight=parentHeight; } } else { if(priv->keepAspect==TRUE) { aspectRatio=largestMinHeight/largestMinWidth; largestMinWidth=parentWidth; largestMinHeight=largestMinWidth*aspectRatio; aspectRatio=largestNaturalHeight/largestNaturalWidth; largestNaturalWidth=parentWidth; largestNaturalHeight=largestNaturalWidth*aspectRatio; } else { largestMinWidth=parentWidth; largestNaturalWidth=parentWidth; } } } /* Set return values */ if(outMinWidth) *outMinWidth=largestMinWidth; if(outNaturalWidth) *outNaturalWidth=largestNaturalWidth; if(outMinHeight) *outMinHeight=largestMinHeight; if(outNaturalHeight) *outNaturalHeight=largestNaturalHeight; /* Return number of visible children */ return(numberChildren); }
static void mx_tooltip_update_position (MxTooltip *tooltip) { MxTooltipPrivate *priv = tooltip->priv; ClutterGeometry tip_area = *tooltip->priv->tip_area; gfloat tooltip_w, tooltip_h, tooltip_x, tooltip_y, abs_x, abs_y; ClutterActor *stage, *parent; gfloat stage_w, stage_h, parent_w, parent_h; MxWindow *window; /* If there's no stage, bail out - there's nothing we can do */ stage = clutter_actor_get_stage ((ClutterActor *) tooltip); if (!stage) return; /* find out the stage's size to keep the tooltip on-screen */ clutter_actor_get_size (stage, &stage_w, &stage_h); parent = clutter_actor_get_parent ((ClutterActor *) tooltip); clutter_actor_get_transformed_position (parent, &abs_x, &abs_y); clutter_actor_get_size (parent, &parent_w, &parent_h); /* ensure the tooltip with is not fixed size */ clutter_actor_set_size ((ClutterActor*) tooltip, -1, -1); /* if no area set, just position ourselves top left */ if (!priv->tip_area) { clutter_actor_set_position ((ClutterActor*) tooltip, abs_x, abs_y); return; } /* check if we're in a window and if there's rotation */ window = mx_window_get_for_stage (CLUTTER_STAGE (stage)); if (window) { MxWindowRotation rotation; gfloat old_x; g_object_get (G_OBJECT (window), "window-rotation", &rotation, NULL); if (rotation == MX_WINDOW_ROTATION_90 || rotation == MX_WINDOW_ROTATION_270) { /* swap stage width and height */ old_x = stage_w; stage_w = stage_h; stage_h = old_x; /* swap tip area width and height */ old_x = tip_area.width; tip_area.width = tip_area.height; tip_area.height = old_x; } switch (rotation) { case MX_WINDOW_ROTATION_90: /* absolute position */ old_x = abs_x; abs_x = abs_y; abs_y = stage_h - old_x; /* tip area */ old_x = tip_area.x; tip_area.x = tip_area.y; tip_area.y = stage_h - old_x - tip_area.height; break; case MX_WINDOW_ROTATION_180: tip_area.x = stage_w - tip_area.x - tip_area.width; tip_area.y = stage_h - tip_area.y - tip_area.height; abs_x = stage_w - abs_x; abs_y = stage_h - abs_y; break; case MX_WINDOW_ROTATION_270: /* absolute position */ old_x = abs_x; abs_x = stage_w - abs_y; abs_y = old_x; /* tip area */ old_x = tip_area.x; tip_area.x = stage_w - tip_area.y - tip_area.width; tip_area.y = old_x; break; default: break; } } /* we need to have a style in case there are padding values to take into * account when calculating width/height */ mx_stylable_style_changed (MX_STYLABLE (tooltip), MX_STYLE_CHANGED_FORCE); /* find out the tooltip's size */ clutter_actor_get_size ((ClutterActor*) tooltip, &tooltip_w, &tooltip_h); /* attempt to place the tooltip */ /* This special-cases the 4 window rotations, as doing this with * arbitrary rotations would massively complicate the code for * little benefit. */ priv->actor_below = FALSE; tooltip_x = (int)(tip_area.x + (tip_area.width / 2) - (tooltip_w / 2)); tooltip_y = (int)(tip_area.y + tip_area.height); /* Keep on the screen vertically */ if (tooltip_y + tooltip_h > stage_h) { priv->actor_below = TRUE; /* re-query size as may have changed */ clutter_actor_get_preferred_height ((ClutterActor*) tooltip, -1, NULL, &tooltip_h); tooltip_y = MAX (0, tip_area.y - tooltip_h); } /* Keep on the screen horizontally */ if (tooltip_w > stage_w) { tooltip_x = 0; clutter_actor_set_width ((ClutterActor*) tooltip, stage_w); } else if (tooltip_x < 0) tooltip_x = 0; else if (tooltip_x + tooltip_w > stage_w) tooltip_x = (int)(stage_w) - tooltip_w; gfloat pos_x, pos_y; pos_x = tooltip_x - abs_x; pos_y = tooltip_y - abs_y; /* calculate the arrow offset */ priv->arrow_offset = tip_area.x + tip_area.width / 2 - tooltip_x; clutter_actor_set_position ((ClutterActor*) tooltip, pos_x, pos_y); }
static void sync_actor_stacking (MetaCompositor *compositor) { GList *children; GList *expected_window_node; GList *tmp; GList *old; GList *backgrounds; gboolean has_windows; gboolean reordered; /* NB: The first entries in the lists are stacked the lowest */ /* Restacking will trigger full screen redraws, so it's worth a * little effort to make sure we actually need to restack before * we go ahead and do it */ children = clutter_actor_get_children (compositor->window_group); has_windows = FALSE; reordered = FALSE; /* We allow for actors in the window group other than the actors we * know about, but it's up to a plugin to try and keep them stacked correctly * (we really need extra API to make that reliable.) */ /* First we collect a list of all backgrounds, and check if they're at the * bottom. Then we check if the window actors are in the correct sequence */ backgrounds = NULL; expected_window_node = compositor->windows; for (old = children; old != NULL; old = old->next) { ClutterActor *actor = old->data; if (META_IS_BACKGROUND_GROUP (actor) || META_IS_BACKGROUND_ACTOR (actor)) { backgrounds = g_list_prepend (backgrounds, actor); if (has_windows) reordered = TRUE; } else if (META_IS_WINDOW_ACTOR (actor) && !reordered) { has_windows = TRUE; if (expected_window_node != NULL && actor == expected_window_node->data) expected_window_node = expected_window_node->next; else reordered = TRUE; } } g_list_free (children); if (!reordered) { g_list_free (backgrounds); return; } /* reorder the actors by lowering them in turn to the bottom of the stack. * windows first, then background. * * We reorder the actors even if they're not parented to the window group, * to allow stacking to work with intermediate actors (eg during effects) */ for (tmp = g_list_last (compositor->windows); tmp != NULL; tmp = tmp->prev) { ClutterActor *actor = tmp->data, *parent; parent = clutter_actor_get_parent (actor); clutter_actor_set_child_below_sibling (parent, actor, NULL); } /* we prepended the backgrounds above so the last actor in the list * should get lowered to the bottom last. */ for (tmp = backgrounds; tmp != NULL; tmp = tmp->next) { ClutterActor *actor = tmp->data, *parent; parent = clutter_actor_get_parent (actor); clutter_actor_set_child_below_sibling (parent, actor, NULL); } g_list_free (backgrounds); }
/* 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 MxFocusable * mex_column_move_focus (MxFocusable *focusable, MxFocusDirection direction, MxFocusable *from) { MxFocusHint hint; GList *link_ = NULL; MexColumn *self = MEX_COLUMN (focusable); MexColumnPrivate *priv = self->priv; focusable = NULL; if ((ClutterActor *)from == priv->header) { if (((direction == MX_FOCUS_DIRECTION_NEXT) || (direction == MX_FOCUS_DIRECTION_DOWN)) && priv->n_items) { hint = (direction == MX_FOCUS_DIRECTION_NEXT) ? MX_FOCUS_HINT_FIRST : MX_FOCUS_HINT_FROM_ABOVE; if ((focusable = mx_focusable_accept_focus ( MX_FOCUSABLE (priv->children->data), hint))) { priv->current_focus = priv->children->data; return focusable; } } else return NULL; } link_ = g_list_find (priv->children, from); if (!link_) return NULL; switch (direction) { case MX_FOCUS_DIRECTION_PREVIOUS: case MX_FOCUS_DIRECTION_UP: hint = (direction == MX_FOCUS_DIRECTION_PREVIOUS) ? MX_FOCUS_HINT_LAST : MX_FOCUS_HINT_FROM_BELOW; link_ = g_list_previous (link_); if (!link_) { if ((focusable = mx_focusable_accept_focus ( MX_FOCUSABLE (priv->header), hint))) priv->current_focus = priv->header; } else if ((focusable = mx_focusable_accept_focus ( MX_FOCUSABLE (link_->data), hint))) priv->current_focus = link_->data; break; case MX_FOCUS_DIRECTION_NEXT: case MX_FOCUS_DIRECTION_DOWN: hint = (direction == MX_FOCUS_DIRECTION_NEXT) ? MX_FOCUS_HINT_FIRST : MX_FOCUS_HINT_FROM_ABOVE; link_ = g_list_next (link_); if (link_ && (focusable = mx_focusable_accept_focus ( MX_FOCUSABLE (link_->data), hint))) priv->current_focus = link_->data; break; case MX_FOCUS_DIRECTION_OUT: if (from && (clutter_actor_get_parent (CLUTTER_ACTOR (from)) == CLUTTER_ACTOR (self))) priv->current_focus = CLUTTER_ACTOR (from); break; default: break; } return focusable; }
static void mex_column_notify_focused_cb (MxFocusManager *manager, GParamSpec *pspec, MexColumn *self) { GList *c; guint offset, increment; ClutterActor *focused, *focused_cell; gboolean cell_has_focus, has_focus, open, set_tile_important; MexColumnPrivate *priv = self->priv; focused = (ClutterActor *)mx_focus_manager_get_focused (manager); /* Check if we have focus, and what child is focused */ focused_cell = NULL; set_tile_important = FALSE; cell_has_focus = has_focus = FALSE; if (focused) { gboolean contains_column = FALSE; ClutterActor *parent = clutter_actor_get_parent (focused); while (parent) { if (parent == (ClutterActor *)self) { has_focus = TRUE; if (!priv->has_focus) { set_tile_important = TRUE; priv->has_focus = TRUE; } if (focused != priv->header) { cell_has_focus = TRUE; focused_cell = focused; } break; } else if (MEX_IS_COLUMN (parent)) { contains_column = TRUE; } focused = parent; parent = clutter_actor_get_parent (focused); } if (!contains_column) has_focus = TRUE; } if (!has_focus && priv->has_focus) { priv->has_focus = FALSE; set_tile_important = TRUE; } /* Scroll the adjustment to the top */ if (!cell_has_focus && priv->adjustment) mx_adjustment_interpolate (priv->adjustment, 0, 250, CLUTTER_EASE_OUT_CUBIC); /* Open/close boxes as appropriate */ offset = 0; increment = 150; /* If we're changing the tile importance, initialise the state manager */ if (set_tile_important && priv->n_items > 0) { if (priv->expand_timeline) g_object_unref (priv->expand_timeline); priv->expand_timeline = clutter_timeline_new (priv->n_items * increment); clutter_timeline_set_delay (priv->expand_timeline, 350); } /* Loop through children and set the expander box important/unimportant * as necessary, and if necessary, do the same for the tile inside the * expander-box. */ open = has_focus && !cell_has_focus; for (c = priv->children; c; c = c->next) { gchar signal_name[32+16]; ClutterActor *child = c->data; if ((!priv->collapse && priv->has_focus) || (child == focused_cell)) open = TRUE; if (!MEX_IS_EXPANDER_BOX (child)) continue; /* Note, 'marker-reached::' is 16 characters long */ g_snprintf (signal_name, G_N_ELEMENTS (signal_name), "marker-reached::%p", child); if (MEX_IS_CONTENT_BOX (child)) { ClutterActor *tile = mex_content_box_get_tile (MEX_CONTENT_BOX (child)); mex_tile_set_important (MEX_TILE (tile), priv->has_focus); } if (!open) { if (priv->expand_timeline) { if (clutter_timeline_has_marker (priv->expand_timeline, signal_name + 16)) clutter_timeline_remove_marker (priv->expand_timeline, signal_name + 16); g_signal_handlers_disconnect_by_func (priv->expand_timeline, mex_column_expand_drawer_cb, child); } mex_expander_box_set_important (MEX_EXPANDER_BOX (child), FALSE); } else if (set_tile_important) { mex_expander_box_set_important (MEX_EXPANDER_BOX (child), FALSE); clutter_timeline_add_marker_at_time (priv->expand_timeline, signal_name + 16, offset); g_signal_connect_swapped (priv->expand_timeline, signal_name, G_CALLBACK (mex_column_expand_drawer_cb), child); offset += increment; } else mex_expander_box_set_important (MEX_EXPANDER_BOX (child), TRUE); } if (priv->expand_timeline && set_tile_important && (offset >= increment)) clutter_timeline_start (priv->expand_timeline); }