mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 15:40:41 -05:00
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:
parent
d8561cb4c3
commit
11b14d327f
13
ChangeLog
13
ChangeLog
@ -1,10 +1,19 @@
|
||||
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. A precursor to flashier animations
|
||||
that take more CPU to do.
|
||||
as appropriate.
|
||||
|
||||
* src/window.c (meta_window_shade): draw animation
|
||||
for shading too
|
||||
|
157
src/effects.c
157
src/effects.c
@ -21,12 +21,11 @@
|
||||
|
||||
#include "effects.h"
|
||||
#include "display.h"
|
||||
#include "ui.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaScreen *screen;
|
||||
|
||||
GC gc;
|
||||
|
||||
double millisecs_duration;
|
||||
GTimeVal start_time;
|
||||
@ -38,6 +37,18 @@ typedef struct
|
||||
|
||||
/* rect to erase */
|
||||
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;
|
||||
|
||||
@ -51,12 +62,15 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
|
||||
|
||||
if (!context->first_time)
|
||||
{
|
||||
/* 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);
|
||||
if (!context->use_opaque)
|
||||
{
|
||||
/* 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;
|
||||
@ -78,9 +92,18 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
|
||||
if (elapsed > context->millisecs_duration)
|
||||
{
|
||||
/* All done */
|
||||
meta_display_ungrab (context->screen->display);
|
||||
XFreeGC (context->screen->display->xdisplay,
|
||||
context->gc);
|
||||
if (context->use_opaque)
|
||||
{
|
||||
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);
|
||||
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.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)
|
||||
draw_rect.width = 1;
|
||||
if (draw_rect.height < 1)
|
||||
draw_rect.height = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
meta_effects_draw_box_animation (MetaScreen *screen,
|
||||
MetaRectangle *initial_rect,
|
||||
@ -121,7 +174,6 @@ meta_effects_draw_box_animation (MetaScreen *screen,
|
||||
double seconds_duration)
|
||||
{
|
||||
BoxAnimationContext *context;
|
||||
XGCValues gc_values;
|
||||
|
||||
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 */
|
||||
|
||||
/* Create the animation context */
|
||||
context = g_new (BoxAnimationContext, 1);
|
||||
|
||||
gc_values.subwindow_mode = IncludeInferiors;
|
||||
gc_values.function = GXinvert;
|
||||
|
||||
/* Create a gc for the root window */
|
||||
context = g_new0 (BoxAnimationContext, 1);
|
||||
|
||||
context->screen = screen;
|
||||
context->gc = XCreateGC (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
GCSubwindowMode | GCFunction,
|
||||
&gc_values);
|
||||
|
||||
context->millisecs_duration = seconds_duration * 1000.0;
|
||||
g_get_current_time (&context->start_time);
|
||||
context->first_time = TRUE;
|
||||
context->start_rect = *initial_rect;
|
||||
context->end_rect = *destination_rect;
|
||||
|
||||
/* Grab the X server to avoid screen dirt */
|
||||
meta_display_grab (context->screen->display);
|
||||
|
||||
context->use_opaque = use_opaque_animations;
|
||||
|
||||
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,
|
||||
* but this is maybe more CPU-friendly.
|
||||
@ -157,3 +245,6 @@ meta_effects_draw_box_animation (MetaScreen *screen,
|
||||
(GSourceFunc)effects_draw_box_animation_timeout,
|
||||
context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "util.h"
|
||||
#include "screen.h"
|
||||
|
||||
#define META_MINIMIZE_ANIMATION_LENGTH 0.3
|
||||
#define META_SHADE_ANIMATION_LENGTH 0.15
|
||||
#define META_MINIMIZE_ANIMATION_LENGTH 0.5
|
||||
#define META_SHADE_ANIMATION_LENGTH 0.2
|
||||
|
||||
void meta_effects_draw_box_animation (MetaScreen *screen,
|
||||
MetaRectangle *initial_rect,
|
||||
|
91
src/ui.c
91
src/ui.c
@ -232,3 +232,94 @@ meta_ui_window_menu_free (MetaWindowMenu *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;
|
||||
}
|
||||
|
||||
|
22
src/ui.h
22
src/ui.h
@ -22,13 +22,16 @@
|
||||
#ifndef 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 <X11/Xlib.h>
|
||||
#include <glib.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
typedef struct _MetaUI MetaUI;
|
||||
|
||||
typedef struct _MetaImageWindow MetaImageWindow;
|
||||
|
||||
typedef gboolean (* MetaEventFunc) (XEvent *xevent, gpointer data);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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
|
||||
|
36
src/window.c
36
src/window.c
@ -1063,22 +1063,26 @@ meta_window_shade (MetaWindow *window)
|
||||
meta_verbose ("Shading %s\n", window->desc);
|
||||
if (!window->shaded)
|
||||
{
|
||||
{
|
||||
/* Animation */
|
||||
MetaRectangle starting_size;
|
||||
MetaRectangle titlebar_size;
|
||||
|
||||
meta_window_get_outer_rect (window, &starting_size);
|
||||
if (window->frame)
|
||||
starting_size.y += window->frame->child_y;
|
||||
titlebar_size = starting_size;
|
||||
titlebar_size.height = 0;
|
||||
|
||||
meta_effects_draw_box_animation (window->screen,
|
||||
&starting_size,
|
||||
&titlebar_size,
|
||||
META_SHADE_ANIMATION_LENGTH);
|
||||
}
|
||||
if (window->mapped)
|
||||
{
|
||||
/* Animation */
|
||||
MetaRectangle starting_size;
|
||||
MetaRectangle titlebar_size;
|
||||
|
||||
meta_window_get_outer_rect (window, &starting_size);
|
||||
if (window->frame)
|
||||
{
|
||||
starting_size.y += window->frame->child_y;
|
||||
starting_size.height -= window->frame->child_y;
|
||||
}
|
||||
titlebar_size = starting_size;
|
||||
titlebar_size.height = 0;
|
||||
|
||||
meta_effects_draw_box_animation (window->screen,
|
||||
&starting_size,
|
||||
&titlebar_size,
|
||||
META_SHADE_ANIMATION_LENGTH);
|
||||
}
|
||||
|
||||
window->shaded = TRUE;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user