summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--src/effects.c157
-rw-r--r--src/effects.h4
-rw-r--r--src/ui.c91
-rw-r--r--src/ui.h24
-rw-r--r--src/window.c36
6 files changed, 270 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index ff4b3f8f..98bdc16b 100644
--- a/ChangeLog
+++ b/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
diff --git a/src/effects.c b/src/effects.c
index bb9694fd..bc9f7606 100644
--- a/src/effects.c
+++ b/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);
}
+
+
+
diff --git a/src/effects.h b/src/effects.h
index 9b057441..801b099c 100644
--- a/src/effects.h
+++ b/src/effects.h
@@ -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,
diff --git a/src/ui.c b/src/ui.c
index c9c66b51..2e311518 100644
--- a/src/ui.c
+++ b/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;
+}
+
diff --git a/src/ui.h b/src/ui.h
index 874fdfc6..6c03ae62 100644
--- a/src/ui.h
+++ b/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
diff --git a/src/window.c b/src/window.c
index bce536b9..5bfc6573 100644
--- a/src/window.c
+++ b/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;