Exemple #1
0
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);
}
Exemple #5
0
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);
}
Exemple #6
0
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);
				}
			}
		}
	}
}
Exemple #8
0
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;
}
Exemple #9
0
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);
}