add opaque minimize/shade feature. The wireframe seemed kind of confusing

2001-08-06  Havoc Pennington  <hp@pobox.com>

	* src/effects.c: add opaque minimize/shade feature.  The wireframe
	seemed kind of confusing and unclear from a UI standpoint.
	I know, I know. The bloat begins here.

	Also, we don't need to grab the server during opaque min/shade,
	which has some nice implications.

	* src/ui.c: Add features to render a window with an image in it,
	and also wrap pixbuf_from_drawable

	* src/effects.c (meta_effects_draw_box_animation):
	modify to be smoother (at least theoretically) by
	syncing to current time and "dropping frames"
	as appropriate.

	* src/window.c (meta_window_shade): draw animation
	for shading too
This commit is contained in:
Havoc Pennington 2001-08-06 07:58:49 +00:00 committed by rhp
parent d8561cb4c3
commit 11b14d327f
6 changed files with 269 additions and 54 deletions

View File

@ -1,10 +1,19 @@
2001-08-06 Havoc Pennington <hp@pobox.com> 2001-08-06 Havoc Pennington <hp@pobox.com>
* src/effects.c: add opaque minimize/shade feature. The wireframe
seemed kind of confusing and unclear from a UI standpoint.
I know, I know. The bloat begins here.
Also, we don't need to grab the server during opaque min/shade,
which has some nice implications.
* src/ui.c: Add features to render a window with an image in it,
and also wrap pixbuf_from_drawable
* src/effects.c (meta_effects_draw_box_animation): * src/effects.c (meta_effects_draw_box_animation):
modify to be smoother (at least theoretically) by modify to be smoother (at least theoretically) by
syncing to current time and "dropping frames" syncing to current time and "dropping frames"
as appropriate. A precursor to flashier animations as appropriate.
that take more CPU to do.
* src/window.c (meta_window_shade): draw animation * src/window.c (meta_window_shade): draw animation
for shading too for shading too

View File

