0201fcfc6c
2006-10-01 Elijah Newren <newren gmail com> * src/*.[ch]: Stick an emacs comment directive at the beginning of all the code files so that people using emacs will be more likely to get coding style correct in their patches. We still need a similar vi directive. #358866
787 lines
23 KiB
C
787 lines
23 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/* Metacity animation effects */
|
|
|
|
/*
|
|
* Copyright (C) 2001 Anders Carlsson, Havoc Pennington
|
|
*
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include "effects.h"
|
|
#include "display.h"
|
|
#include "ui.h"
|
|
#include "window.h"
|
|
|
|
#ifdef HAVE_SHAPE
|
|
#include <X11/extensions/shape.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
typedef enum
|
|
{
|
|
META_ANIMATION_DRAW_ROOT,
|
|
META_ANIMATION_WINDOW_WIREFRAME,
|
|
META_ANIMATION_WINDOW_OPAQUE
|
|
|
|
} MetaAnimationStyle;
|
|
|
|
typedef struct
|
|
{
|
|
MetaScreen *screen;
|
|
|
|
double millisecs_duration;
|
|
GTimeVal start_time;
|
|
|
|
gboolean first_time;
|
|
|
|
MetaRectangle start_rect;
|
|
MetaRectangle end_rect;
|
|
|
|
/* rect to erase */
|
|
MetaRectangle last_rect;
|
|
|
|
/* used instead of the global flag, since
|
|
* we don't want to change midstream.
|
|
*/
|
|
MetaAnimationStyle style;
|
|
|
|
/* For wireframe drawn on root window */
|
|
GC gc;
|
|
|
|
/* For wireframe window */
|
|
Window wireframe_xwindow;
|
|
|
|
/* For opaque */
|
|
MetaImageWindow *image_window;
|
|
GdkPixbuf *orig_pixbuf;
|
|
|
|
MetaBoxAnimType anim_type;
|
|
|
|
} BoxAnimationContext;
|
|
|
|
struct MetaEffectPriv
|
|
{
|
|
MetaEffectFinished finished;
|
|
gpointer finished_data;
|
|
};
|
|
|
|
static void run_default_effect_handler (MetaEffect *effect);
|
|
static void run_handler (MetaEffect *effect);
|
|
|
|
static MetaEffectHandler effect_handler;
|
|
static gpointer effect_handler_data;
|
|
|
|
void
|
|
meta_push_effect_handler (MetaEffectHandler handler,
|
|
gpointer data)
|
|
{
|
|
effect_handler = handler;
|
|
effect_handler_data = data;
|
|
}
|
|
|
|
void
|
|
meta_pop_effect_handler (void)
|
|
{
|
|
/* FIXME: not implemented yet */
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static MetaEffect *
|
|
create_effect (MetaEffectType type,
|
|
MetaWindow *window,
|
|
MetaEffectFinished finished,
|
|
gpointer finished_data)
|
|
{
|
|
MetaEffect *effect = g_new (MetaEffect, 1);
|
|
|
|
effect->type = type;
|
|
effect->window = window;
|
|
effect->priv = g_new (MetaEffectPriv, 1);
|
|
effect->priv->finished = finished;
|
|
effect->priv->finished_data = finished_data;
|
|
|
|
return effect;
|
|
}
|
|
|
|
void
|
|
meta_effect_end (MetaEffect *effect)
|
|
{
|
|
if (effect->priv->finished)
|
|
effect->priv->finished (effect, effect->priv->finished_data);
|
|
|
|
g_free (effect->priv);
|
|
g_free (effect);
|
|
}
|
|
|
|
void
|
|
meta_effect_run_focus (MetaWindow *window,
|
|
MetaEffectFinished finished,
|
|
gpointer data)
|
|
{
|
|
MetaEffect *effect;
|
|
|
|
g_return_if_fail (window != NULL);
|
|
|
|
effect = create_effect (META_EFFECT_FOCUS, window, finished, data);
|
|
|
|
run_handler (effect);
|
|
}
|
|
|
|
void
|
|
meta_effect_run_minimize (MetaWindow *window,
|
|
MetaRectangle *window_rect,
|
|
MetaRectangle *icon_rect,
|
|
MetaEffectFinished finished,
|
|
gpointer data)
|
|
{
|
|
MetaEffect *effect;
|
|
|
|
g_return_if_fail (window != NULL);
|
|
g_return_if_fail (icon_rect != NULL);
|
|
|
|
effect = create_effect (META_EFFECT_MINIMIZE, window, finished, data);
|
|
|
|
effect->u.minimize.window_rect = *window_rect;
|
|
effect->u.minimize.icon_rect = *icon_rect;
|
|
|
|
run_handler (effect);
|
|
}
|
|
|
|
void
|
|
meta_effect_run_unminimize (MetaWindow *window,
|
|
MetaRectangle *window_rect,
|
|
MetaRectangle *icon_rect,
|
|
MetaEffectFinished finished,
|
|
gpointer data)
|
|
{
|
|
MetaEffect *effect;
|
|
|
|
g_return_if_fail (window != NULL);
|
|
g_return_if_fail (icon_rect != NULL);
|
|
|
|
effect = create_effect (META_EFFECT_UNMINIMIZE, window, finished, data);
|
|
|
|
effect->u.minimize.window_rect = *window_rect;
|
|
effect->u.minimize.icon_rect = *icon_rect;
|
|
|
|
run_handler (effect);
|
|
}
|
|
|
|
void
|
|
meta_effect_run_close (MetaWindow *window,
|
|
MetaEffectFinished finished,
|
|
gpointer data)
|
|
{
|
|
MetaEffect *effect;
|
|
|
|
g_return_if_fail (window != NULL);
|
|
|
|
effect = create_effect (META_EFFECT_CLOSE, window,
|
|
finished, data);
|
|
|
|
run_handler (effect);
|
|
}
|
|
|
|
|
|
/* old ugly minimization effect */
|
|
|
|
static void
|
|
update_wireframe_window (MetaDisplay *display,
|
|
Window xwindow,
|
|
const MetaRectangle *rect)
|
|
{
|
|
XMoveResizeWindow (display->xdisplay,
|
|
xwindow,
|
|
rect->x, rect->y,
|
|
rect->width, rect->height);
|
|
|
|
#ifdef HAVE_SHAPE
|
|
|
|
#define OUTLINE_WIDTH 3
|
|
|
|
if (rect->width > OUTLINE_WIDTH * 2 &&
|
|
rect->height > OUTLINE_WIDTH * 2)
|
|
{
|
|
XRectangle xrect;
|
|
Region inner_xregion;
|
|
Region outer_xregion;
|
|
|
|
inner_xregion = XCreateRegion ();
|
|
outer_xregion = XCreateRegion ();
|
|
|
|
xrect.x = 0;
|
|
xrect.y = 0;
|
|
xrect.width = rect->width;
|
|
xrect.height = rect->height;
|
|
|
|
XUnionRectWithRegion (&xrect, outer_xregion, outer_xregion);
|
|
|
|
xrect.x += OUTLINE_WIDTH;
|
|
xrect.y += OUTLINE_WIDTH;
|
|
xrect.width -= OUTLINE_WIDTH * 2;
|
|
xrect.height -= OUTLINE_WIDTH * 2;
|
|
|
|
XUnionRectWithRegion (&xrect, inner_xregion, inner_xregion);
|
|
|
|
XSubtractRegion (outer_xregion, inner_xregion, outer_xregion);
|
|
|
|
XShapeCombineRegion (display->xdisplay, xwindow,
|
|
ShapeBounding, 0, 0, outer_xregion, ShapeSet);
|
|
|
|
XDestroyRegion (outer_xregion);
|
|
XDestroyRegion (inner_xregion);
|
|
}
|
|
else
|
|
{
|
|
/* Unset the shape */
|
|
XShapeCombineMask (display->xdisplay, xwindow,
|
|
ShapeBounding, 0, 0, None, ShapeSet);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
graphics_sync (BoxAnimationContext *context)
|
|
{
|
|
XImage *image;
|
|
|
|
/* A hack to force the X server to synchronize with the
|
|
* graphics hardware
|
|
*/
|
|
image = XGetImage (context->screen->display->xdisplay,
|
|
context->screen->xroot,
|
|
0, 0, 1, 1,
|
|
AllPlanes, ZPixmap);
|
|
|
|
XDestroyImage (image);
|
|
}
|
|
|
|
static gboolean
|
|
effects_draw_box_animation_timeout (BoxAnimationContext *context)
|
|
{
|
|
double elapsed;
|
|
GTimeVal current_time;
|
|
MetaRectangle draw_rect;
|
|
double fraction;
|
|
|
|
if (!context->first_time)
|
|
{
|
|
if (context->style == META_ANIMATION_DRAW_ROOT)
|
|
{
|
|
/* Restore the previously drawn background */
|
|
XDrawRectangle (context->screen->display->xdisplay,
|
|
context->screen->xroot,
|
|
context->gc,
|
|
context->last_rect.x, context->last_rect.y,
|
|
context->last_rect.width, context->last_rect.height);
|
|
}
|
|
}
|
|
|
|
context->first_time = FALSE;
|
|
|
|
g_get_current_time (¤t_time);
|
|
|
|
/* We use milliseconds for all times */
|
|
elapsed =
|
|
((((double)current_time.tv_sec - context->start_time.tv_sec) * G_USEC_PER_SEC +
|
|
(current_time.tv_usec - context->start_time.tv_usec))) / 1000.0;
|
|
|
|
if (elapsed < 0)
|
|
{
|
|
/* Probably the system clock was set backwards? */
|
|
meta_warning ("System clock seemed to go backwards?\n");
|
|
elapsed = G_MAXDOUBLE; /* definitely done. */
|
|
}
|
|
|
|
if (elapsed > context->millisecs_duration)
|
|
{
|
|
/* All done */
|
|
if (context->style == META_ANIMATION_WINDOW_OPAQUE)
|
|
{
|
|
g_object_unref (G_OBJECT (context->orig_pixbuf));
|
|
meta_image_window_free (context->image_window);
|
|
}
|
|
else if (context->style == META_ANIMATION_DRAW_ROOT)
|
|
{
|
|
meta_display_ungrab (context->screen->display);
|
|
meta_ui_pop_delay_exposes (context->screen->ui);
|
|
XFreeGC (context->screen->display->xdisplay,
|
|
context->gc);
|
|
}
|
|
else if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
|
{
|
|
XDestroyWindow (context->screen->display->xdisplay,
|
|
context->wireframe_xwindow);
|
|
}
|
|
|
|
graphics_sync (context);
|
|
|
|
g_free (context);
|
|
return FALSE;
|
|
}
|
|
|
|
g_assert (context->millisecs_duration > 0.0);
|
|
fraction = elapsed / context->millisecs_duration;
|
|
|
|
draw_rect = context->start_rect;
|
|
|
|
/* Now add a delta proportional to elapsed time. */
|
|
draw_rect.x += (context->end_rect.x - context->start_rect.x) * fraction;
|
|
draw_rect.y += (context->end_rect.y - context->start_rect.y) * fraction;
|
|
draw_rect.width += (context->end_rect.width - context->start_rect.width) * fraction;
|
|
draw_rect.height += (context->end_rect.height - context->start_rect.height) * fraction;
|
|
|
|
/* don't confuse X or gdk-pixbuf with bogus rectangles */
|
|
if (draw_rect.width < 1)
|
|
draw_rect.width = 1;
|
|
if (draw_rect.height < 1)
|
|
draw_rect.height = 1;
|
|
|
|
context->last_rect = draw_rect;
|
|
|
|
if (context->style == META_ANIMATION_WINDOW_OPAQUE)
|
|
{
|
|
GdkPixbuf *scaled;
|
|
|
|
scaled = NULL;
|
|
switch (context->anim_type)
|
|
{
|
|
case META_BOX_ANIM_SCALE:
|
|
scaled = gdk_pixbuf_scale_simple (context->orig_pixbuf,
|
|
draw_rect.width,
|
|
draw_rect.height,
|
|
GDK_INTERP_BILINEAR);
|
|
break;
|
|
case META_BOX_ANIM_SLIDE_UP:
|
|
{
|
|
int x, y;
|
|
|
|
x = context->start_rect.width - draw_rect.width;
|
|
y = context->start_rect.height - draw_rect.height;
|
|
|
|
/* paranoia */
|
|
if (x < 0)
|
|
x = 0;
|
|
if (y < 0)
|
|
y = 0;
|
|
|
|
scaled = gdk_pixbuf_new_subpixbuf (context->orig_pixbuf,
|
|
x, y,
|
|
draw_rect.width,
|
|
draw_rect.height);
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* handle out-of-memory */
|
|
if (scaled != NULL)
|
|
{
|
|
meta_image_window_set (context->image_window,
|
|
scaled,
|
|
draw_rect.x, draw_rect.y);
|
|
|
|
g_object_unref (G_OBJECT (scaled));
|
|
}
|
|
}
|
|
else if (context->style == META_ANIMATION_DRAW_ROOT)
|
|
{
|
|
/* Draw the rectangle */
|
|
XDrawRectangle (context->screen->display->xdisplay,
|
|
context->screen->xroot,
|
|
context->gc,
|
|
draw_rect.x, draw_rect.y,
|
|
draw_rect.width, draw_rect.height);
|
|
}
|
|
else if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
|
{
|
|
update_wireframe_window (context->screen->display,
|
|
context->wireframe_xwindow,
|
|
&draw_rect);
|
|
}
|
|
|
|
/* kick changes onto the server */
|
|
graphics_sync (context);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* I really don't want this to be a configuration option, but I think
|
|
* the wireframe is sucky from a UI standpoint (more confusing than
|
|
* opaque), but the opaque is definitely still too slow on some
|
|
* systems, and also doesn't look quite right due to the mapping
|
|
* and unmapping of windows that's going on.
|
|
*/
|
|
|
|
static MetaAnimationStyle animation_style = META_ANIMATION_WINDOW_WIREFRAME;
|
|
|
|
void
|
|
meta_effects_draw_box_animation (MetaScreen *screen,
|
|
MetaRectangle *initial_rect,
|
|
MetaRectangle *destination_rect,
|
|
double seconds_duration,
|
|
MetaBoxAnimType anim_type)
|
|
{
|
|
BoxAnimationContext *context;
|
|
|
|
g_return_if_fail (seconds_duration > 0.0);
|
|
|
|
if (g_getenv ("METACITY_DEBUG_EFFECTS"))
|
|
seconds_duration *= 10; /* slow things down */
|
|
|
|
/* Create the animation context */
|
|
context = g_new0 (BoxAnimationContext, 1);
|
|
|
|
context->screen = screen;
|
|
|
|
context->millisecs_duration = seconds_duration * 1000.0;
|
|
context->first_time = TRUE;
|
|
context->start_rect = *initial_rect;
|
|
context->end_rect = *destination_rect;
|
|
context->anim_type = anim_type;
|
|
|
|
context->style = animation_style;
|
|
|
|
#ifndef HAVE_SHAPE
|
|
if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
|
context->style = META_ANIMATION_DRAW_ROOT;
|
|
#endif
|
|
|
|
if (context->style == META_ANIMATION_WINDOW_OPAQUE)
|
|
{
|
|
GdkPixbuf *pix;
|
|
|
|
pix = meta_gdk_pixbuf_get_from_window (NULL,
|
|
screen->xroot,
|
|
initial_rect->x,
|
|
initial_rect->y,
|
|
0, 0,
|
|
initial_rect->width,
|
|
initial_rect->height);
|
|
|
|
if (pix == NULL)
|
|
{
|
|
/* Fall back to wireframe */
|
|
context->style = META_ANIMATION_WINDOW_WIREFRAME;
|
|
}
|
|
else
|
|
{
|
|
context->image_window = meta_image_window_new (screen->display->xdisplay,
|
|
screen->number,
|
|
initial_rect->width,
|
|
initial_rect->height);
|
|
context->orig_pixbuf = pix;
|
|
meta_image_window_set (context->image_window,
|
|
context->orig_pixbuf,
|
|
initial_rect->x,
|
|
initial_rect->y);
|
|
meta_image_window_set_showing (context->image_window, TRUE);
|
|
}
|
|
}
|
|
|
|
/* Not an else, so that fallback works */
|
|
if (context->style == META_ANIMATION_WINDOW_WIREFRAME)
|
|
{
|
|
XSetWindowAttributes attrs;
|
|
|
|
attrs.override_redirect = True;
|
|
attrs.background_pixel = BlackPixel (screen->display->xdisplay,
|
|
screen->number);
|
|
|
|
context->wireframe_xwindow = XCreateWindow (screen->display->xdisplay,
|
|
screen->xroot,
|
|
initial_rect->x,
|
|
initial_rect->y,
|
|
initial_rect->width,
|
|
initial_rect->height,
|
|
0,
|
|
CopyFromParent,
|
|
CopyFromParent,
|
|
(Visual *)CopyFromParent,
|
|
CWOverrideRedirect | CWBackPixel,
|
|
&attrs);
|
|
|
|
update_wireframe_window (screen->display,
|
|
context->wireframe_xwindow,
|
|
initial_rect);
|
|
|
|
XMapWindow (screen->display->xdisplay,
|
|
context->wireframe_xwindow);
|
|
}
|
|
|
|
if (context->style == META_ANIMATION_DRAW_ROOT)
|
|
{
|
|
XGCValues gc_values;
|
|
|
|
gc_values.subwindow_mode = IncludeInferiors;
|
|
gc_values.function = GXinvert;
|
|
|
|
context->gc = XCreateGC (screen->display->xdisplay,
|
|
screen->xroot,
|
|
GCSubwindowMode | GCFunction,
|
|
&gc_values);
|
|
|
|
/* Grab the X server to avoid screen dirt */
|
|
meta_display_grab (context->screen->display);
|
|
meta_ui_push_delay_exposes (context->screen->ui);
|
|
}
|
|
|
|
/* Do this only after we get the pixbuf from the server,
|
|
* so that the animation doesn't get truncated.
|
|
*/
|
|
g_get_current_time (&context->start_time);
|
|
|
|
/* Add the timeout - a short one, could even use an idle,
|
|
* but this is maybe more CPU-friendly.
|
|
*/
|
|
g_timeout_add (15,
|
|
(GSourceFunc)effects_draw_box_animation_timeout,
|
|
context);
|
|
|
|
/* kick changes onto the server */
|
|
XFlush (context->screen->display->xdisplay);
|
|
}
|
|
|
|
void
|
|
meta_effects_begin_wireframe (MetaScreen *screen,
|
|
const MetaRectangle *rect,
|
|
int width,
|
|
int height)
|
|
{
|
|
/* Grab the X server to avoid screen dirt */
|
|
meta_display_grab (screen->display);
|
|
meta_ui_push_delay_exposes (screen->ui);
|
|
|
|
meta_effects_update_wireframe (screen,
|
|
NULL, -1, -1,
|
|
rect, width, height);
|
|
}
|
|
|
|
static void
|
|
draw_xor_rect (MetaScreen *screen,
|
|
const MetaRectangle *rect,
|
|
int width,
|
|
int height)
|
|
{
|
|
/* The lines in the center can't overlap the rectangle or each
|
|
* other, or the XOR gets reversed. So we have to draw things
|
|
* a bit oddly.
|
|
*/
|
|
XSegment segments[8];
|
|
MetaRectangle shrunk_rect;
|
|
int i;
|
|
|
|
#define LINE_WIDTH META_WIREFRAME_XOR_LINE_WIDTH
|
|
|
|
/* We don't want the wireframe going outside the window area.
|
|
* It makes it harder for the user to position windows and it exposes other
|
|
* annoying bugs.
|
|
*/
|
|
shrunk_rect = *rect;
|
|
|
|
shrunk_rect.x += LINE_WIDTH / 2 + LINE_WIDTH % 2;
|
|
shrunk_rect.y += LINE_WIDTH / 2 + LINE_WIDTH % 2;
|
|
shrunk_rect.width -= LINE_WIDTH + 2 * (LINE_WIDTH % 2);
|
|
shrunk_rect.height -= LINE_WIDTH + 2 * (LINE_WIDTH % 2);
|
|
|
|
XDrawRectangle (screen->display->xdisplay,
|
|
screen->xroot,
|
|
screen->root_xor_gc,
|
|
shrunk_rect.x, shrunk_rect.y,
|
|
shrunk_rect.width, shrunk_rect.height);
|
|
|
|
/* Don't put lines inside small rectangles where they won't fit */
|
|
if (shrunk_rect.width < (LINE_WIDTH * 4) ||
|
|
shrunk_rect.height < (LINE_WIDTH * 4))
|
|
return;
|
|
|
|
if ((width >= 0) && (height >= 0))
|
|
{
|
|
XGCValues gc_values = { 0 };
|
|
|
|
if (XGetGCValues (screen->display->xdisplay,
|
|
screen->root_xor_gc,
|
|
GCFont, &gc_values))
|
|
{
|
|
char *text;
|
|
int text_length;
|
|
|
|
XFontStruct *font_struct;
|
|
int text_width, text_height;
|
|
int box_x, box_y;
|
|
int box_width, box_height;
|
|
|
|
font_struct = XQueryFont (screen->display->xdisplay,
|
|
gc_values.font);
|
|
|
|
if (font_struct != NULL)
|
|
{
|
|
text = g_strdup_printf ("%d x %d", width, height);
|
|
text_length = strlen (text);
|
|
|
|
text_width = text_length * font_struct->max_bounds.width;
|
|
text_height = font_struct->max_bounds.descent +
|
|
font_struct->max_bounds.ascent;
|
|
|
|
box_width = text_width + 2 * LINE_WIDTH;
|
|
box_height = text_height + 2 * LINE_WIDTH;
|
|
|
|
|
|
box_x = shrunk_rect.x + (shrunk_rect.width - box_width) / 2;
|
|
box_y = shrunk_rect.y + (shrunk_rect.height - box_height) / 2;
|
|
|
|
if ((box_width < shrunk_rect.width) &&
|
|
(box_height < shrunk_rect.height))
|
|
{
|
|
XFillRectangle (screen->display->xdisplay,
|
|
screen->xroot,
|
|
screen->root_xor_gc,
|
|
box_x, box_y,
|
|
box_width, box_height);
|
|
XDrawString (screen->display->xdisplay,
|
|
screen->xroot,
|
|
screen->root_xor_gc,
|
|
box_x + LINE_WIDTH,
|
|
box_y + LINE_WIDTH + font_struct->max_bounds.ascent,
|
|
text, text_length);
|
|
}
|
|
|
|
g_free (text);
|
|
|
|
XFreeFontInfo (NULL, font_struct, 1);
|
|
|
|
if ((box_width + LINE_WIDTH) >= (shrunk_rect.width / 3))
|
|
return;
|
|
|
|
if ((box_height + LINE_WIDTH) >= (shrunk_rect.height / 3))
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Two vertical lines at 1/3 and 2/3 */
|
|
segments[0].x1 = shrunk_rect.x + shrunk_rect.width / 3;
|
|
segments[0].y1 = shrunk_rect.y + LINE_WIDTH / 2 + LINE_WIDTH % 2;
|
|
segments[0].x2 = segments[0].x1;
|
|
segments[0].y2 = shrunk_rect.y + shrunk_rect.height - LINE_WIDTH / 2;
|
|
|
|
segments[1] = segments[0];
|
|
segments[1].x1 = shrunk_rect.x + (shrunk_rect.width / 3) * 2;
|
|
segments[1].x2 = segments[1].x1;
|
|
|
|
/* Now make two horizontal lines at 1/3 and 2/3, but not
|
|
* overlapping the verticals
|
|
*/
|
|
|
|
segments[2].x1 = shrunk_rect.x + LINE_WIDTH / 2 + LINE_WIDTH % 2;
|
|
segments[2].x2 = segments[0].x1 - LINE_WIDTH / 2;
|
|
segments[2].y1 = shrunk_rect.y + shrunk_rect.height / 3;
|
|
segments[2].y2 = segments[2].y1;
|
|
|
|
segments[3] = segments[2];
|
|
segments[3].x1 = segments[2].x2 + LINE_WIDTH;
|
|
segments[3].x2 = segments[1].x1 - LINE_WIDTH / 2;
|
|
|
|
segments[4] = segments[3];
|
|
segments[4].x1 = segments[3].x2 + LINE_WIDTH;
|
|
segments[4].x2 = shrunk_rect.x + shrunk_rect.width - LINE_WIDTH / 2;
|
|
|
|
/* Second horizontal line is just like the first, but
|
|
* shifted down
|
|
*/
|
|
i = 5;
|
|
while (i < 8)
|
|
{
|
|
segments[i] = segments[i - 3];
|
|
segments[i].y1 = shrunk_rect.y + (shrunk_rect.height / 3) * 2;
|
|
segments[i].y2 = segments[i].y1;
|
|
++i;
|
|
}
|
|
|
|
XDrawSegments (screen->display->xdisplay,
|
|
screen->xroot,
|
|
screen->root_xor_gc,
|
|
segments,
|
|
G_N_ELEMENTS (segments));
|
|
}
|
|
|
|
void
|
|
meta_effects_update_wireframe (MetaScreen *screen,
|
|
const MetaRectangle *old_rect,
|
|
int old_width,
|
|
int old_height,
|
|
const MetaRectangle *new_rect,
|
|
int new_width,
|
|
int new_height)
|
|
{
|
|
if (old_rect)
|
|
draw_xor_rect (screen, old_rect, old_width, old_height);
|
|
|
|
if (new_rect)
|
|
draw_xor_rect (screen, new_rect, new_width, new_height);
|
|
|
|
XFlush (screen->display->xdisplay);
|
|
}
|
|
|
|
void
|
|
meta_effects_end_wireframe (MetaScreen *screen,
|
|
const MetaRectangle *old_rect,
|
|
int old_width,
|
|
int old_height)
|
|
{
|
|
meta_effects_update_wireframe (screen,
|
|
old_rect, old_width, old_height,
|
|
NULL, -1, -1);
|
|
|
|
meta_display_ungrab (screen->display);
|
|
meta_ui_pop_delay_exposes (screen->ui);
|
|
}
|
|
|
|
static void
|
|
run_default_effect_handler (MetaEffect *effect)
|
|
{
|
|
switch (effect->type)
|
|
{
|
|
case META_EFFECT_MINIMIZE:
|
|
meta_effects_draw_box_animation (effect->window->screen,
|
|
&(effect->u.minimize.window_rect),
|
|
&(effect->u.minimize.icon_rect),
|
|
META_MINIMIZE_ANIMATION_LENGTH,
|
|
META_BOX_ANIM_SCALE);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
run_handler (MetaEffect *effect)
|
|
{
|
|
if (effect_handler)
|
|
{
|
|
effect_handler (effect, effect_handler_data);
|
|
}
|
|
else
|
|
{
|
|
run_default_effect_handler (effect);
|
|
meta_effect_end (effect);
|
|
}
|
|
}
|