mirror of
https://github.com/brl/mutter.git
synced 2024-11-30 20:01:00 -05:00
2f4a68c8c3
The order and way include macros were structured was chaotic, with no real common thread between files. Try to tidy up the mess with some common scheme, to make things look less messy.
260 lines
7.1 KiB
C
260 lines
7.1 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
* MetaWindowShape
|
|
*
|
|
* Extracted invariant window shape
|
|
*
|
|
* Copyright (C) 2010 Red Hat, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "meta/meta-window-shape.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "compositor/region-utils.h"
|
|
|
|
struct _MetaWindowShape
|
|
{
|
|
guint ref_count;
|
|
|
|
int top, right, bottom, left;
|
|
int n_rectangles;
|
|
cairo_rectangle_int_t *rectangles;
|
|
guint hash;
|
|
};
|
|
|
|
MetaWindowShape *
|
|
meta_window_shape_new (cairo_region_t *region)
|
|
{
|
|
MetaWindowShape *shape;
|
|
MetaRegionIterator iter;
|
|
cairo_rectangle_int_t extents;
|
|
int max_yspan_y1 = 0;
|
|
int max_yspan_y2 = 0;
|
|
int max_xspan_x1 = -1;
|
|
int max_xspan_x2 = -1;
|
|
guint hash;
|
|
|
|
shape = g_slice_new0 (MetaWindowShape);
|
|
shape->ref_count = 1;
|
|
|
|
cairo_region_get_extents (region, &extents);
|
|
|
|
shape->n_rectangles = cairo_region_num_rectangles (region);
|
|
|
|
if (shape->n_rectangles == 0)
|
|
{
|
|
shape->rectangles = NULL;
|
|
shape->top = shape->right = shape->bottom = shape->left = 0;
|
|
shape->hash = 0;
|
|
return shape;
|
|
}
|
|
|
|
for (meta_region_iterator_init (&iter, region);
|
|
!meta_region_iterator_at_end (&iter);
|
|
meta_region_iterator_next (&iter))
|
|
{
|
|
int max_line_xspan_x1 = -1;
|
|
int max_line_xspan_x2 = -1;
|
|
|
|
if (iter.rectangle.width > max_line_xspan_x2 - max_line_xspan_x1)
|
|
{
|
|
max_line_xspan_x1 = iter.rectangle.x;
|
|
max_line_xspan_x2 = iter.rectangle.x + iter.rectangle.width;
|
|
}
|
|
|
|
if (iter.line_end)
|
|
{
|
|
if (iter.rectangle.height > max_yspan_y2 - max_yspan_y1)
|
|
{
|
|
max_yspan_y1 = iter.rectangle.y;
|
|
max_yspan_y2 = iter.rectangle.y + iter.rectangle.height;
|
|
}
|
|
|
|
if (max_xspan_x1 < 0) /* First line */
|
|
{
|
|
max_xspan_x1 = max_line_xspan_x1;
|
|
max_xspan_x2 = max_line_xspan_x2;
|
|
}
|
|
else
|
|
{
|
|
max_xspan_x1 = MAX (max_xspan_x1, max_line_xspan_x1);
|
|
max_xspan_x2 = MIN (max_xspan_x2, max_line_xspan_x2);
|
|
|
|
if (max_xspan_x2 < max_xspan_x1)
|
|
max_xspan_x2 = max_xspan_x1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
g_print ("xspan: %d -> %d, yspan: %d -> %d\n",
|
|
max_xspan_x1, max_xspan_x2,
|
|
max_yspan_y1, max_yspan_y2);
|
|
#endif
|
|
|
|
shape->top = max_yspan_y1 - extents.y;
|
|
shape->right = extents.x + extents.width - max_xspan_x2;
|
|
shape->bottom = extents.y + extents.height - max_yspan_y2;
|
|
shape->left = max_xspan_x1 - extents.x;
|
|
|
|
shape->rectangles = g_new (cairo_rectangle_int_t, shape->n_rectangles);
|
|
|
|
hash = 0;
|
|
for (meta_region_iterator_init (&iter, region);
|
|
!meta_region_iterator_at_end (&iter);
|
|
meta_region_iterator_next (&iter))
|
|
{
|
|
int x1, x2, y1, y2;
|
|
|
|
x1 = iter.rectangle.x;
|
|
x2 = iter.rectangle.x + iter.rectangle.width;
|
|
y1 = iter.rectangle.y;
|
|
y2 = iter.rectangle.y + iter.rectangle.height;
|
|
|
|
if (x1 > max_xspan_x1)
|
|
x1 -= MIN (x1, max_xspan_x2 - 1) - max_xspan_x1;
|
|
if (x2 > max_xspan_x1)
|
|
x2 -= MIN (x2, max_xspan_x2 - 1) - max_xspan_x1;
|
|
if (y1 > max_yspan_y1)
|
|
y1 -= MIN (y1, max_yspan_y2 - 1) - max_yspan_y1;
|
|
if (y2 > max_yspan_y1)
|
|
y2 -= MIN (y2, max_yspan_y2 - 1) - max_yspan_y1;
|
|
|
|
shape->rectangles[iter.i].x = x1 - extents.x;
|
|
shape->rectangles[iter.i].y = y1 - extents.y;
|
|
shape->rectangles[iter.i].width = x2 - x1;
|
|
shape->rectangles[iter.i].height = y2 - y1;
|
|
|
|
#if 0
|
|
g_print ("%d: +%d+%dx%dx%d => +%d+%dx%dx%d\n",
|
|
iter.i, iter.rectangle.x, iter.rectangle.y, iter.rectangle.width, iter.rectangle.height,
|
|
shape->rectangles[iter.i].x, shape->rectangles[iter.i].y,
|
|
hape->rectangles[iter.i].width, shape->rectangles[iter.i].height);
|
|
#endif
|
|
|
|
hash = hash * 31 + x1 * 17 + x2 * 27 + y1 * 37 + y2 * 43;
|
|
}
|
|
|
|
shape->hash = hash;
|
|
|
|
#if 0
|
|
g_print ("%d %d %d %d: %#x\n\n", shape->top, shape->right, shape->bottom, shape->left, shape->hash);
|
|
#endif
|
|
|
|
return shape;
|
|
}
|
|
|
|
MetaWindowShape *
|
|
meta_window_shape_ref (MetaWindowShape *shape)
|
|
{
|
|
shape->ref_count++;
|
|
|
|
return shape;
|
|
}
|
|
|
|
void
|
|
meta_window_shape_unref (MetaWindowShape *shape)
|
|
{
|
|
shape->ref_count--;
|
|
if (shape->ref_count == 0)
|
|
{
|
|
g_free (shape->rectangles);
|
|
g_slice_free (MetaWindowShape, shape);
|
|
}
|
|
}
|
|
|
|
guint
|
|
meta_window_shape_hash (MetaWindowShape *shape)
|
|
{
|
|
return shape->hash;
|
|
}
|
|
|
|
gboolean
|
|
meta_window_shape_equal (MetaWindowShape *shape_a,
|
|
MetaWindowShape *shape_b)
|
|
{
|
|
if (shape_a->n_rectangles != shape_b->n_rectangles)
|
|
return FALSE;
|
|
|
|
return memcmp (shape_a->rectangles, shape_b->rectangles,
|
|
sizeof (cairo_rectangle_int_t) * shape_a->n_rectangles) == 0;
|
|
}
|
|
|
|
void
|
|
meta_window_shape_get_borders (MetaWindowShape *shape,
|
|
int *border_top,
|
|
int *border_right,
|
|
int *border_bottom,
|
|
int *border_left)
|
|
{
|
|
if (border_top)
|
|
*border_top = shape->top;
|
|
if (border_right)
|
|
*border_right = shape->right;
|
|
if (border_bottom)
|
|
*border_bottom = shape->bottom;
|
|
if (border_left)
|
|
*border_left = shape->left;
|
|
}
|
|
|
|
/**
|
|
* meta_window_shape_to_region:
|
|
* @shape: a #MetaWindowShape
|
|
* @center_width: size of the central region horizontally
|
|
* @center_height: size of the central region vertically
|
|
*
|
|
* Converts the shape to to a cairo_region_t using the given width
|
|
* and height for the central scaled region.
|
|
*
|
|
* Return value: a newly created region
|
|
*/
|
|
cairo_region_t *
|
|
meta_window_shape_to_region (MetaWindowShape *shape,
|
|
int center_width,
|
|
int center_height)
|
|
{
|
|
cairo_region_t *region;
|
|
int i;
|
|
|
|
region = cairo_region_create ();
|
|
|
|
for (i = 0; i < shape->n_rectangles; i++)
|
|
{
|
|
cairo_rectangle_int_t rect = shape->rectangles[i];
|
|
|
|
if (rect.x <= shape->left && rect.x + rect.width >= shape->left + 1)
|
|
rect.width += center_width;
|
|
else if (rect.x >= shape->left + 1)
|
|
rect.x += center_width;
|
|
|
|
if (rect.y <= shape->top && rect.y + rect.height >= shape->top + 1)
|
|
rect.height += center_height;
|
|
else if (rect.y >= shape->top + 1)
|
|
rect.y += center_height;
|
|
|
|
cairo_region_union_rectangle (region, &rect);
|
|
}
|
|
|
|
return region;
|
|
}
|
|
|
|
G_DEFINE_BOXED_TYPE (MetaWindowShape, meta_window_shape,
|
|
meta_window_shape_ref, meta_window_shape_unref)
|