@ -21,12 +21,11 @@
#include "effects.h" #include "effects.h"
#include "display.h" #include "display.h"
#include "ui.h"
typedef struct typedef struct
{ {
MetaScreen *screen; MetaScreen *screen;
GC gc;
double millisecs_duration; double millisecs_duration;
GTimeVal start_time; GTimeVal start_time;
@ -38,6 +37,18 @@ typedef struct
/* rect to erase */ /* rect to erase */
MetaRectangle last_rect; MetaRectangle last_rect;
/* used instead of the global flag, since
* we don't want to change midstream.
*/
gboolean use_opaque;
/* For wireframe */
GC gc;
/* For opaque */
MetaImageWindow *image_window;
GdkPixbuf *orig_pixbuf;
} BoxAnimationContext; } BoxAnimationContext;
@ -51,12 +62,15 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
if (!context->first_time) if (!context->first_time)
{ {
/* Restore the previously drawn background */ if (!context->use_opaque)
XDrawRectangle (context->screen->display->xdisplay, {
context->screen->xroot, /* Restore the previously drawn background */
context->gc, XDrawRectangle (context->screen->display->xdisplay,
context->last_rect.x, context->last_rect.y, context->screen->xroot,
context->last_rect.width, context->last_rect.height); context->gc,
context->last_rect.x, context->last_rect.y,
context->last_rect.width, context->last_rect.height);
}
} }
context->first_time = FALSE; context->first_time = FALSE;
@ -78,9 +92,18 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
if (elapsed > context->millisecs_duration) if (elapsed > context->millisecs_duration)
{ {
/* All done */ /* All done */
meta_display_ungrab (context->screen->display); if (context->use_opaque)
XFreeGC (context->screen->display->xdisplay, {
context->gc); g_object_unref (G_OBJECT (context->orig_pixbuf));
meta_image_window_free (context->image_window);
}
else
{
meta_display_ungrab (context->screen->display);
XFreeGC (context->screen->display->xdisplay,
context->gc);
}
g_free (context); g_free (context);
return FALSE; return FALSE;
} }
@ -96,24 +119,54 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
draw_rect.width += (context->end_rect.width - context->start_rect.width) * 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; draw_rect.height += (context->end_rect.height - context->start_rect.height) * fraction;
/* don't confuse X with bogus rectangles */ /* don't confuse X or gdk-pixbuf with bogus rectangles */
if (draw_rect.width < 1) if (draw_rect.width < 1)
draw_rect.width = 1; draw_rect.width = 1;
if (draw_rect.height < 1) if (draw_rect.height < 1)
draw_rect.height = 1; draw_rect.height = 1;
context->last_rect = draw_rect; context->last_rect = draw_rect;
/* 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);
if (context->use_opaque)
{
GdkPixbuf *scaled;
scaled = gdk_pixbuf_scale_simple (context->orig_pixbuf,
draw_rect.width,
draw_rect.height,
GDK_INTERP_BILINEAR);
meta_image_window_set_image (context->image_window,
scaled);
meta_image_window_set_position (context->image_window,
draw_rect.x, draw_rect.y);
g_object_unref (G_OBJECT (scaled));
}
else
{
/* 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);
}
/* kick changes onto the server */
XFlush (context->screen->display->xdisplay);
return TRUE; 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 maybe
* too slow on some systems; so perhaps we could autodetect
* system beefiness or someting, or have some global
* "my system is slow" config option.
*/
static gboolean use_opaque_animations = TRUE;
void void
meta_effects_draw_box_animation (MetaScreen *screen, meta_effects_draw_box_animation (MetaScreen *screen,
MetaRectangle *initial_rect, MetaRectangle *initial_rect,
@ -121,7 +174,6 @@ meta_effects_draw_box_animation (MetaScreen *screen,
double seconds_duration) double seconds_duration)
{ {
BoxAnimationContext *context; BoxAnimationContext *context;
XGCValues gc_values;
g_return_if_fail (seconds_duration > 0.0); g_return_if_fail (seconds_duration > 0.0);
@ -129,26 +181,62 @@ meta_effects_draw_box_animation (MetaScreen *screen,
seconds_duration *= 10; /* slow things down */ seconds_duration *= 10; /* slow things down */
/* Create the animation context */ /* Create the animation context */
context = g_new (BoxAnimationContext, 1); context = g_new0 (BoxAnimationContext, 1);
gc_values.subwindow_mode = IncludeInferiors;
gc_values.function = GXinvert;
/* Create a gc for the root window */
context->screen = screen; context->screen = screen;
context->gc = XCreateGC (screen->display->xdisplay,
screen->xroot,
GCSubwindowMode | GCFunction,
&gc_values);
context->millisecs_duration = seconds_duration * 1000.0; context->millisecs_duration = seconds_duration * 1000.0;
g_get_current_time (&context->start_time); g_get_current_time (&context->start_time);
context->first_time = TRUE; context->first_time = TRUE;
context->start_rect = *initial_rect; context->start_rect = *initial_rect;
context->end_rect = *destination_rect; context->end_rect = *destination_rect;
/* Grab the X server to avoid screen dirt */ context->use_opaque = use_opaque_animations;
meta_display_grab (context->screen->display);
if (context->use_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->use_opaque = FALSE;
}
else
{
context->image_window = meta_image_window_new ();
context->orig_pixbuf = pix;
meta_image_window_set_position (context->image_window,
initial_rect->x,
initial_rect->y);
meta_image_window_set_showing (context->image_window, TRUE);
}
}
/* Not an else, so that fallback works */
if (!context->use_opaque)
{
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);
}
/* Add the timeout - a short one, could even use an idle, /* Add the timeout - a short one, could even use an idle,
* but this is maybe more CPU-friendly. * but this is maybe more CPU-friendly.
@ -157,3 +245,6 @@ meta_effects_draw_box_animation (MetaScreen *screen,
(GSourceFunc)effects_draw_box_animation_timeout, (GSourceFunc)effects_draw_box_animation_timeout,
context); context);
} }

View File

@ -25,8 +25,8 @@
#include "util.h" #include "util.h"
#include "screen.h" #include "screen.h"
#define META_MINIMIZE_ANIMATION_LENGTH 0.3 #define META_MINIMIZE_ANIMATION_LENGTH 0.5
#define META_SHADE_ANIMATION_LENGTH 0.15 #define META_SHADE_ANIMATION_LENGTH 0.2
void meta_effects_draw_box_animation (MetaScreen *screen, void meta_effects_draw_box_animation (MetaScreen *screen,
MetaRectangle *initial_rect, MetaRectangle *initial_rect,

View File

@ -232,3 +232,94 @@ meta_ui_window_menu_free (MetaWindowMenu *menu)
meta_window_menu_free (menu); meta_window_menu_free (menu);
} }
struct _MetaImageWindow
{
GtkWidget *window;
GtkWidget *image;
};
MetaImageWindow*
meta_image_window_new (void)
{
MetaImageWindow *iw;
iw = g_new (MetaImageWindow, 1);
iw->window = gtk_window_new (GTK_WINDOW_POPUP);
iw->image = g_object_new (GTK_TYPE_IMAGE, NULL);
gtk_container_add (GTK_CONTAINER (iw->window), iw->image);
/* Ensure we auto-shrink to fit image */
gtk_window_set_resizable (GTK_WINDOW (iw->window),
FALSE);
return iw;
}
void
meta_image_window_free (MetaImageWindow *iw)
{
gtk_widget_destroy (iw->window);
g_free (iw);
}
void
meta_image_window_set_showing (MetaImageWindow *iw,
gboolean showing)
{
if (showing)
gtk_widget_show_all (iw->window);
else
gtk_widget_hide (iw->window);
}
void
meta_image_window_set_image (MetaImageWindow *iw,
GdkPixbuf *pixbuf)
{
gtk_image_set_from_pixbuf (GTK_IMAGE (iw->image), pixbuf);
}
void
meta_image_window_set_position (MetaImageWindow *iw,
int x,
int y)
{
gtk_widget_set_uposition (iw->window, x, y);
}
GdkPixbuf*
meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
Window xwindow,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
GdkDrawable *drawable;
GdkPixbuf *retval;
retval = NULL;
drawable = gdk_xid_table_lookup (xwindow);
if (drawable)
g_object_ref (G_OBJECT (drawable));
else
drawable = gdk_window_foreign_new (xwindow);
retval = gdk_pixbuf_get_from_drawable (dest,
drawable,
/* We assume root window cmap */
gdk_colormap_get_system (),
src_x, src_y,
dest_x, dest_y,
width, height);
g_object_unref (G_OBJECT (drawable));
return retval;
}

