NtfNotification * ntf_tray_find_notification (NtfTray *tray, gint subsystem, gint id) { NtfTrayPrivate *priv; GList *notifiers, *l; NtfNotification *ntf = NULL; g_return_val_if_fail (NTF_IS_TRAY (tray), NULL); priv = tray->priv; notifiers = clutter_actor_get_children (CLUTTER_ACTOR (priv->notifiers)); for (l = notifiers; l; l = l->next) { gint s = ntf_notification_get_subsystem (NTF_NOTIFICATION (l->data)); gint i = ntf_notification_get_id (NTF_NOTIFICATION (l->data)); if (subsystem == s && id == i) { ntf = l->data; break; } } g_list_free (notifiers); return ntf; }
static MxFocusable* mx_table_accept_focus (MxFocusable *focusable, MxFocusHint hint) { MxTablePrivate *priv = MX_TABLE (focusable)->priv; MxFocusable *return_focusable; GList* list, *l, *children; return_focusable = NULL; children = clutter_actor_get_children (CLUTTER_ACTOR (focusable)); /* find the first/last focusable widget */ switch (hint) { case MX_FOCUS_HINT_LAST: list = g_list_reverse (g_list_copy (children)); break; case MX_FOCUS_HINT_PRIOR: if (priv->last_focus) { list = g_list_copy (g_list_find (children, priv->last_focus)); if (list) break; } /* This intentionally runs into the next switch case */ default: case MX_FOCUS_HINT_FIRST: list = g_list_copy (children); break; } for (l = list; l; l = g_list_next (l)) { if (MX_IS_FOCUSABLE (l->data)) { return_focusable = mx_focusable_accept_focus (MX_FOCUSABLE (l->data), hint); if (return_focusable) break; } } g_list_free (list); g_list_free (children); return return_focusable; }
static void cally_actor_initialize (AtkObject *obj, gpointer data) { CallyActor *self = NULL; CallyActorPrivate *priv = NULL; ClutterActor *actor = NULL; guint handler_id; ATK_OBJECT_CLASS (cally_actor_parent_class)->initialize (obj, data); self = CALLY_ACTOR(obj); priv = self->priv; actor = CLUTTER_ACTOR (data); g_signal_connect (actor, "notify", G_CALLBACK (cally_actor_notify_clutter), NULL); g_object_set_data (G_OBJECT (obj), "atk-component-layer", GINT_TO_POINTER (ATK_LAYER_MDI)); priv->children = clutter_actor_get_children (actor); /* * We store the handler ids for these signals in case some objects * need to remove these handlers. */ handler_id = g_signal_connect (actor, "actor-added", G_CALLBACK (cally_actor_add_actor), obj); g_object_set_data (G_OBJECT (obj), "cally-add-handler-id", GUINT_TO_POINTER (handler_id)); handler_id = g_signal_connect (actor, "actor-removed", G_CALLBACK (cally_actor_remove_actor), obj); g_object_set_data (G_OBJECT (obj), "cally-remove-handler-id", GUINT_TO_POINTER (handler_id)); obj->role = ATK_ROLE_PANEL; /* typically objects implementing ClutterContainer interface would be a panel */ }
static void row_removed_cb (ClutterModel *model, ClutterModelIter *iter, MxListView *list_view) { GList *children; GList *l; ClutterActor *child; if (list_view->priv->is_frozen) return; children = clutter_actor_get_children (CLUTTER_ACTOR (list_view)); l = g_list_nth (children, clutter_model_iter_get_row (iter)); child = (ClutterActor *) l->data; clutter_actor_remove_child (CLUTTER_ACTOR (list_view), child); g_list_free (children); }
static gboolean ntf_tray_key_press_event (ClutterActor *actor, ClutterKeyEvent *event) { NtfTray *tray = NTF_TRAY (actor); NtfTrayPrivate *priv = tray->priv; gboolean retval = FALSE; switch (event->keyval) { case CLUTTER_Escape: ntf_tray_dismiss_all_cb (NULL, tray); retval = TRUE; break; default: { GList *notifiers; GList *last; notifiers = clutter_actor_get_children (CLUTTER_ACTOR (priv->notifiers)); last = g_list_last (notifiers); if (last) { NtfNotification *ntf = NTF_NOTIFICATION (last->data); ntf_notification_handle_key_event (ntf, event); retval = TRUE; } g_list_free (notifiers); } break; } return retval; }
static void meta_window_group_paint (ClutterActor *actor) { cairo_region_t *visible_region; ClutterActor *stage; cairo_rectangle_int_t visible_rect; GList *children, *l; int paint_x_origin, paint_y_origin; int actor_x_origin, actor_y_origin; int paint_x_offset, paint_y_offset; MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen); /* Normally we expect an actor to be drawn at it's position on the screen. * However, if we're inside the paint of a ClutterClone, that won't be the * case and we need to compensate. We look at the position of the window * group under the current model-view matrix and the position of the actor. * If they are both simply integer translations, then we can compensate * easily, otherwise we give up. * * Possible cleanup: work entirely in paint space - we can compute the * combination of the model-view matrix with the local matrix for each child * actor and get a total transformation for that actor for how we are * painting currently, and never worry about how actors are positioned * on the stage. */ if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) || !meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin)) { CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor); return; } paint_x_offset = paint_x_origin - actor_x_origin; paint_y_offset = paint_y_origin - actor_y_origin; /* We walk the list from top to bottom (opposite of painting order), * and subtract the opaque area of each window out of the visible * region that we pass to the windows below. */ children = clutter_actor_get_children (actor); children = g_list_reverse (children); /* Get the clipped redraw bounds from Clutter so that we can avoid * painting shadows on windows that don't need to be painted in this * frame. In the case of a multihead setup with mismatched monitor * sizes, we could intersect this with an accurate union of the * monitors to avoid painting shadows that are visible only in the * holes. */ stage = clutter_actor_get_stage (actor); clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage), &visible_rect); visible_region = cairo_region_create_rectangle (&visible_rect); if (info->unredirected_window != NULL) { cairo_rectangle_int_t unredirected_rect; MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window); meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect); cairo_region_subtract_rectangle (visible_region, &unredirected_rect); } for (l = children; l; l = l->next) { if (!CLUTTER_ACTOR_IS_VISIBLE (l->data)) continue; if (l->data == info->unredirected_window) continue; /* If an actor has effects applied, then that can change the area * it paints and the opacity, so we no longer can figure out what * portion of the actor is obscured and what portion of the screen * it obscures, so we skip the actor. * * This has a secondary beneficial effect: if a ClutterOffscreenEffect * is applied to an actor, then our clipped redraws interfere with the * caching of the FBO - even if we only need to draw a small portion * of the window right now, ClutterOffscreenEffect may use other portions * of the FBO later. So, skipping actors with effects applied also * prevents these bugs. * * Theoretically, we should check clutter_actor_get_offscreen_redirect() * as well for the same reason, but omitted for simplicity in the * hopes that no-one will do that. */ if (clutter_actor_has_effects (l->data)) continue; if (META_IS_WINDOW_ACTOR (l->data)) { MetaWindowActor *window_actor = l->data; int x, y; if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y)) continue; x += paint_x_offset; y += paint_y_offset; /* Temporarily move to the coordinate system of the actor */ cairo_region_translate (visible_region, - x, - y); meta_window_actor_set_visible_region (window_actor, visible_region); if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff) { cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor); if (obscured_region) cairo_region_subtract (visible_region, obscured_region); } meta_window_actor_set_visible_region_beneath (window_actor, visible_region); cairo_region_translate (visible_region, x, y); } else if (META_IS_BACKGROUND_ACTOR (l->data) || META_IS_BACKGROUND_GROUP (l->data)) { ClutterActor *background_actor = l->data; int x, y; if (!meta_actor_is_untransformed (CLUTTER_ACTOR (background_actor), &x, &y)) continue; x += paint_x_offset; y += paint_y_offset; cairo_region_translate (visible_region, - x, - y); if (META_IS_BACKGROUND_GROUP (background_actor)) meta_background_group_set_visible_region (META_BACKGROUND_GROUP (background_actor), visible_region); else meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (background_actor), visible_region); cairo_region_translate (visible_region, x, y); } } cairo_region_destroy (visible_region); CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor); /* Now that we are done painting, unset the visible regions (they will * mess up painting clones of our actors) */ for (l = children; l; l = l->next) { if (META_IS_WINDOW_ACTOR (l->data)) { MetaWindowActor *window_actor = l->data; meta_window_actor_reset_visible_regions (window_actor); } else if (META_IS_BACKGROUND_ACTOR (l->data)) { MetaBackgroundActor *background_actor = l->data; meta_background_actor_set_visible_region (background_actor, NULL); } } g_list_free (children); }
/* model monitors */ static void model_changed_cb (ClutterModel *model, MxListView *list_view) { GSList *p; GList *l, *children; MxListViewPrivate *priv = list_view->priv; ClutterModelIter *iter = NULL; gint model_n = 0, child_n = 0; /* bail out if we don't yet have an item type or a factory */ if (!priv->item_type && !priv->factory) return; if (priv->is_frozen) return; if (priv->item_type) { /* check the item-type is an descendant of ClutterActor */ if (!g_type_is_a (priv->item_type, CLUTTER_TYPE_ACTOR)) { g_warning ("%s is not a subclass of ClutterActor and therefore" " cannot be used as items in an MxListView", g_type_name (priv->item_type)); return; } } children = clutter_actor_get_children (CLUTTER_ACTOR (list_view)); child_n = g_list_length (children); if (model) model_n = clutter_model_get_n_rows (priv->model); else model_n = 0; /* add children as needed */ while (model_n > child_n) { ClutterActor *new_child; if (priv->item_type) { new_child = g_object_new (priv->item_type, NULL); } else { new_child = mx_item_factory_create (priv->factory); } clutter_actor_add_child (CLUTTER_ACTOR (list_view), new_child); child_n++; } /* remove children as needed */ l = g_list_last (children); while (child_n > model_n) { clutter_actor_remove_child (CLUTTER_ACTOR (list_view), l->data); l = g_list_previous (l); child_n--; } g_list_free (children); if (!priv->model) return; children = clutter_actor_get_children (CLUTTER_ACTOR (list_view)); /* set the properties on the children */ iter = clutter_model_get_first_iter (priv->model); l = children; while (iter && !clutter_model_iter_is_last (iter)) { GObject *child; child = G_OBJECT (l->data); g_object_freeze_notify (child); for (p = priv->attributes; p; p = p->next) { GValue value = { 0, }; AttributeData *attr = p->data; clutter_model_iter_get_value (iter, attr->col, &value); g_object_set_property (child, attr->name, &value); g_value_unset (&value); } g_object_thaw_notify (child); l = g_list_next (l); clutter_model_iter_next (iter); } g_list_free (children); if (iter) g_object_unref (iter); }
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); }
static MxFocusable* mx_table_move_focus (MxFocusable *focusable, MxFocusDirection direction, MxFocusable *from) { MxTablePrivate *priv = MX_TABLE (focusable)->priv; MxTable *table = MX_TABLE (focusable); GList *l, *childlink, *children; MxTableChild *child_meta; ClutterActor *child_actor; MxFocusable *focused; gint row, column; ClutterActor *found; /* find the current focus */ child_actor = CLUTTER_ACTOR (from); child_meta = (MxTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (focusable), child_actor); if (!child_meta) return NULL; priv->last_focus = from; /* find the next widget to focus */ switch (direction) { case MX_FOCUS_DIRECTION_NEXT: children = clutter_actor_get_children (CLUTTER_ACTOR (focusable)); childlink = g_list_find (children, from); for (l = childlink->next; l; l = g_list_next (l)) { if (MX_IS_FOCUSABLE (l->data)) { focused = mx_focusable_accept_focus (MX_FOCUSABLE (l->data), MX_FOCUS_HINT_FIRST); if (focused) { g_list_free (children); return focused; } } } /* no next widgets to focus */ g_list_free (children); return NULL; case MX_FOCUS_DIRECTION_PREVIOUS: children = clutter_actor_get_children (CLUTTER_ACTOR (focusable)); childlink = g_list_find (children, from); for (l = g_list_previous (childlink); l; l = g_list_previous (l)) { if (MX_IS_FOCUSABLE (l->data)) { focused = mx_focusable_accept_focus (MX_FOCUSABLE (l->data), MX_FOCUS_HINT_LAST); if (focused) { g_list_free (children); return focused; } } } /* no widget found in the previous position */ g_list_free (children); return NULL; case MX_FOCUS_DIRECTION_UP: /* move focus up */ row = child_meta->row - 1; column = child_meta->col; focused = NULL; while (!focused && row >= 0) { found = mx_table_find_actor_at (table, row, column); if (found) { if (MX_IS_FOCUSABLE (found)) { focused = mx_focusable_accept_focus (MX_FOCUSABLE (found), MX_FOCUS_HINT_FIRST); if (focused) break; } child_meta = (MxTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (focusable), found); /* row might not be the top row if @found is a spanned actor */ row = child_meta->row - 1; } else row --; } return focused; case MX_FOCUS_DIRECTION_DOWN: /* move focus down */ row = child_meta->row + child_meta->row_span; column = child_meta->col; focused = NULL; while (!focused && row < priv->n_rows) { found = mx_table_find_actor_at (table, row, column); if (found) { if (MX_IS_FOCUSABLE (found)) { focused = mx_focusable_accept_focus (MX_FOCUSABLE (found), MX_FOCUS_HINT_FIRST); if (focused) break; } child_meta = (MxTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (focusable), found); row = child_meta->row + child_meta->row_span; } else row ++; } return focused; case MX_FOCUS_DIRECTION_LEFT: /* move focus left */ row = child_meta->row; column = child_meta->col - 1; focused = NULL; while (!focused && column >= 0) { found = mx_table_find_actor_at (table, row, column); if (found) { if (MX_IS_FOCUSABLE (found)) { focused = mx_focusable_accept_focus (MX_FOCUSABLE (found), MX_FOCUS_HINT_FIRST); if (focused) break; } child_meta = (MxTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (focusable), found); /* col might not be the first column if @found is a spanned actor */ column = child_meta->col - 1; } else column --; } return focused; case MX_FOCUS_DIRECTION_RIGHT: /* move focus right */ row = child_meta->row; column = child_meta->col + child_meta->col_span; focused = NULL; while (!focused && column < priv->n_cols) { found = mx_table_find_actor_at (table, row, column); if (found) { if (MX_IS_FOCUSABLE (found)) { focused = mx_focusable_accept_focus (MX_FOCUSABLE (found), MX_FOCUS_HINT_FIRST); if (focused) break; } child_meta = (MxTableChild *) clutter_container_get_child_meta (CLUTTER_CONTAINER (focusable), found); column = child_meta->col + child_meta->col_span; } else column ++; } return focused; default: break; } return NULL; }