Beginning of new layer that abstracts transition effects.

Mon May 22 17:35:52 2006  Søren Sandmann  <sandmann@redhat.com>

	* src/effects.[ch]: Beginning of new layer that abstracts
	transition effects.

	New functions:
	(meta_push_effect_handler): Install an effect handler
	(meta_pop_effect_handler): Remove last effect handler
	(meta_effect_run_minimize): Create a minimize effect and pass it
	to the handler.
	(meta_effect_end): Called by handler when the effect is finished.

	* src/compositor.c: Move explosion code form there to src/c-window.c.

	* src/c-screen.c: Delete explosion related code.
This commit is contained in:
Søren Sandmann 2006-05-22 21:46:14 +00:00 committed by Søren Sandmann Pedersen
parent cdb94d7e57
commit 3e5b9776c6
10 changed files with 440 additions and 244 deletions

View File

@ -1,3 +1,19 @@
Mon May 22 17:35:52 2006 Søren Sandmann <sandmann@redhat.com>
* src/effects.[ch]: Beginning of new layer that abstracts
transition effects.
New functions:
(meta_push_effect_handler): Install an effect handler
(meta_pop_effect_handler): Remove last effect handler
(meta_effect_run_minimize): Create a minimize effect and pass it
to the handler.
(meta_effect_end): Called by handler when the effect is finished.
* src/compositor.c: Move explosion code form there to src/c-window.c.
* src/c-screen.c: Delete explosion related code.
2006-05-22 Björn Lindqvist <bjourne@gmail.com>
* common.h (enum MetaCursor):

View File

@ -64,6 +64,13 @@ meta_comp_window_lookup (MetaCompScreen *info,
return window;
}
MetaCompWindow *
meta_comp_screen_lookup_window (MetaCompScreen *info,
Window xwindow)
{
return meta_comp_window_lookup (info, xwindow);
}
#if 0
static void
update_frame_counter (void)
@ -650,23 +657,6 @@ meta_comp_screen_set_target_rect (MetaCompScreen *info,
cm_drawable_node_set_scale_rect (node, rect);
}
void
meta_comp_screen_set_explode (MetaCompScreen *info,
Window xwindow,
gdouble level)
{
CmDrawableNode *node = CM_DRAWABLE_NODE (find_node (info, xwindow));
if (node)
{
#if 0
g_print ("level: %f\n", level);
#endif
cm_drawable_node_set_explosion_level (node, level);
}
}
void
meta_comp_screen_hide_window (MetaCompScreen *info,
Window xwindow)

View File

@ -1,4 +1,5 @@
#include "screen.h"
#include "c-window.h"
typedef struct MetaCompScreen MetaCompScreen;
@ -48,4 +49,5 @@ void meta_comp_screen_hide_window (MetaCompScreen *info,
Window xwindow);
void meta_comp_screen_unmap (MetaCompScreen *info,
Window xwindow);
MetaCompWindow *meta_comp_screen_lookup_window (MetaCompScreen *info,
Window xwindow);

View File