View File

@ -22,13 +22,16 @@
#ifndef META_UI_H #ifndef META_UI_H
#define META_UI_H #define META_UI_H
/* Don't include gtk.h here */ /* Don't include gtk.h or gdk.h here */
#include "common.h" #include "common.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <glib.h> #include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
typedef struct _MetaUI MetaUI; typedef struct _MetaUI MetaUI;
typedef struct _MetaImageWindow MetaImageWindow;
typedef gboolean (* MetaEventFunc) (XEvent *xevent, gpointer data); typedef gboolean (* MetaEventFunc) (XEvent *xevent, gpointer data);
void meta_ui_init (int *argc, char ***argv); void meta_ui_init (int *argc, char ***argv);
@ -88,5 +91,22 @@ void meta_ui_window_menu_popup (MetaWindowMenu *menu,
void meta_ui_window_menu_free (MetaWindowMenu *menu); void meta_ui_window_menu_free (MetaWindowMenu *menu);
MetaImageWindow* meta_image_window_new (void);
void meta_image_window_free (MetaImageWindow *iw);
void meta_image_window_set_showing (MetaImageWindow *iw,
gboolean showing);
void meta_image_window_set_image (MetaImageWindow *iw,
GdkPixbuf *pixbuf);
void meta_image_window_set_position (MetaImageWindow *iw,
int x,
int y);
GdkPixbuf* meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
Window xwindow,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height);
#endif #endif

View File

@ -1063,22 +1063,26 @@ meta_window_shade (MetaWindow *window)
meta_verbose ("Shading %s\n", window->desc); meta_verbose ("Shading %s\n", window->desc);
if (!window->shaded) if (!window->shaded)
{ {
{ if (window->mapped)
/* Animation */ {
MetaRectangle starting_size; /* Animation */
MetaRectangle titlebar_size; MetaRectangle starting_size;
MetaRectangle titlebar_size;
meta_window_get_outer_rect (window, &starting_size);
if (window->frame) meta_window_get_outer_rect (window, &starting_size);
starting_size.y += window->frame->child_y; if (window->frame)
titlebar_size = starting_size; {
titlebar_size.height = 0; starting_size.y += window->frame->child_y;
starting_size.height -= window->frame->child_y;
meta_effects_draw_box_animation (window->screen, }
&starting_size, titlebar_size = starting_size;
&titlebar_size, titlebar_size.height = 0;
META_SHADE_ANIMATION_LENGTH);
} meta_effects_draw_box_animation (window->screen,
&starting_size,
&titlebar_size,
META_SHADE_ANIMATION_LENGTH);
}
window->shaded = TRUE; window->shaded = TRUE;