static gint window_compare(gconstpointer a, gconstpointer b) { ClutterActor* aa = *(ClutterActor**)a; ClutterActor* bb = *(ClutterActor**)b; MetaWindowActor* a1 = META_WINDOW_ACTOR(clutter_clone_get_source(CLUTTER_CLONE(aa))); MetaWindowActor* b1 = META_WINDOW_ACTOR(clutter_clone_get_source(CLUTTER_CLONE(bb))); MetaWindow* w1 = meta_window_actor_get_meta_window(a1); MetaWindow* w2 = meta_window_actor_get_meta_window(b1); return meta_window_get_stable_sequence(w1) - meta_window_get_stable_sequence(w2); }
static void clutter_clone_dispose (GObject *gobject) { clutter_clone_set_source_internal (CLUTTER_CLONE (gobject), NULL); G_OBJECT_CLASS (clutter_clone_parent_class)->dispose (gobject); }
static void clutter_clone_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActorClass *parent_class; /* chain up */ parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class); parent_class->allocate (self, box, flags); if (priv->clone_source == NULL) return; #if 0 /* XXX - this is wrong: ClutterClone cannot clone unparented * actors, as it will break all invariants */ /* we act like a "foster parent" for the source we are cloning; * if the source has not been parented we have to force an * allocation on it, so that we can paint it correctly from * within our paint() implementation. since the actor does not * have a parent, and thus it won't be painted by the usual * paint cycle, we can safely give it as much size as it requires */ if (clutter_actor_get_parent (priv->clone_source) == NULL) clutter_actor_allocate_preferred_size (priv->clone_source, flags); #endif }
static void clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActorBox box, source_box; gfloat x_scale, y_scale; /* First chain up and apply all the standard ClutterActor * transformations... */ CLUTTER_ACTOR_CLASS (clutter_clone_parent_class)->apply_transform (self, matrix); /* if we don't have a source, nothing else to do */ if (priv->clone_source == NULL) return; /* get our allocated size */ clutter_actor_get_allocation_box (self, &box); /* and get the allocated size of the source */ clutter_actor_get_allocation_box (priv->clone_source, &source_box); /* We need to scale what the clone-source actor paints to fill our own * allocation... */ x_scale = clutter_actor_box_get_width (&box) / clutter_actor_box_get_width (&source_box); y_scale = clutter_actor_box_get_height (&box) / clutter_actor_box_get_height (&source_box); cogl_matrix_scale (matrix, x_scale, y_scale, x_scale); }
static void overview_animated_destroy(MosesOverview* self, MosesOverviewQuitReason reason, gboolean animate) { MosesOverviewPrivate* priv = self->priv; gboolean just_destroy = !animate; if (reason == MOSES_OV_REASON_ACTIVATE_WINDOW && !priv->selected_actor) { just_destroy = TRUE; } else if (reason == MOSES_OV_REASON_ACTIVATE_WORKSPACE && !priv->selected_workspace) { just_destroy = TRUE; } else if (reason == MOSES_OV_REASON_NORMAL) { just_destroy = TRUE; } if (just_destroy) { clutter_actor_destroy(CLUTTER_ACTOR(self)); return; } gfloat x, y, w, h; ClutterActor* target = NULL; if (reason == MOSES_OV_REASON_ACTIVATE_WINDOW) { target = self->priv->selected_actor; ClutterActor* orig = clutter_clone_get_source(CLUTTER_CLONE(target)); clutter_actor_get_position(orig, &x, &y); clutter_actor_get_size(orig, &w, &h); g_signal_handlers_disconnect_by_func(target, on_effect_complete, self); } else if (reason == MOSES_OV_REASON_ACTIVATE_WORKSPACE) { g_assert(priv->selected_actor == NULL); MetaScreen* screen = meta_plugin_get_screen(priv->plugin); target = overview_head_get_actor_for_workspace(priv->ov_head, priv->selected_workspace); MetaRectangle geom; int focused_monitor = meta_screen_get_current_monitor(screen); meta_screen_get_monitor_geometry(screen, focused_monitor, &geom); x = geom.x, y = geom.y, w = geom.width, h = geom.height; } if (target) { clutter_actor_remove_all_transitions(target); clutter_actor_set_child_above_sibling(clutter_actor_get_parent(target), target, NULL); clutter_actor_save_easing_state(target); clutter_actor_set_easing_mode(target, CLUTTER_LINEAR); clutter_actor_set_easing_duration(target, 150); clutter_actor_set_position(target, x, y); clutter_actor_set_scale(target, w / clutter_actor_get_width(target), h / clutter_actor_get_height(target)); clutter_actor_restore_easing_state(target); g_object_connect(target, "signal::transitions-completed", G_CALLBACK(on_restore_position_effect_complete), self, NULL); } }
static void prepare_workspace_content(MosesOverview *self, MetaWorkspace *ws) { MosesOverviewPrivate* priv = self->priv; GList* l = meta_workspace_list_windows(ws); if (!priv->clones) { priv->clones = g_ptr_array_new(); } while (l) { MetaWindow* win = l->data; MetaWindowActor* win_actor = META_WINDOW_ACTOR(meta_window_get_compositor_private(win)); if (meta_window_get_window_type(win) == META_WINDOW_DESKTOP) { g_debug("%s: got desktop actor", __func__); priv->background_actor = clutter_clone_new(CLUTTER_ACTOR(win_actor)); } else if (meta_window_get_window_type(win) == META_WINDOW_NORMAL && !meta_window_is_hidden(win)) { ClutterActor* clone = clutter_clone_new(CLUTTER_ACTOR(win_actor)); clutter_actor_set_reactive(clone, TRUE); float x = 0.0, y = 0.0; clutter_actor_get_position(CLUTTER_ACTOR(win_actor), &x, &y); clutter_actor_set_position(clone, x, y); clutter_actor_hide(CLUTTER_ACTOR(win_actor)); g_ptr_array_add(priv->clones, clone); clutter_actor_add_child(CLUTTER_ACTOR(self), clone); g_object_connect(clone, "signal::transitions-completed", G_CALLBACK(on_effect_complete), self, "signal::button-press-event", on_thumb_button_press, self, "signal::enter-event", on_thumb_enter, self, "signal::leave-event", on_thumb_leave, self, NULL); } l = l->next; } ClutterColor clr = CLUTTER_COLOR_INIT(0xff, 0xff, 0xff, 0xff); clutter_actor_set_background_color(CLUTTER_ACTOR(self), &clr); if (priv->background_actor) { #if 0 ClutterEffect* blur = moses_blur_effect_new(); clutter_actor_add_effect_with_name(priv->background_actor, "blur", blur); clutter_actor_insert_child_below(CLUTTER_ACTOR(self), priv->background_actor, NULL); clutter_actor_hide(clutter_clone_get_source(CLUTTER_CLONE(priv->background_actor))); clutter_actor_set_reactive(priv->background_actor, TRUE); #endif } g_object_connect(priv->background_actor ? priv->background_actor: CLUTTER_ACTOR(self), "signal::button-press-event", on_bg_button_press, self, NULL); }
static void clutter_clone_paint (ClutterActor *self) { ClutterClone *clone = CLUTTER_CLONE (self); ClutterClonePrivate *priv = clone->priv; ClutterGeometry geom, clone_geom; gfloat x_scale, y_scale; gboolean was_unmapped = FALSE; if (G_UNLIKELY (priv->clone_source == NULL)) return; CLUTTER_NOTE (PAINT, "painting clone actor '%s'", clutter_actor_get_name (self) ? clutter_actor_get_name (self) : "unknown"); /* get our allocated size */ clutter_actor_get_allocation_geometry (self, &geom); /* and get the allocated size of the source */ clutter_actor_get_allocation_geometry (priv->clone_source, &clone_geom); /* We need to scale what the clone-source actor paints to fill our own * allocation... */ x_scale = (gfloat) geom.width / clone_geom.width; y_scale = (gfloat) geom.height / clone_geom.height; cogl_scale (x_scale, y_scale, 1.0); /* The final bits of magic: * - We need to make sure that when the clone-source actor's paint * method calls clutter_actor_get_paint_opacity, it traverses to * us and our parent not it's real parent. * - We need to stop clutter_actor_paint applying the model view matrix of * the clone source actor. */ _clutter_actor_set_opacity_parent (priv->clone_source, self); _clutter_actor_set_enable_model_view_transform (priv->clone_source, FALSE); if (!CLUTTER_ACTOR_IS_MAPPED (priv->clone_source)) { _clutter_actor_set_enable_paint_unmapped (priv->clone_source, TRUE); was_unmapped = TRUE; } clutter_actor_paint (priv->clone_source); if (was_unmapped) _clutter_actor_set_enable_paint_unmapped (priv->clone_source, FALSE); _clutter_actor_set_enable_model_view_transform (priv->clone_source, TRUE); _clutter_actor_set_opacity_parent (priv->clone_source, NULL); }
static gboolean clutter_clone_has_overlaps (ClutterActor *actor) { ClutterClonePrivate *priv = CLUTTER_CLONE (actor)->priv; /* The clone has overlaps iff the source has overlaps */ if (priv->clone_source == NULL) return FALSE; return clutter_actor_has_overlaps (priv->clone_source); }
void mnb_fancy_bin_set_child (MnbFancyBin *bin, ClutterActor *child) { MnbFancyBinPrivate *priv = bin->priv; if (priv->real_child) { clutter_clone_set_source (CLUTTER_CLONE (priv->child), NULL); clutter_clone_set_source (CLUTTER_CLONE (priv->clone), NULL); clutter_actor_remove_child (clutter_actor_get_parent(priv->real_child), priv->real_child); } priv->real_child = child; if (priv->real_child) { clutter_actor_add_child(CLUTTER_ACTOR (bin), priv->real_child); clutter_clone_set_source (CLUTTER_CLONE (priv->child), priv->real_child); clutter_clone_set_source (CLUTTER_CLONE (priv->clone), priv->real_child); } clutter_actor_queue_relayout (CLUTTER_ACTOR (bin)); }
static void clutter_clone_paint (ClutterActor *actor) { ClutterClone *self = CLUTTER_CLONE (actor); ClutterClonePrivate *priv = self->priv; gboolean was_unmapped = FALSE; if (priv->clone_source == NULL) return; CLUTTER_NOTE (PAINT, "painting clone actor '%s'", _clutter_actor_get_debug_name (actor)); /* The final bits of magic: * - We need to override the paint opacity of the actor with our own * opacity. * - We need to inform the actor that it's in a clone paint (for the function * clutter_actor_is_in_clone_paint()) * - We need to stop clutter_actor_paint applying the model view matrix of * the clone source actor. */ _clutter_actor_set_in_clone_paint (priv->clone_source, TRUE); _clutter_actor_set_opacity_override (priv->clone_source, clutter_actor_get_paint_opacity (actor)); _clutter_actor_set_enable_model_view_transform (priv->clone_source, FALSE); if (!CLUTTER_ACTOR_IS_MAPPED (priv->clone_source)) { _clutter_actor_set_enable_paint_unmapped (priv->clone_source, TRUE); was_unmapped = TRUE; } _clutter_actor_push_clone_paint (); clutter_actor_paint (priv->clone_source); _clutter_actor_pop_clone_paint (); if (was_unmapped) _clutter_actor_set_enable_paint_unmapped (priv->clone_source, FALSE); _clutter_actor_set_enable_model_view_transform (priv->clone_source, TRUE); _clutter_actor_set_opacity_override (priv->clone_source, -1); _clutter_actor_set_in_clone_paint (priv->clone_source, FALSE); }
static void clutter_clone_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterClone *self = CLUTTER_CLONE (gobject); switch (prop_id) { case PROP_SOURCE: clutter_clone_set_source (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
static void clutter_clone_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterClonePrivate *priv = CLUTTER_CLONE (gobject)->priv; switch (prop_id) { case PROP_SOURCE: g_value_set_object (value, priv->clone_source); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
static gboolean clutter_clone_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { ClutterClonePrivate *priv = CLUTTER_CLONE (actor)->priv; const ClutterPaintVolume *source_volume; /* if the source is not set the paint volume is defined to be empty */ if (priv->clone_source == NULL) return TRUE; /* query the volume of the source actor and simply masquarade it as * the clones volume... */ source_volume = clutter_actor_get_paint_volume (priv->clone_source); if (source_volume == NULL) return FALSE; _clutter_paint_volume_set_from_volume (volume, source_volume); _clutter_paint_volume_set_reference_actor (volume, actor); return TRUE; }
static void clutter_clone_get_preferred_height (ClutterActor *self, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterActor *clone_source = priv->clone_source; if (clone_source == NULL) { if (min_height_p) *min_height_p = 0; if (natural_height_p) *natural_height_p = 0; } else clutter_actor_get_preferred_height (clone_source, for_width, min_height_p, natural_height_p); }
static void _clone_paint_cb (ClutterActor *actor) { ClutterActor *source; ClutterActorBox box; CoglHandle material; gfloat width, height; guint8 opacity; CoglColor color_1, color_2; CoglTextureVertex vertices[4]; /* if we don't have a source actor, don't paint */ source = clutter_clone_get_source (CLUTTER_CLONE (actor)); if (source == NULL) goto out; /* if the source texture does not have any content, don't paint */ material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (source)); if (material == NULL) goto out; /* get the size of the reflection */ clutter_actor_get_allocation_box (actor, &box); clutter_actor_box_get_size (&box, &width, &height); /* get the composite opacity of the actor */ opacity = clutter_actor_get_paint_opacity (actor); /* figure out the two colors for the reflection: the first is * full color and the second is the same, but at 0 opacity */ cogl_color_init_from_4f (&color_1, 1.0, 1.0, 1.0, opacity / 255.0); cogl_color_premultiply (&color_1); cogl_color_init_from_4f (&color_2, 1.0, 1.0, 1.0, 0.0); cogl_color_premultiply (&color_2); /* now describe the four vertices of the quad; since it has * to be a reflection, we need to invert it as well */ vertices[0].x = 0; vertices[0].y = 0; vertices[0].z = 0; vertices[0].tx = 0.0; vertices[0].ty = 1.0; vertices[0].color = color_1; vertices[1].x = width; vertices[1].y = 0; vertices[1].z = 0; vertices[1].tx = 1.0; vertices[1].ty = 1.0; vertices[1].color = color_1; vertices[2].x = width; vertices[2].y = height; vertices[2].z = 0; vertices[2].tx = 1.0; vertices[2].ty = 0.0; vertices[2].color = color_2; vertices[3].x = 0; vertices[3].y = height; vertices[3].z = 0; vertices[3].tx = 0.0; vertices[3].ty = 0.0; vertices[3].color = color_2; /* paint the same texture but with a different geometry */ cogl_set_source (material); cogl_polygon (vertices, 4, TRUE); out: /* prevent the default clone handler from running */ g_signal_stop_emission_by_name (actor, "paint"); }
static void moses_overview_dispose(GObject *object) { MosesOverview *overview = MOSES_OVERVIEW(object); MosesOverviewPrivate* priv = overview->priv; if (priv->disposed) return; priv->disposed = TRUE; g_clear_pointer(&priv->ov_head, g_object_unref); MetaScreen* screen = meta_plugin_get_screen(priv->plugin); ClutterActor* stage = meta_get_stage_for_screen(screen); ClutterActor* to_focus = NULL; if (priv->selected_actor) { to_focus = clutter_clone_get_source(CLUTTER_CLONE(priv->selected_actor)); } for (int i = 0; priv->clones && i < priv->clones->len; i++) { ClutterActor* clone = g_ptr_array_index(priv->clones, i); ClutterActor* orig = clutter_clone_get_source(CLUTTER_CLONE(clone)); clutter_actor_show(orig); // FIXME: maybe some actors had not been shown. clutter_actor_destroy(clone); } for (int i = 0; priv->badges && i < priv->badges->len; i++) { clutter_actor_destroy(CLUTTER_ACTOR(g_ptr_array_index(priv->badges, i))); } if (priv->background_actor) { clutter_actor_show(clutter_clone_get_source(CLUTTER_CLONE(priv->background_actor))); g_clear_pointer(&priv->background_actor, clutter_actor_destroy); } if (priv->modaled) { meta_plugin_end_modal(priv->plugin, clutter_get_current_event_time()); meta_enable_unredirect_for_screen(screen); if (priv->selected_workspace) { meta_workspace_activate(priv->selected_workspace, CLUTTER_CURRENT_TIME); MetaDisplay* display = meta_screen_get_display(screen); meta_compositor_switch_workspace(meta_display_get_compositor(display), meta_screen_get_active_workspace(screen), priv->selected_workspace, META_MOTION_DOWN); } else if (to_focus) { clutter_stage_set_key_focus(CLUTTER_STAGE(stage), to_focus); MetaWindowActor* actor = META_WINDOW_ACTOR(to_focus); MetaWindow* win = meta_window_actor_get_meta_window(actor); meta_window_raise(win); meta_window_focus(win, CLUTTER_CURRENT_TIME); } else if (priv->previous_focused) { if (!CLUTTER_IS_STAGE(priv->previous_focused)) { clutter_stage_set_key_focus(CLUTTER_STAGE(stage), priv->previous_focused); } } } G_OBJECT_CLASS(moses_overview_parent_class)->dispose(object); }
static void clutter_reflect_texture_paint (ClutterActor *actor) { ClutterReflectTexturePrivate *priv; ClutterReflectTexture *texture; ClutterClone *clone; ClutterTexture *parent; guint width, height; gfloat fwidth, fheight; gint r_height; gint opacity; gint bottom; CoglHandle cogl_texture; CoglTextureVertex tvert[4]; CoglFixed rty; texture = CLUTTER_REFLECT_TEXTURE (actor); clone = CLUTTER_CLONE (actor); parent = (ClutterTexture*) clutter_clone_get_source (clone); if (!parent) return; if (!CLUTTER_ACTOR_IS_REALIZED (parent)) clutter_actor_realize (CLUTTER_ACTOR (parent)); cogl_texture = clutter_texture_get_cogl_texture (parent); if (cogl_texture == COGL_INVALID_HANDLE) return; priv = texture->priv; clutter_actor_get_size (CLUTTER_ACTOR(parent), &fwidth, &fheight); width = fwidth; height = fheight; if (!height) // probably won't happen, but just in case, to avoid divide by zero. return; r_height = priv->reflection_height; bottom = priv->reflect_bottom; opacity = clutter_actor_get_opacity(actor); if (r_height < 0 || r_height > height) r_height = height; #define FX(x) COGL_FIXED_FROM_INT(x) rty = COGL_FIXED_FAST_DIV(FX(bottom ? height-r_height : r_height),FX(height)); /* clockise vertices and tex coords and colors! */ tvert[0].x = tvert[0].y = tvert[0].z = 0; tvert[0].tx = 0; tvert[0].ty = bottom ? COGL_FIXED_1 : rty; tvert[0].color.red = tvert[0].color.green = tvert[0].color.blue = 0xff; tvert[0].color.alpha = bottom ? opacity : 0; tvert[1].x = FX(width); tvert[1].y = tvert[1].z = 0; tvert[1].tx = COGL_FIXED_1; tvert[1].ty = bottom ? COGL_FIXED_1 : rty; tvert[1].color.red = tvert[1].color.green = tvert[1].color.blue = 0xff; tvert[1].color.alpha = bottom ? opacity : 0; tvert[2].x = FX(width); tvert[2].y = FX(r_height); tvert[2].z = 0; tvert[2].tx = COGL_FIXED_1; tvert[2].ty = bottom ? rty : 0; tvert[2].color.red = tvert[2].color.green = tvert[2].color.blue = 0xff; tvert[2].color.alpha = bottom ? 0 : opacity; tvert[3].x = 0; tvert[3].y = FX(r_height); tvert[3].z = 0; tvert[3].tx = 0; tvert[3].ty = bottom ? rty : 0; tvert[3].color.red = tvert[3].color.green = tvert[3].color.blue = 0xff; tvert[3].color.alpha = bottom ? 0 : opacity; cogl_push_matrix (); cogl_set_source_texture(cogl_texture); /* FIXME: this does not work as expected */ /* cogl_polygon(tvert, 4, TRUE); */ cogl_pop_matrix (); }
static void natural_placement (MosesOverview* self, MetaRectangle area) { g_debug("%s: geom: %d,%d,%d,%d", __func__, area.x, area.y, area.width, area.height); MosesOverviewPrivate* priv = self->priv; GPtrArray* clones = priv->clones; MetaRectangle bounds = {area.x, area.y, area.width, area.height}; int direction = 0; int* directions = g_malloc(sizeof(int)*clones->len); MetaRectangle* rects = g_malloc(sizeof(MetaRectangle)*clones->len); for (int i = 0; i < clones->len; i++) { // save rectangles into 4-dimensional arrays representing two corners of the rectangular: [left_x, top_y, right_x, bottom_y] MetaRectangle rect; ClutterActor* clone = g_ptr_array_index(clones, i); MetaWindowActor* actor = META_WINDOW_ACTOR(clutter_clone_get_source(CLUTTER_CLONE(clone))); MetaWindow* win = meta_window_actor_get_meta_window(actor); meta_window_get_frame_rect(win, &rect); rect = rect_adjusted(rect, -GAPS, -GAPS, GAPS, GAPS); rects[i] = rect; g_debug("%s: frame: %d,%d,%d,%d", __func__, rect.x, rect.y, rect.width, rect.height); meta_rectangle_union(&bounds, &rect, &bounds); // This is used when the window is on the edge of the screen to try to use as much screen real estate as possible. directions[i] = direction; direction++; if (direction == 4) direction = 0; } int loop_counter = 0; gboolean overlap = FALSE; do { overlap = FALSE; for (int i = 0; i < clones->len; i++) { for (int j = 0; j < clones->len; j++) { if (i == j) continue; MetaRectangle rect = rects[i]; MetaRectangle comp = rects[j]; if (!meta_rectangle_overlap(&rect, &comp)) continue; loop_counter ++; overlap = TRUE; // Determine pushing direction GdkPoint i_center = rect_center (rect); GdkPoint j_center = rect_center (comp); GdkPoint diff = {j_center.x - i_center.x, j_center.y - i_center.y}; // Prevent dividing by zero and non-movement if (diff.x == 0 && diff.y == 0) diff.x = 1; // Approximate a vector of between 10px and 20px in magnitude in the same direction float length = sqrtf (diff.x * diff.x + diff.y * diff.y); diff.x = (int)floorf (diff.x * ACCURACY / length); diff.y = (int)floorf (diff.y * ACCURACY / length); // Move both windows apart rect.x += -diff.x; rect.y += -diff.y; comp.x += diff.x; comp.y += diff.y; // Try to keep the bounding rect the same aspect as the screen so that more // screen real estate is utilised. We do this by splitting the screen into nine // equal sections, if the window center is in any of the corner sections pull the // window towards the outer corner. If it is in any of the other edge sections // alternate between each corner on that edge. We don't want to determine it // randomly as it will not produce consistant locations when using the filter. // Only move one window so we don't cause large amounts of unnecessary zooming // in some situations. We need to do this even when expanding later just in case // all windows are the same size. // (We are using an old bounding rect for this, hopefully it doesn't matter) int x_section = (int)roundf ((rect.x - bounds.x) / (bounds.width / 3.0f)); int y_section = (int)roundf ((comp.y - bounds.y) / (bounds.height / 3.0f)); i_center = rect_center (rect); diff.x = 0; diff.y = 0; if (x_section != 1 || y_section != 1) { // Remove this if you want the center to pull as well if (x_section == 1) x_section = (directions[i] / 2 == 1 ? 2 : 0); if (y_section == 1) y_section = (directions[i] % 2 == 1 ? 2 : 0); } if (x_section == 0 && y_section == 0) { diff.x = bounds.x - i_center.x; diff.y = bounds.y - i_center.y; } if (x_section == 2 && y_section == 0) { diff.x = bounds.x + bounds.width - i_center.x; diff.y = bounds.y - i_center.y; } if (x_section == 2 && y_section == 2) { diff.x = bounds.x + bounds.width - i_center.x; diff.y = bounds.y + bounds.height - i_center.y; } if (x_section == 0 && y_section == 2) { diff.x = bounds.x - i_center.x; diff.y = bounds.y + bounds.height - i_center.y; } if (diff.x != 0 || diff.y != 0) { length = sqrtf (diff.x * diff.x + diff.y * diff.y); diff.x *= (int)floorf (ACCURACY / length / 2.0f); diff.y *= (int)floorf (ACCURACY / length / 2.0f); rect.x += diff.x; rect.y += diff.y; } // Update bounding rect meta_rectangle_union(&bounds, &rect, &bounds); meta_rectangle_union(&bounds, &comp, &bounds); //we took copies from the rects from our list so we need to reassign them rects[i] = rect; rects[j] = comp; } } } while (overlap && loop_counter < MAX_TRANSLATIONS); // Work out scaling by getting the most top-left and most bottom-right window coords. float scale = fminf (fminf (area.width / (float)bounds.width, area.height / (float)bounds.height), 1.0f); // Make bounding rect fill the screen size for later steps bounds.x = (int)floorf (bounds.x - (area.width - bounds.width * scale) / 2); bounds.y = (int)floorf (bounds.y - (area.height - bounds.height * scale) / 2); bounds.width = (int)floorf (area.width / scale); bounds.height = (int)floorf (area.height / scale); // Move all windows back onto the screen and set their scale int index = 0; for (; index < clones->len; index++) { MetaRectangle rect = rects[index]; rects[index] = (MetaRectangle){ (int)floorf ((rect.x - bounds.x) * scale + area.x), (int)floorf ((rect.y - bounds.y) * scale + area.y), (int)floorf (rect.width * scale), (int)floorf (rect.height * scale) }; } // fill gaps by enlarging windows gboolean moved = FALSE; MetaRectangle border = area; do { moved = FALSE; index = 0; for (; index < clones->len; index++) { MetaRectangle rect = rects[index]; int width_diff = ACCURACY; int height_diff = (int)floorf ((((rect.width + width_diff) - rect.height) / (float)rect.width) * rect.height); int x_diff = width_diff / 2; int y_diff = height_diff / 2; //top right MetaRectangle old = rect; rect = (MetaRectangle){ rect.x + x_diff, rect.y - y_diff - height_diff, rect.width + width_diff, rect.height + width_diff }; if (rect_is_overlapping_any (rect, rects, clones->len, border)) rect = old; else moved = TRUE; //bottom right old = rect; rect = (MetaRectangle){rect.x + x_diff, rect.y + y_diff, rect.width + width_diff, rect.height + width_diff}; if (rect_is_overlapping_any (rect, rects, clones->len, border)) rect = old; else moved = TRUE; //bottom left old = rect; rect = (MetaRectangle){rect.x - x_diff, rect.y + y_diff, rect.width + width_diff, rect.height + width_diff}; if (rect_is_overlapping_any (rect, rects, clones->len, border)) rect = old; else moved = TRUE; //top left old = rect; rect = (MetaRectangle){rect.x - x_diff, rect.y - y_diff - height_diff, rect.width + width_diff, rect.height + width_diff}; if (rect_is_overlapping_any (rect, rects, clones->len, border)) rect = old; else moved = TRUE; rects[index] = rect; } } while (moved); index = 0; for (; index < clones->len; index++) { MetaRectangle rect = rects[index]; ClutterActor* clone = g_ptr_array_index(clones, index); MetaWindowActor* actor = META_WINDOW_ACTOR(clutter_clone_get_source(CLUTTER_CLONE(clone))); MetaWindow* window = meta_window_actor_get_meta_window(actor); MetaRectangle window_rect; meta_window_get_frame_rect(window, &window_rect); rect = rect_adjusted(rect, GAPS, GAPS, -GAPS, -GAPS); scale = rect.width / (float)window_rect.width; if (scale > 2.0 || (scale > 1.0 && (window_rect.width > 300 || window_rect.height > 300))) { scale = (window_rect.width > 300 || window_rect.height > 300) ? 1.0f : 2.0f; rect = (MetaRectangle){rect_center (rect).x - (int)floorf (window_rect.width * scale) / 2, rect_center (rect).y - (int)floorf (window_rect.height * scale) / 2, (int)floorf (window_rect.width * scale), (int)floorf (window_rect.height * scale)}; } place_window(self, clone, rect); } g_free(directions); g_free(rects); }