@ -28,7 +28,9 @@
#include <cm/node.h>
#include <cm/drawable-node.h>
#include <string.h>
#include <math.h>
#include "effects.h"
#include "c-window.h"
#include "window.h"
@ -42,19 +44,135 @@ struct _MetaCompWindow
WsSyncAlarm *alarm;
WsRectangle size;
gboolean waiting_for_paint;
};
static Window
find_app_window (MetaCompWindow *comp_window)
{
Window xwindow = WS_RESOURCE_XID (comp_window->drawable);
MetaWindow *meta_window =
meta_display_lookup_x_window (comp_window->display, xwindow);
if (meta_window)
return meta_window->xwindow;
else
return xwindow;
}
static WsPixmap *
take_snapshot (WsDrawable *drawable)
{
WsDisplay *display = WS_RESOURCE (drawable)->display;
WsRectangle geometry;
WsPixmap *pixmap;
ws_display_begin_error_trap (display);
ws_drawable_query_geometry (drawable, &geometry);
pixmap = ws_pixmap_new (drawable, geometry.width, geometry.height);
ws_drawable_copy_area (drawable, 0, 0, geometry.width, geometry.height,
WS_DRAWABLE (pixmap), 0, 0,
NULL);
ws_display_end_error_trap (display);
return pixmap;
}
static void
on_alarm (WsSyncAlarm *alarm,
WsAlarmNotifyEvent *event,
MetaCompWindow *window)
{
if (window->pixmap)
g_object_unref (window->pixmap);
window->pixmap = take_snapshot (window->drawable);
ws_sync_alarm_set (window->alarm, event->counter_value + 2);
ws_sync_counter_change (event->counter, 1);
}
static gboolean
has_counter (MetaCompWindow *comp_window)
{
Window xwindow = find_app_window (comp_window);
WsDisplay *display = WS_RESOURCE (comp_window->drawable)->display;
WsWindow *window = ws_window_lookup (display, xwindow);
WsSyncCounter *counter;
ws_display_init_sync (display);
counter = ws_window_get_property_sync_counter (
window, "_NET_WM_FINISH_FRAME_COUNTER");
if (counter)
{
WsSyncAlarm *alarm;
gint64 value = ws_sync_counter_query_value (counter);
g_print ("counter value %lld\n", ws_sync_counter_query_value (counter));
alarm = ws_sync_alarm_new (display, counter);
g_signal_connect (alarm, "alarm_notify_event",
G_CALLBACK (on_alarm), comp_window);
if (value % 2 == 1)
{
ws_sync_alarm_set (alarm, value + 2);
g_print ("wait for %lld\n", value + 2);
g_print ("increasing counter\n");
ws_sync_counter_change (counter, 1);
g_print ("counter value %lld\n", ws_sync_counter_query_value (counter));
}
else
{
g_print ("wait for %lld\n", value + 1);
ws_sync_alarm_set (alarm, value + 1);
}
comp_window->alarm = alarm;
}
if (counter)
return TRUE;
else
return FALSE;
#if 0
if (counter)
{
g_print ("found counter %lx on %lx\n",
WS_RESOURCE_XID (counter),
WS_RESOURCE_XID (window));
}
else
{
g_print ("no counter found for %lx\n", WS_RESOURCE_XID (window));
}
#endif
return TRUE;
}
MetaCompWindow *
meta_comp_window_new (MetaDisplay *display,
WsDrawable *drawable)
{
MetaCompWindow *window;
WsRectangle geometry;
ws_drawable_query_geometry (drawable, &geometry);
window = g_new0 (MetaCompWindow, 1);
window->display = display;
window->drawable = g_object_ref (drawable);
window->node = CM_NODE (cm_drawable_node_new (drawable, &geometry));
@ -68,6 +186,8 @@ meta_comp_window_free (MetaCompWindow *window)
{
g_object_unref (window->drawable);
g_object_unref (window->node);
if (window->alarm)
g_object_unref (window->alarm);
g_free (window);
}
@ -107,23 +227,23 @@ has_type (WsWindow *window, const char *check_type)
gchar **types = ws_window_get_property_atom_list (window, "_NET_WM_WINDOW_TYPE");
int i;
gboolean result;
if (!types)
return FALSE;
result = FALSE;
for (i = 0; types[i] != NULL; ++i)
{
gchar *type = types[i];
if (strcmp (type, check_type) == 0)
{
result = TRUE;
break;
}
}
g_strfreev (types);
return result;
}
@ -134,122 +254,10 @@ find_meta_window (MetaCompWindow *comp_window)
Window xwindow = WS_RESOURCE_XID (comp_window->drawable);
MetaWindow *window =
meta_display_lookup_x_window (comp_window->display, xwindow);
return window;
}
static Window
find_app_window (MetaCompWindow *comp_window)
{
Window xwindow = WS_RESOURCE_XID (comp_window->drawable);
MetaWindow *meta_window =
meta_display_lookup_x_window (comp_window->display, xwindow);
if (meta_window)
return meta_window->xwindow;
else
return xwindow;
}
static WsPixmap *
take_snapshot (WsDrawable *drawable)
{
WsDisplay *display = WS_RESOURCE (drawable)->display;
WsRectangle geometry;
WsPixmap *pixmap;
ws_display_begin_error_trap (display);
ws_drawable_query_geometry (drawable, &geometry);
pixmap = ws_pixmap_new (drawable, geometry.width, geometry.height);
ws_drawable_copy_area (drawable, 0, 0, geometry.width, geometry.height,
WS_DRAWABLE (pixmap), 0, 0,
NULL);
ws_display_end_error_trap (display);
return pixmap;
}
static void
on_alarm (WsSyncAlarm *alarm,
WsAlarmNotifyEvent *event,
MetaCompWindow *window)
{
g_print ("received alarm\n");
if (window->pixmap)
g_object_unref (window->pixmap);
window->pixmap = take_snapshot (window->drawable);
ws_sync_alarm_set (window->alarm, event->counter_value + 2);
ws_sync_counter_change (event->counter, 1);
}
static gboolean
has_counter (MetaCompWindow *comp_window)
{
Window xwindow = find_app_window (comp_window);
WsDisplay *display = WS_RESOURCE (comp_window->drawable)->display;
WsWindow *window = ws_window_lookup (display, xwindow);
WsSyncCounter *counter;
ws_display_init_sync (display);
counter = ws_window_get_property_sync_counter (
window, "_NET_WM_FINISH_FRAME_COUNTER");
if (counter)
{
WsSyncAlarm *alarm;
gint64 value = ws_sync_counter_query_value (counter);
g_print ("counter value %lld\n", ws_sync_counter_query_value (counter));
alarm = ws_sync_alarm_new (display, counter);
g_signal_connect (alarm, "alarm_notify_event",
G_CALLBACK (on_alarm), comp_window);
if (value % 2 == 1)
{
ws_sync_alarm_set (alarm, value + 2);
g_print ("wait for %lld\n", value + 2);
g_print ("increasing counter\n");
ws_sync_counter_change (counter, 1);
g_print ("counter value %lld\n", ws_sync_counter_query_value (counter));
}
else
{
g_print ("wait for %lld\n", value + 1);
ws_sync_alarm_set (alarm, value + 1);
}
comp_window->alarm = alarm;
}
#if 0
if (counter)
{
g_print ("found counter %lx on %lx\n",
WS_RESOURCE_XID (counter),
WS_RESOURCE_XID (window));
}
else
{
g_print ("no counter found for %lx\n", WS_RESOURCE_XID (window));
}
#endif
return TRUE;
}
void
meta_comp_window_refresh_attrs (MetaCompWindow *comp_window)
{
@ -260,19 +268,18 @@ meta_comp_window_refresh_attrs (MetaCompWindow *comp_window)
double alpha = 1.0;
CmDrawableNode *node = CM_DRAWABLE_NODE (comp_window->node);
if (ws_window_query_mapped (WS_WINDOW (comp_window->drawable)))
if (ws_window_query_mapped (WS_WINDOW (comp_window->drawable)) &&
!comp_window->waiting_for_paint)
{
WsWindow *window = WS_WINDOW (comp_window->drawable);
cm_drawable_node_unset_patch (CM_DRAWABLE_NODE (node));
find_meta_window (comp_window);
has_counter (comp_window);
if (has_type (window, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"))
{
alpha = 0.3;
alpha = 0.9;
}
else if (has_type (window, "_NET_WM_WINDOW_TYPE_POPUP_MENU"))
{
@ -284,7 +291,14 @@ meta_comp_window_refresh_attrs (MetaCompWindow *comp_window)
}
cm_drawable_node_set_alpha (node, alpha);
#if 0
if (cm_drawable_node_get_viewable (node))
g_print ("mapping new window\n");
#endif
cm_drawable_node_set_viewable (node, TRUE);
cm_drawable_node_update_pixmap (node);
}
else
@ -298,9 +312,9 @@ meta_comp_window_set_updates (MetaCompWindow *comp_window,
gboolean updates)
{
CmDrawableNode *node = CM_DRAWABLE_NODE (comp_window->node);
comp_window->updates = updates;
cm_drawable_node_set_updates (node, updates);
if (updates)
@ -326,4 +340,66 @@ meta_comp_window_get_node (MetaCompWindow *comp_window)
return comp_window->node;
}
/*
* Explosion effect
*/
#define EXPLODE_TIME 1.0
#define BASE 0.5
static double
transform (double in)
{
return (pow (BASE, in) - 1) / (BASE - 1);
}
typedef struct
{
MetaEffect *effect;
MetaCompWindow *window;
gdouble level;
GTimer * timer;
} ExplodeInfo;
static gboolean
update_explosion (gpointer data)
{
ExplodeInfo *info = data;
CmDrawableNode *node = (CmDrawableNode *)info->window->node;
gdouble elapsed = g_timer_elapsed (info->timer, NULL);
if (elapsed > EXPLODE_TIME)
{
meta_effect_end (info->effect);
cm_drawable_node_set_viewable (node, FALSE);
cm_drawable_node_set_explosion_level (node, 0.0);
return FALSE;
}
else
{
gdouble t = elapsed / EXPLODE_TIME;
cm_drawable_node_set_explosion_level (node,
transform (t));
return TRUE;
}
}
void
meta_comp_window_explode (MetaCompWindow *comp_window,
MetaEffect *effect)
{
ExplodeInfo *info = g_new0 (ExplodeInfo, 1);
info->window = comp_window;
info->effect = effect;
info->level = 0.0;
info->timer = g_timer_new ();
g_idle_add (update_explosion, info);
}
#endif

View File

@ -19,6 +19,10 @@
#include <cm/node.h>
#include "display.h"
#include "effects.h"
#ifndef C_WINDOW_H
#define C_WINDOW_H
typedef struct _MetaCompWindow MetaCompWindow;
@ -32,3 +36,14 @@ void meta_comp_window_set_size (MetaCompWindow *window,
void meta_comp_window_refresh_attrs (MetaCompWindow *comp_window);
void meta_comp_window_set_updates (MetaCompWindow *comp_window,
gboolean updates);
void meta_comp_window_explode (MetaCompWindow *comp_window,
MetaEffect *effect);
#if 0
void meta_comp_window_set_explode (MetaCompWindow *comp_window,
double level);
#endif
#endif

View File

@ -50,6 +50,8 @@
#include "spring-model.h"
#include <cm/state.h>
#include "effects.h"
#include "c-screen.h"
#endif /* HAVE_COMPOSITE_EXTENSIONS */
@ -94,6 +96,39 @@ handle_error (Display *dpy, XErrorEvent *ev, gpointer data)
}
#endif
static Window
get_xid (MetaWindow *window)
{
if (window->frame)
return window->frame->xwindow;
else
return window->xwindow;
}
static void
do_effect (MetaEffect *effect,
gpointer data)
{
switch (effect->type)
{
case META_EFFECT_MINIMIZE:
{
MetaCompScreen *screen = meta_comp_screen_get_by_xwindow (
get_xid (effect->u.minimize.window));
MetaCompWindow *window =
meta_comp_screen_lookup_window (screen, effect->u.minimize.window->frame->xwindow);
meta_comp_window_explode (window, effect);
break;
}
default:
{
g_assert_not_reached();
break;
}
}
}
MetaCompositor *
meta_compositor_new (MetaDisplay *display)
{
@ -138,6 +173,8 @@ meta_compositor_new (MetaDisplay *display)
compositor->enabled = TRUE;
meta_push_effect_handler (do_effect, compositor);
return compositor;
#else /* HAVE_COMPOSITE_EXTENSIONS */
return NULL;
@ -673,6 +710,7 @@ interpolate_rectangle (gdouble t,
#if MINIMIZE_STYLE == 0
#if 0
void
meta_compositor_minimize (MetaCompositor *compositor,
MetaWindow *window,
@ -684,6 +722,7 @@ meta_compositor_minimize (MetaCompositor *compositor,
gpointer data)
{
}
#endif
#elif MINIMIZE_STYLE == 1
@ -718,15 +757,6 @@ typedef struct
gboolean phase_5_started;
} MiniInfo;
static Window
get_xid (MetaWindow *window)
{
if (window->frame)
return window->frame->xwindow;
else
return window->xwindow;
}
static void
set_geometry (MiniInfo *info, gdouble elapsed)
{
@ -923,72 +953,6 @@ run_animation_01 (gpointer data)
return TRUE;
}
#define EXPLODE_TIME 1.0
#define BASE 0.5
static double
transform (double in)
{
return (pow (BASE, in) - 1) / (BASE - 1);
}
typedef struct
{
MetaWindow * window;
gdouble level;
GTimer * timer;
MetaAnimationFinishedFunc func;
gpointer data;
MetaCompScreen * minfo;
} ExplodeInfo;
static gboolean
update_explosion (gpointer data)
{
ExplodeInfo *info = data;
gdouble elapsed = g_timer_elapsed (info->timer, NULL);
gdouble t = elapsed / EXPLODE_TIME;
meta_comp_screen_set_explode (info->minfo, get_xid (info->window), transform (t));
if (elapsed > EXPLODE_TIME)
{
if (info->func)
info->func (info->data);
meta_comp_screen_hide_window (info->minfo, get_xid (info->window));
meta_comp_screen_set_explode (info->minfo, get_xid (info->window), 0.0);
return FALSE;
}
else
{
return TRUE;
}
}
void
meta_compositor_minimize (MetaCompositor *compositor,
MetaWindow *window,
int x,
int y,
int width,
int height,
MetaAnimationFinishedFunc finished,
gpointer data)
{
ExplodeInfo *info = g_new0 (ExplodeInfo, 1);
info->window = window;
info->level = 0.0;
info->timer = g_timer_new ();
info->func = finished;
info->data = data;
info->minfo = meta_comp_screen_get_by_xwindow (get_xid (window));
g_idle_add (update_explosion, info);
}
#if 0
void
meta_compositor_minimize (MetaCompositor *compositor,

View File

@ -45,6 +45,7 @@ void meta_compositor_manage_screen (MetaCompositor *compositor,
void meta_compositor_unmanage_screen (MetaCompositor *compositor,
MetaScreen *screen);
#if 0
void meta_compositor_minimize (MetaCompositor *compositor,
MetaWindow *window,
int x,
@ -53,6 +54,7 @@ void meta_compositor_minimize (MetaCompositor *compositor,
int height,
MetaAnimationFinishedFunc finished_cb,
gpointer finished_data);
#endif
void
meta_compositor_set_updates (MetaCompositor *compositor,

View File

@ -23,6 +23,7 @@
#include "effects.h"
#include "display.h"
#include "ui.h"
#include "window.h"
#ifdef HAVE_SHAPE
#include <X11/extensions/shape.h>
@ -72,6 +73,87 @@ typedef struct
} BoxAnimationContext;
struct MetaEffectPriv
{
MetaEffectFinished finished;
gpointer finished_data;
};
static void run_default_effect_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,
MetaEffectFinished finished,
gpointer finished_data)
{
MetaEffect *effect = g_new (MetaEffect, 1);
effect->type = type;
effect->priv = g_new (MetaEffectPriv, 1);
effect->priv->finished = finished;
effect->priv->finished_data = finished_data;
return 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,
finished, data);
effect->u.minimize.window = window;
effect->u.minimize.window_rect = *window_rect;
effect->u.minimize.icon_rect = *icon_rect;
if (effect_handler)
{
effect_handler (effect, effect_handler_data);
}
else
{
run_default_effect_handler (effect);
meta_effect_end (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);
}
static void
update_wireframe_window (MetaDisplay *display,
Window xwindow,
@ -374,7 +456,7 @@ meta_effects_draw_box_animation (MetaScreen *screen,
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,
@ -624,3 +706,20 @@ meta_effects_end_wireframe (MetaScreen *screen,
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->u.minimize.window->screen,
&(effect->u.minimize.window_rect),
&(effect->u.minimize.icon_rect),
META_MINIMIZE_ANIMATION_LENGTH,
META_BOX_ANIM_SCALE);
break;
default:
break;
}
}

View File

@ -25,6 +25,9 @@
#include "util.h"
#include "screen.h"
typedef struct MetaEffect MetaEffect;
typedef struct MetaEffectPriv MetaEffectPriv;
#define META_MINIMIZE_ANIMATION_LENGTH 0.25
#define META_SHADE_ANIMATION_LENGTH 0.2
@ -35,6 +38,51 @@ typedef enum
} MetaBoxAnimType;
typedef enum
{
META_EFFECT_MINIMIZE
} MetaEffectType;
typedef void (* MetaEffectHandler) (MetaEffect *effect,
gpointer data);
typedef void (* MetaEffectFinished) (const MetaEffect *effect,
gpointer data);
typedef struct
{
MetaWindow *window;
MetaRectangle window_rect;
MetaRectangle icon_rect;
} MetaMinimizeEffect;
struct MetaEffect
{
MetaEffectType type;
gpointer info; /* effect handler can hang data here */
union
{
MetaMinimizeEffect minimize;
} u;
MetaEffectPriv *priv;
};
void meta_push_effect_handler (MetaEffectHandler handler,
gpointer data);
void meta_pop_effect_handler (void);
void meta_effect_run_minimize (MetaWindow *window,
MetaRectangle *window_rect,
MetaRectangle *target,
MetaEffectFinished finished,
gpointer data);
void meta_effect_end (MetaEffect *effect);
/* Stuff that should become static functions */
void meta_effects_draw_box_animation (MetaScreen *screen,
MetaRectangle *initial_rect,
MetaRectangle *destination_rect,

View File

@ -1324,7 +1324,8 @@ meta_window_should_be_showing (MetaWindow *window)
}
static void
finish_minimize (gpointer data)
finish_minimize (const MetaEffect *effect,
gpointer data)
{
MetaWindow *window = data;
@ -1381,32 +1382,15 @@ implement_showing (MetaWindow *window,
meta_window_get_outer_rect (window, &window_rect);
if (window->display->compositor)
{
/* Draw a nice cool animation */
meta_compositor_minimize (window->display->compositor,
window,
icon_rect.x,
icon_rect.y,
icon_rect.width,
icon_rect.height,
finish_minimize,
window);
}
else
{
meta_effects_draw_box_animation (window->screen,
&window_rect,
&icon_rect,
META_MINIMIZE_ANIMATION_LENGTH,
META_BOX_ANIM_SCALE);
finish_minimize (window);
}
meta_effect_run_minimize (window,
&window_rect,
&icon_rect,
finish_minimize,
window);
}
else
{
finish_minimize (window);
finish_minimize (NULL, window);
}
}
else