From c2a6eeaf5e543ab987be15fe20fd8c1c9193fa21 Mon Sep 17 00:00:00 2001 From: Iain Holmes Date: Wed, 19 Dec 2007 03:49:50 +0000 Subject: [PATCH] Merge compositor branch. 2007-12-18 Iain Holmes * configure.in, src/theme.c, src/display.c, src/theme.h, src/display.h, src/theme-parser.c, src/compositor.c, src/c-screen.c, src/compositor.h, src/c-screen.h, src/ui.c, src/screen.c, src/ui.h, src/screen.h, src/c-window.c, src/c-window.h, src/theme-viewer.c, src/Makefile.am: Merge compositor branch. svn path=/trunk/; revision=3483 --- ChangeLog | 9 + configure.in | 8 +- src/Makefile.am | 4 - src/c-screen.c | 677 ---------- src/c-screen.h | 53 - src/c-window.c | 1259 ------------------ src/c-window.h | 72 - src/compositor.c | 3149 ++++++++++++++++++++++++++++++++------------ src/compositor.h | 37 +- src/display.c | 106 +- src/display.h | 22 +- src/screen.c | 148 ++- src/screen.h | 11 +- src/theme-parser.c | 226 ++-- src/theme-viewer.c | 16 +- src/theme.c | 724 +++++----- src/theme.h | 212 ++- src/ui.c | 31 + src/ui.h | 2 + 19 files changed, 3308 insertions(+), 3458 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4571d965..10e5a341b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-12-18 Iain Holmes + + * configure.in, src/theme.c, src/display.c, + src/theme.h, src/display.h, src/theme-parser.c, + src/compositor.c, src/c-screen.c, src/compositor.h, + src/c-screen.h, src/ui.c, src/screen.c, src/ui.h, + src/screen.h, src/c-window.c, src/c-window.h, + src/theme-viewer.c, src/Makefile.am: Merge compositor branch. + 2007-12-14 Thomas Thurman * configure.in: Post-release bump to 2.21.5. diff --git a/configure.in b/configure.in index af7311e76..ddc1f6164 100644 --- a/configure.in +++ b/configure.in @@ -231,7 +231,7 @@ fi if test x$have_xcomposite = xyes; then echo "Building with CompositeExt" - METACITY_PC_MODULES="$METACITY_PC_MODULES xcomposite >= $XCOMPOSITE_VERSION xfixes xrender xdamage cm" + METACITY_PC_MODULES="$METACITY_PC_MODULES xcomposite >= $XCOMPOSITE_VERSION xfixes xrender xdamage" AC_DEFINE(HAVE_COMPOSITE_EXTENSIONS, , [Building with compositing manager support]) ## force on render also @@ -477,6 +477,12 @@ else GCONF_SCHEMAS_INSTALL_FALSE= fi +AC_ARG_ENABLE(debug, + [ --enable-debug enable debugging],, + enable_debug=no) +if test "x$enable_debug" = "xyes"; then + CFLAGS="$CFLAGS -g -O -Wall" +fi AC_CONFIG_FILES([ Makefile doc/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index bfcbef554..0f1bb9535 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,10 +12,6 @@ metacity_SOURCES= \ boxes.h \ boxes.c \ common.h \ - c-screen.c \ - c-screen.h \ - c-window.c \ - c-window.h \ compositor.c \ compositor.h \ constraints.c \ diff --git a/src/c-screen.c b/src/c-screen.c index ea6f95e96..e69de29bb 100644 --- a/src/c-screen.c +++ b/src/c-screen.c @@ -1,677 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2006 Red Hat, Inc. - * - * 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 - -#ifdef HAVE_COMPOSITE_EXTENSIONS -#include -#include -#include -#include -#include -#include -#include -#include - -#include "screen.h" -#include "c-screen.h" -#include "c-window.h" - -struct MetaCompScreen -{ - WsDisplay *display; - CmStacker *stacker; - CmMagnifier *magnifier; - - WsWindow *gl_window; - WsWindow *root_window; - - WsScreen *screen; - MetaScreen *meta_screen; - - int repaint_id; - int idle_id; - - WsWindow *selection_window; - - GHashTable *windows_by_xid; -}; - -static MetaCompWindow * -meta_comp_window_lookup (MetaCompScreen *info, - Window xid) -{ - MetaCompWindow *window; - - window = g_hash_table_lookup (info->windows_by_xid, (gpointer)xid); - - 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) -{ -#define BUFSIZE 128 - static GTimer *timer; - static double buffer [BUFSIZE]; - static int next = 0; - - if (!timer) - timer = g_timer_new (); - - buffer[next++] = g_timer_elapsed (timer, NULL); - - if (next == BUFSIZE) - { - int i; - double total; - - next = 0; - - total = 0.0; - for (i = 1; i < BUFSIZE; ++i) - total += buffer[i] - buffer[i - 1]; - - g_print ("frames per second: %f\n", 1 / (total / (BUFSIZE - 1))); - } -} -#endif - -static void -dump_stacking_order (GList *nodes) -{ - GList *list; - - for (list = nodes; list != NULL; list = list->next) - { - CmDrawableNode *node = list->data; - - if (node) - g_print ("%lx, ", WS_RESOURCE_XID (node->drawable)); - } - g_print ("\n"); -} - -static gboolean -repaint (gpointer data) -{ - MetaCompScreen *info = data; - CmState *state; -#if 0 - g_print ("repaint\n"); -#endif - glViewport (0, 0, - info->meta_screen->rect.width, - info->meta_screen->rect.height); - - glLoadIdentity(); - -#if 0 - glClearColor (0, 0, 0, 1.0); - glClear (GL_COLOR_BUFFER_BIT); -#endif - - ws_window_raise (info->gl_window); - -#if 0 - glDisable (GL_TEXTURE_2D); - glDisable (GL_TEXTURE_RECTANGLE_ARB); - glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - glColor4f (0.0, 1.0, 0.0, 1.0); - glRectf (-1.0, -1.0, 1.0, 1.0); - glFinish(); -#endif - - state = cm_state_new (); - - cm_state_disable_depth_buffer_update (state); - - cm_node_render (CM_NODE (info->magnifier), state); - - cm_state_enable_depth_buffer_update (state); - - g_object_unref (state); - - ws_window_gl_swap_buffers (info->gl_window); - glFinish(); - -#if 0 - dump_stacking_order (info->stacker->children); -#endif - - info->idle_id = 0; - return FALSE; -} - -static MetaCompWindow * -find_comp_window (MetaCompScreen *info, - Window xwindow) -{ - return meta_comp_window_lookup (info, xwindow); -} - -static CmNode * -find_node (MetaCompScreen *info, - Window xwindow) -{ - MetaCompWindow *window = meta_comp_window_lookup (info, xwindow); - - if (window) - return meta_comp_window_get_node (window); - - return NULL; -} - -static GList *all_screen_infos; - -MetaCompScreen * -meta_comp_screen_get_by_xwindow (Window xwindow) -{ - GList *list; - - for (list = all_screen_infos; list != NULL; list = list->next) - { - MetaCompScreen *info = list->data; - - if (find_node (info, xwindow)) - return info; - } - - return NULL; -} - -MetaCompScreen * -meta_comp_screen_new (WsDisplay *display, - MetaScreen *screen) -{ - MetaCompScreen *scr_info = g_new0 (MetaCompScreen, 1); - - scr_info->screen = ws_display_get_screen_from_number ( - display, screen->number); - scr_info->root_window = ws_screen_get_root_window (scr_info->screen); - scr_info->display = display; - scr_info->meta_screen = screen; - scr_info->windows_by_xid = g_hash_table_new (g_direct_hash, g_direct_equal); - - all_screen_infos = g_list_prepend (all_screen_infos, scr_info); - - return scr_info; -} - -static char * -make_selection_name (MetaCompScreen *info) -{ - char *buffer; - - buffer = g_strdup_printf ("_NET_WM_CM_S%d", info->meta_screen->number); - - return buffer; -} - -static void -on_selection_clear (WsWindow *window, - WsSelectionClearEvent *event, - gpointer data) -{ - MetaCompScreen *info = data; - char *buffer = make_selection_name (info); - - if (strcmp (event->selection, buffer)) - { - /* We lost the selection */ - meta_comp_screen_unredirect (info); - } -} - -static WsWindow * -claim_selection (MetaCompScreen *info) -{ - WsWindow *window = ws_window_new (info->root_window); - char *buffer = make_selection_name (info); - -#if 0 - g_print ("selection window: %lx\n", WS_RESOURCE_XID (window)); -#endif - - ws_window_own_selection (window, buffer, WS_CURRENT_TIME); - - g_signal_connect (window, "selection_clear_event", G_CALLBACK (on_selection_clear), info); - - g_free (buffer); - - return window; -} - -static void -queue_paint (CmNode *node, - MetaCompScreen *info) -{ -#if 0 - g_print ("queueing %s\n", G_OBJECT_TYPE_NAME (node)); -#endif - meta_comp_screen_queue_paint (info); -} - -void -meta_comp_screen_redirect (MetaCompScreen *info) -{ - WsWindow *root = ws_screen_get_root_window (info->screen); - WsRectangle source; - WsRectangle target; - WsServerRegion *region; - int screen_w; - int screen_h; - CmSquare *square; - -#if 0 - g_print ("redirecting %lx\n", WS_RESOURCE_XID (root)); -#endif - - ws_window_redirect_subwindows (root); - info->gl_window = ws_screen_get_gl_window (info->screen); - /* FIXME: This should probably happen in libcm */ - ws_window_set_override_redirect (info->gl_window, TRUE); - region = ws_server_region_new (info->display); - ws_window_set_input_shape (info->gl_window, region); - g_object_unref (G_OBJECT (region)); - - ws_display_begin_error_trap (info->display); - - ws_window_unredirect (info->gl_window); - - ws_display_end_error_trap (info->display); - - info->selection_window = claim_selection (info); - - ws_window_map (info->gl_window); - - info->stacker = cm_stacker_new (); - - square = cm_square_new (0.3, 0.3, 0.8, 1.0); - - cm_stacker_add_child (info->stacker, CM_NODE (square)); - - g_object_unref (square); - - screen_w = ws_screen_get_width (info->screen); - screen_h = ws_screen_get_height (info->screen); - -#if 0 - g_print ("width: %d height %d\n", screen_w, screen_h); -#endif - - source.x = (screen_w - (screen_w / 4)) / 2; - source.y = screen_h / 16; - source.width = screen_w / 4; - source.height = screen_h / 16; - - target.x = 0; - target.y = screen_h - screen_h / 4; - target.width = screen_w; - target.height = screen_h / 4; - - info->magnifier = cm_magnifier_new (CM_NODE (info->stacker), &source, &target); - - if (g_getenv ("USE_MAGNIFIER")) - cm_magnifier_set_active (info->magnifier, TRUE); - else - cm_magnifier_set_active (info->magnifier, FALSE); - - info->repaint_id = - g_signal_connect (info->magnifier, "need_repaint", - G_CALLBACK (queue_paint), info); - - ws_display_sync (info->display); -} - -static void -listify (gpointer key, - gpointer value, - gpointer data) -{ - GList **windows = data; - - *windows = g_list_prepend (*windows, (gpointer)value); -} - -static void -free_all_windows (MetaCompScreen *info) -{ - GList *windows = NULL, *list; - - g_hash_table_foreach (info->windows_by_xid, listify, &windows); - - for (list = windows; list != NULL; list = list->next) - { - MetaCompWindow *window = list->data; - - meta_comp_window_free (window); - } - - g_list_free (windows); -} - -void -meta_comp_screen_unredirect (MetaCompScreen *info) -{ - WsScreen *ws_screen = info->screen; - WsWindow *root = ws_screen_get_root_window (ws_screen); - - g_signal_handler_disconnect (info->magnifier, info->repaint_id); - g_object_unref (info->magnifier); - - ws_window_unredirect_subwindows (root); - ws_screen_release_gl_window (ws_screen); - - free_all_windows (info); - - ws_display_sync (info->display); - - /* FIXME: libcm needs a way to guarantee that a window is destroyed, - * without relying on ref counting having it as a side effect - */ - g_object_unref (info->selection_window); -} - -void -meta_comp_screen_queue_paint (MetaCompScreen *info) -{ -#if 0 - g_print ("queuing\n"); -#endif - if (!info->idle_id) - info->idle_id = g_idle_add (repaint, info); -} - -void -meta_comp_screen_restack (MetaCompScreen *info, - Window window, - Window above_this) -{ - MetaCompWindow *comp_window = find_comp_window (info, window); - MetaCompWindow *above_comp_window = find_comp_window (info, above_this); - CmNode *window_node = find_node (info, window); - CmNode *above_node = find_node (info, above_this); - - if ((comp_window && meta_comp_window_stack_frozen (comp_window)) || - (above_comp_window && meta_comp_window_stack_frozen (above_comp_window))) - { - return; - } - -#if 0 - dump_stacking_order (info->stacker->children); -#endif - - if (window_node == above_node) - return; - - if (window_node && above_this == WS_RESOURCE_XID (info->gl_window)) - { - cm_stacker_raise_child (info->stacker, window_node); - } - else if (window_node && above_this == None) - { - cm_stacker_lower_child (info->stacker, window_node); - } - else if (window_node && above_node) - { - cm_stacker_restack_child (info->stacker, window_node, above_node); - } -#if 0 - else - g_print ("nothing happened\n"); -#endif - -#if 0 - g_print ("done restacking; new order:\n"); -#endif -#if 0 - dump_stacking_order (info->stacker->children); -#endif - -} - -void -meta_comp_screen_raise_window (MetaCompScreen *info, - Window window) -{ - CmNode *node = find_node (info, window); - - if (node) - cm_stacker_raise_child (info->stacker, node); -} - -void -meta_comp_screen_set_size (MetaCompScreen *info, - Window xwindow, - gint x, - gint y, - gint width, - gint height) -{ - MetaCompWindow *comp_window = meta_comp_window_lookup (info, xwindow); - - if (comp_window) - { - WsRectangle rect; - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - - meta_comp_window_set_size (comp_window, &rect); - } -} - -static void -print_child_titles (WsWindow *window) -{ - GList *children = ws_window_query_subwindows (window); - GList *list; - int i; - - g_print ("window: %lx %s\n", WS_RESOURCE_XID (window), ws_window_query_title (window)); - - i = 0; - for (list = children; list != NULL; list = list->next) - { - WsWindow *child = list->data; - - g_print (" %d adding: %lx %s\n", i++, WS_RESOURCE_XID (child), ws_window_query_title (child)); - } -} - -typedef struct -{ - MetaCompScreen *cscreen; - XID xid; -} DestroyData; - -static void -on_window_destroy (MetaCompWindow *comp_window, - gpointer closure) -{ - DestroyData *data = closure; - CmNode *node = meta_comp_window_get_node (comp_window); - - cm_stacker_remove_child (data->cscreen->stacker, node); - g_hash_table_remove (data->cscreen->windows_by_xid, (gpointer)data->xid); -} - -void -meta_comp_screen_add_window (MetaCompScreen *info, - Window xwindow) -{ - WsDrawable *drawable; - MetaCompWindow *comp_window; - DestroyData *data; - - ws_display_begin_error_trap (info->display); - - comp_window = meta_comp_window_lookup (info, xwindow); - - if (comp_window) - goto out; - - drawable = WS_DRAWABLE (ws_window_lookup (info->display, xwindow)); - - if (ws_window_query_input_only (WS_WINDOW (drawable))) - goto out; - - if (WS_WINDOW (drawable) == info->gl_window || - WS_WINDOW (drawable) == info->screen->overlay_window) - { -#if 0 - g_print ("gl window\n"); -#endif - goto out; - } - - data = g_new (DestroyData, 1); - data->cscreen = info; - data->xid = WS_RESOURCE_XID (drawable); - - comp_window = meta_comp_window_new (info->meta_screen, drawable, - on_window_destroy, data); - - g_hash_table_insert (info->windows_by_xid, (gpointer)WS_RESOURCE_XID (drawable), comp_window); - - cm_stacker_add_child (info->stacker, meta_comp_window_get_node (comp_window)); - - out: - if (comp_window) - { - /* This function is called both when windows are created and when they - * are mapped, so for now we have this silly function. - */ - meta_comp_window_refresh_attrs (comp_window); - } - - ws_display_end_error_trap (info->display); - -#if 0 - g_print ("done checking\n"); -#endif - - return; -} - - -void -meta_comp_screen_remove_window (MetaCompScreen *info, - Window xwindow) -{ - MetaCompWindow *comp_window = meta_comp_window_lookup (info, xwindow); - - if (comp_window) - meta_comp_window_free (comp_window); -} - -void -meta_comp_screen_set_updates (MetaCompScreen *info, - Window xwindow, - gboolean updates) -{ - MetaCompWindow *comp_window = meta_comp_window_lookup (info, xwindow); - - meta_comp_window_set_updates (comp_window, updates); -} - - -void -meta_comp_screen_set_patch (MetaCompScreen *info, - Window xwindow, - CmPoint points[4][4]) -{ - CmDrawableNode *node = CM_DRAWABLE_NODE (find_node (info, xwindow)); - - if (node) - cm_drawable_node_set_patch (node, points); -} - -void -meta_comp_screen_unset_patch (MetaCompScreen *info, - Window xwindow) -{ - CmDrawableNode *node = CM_DRAWABLE_NODE (find_node (info, xwindow)); - - if (node) - cm_drawable_node_unset_patch (node); -} - -void -meta_comp_screen_set_alpha (MetaCompScreen *info, - Window xwindow, - gdouble alpha) -{ - CmDrawableNode *node = CM_DRAWABLE_NODE (find_node (info, xwindow)); -#if 0 - g_print ("alpha: %f\n", alpha); -#endif - cm_drawable_node_set_alpha (node, alpha); -} - -void -meta_comp_screen_get_real_size (MetaCompScreen *info, - Window xwindow, - WsRectangle *size) -{ - CmDrawableNode *node = CM_DRAWABLE_NODE (find_node (info, xwindow)); - - if (!size) - return; - - cm_drawable_node_get_clipbox (node, size); -} - -void -meta_comp_screen_unmap (MetaCompScreen *info, - Window xwindow) -{ - MetaCompWindow *window = find_comp_window (info, xwindow); - - if (window) - meta_comp_window_hide (window); -} - -void -meta_comp_screen_set_target_rect (MetaCompScreen *info, - Window xwindow, - WsRectangle *rect) -{ - CmDrawableNode *node = CM_DRAWABLE_NODE (find_node (info, xwindow)); - - if (node) - cm_drawable_node_set_scale_rect (node, rect); -} - -#endif - diff --git a/src/c-screen.h b/src/c-screen.h index 7d6c2167b..e69de29bb 100644 --- a/src/c-screen.h +++ b/src/c-screen.h @@ -1,53 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#include "screen.h" -#include "c-window.h" - -typedef struct MetaCompScreen MetaCompScreen; - -MetaCompScreen *meta_comp_screen_new (WsDisplay *display, - MetaScreen *screen); -MetaCompScreen *meta_comp_screen_get_by_xwindow (Window xwindow); -void meta_comp_screen_destroy (MetaCompScreen *scr_info); -void meta_comp_screen_redirect (MetaCompScreen *info); -void meta_comp_screen_unredirect (MetaCompScreen *info); -void meta_comp_screen_add_window (MetaCompScreen *scr_info, - Window xwindow); -void meta_comp_screen_remove_window (MetaCompScreen *scr_info, - Window xwindow); -void meta_comp_screen_restack (MetaCompScreen *scr_info, - Window window, - Window above_this); -void meta_comp_screen_set_size (MetaCompScreen *info, - Window window, - gint x, - gint y, - gint width, - gint height); -void meta_comp_screen_raise_window (MetaCompScreen *scr_info, - Window window); -void meta_comp_screen_queue_paint (MetaCompScreen *info); -void meta_comp_screen_set_updates (MetaCompScreen *info, - Window xwindow, - gboolean updates); -void meta_comp_screen_set_patch (MetaCompScreen *info, - Window xwindow, - CmPoint points[4][4]); -void meta_comp_screen_unset_patch (MetaCompScreen *info, - Window xwindow); -void meta_comp_screen_set_alpha (MetaCompScreen *info, - Window xwindow, - gdouble alpha); -void meta_comp_screen_get_real_size (MetaCompScreen *info, - Window xwindow, - WsRectangle *size); -void meta_comp_screen_set_target_rect (MetaCompScreen *info, - Window xwindow, - WsRectangle *rect); -void meta_comp_screen_set_explode (MetaCompScreen *info, - Window xwindow, - gdouble level); -void meta_comp_screen_unmap (MetaCompScreen *info, - Window xwindow); -MetaCompWindow *meta_comp_screen_lookup_window (MetaCompScreen *info, - Window xwindow); diff --git a/src/c-window.c b/src/c-window.c index 43cb70672..e69de29bb 100644 --- a/src/c-window.c +++ b/src/c-window.c @@ -1,1259 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2006 Red Hat, Inc. - * - * 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 - -#ifdef HAVE_COMPOSITE_EXTENSIONS - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "effects.h" -#include "c-window.h" -#include "window.h" -#include "frame.h" -#include "compositor.h" -#include "workspace.h" - -typedef struct UnminimizeInfo UnminimizeInfo; - -struct _MetaCompWindow -{ - MetaDisplay *display; - MetaScreen *screen; - WsDrawable *drawable; - WsPixmap *pixmap; - CmDrawableNode *node; - gboolean updates; - WsSyncAlarm *alarm; - - WsRectangle size; - gboolean waiting_for_paint; - - gint64 counter_value; - gint ref_count; - - gboolean animation_in_progress; - gboolean hide_after_animation; - - int stack_freeze_count; - int fade_in_idle_id; - - MetaCompWindowDestroy destroy; - gpointer closure; - - UnminimizeInfo *unminimize_info; -}; - -static void cancel_fade (MetaCompWindow *comp_window); -static void start_unminimize (MetaCompWindow *comp_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) -{ - 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); - -#if 0 - g_print ("counter value %lld\n", ws_sync_counter_query_value (counter)); - alarm = ws_sync_alarm_new (WS_RESOURCE (comp_window->drawable)->display, - - display, counter); -#endif - - g_signal_connect (alarm, "alarm_notify_event", - G_CALLBACK (on_alarm), comp_window); - - if (value % 2 == 1) - { - ws_sync_alarm_set (alarm, value + 2); - -#if 0 - g_print ("wait for %lld\n", value + 2); - - g_print ("increasing counter\n"); -#endif - ws_sync_counter_change (counter, 1); - -#if 0 - g_print ("counter value %lld\n", - ws_sync_counter_query_value (counter)); -#endif - } - else - { -#if 0 - g_print ("wait for %lld\n", value + 1); -#endif - 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; -} - -void -meta_comp_window_show (MetaCompWindow *comp_window) -{ - if (comp_window->animation_in_progress) - comp_window->hide_after_animation = FALSE; - - cm_drawable_node_set_viewable (CM_DRAWABLE_NODE (comp_window->node), TRUE); - cm_drawable_node_update_pixmap (CM_DRAWABLE_NODE (comp_window->node)); -} - -void -meta_comp_window_hide (MetaCompWindow *comp_window) -{ - if (comp_window->animation_in_progress) - { - comp_window->hide_after_animation = TRUE; - return; - } - - cancel_fade (comp_window); - - cm_drawable_node_set_viewable (CM_DRAWABLE_NODE (comp_window->node), - FALSE); -} - -MetaCompWindow * -meta_comp_window_new (MetaScreen *screen, - WsDrawable *drawable, - MetaCompWindowDestroy destroy, - gpointer closure) -{ - MetaDisplay *display = screen->display; - MetaCompWindow *window; - WsRectangle geometry; - - ws_drawable_query_geometry (drawable, &geometry); - - window = g_new0 (MetaCompWindow, 1); - - window->screen = screen; - window->display = display; - window->drawable = g_object_ref (drawable); - window->node = cm_drawable_node_new (drawable, &geometry); - window->updates = TRUE; - window->counter_value = 1; - window->ref_count = 1; - window->destroy = destroy; - window->closure = closure; - - meta_comp_window_hide (window); - - return window; -} - -static MetaCompWindow * -comp_window_ref (MetaCompWindow *comp_window) -{ - comp_window->ref_count++; - - return comp_window; -} - -static gboolean -comp_window_unref (MetaCompWindow *comp_window) -{ - if (--comp_window->ref_count == 0) - { - if (comp_window->destroy) - comp_window->destroy (comp_window, comp_window->closure); - - g_object_unref (comp_window->drawable); - g_object_unref (comp_window->node); - if (comp_window->alarm) - g_object_unref (comp_window->alarm); - memset (comp_window, 'e', sizeof (MetaCompWindow)); - g_free (comp_window); - - return TRUE; - } - - return FALSE; -} - -gboolean -meta_comp_window_free (MetaCompWindow *window) -{ - return comp_window_unref (window); -} - -void -meta_comp_window_set_size (MetaCompWindow *comp_window, - WsRectangle *rect) -{ - if (comp_window->updates) - { - WsWindow *window = WS_WINDOW (comp_window->drawable); - WsDisplay *display = WS_RESOURCE (window)->display; - CmDrawableNode *dnode = CM_DRAWABLE_NODE (comp_window->node); - WsRegion *shape; - - ws_display_begin_error_trap (display); - - cm_drawable_node_set_geometry (dnode, rect); - shape = ws_window_get_output_shape (window); - cm_drawable_node_set_shape (dnode, shape); - ws_region_destroy (shape); - - if (rect->width != comp_window->size.width || - rect->height != comp_window->size.height) - { - cm_drawable_node_update_pixmap (dnode); - } - - comp_window->size = *rect; - - ws_display_end_error_trap (display); - } -} - -static gboolean -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; -} - -static MetaWindow * -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 void -send_configure_notify (WsDrawable *drawable) -{ - WsWindow *window = WS_WINDOW (drawable); - WsRectangle geo; - - ws_drawable_query_geometry (drawable, &geo); - -#if 0 - g_print ("sending configure notify %d %d %d %d\n", - geo.x, geo.y, geo.width, geo.height); -#endif - - ws_window_send_configure_notify ( - window, geo.x, geo.y, geo.width, geo.height, - 0 /* border width */, ws_window_query_override_redirect (window)); -} - -static WsWindow * -find_client_window (MetaCompWindow *comp_window) -{ - MetaWindow *meta_window = find_meta_window (comp_window); - - if (meta_window && meta_window->frame) - { - WsDisplay *ws_display = WS_RESOURCE (comp_window->drawable)->display; - -#if 0 - g_print ("framed window (client: %lx)\n", WS_RESOURCE_XID (comp_window->drawable)); -#endif - -#if 0 - g_print ("framed window (client: %lx\n", meta_window->xwindow); -#endif - -#if 0 - g_print ("framed window: %p\n", comp_window); -#endif - return ws_window_lookup (ws_display, meta_window->xwindow); - } - else - { -#if 0 - if (meta_window) - g_print ("window not framed, but managed (%p)\n", comp_window); - else - g_print ("no meta window %p\n", comp_window); -#endif - - return WS_WINDOW (comp_window->drawable); - } -} - -static gboolean -private_metacity_window (MetaCompWindow *comp_window) -{ - /* Returns TRUE if this is a private metacity window - * such as a tooltip or a menu - */ - XID xid = WS_RESOURCE_XID (comp_window->drawable); - - return meta_ui_window_is_widget (comp_window->screen->ui, xid); -} - -static gboolean -frameless_managed (MetaCompWindow *comp_window) -{ - /* For some reason frameless, managed windows don't respond to - * sync requests messages. FIXME: at some point need to find out - * what's going on - */ - MetaWindow *mw = find_meta_window (comp_window); - - return mw && !mw->frame; -} - -static gdouble -interpolate (gdouble t, gdouble begin, gdouble end, double power) -{ - return (begin + (end - begin) * pow (t, power)); -} - -static void -interpolate_rectangle (gdouble t, - WsRectangle * from, - WsRectangle * to, - WsRectangle * result) -{ - if (!result) - return; - - result->x = interpolate (t, from->x, to->x, 1); - result->y = interpolate (t, from->y, to->y, 1); - result->width = interpolate (t, from->width, to->width, 1); - result->height = interpolate (t, from->height, to->height, 1); -} - -static void -comp_window_set_target_rect (MetaCompWindow *window, - WsRectangle *rect) -{ - cm_drawable_node_set_scale_rect (window->node, rect); -} - -static void -comp_window_get_real_size (MetaCompWindow *window, - WsRectangle *size) -{ - if (!size) - return; - - cm_drawable_node_get_clipbox (window->node, size); -} - -#define FADE_TIME 0.225 - -typedef struct -{ - MetaEffect *effect; - MetaCompWindow *window; - GTimer * timer; - WsRectangle from; - WsRectangle to; - gboolean first_time; - gdouble start_alpha; - gdouble end_alpha; -} FadeInfo; - -static gboolean -update_fade (gpointer data) -{ - FadeInfo *info = data; - gdouble elapsed = g_timer_elapsed (info->timer, NULL); - gdouble t = elapsed / FADE_TIME; - - if (elapsed >= FADE_TIME) - { - comp_window_set_target_rect (info->window, &info->to); - cm_drawable_node_set_alpha (info->window->node, info->end_alpha); - cm_drawable_node_unset_patch (info->window->node); - comp_window_unref (info->window); - return FALSE; - } - else - { - gdouble alpha = interpolate (t, info->start_alpha, info->end_alpha, 1.0); - WsRectangle cur; - - if (info->first_time) - { - meta_comp_window_show (info->window); - info->first_time = FALSE; - } - - interpolate_rectangle (t, &info->from, &info->to, &cur); - comp_window_set_target_rect (info->window, &cur); - cm_drawable_node_set_alpha (info->window->node, alpha); - return TRUE; - } -} - -static void -cancel_fade (MetaCompWindow *comp_window) -{ - if (comp_window->fade_in_idle_id) - { - g_source_remove (comp_window->fade_in_idle_id); - comp_window->fade_in_idle_id = 0; - } -} - -static void -meta_comp_window_fade_in (MetaCompWindow *comp_window) -{ - FadeInfo *info = g_new0 (FadeInfo, 1); - WsWindow *window = find_client_window (comp_window); - - if (comp_window->fade_in_idle_id) - return; - - info->window = comp_window_ref (comp_window); - info->timer = g_timer_new (); - - comp_window_get_real_size (info->window, &info->to); - info->from = info->to; - - info->start_alpha = 0.1; - info->first_time = TRUE; - - if (has_type (window, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU") || - has_type (window, "_NET_WM_WINDOW_TYPE_POPUP_MENU")) - { - info->end_alpha = 0.9; - info->from.width *= 0.6; - info->from.height *= 0.4; - } - else if (has_type (window, "_NET_WM_WINDOW_TYPE_DIALOG")) - { - info->end_alpha = 0.9; - } - else - { - info->end_alpha = 1.0; - } - - comp_window->fade_in_idle_id = g_idle_add (update_fade, info); -} - -static void -on_request_alarm (WsSyncAlarm *alarm, - WsAlarmNotifyEvent *event, - MetaCompWindow *comp_window) -{ - /* This alarm means that the window is ready to be shown on screen */ - - if (comp_window->unminimize_info) - start_unminimize (comp_window); - else - meta_comp_window_fade_in (comp_window); - - g_object_unref (alarm); -} - -static gboolean -send_sync_request (MetaCompWindow *comp_window) -{ - WsDisplay *display; - WsWindow *client_window = find_client_window (comp_window); - WsSyncCounter *request_counter; - WsSyncAlarm *alarm; - guint32 msg[5]; - display = WS_RESOURCE (comp_window->drawable)->display; - ws_display_init_sync (display); - - if (!client_window) - return FALSE; - - request_counter = ws_window_get_property_sync_counter ( - client_window, "_NET_WM_SYNC_REQUEST_COUNTER"); - - if (!request_counter) - return FALSE; - - comp_window->counter_value = ws_sync_counter_query_value (request_counter) + 1; - - msg[0] = comp_window->display->atom_net_wm_sync_request; - msg[1] = meta_display_get_current_time (comp_window->display); - msg[2] = comp_window->counter_value & 0xffffffff; - msg[3] = (comp_window->counter_value >> 32) & 0xffffffff; - - alarm = ws_sync_alarm_new (display, request_counter); - - ws_sync_alarm_set (alarm, comp_window->counter_value); - - g_signal_connect (alarm, "alarm_notify_event", - G_CALLBACK (on_request_alarm), comp_window); - - ws_window_send_client_message (client_window, - "WM_PROTOCOLS", msg); - - send_configure_notify (WS_DRAWABLE (client_window)); - - ws_display_flush (WS_RESOURCE (client_window)->display); - - return TRUE; -} - -void -meta_comp_window_refresh_attrs (MetaCompWindow *comp_window) -{ - /* FIXME: this function should not exist - the real problem is - * probably in meta_screen_info_add_window() where it it called. - */ - - double alpha = 1.0; - CmDrawableNode *node = CM_DRAWABLE_NODE (comp_window->node); - -#if 0 - g_print ("waiting for paint: %d\n", comp_window->waiting_for_paint); -#endif - - if (ws_window_query_mapped (WS_WINDOW (comp_window->drawable)) -#if 0 - && !comp_window->waiting_for_paint -#endif - ) - { - WsWindow *window = WS_WINDOW (comp_window->drawable); - - cm_drawable_node_unset_patch (CM_DRAWABLE_NODE (node)); - - if (has_type (window, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU")) - { - alpha = 0.9; - } - else if (has_type (window, "_NET_WM_WINDOW_TYPE_POPUP_MENU")) - { - alpha = 0.9; - } - else - { - alpha = 1.0; - } - - cm_drawable_node_set_alpha (node, alpha); - - if (!cm_drawable_node_get_viewable (node)) - { - comp_window->waiting_for_paint = TRUE; -#if 0 - alarm = ws_alarm_new (comp_window->display); -#endif -#if 0 - finish_counter = ws_window_get_property_sync_counter ( - window, "_NET_WM_FINISH_FRAME_COUNTER"); -#endif - - /* For some reason the panel and nautilus don't respond to the - * sync counter stuff. FIXME: this should be figured out at - * some point. - */ - if (frameless_managed (comp_window) || - private_metacity_window (comp_window) || - !send_sync_request (comp_window)) - { - meta_comp_window_show (comp_window); - } - } - } - else - { -#if 0 - g_print ("unmapping %p\n", node); -#endif - - meta_comp_window_hide (comp_window); - } -} - -void -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) - { - WsRectangle rect; - WsRegion *shape; - WsDisplay *display = WS_RESOURCE (node->drawable)->display; - - ws_display_begin_error_trap (display); - ws_drawable_query_geometry (node->drawable, &rect); - cm_drawable_node_update_pixmap (node); - cm_drawable_node_set_geometry (node, &rect); - shape = ws_window_get_output_shape (WS_WINDOW (node->drawable)); - cm_drawable_node_set_shape (node, shape); - ws_region_destroy (shape); - ws_display_end_error_trap (display); - } -} - -CmNode * -meta_comp_window_get_node (MetaCompWindow *comp_window) -{ - return CM_NODE (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 *comp_window; - gdouble level; - GTimer * timer; -} ExplodeInfo; - -static gboolean -update_explosion (gpointer data) -{ - ExplodeInfo *info = data; - CmDrawableNode *node = CM_DRAWABLE_NODE (info->comp_window->node); - gdouble elapsed = g_timer_elapsed (info->timer, NULL); - - if (!cm_drawable_node_get_viewable (node) || elapsed > EXPLODE_TIME) - { - meta_effect_end (info->effect); - - info->comp_window->animation_in_progress = FALSE; - if (info->comp_window->hide_after_animation) - meta_comp_window_hide (info->comp_window); - - cm_drawable_node_set_explosion_level (node, 0.0); - - comp_window_unref (info->comp_window); - 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); - - if (!cm_drawable_node_get_viewable (comp_window->node)) - return; - - comp_window->animation_in_progress = TRUE; - - info->comp_window = comp_window_ref (comp_window); - info->effect = effect; - info->level = 0.0; - info->timer = g_timer_new (); - - g_idle_add (update_explosion, info); -} - -/* shrinkydink minimize effect */ - -#define N_PHASES 5 - -typedef struct -{ - WsRectangle start_rect; - WsRectangle end_rect; - gdouble start_alpha; - gdouble end_alpha; - gdouble start_time; - gdouble end_time; -} Phase; - -typedef struct -{ - GTimer *timer; - - MetaCompWindow *comp_window; - - MetaEffect *effect; - - Phase phases[N_PHASES]; -} MiniInfo; - -static void -set_geometry (MetaCompWindow *window, - Phase *phase, - gdouble elapsed) -{ - WsRectangle rect; - gdouble alpha; - gdouble t = (elapsed - phase->start_time) / (phase->end_time - phase->start_time); - - interpolate_rectangle (t, &phase->start_rect, &phase->end_rect, &rect); - alpha = interpolate (t, phase->start_alpha, phase->end_alpha, 1.0); - - comp_window_set_target_rect (window, &rect); - cm_drawable_node_set_alpha (window->node, alpha); -} - -static int -center (gdouble what, gdouble in) -{ - return (in - what) / 2.0 + 0.5; -} - -#define WOBBLE_FACTOR 1.5 - -static void -generate_phases (WsRectangle *start, - WsRectangle *icon, - Phase phases[N_PHASES]) -{ - const double phase_times[5] = { - 0.225, /* scale to size of button */ - 0.100, /* scale up a little */ - 0.100, /* scale back a little */ - 0.100, /* drop down to icon */ - 0.350, /* fade out */ - }; - - WsRectangle cur; - gdouble alpha; - gdouble aspect_ratio; - gdouble time; - int i; - - aspect_ratio = (double)start->width / (double)start->height; - cur = *start; - time = 0.0; - alpha = 1.0; - for (i = 0; i < N_PHASES; ++i) - { - Phase *phase = &(phases[i]); - WsRectangle *end = &(phase->end_rect); - - phase->start_time = time; - phase->start_rect = cur; - phase->start_alpha = alpha; - phase->end_alpha = 1.0; - phase->end_time = time + phase_times[i]; - - if (i == 0) - { - /* Shrink to a little rectangle */ - end->height = icon->height; - end->width = icon->height * aspect_ratio; -#if 0 - end->x = icon->x + center (end->width, icon->width); -#endif - end->x = cur.x + center (end->width, cur.width); - end->y = cur.y + center (icon->height, cur.height); - } - else if (i == 1) - { - /* Zoom out a little */ - end->x = cur.x + center (WOBBLE_FACTOR * cur.width, cur.width); - end->y = cur.y + center (WOBBLE_FACTOR * cur.height, cur.height); - end->width = cur.width * WOBBLE_FACTOR; - end->height = cur.height * WOBBLE_FACTOR; - } - else if (i == 2) - { - /* Zoom back */ - end->height = icon->height; - end->width = icon->height * aspect_ratio; -#if 0 - end->x = icon->x + center (end->width, icon->width); -#endif - end->x = cur.x + center (end->width, cur.width); - end->y = cur.y + center (icon->height, cur.height); - } - else if (i == 3) - { - /* Move down to the button */ - end->height = icon->height; - end->width = icon->height * aspect_ratio; - end->x = icon->x + center (end->width, icon->width); - end->y = icon->y; - } - else if (i == 4) - { - /* Fade out */ - end->x = icon->x; - end->y = icon->y; - end->width = icon->width; - end->height = icon->height; - - phases[i].end_alpha = 0.0; - } - - alpha = phase->end_alpha; - cur = phase->end_rect; - time += phase_times[i]; - } -} - -static gboolean -update_minimize (gpointer data) -{ - MiniInfo *info = data; - Phase *current_phase; - int i; - gdouble elapsed = g_timer_elapsed (info->timer, NULL); - - current_phase = NULL; - for (i = 0; i < N_PHASES; ++i) - { - Phase *p = &(info->phases[i]); - - if (p->start_time < elapsed && p->end_time >= elapsed) - { - current_phase = p; - break; - } - } - - if (current_phase) - { - set_geometry (info->comp_window, current_phase, elapsed); - return TRUE; - } - else - { - meta_comp_window_hide (info->comp_window); - cm_drawable_node_set_alpha (info->comp_window->node, 1.0); - cm_drawable_node_unset_patch (info->comp_window->node); - comp_window_unref (info->comp_window); - - meta_effect_end (info->effect); - - return FALSE; - } -} - -static void -meta_rect_to_ws_rect (MetaRectangle *mrect, - WsRectangle *wrect) -{ - if (!mrect || !wrect) - return; - - wrect->x = mrect->x; - wrect->y = mrect->y; - wrect->width = mrect->width; - wrect->height = mrect->height; -} - -void -meta_comp_window_run_minimize (MetaCompWindow *window, - MetaEffect *effect) -{ - MiniInfo *info = g_new (MiniInfo, 1); - WsRectangle start, end; - - info->timer = g_timer_new (); - - info->comp_window = comp_window_ref (window); - - info->effect = effect; - - meta_rect_to_ws_rect (&(effect->u.minimize.window_rect), &start); - meta_rect_to_ws_rect (&(effect->u.minimize.icon_rect), &end); - - generate_phases (&start, &end, info->phases); - - g_idle_add (update_minimize, info); -} - -struct UnminimizeInfo -{ - GTimer *timer; - - MetaCompWindow *comp_window; - - Phase phases[N_PHASES]; - gboolean first_time; -}; - -#define WOBBLE_FACTOR_OUT 0.7 - -static void -generate_unminimize_phases (WsRectangle *icon, - WsRectangle *full, - Phase phases[N_PHASES]) -{ - const double phase_times[5] = { - 0.350, /* fade in */ - 0.100, /* move up from icon */ - 0.225, /* scale to full size */ - 0.100, /* scale down a little */ - 0.100, /* scale to full size */ - }; - - WsRectangle cur; - gdouble aspect_ratio; - gdouble time; - int i; - - aspect_ratio = (double)full->width / (double)full->height; - cur = *icon; - time = 0.0; - for (i = 0; i < N_PHASES; ++i) - { - Phase *phase = &(phases[i]); - WsRectangle *end = &(phase->end_rect); - - phase->start_time = time; - phase->start_rect = cur; - phase->start_alpha = 1.0; - phase->end_alpha = 1.0; - phase->end_time = time + phase_times[i]; - - if (i == 0) - { - /* Fade in */ - phase->end_alpha = 1.0; - phase->start_alpha = 0.0; - end->height = icon->height; - end->width = icon->height * aspect_ratio; - end->x = icon->x + center (end->width, icon->width); - end->y = icon->y; - } - else if (i == 1) - { - /* Move up from icon */ - end->width = cur.width; - end->height = cur.height; -#if 0 - end->x = cur.x; -#endif - end->x = full->x + center (end->width, full->width); - end->y = full->y + center (icon->height, full->height); - } - else if (i == 2) - { - /* Zoom to full size */ - *end = *full; - } - else if (i == 3) - { - /* Scale down a little */ - end->x = cur.x + center (cur.width * WOBBLE_FACTOR_OUT, cur.width); - end->y = cur.y + center (cur.height * WOBBLE_FACTOR_OUT, cur.height); - end->width = cur.width * WOBBLE_FACTOR_OUT; - end->height = cur.height * WOBBLE_FACTOR_OUT; - } - else if (i == 4) - { - /* Scale up to full size again */ - *end = *full; - } - - cur = phase->end_rect; - time += phase_times[i]; - } -} - -static gboolean -update_unminimize (gpointer data) -{ - UnminimizeInfo *info = data; - Phase *current_phase; - int i; - gdouble elapsed = g_timer_elapsed (info->timer, NULL); - - current_phase = NULL; - for (i = 0; i < N_PHASES; ++i) - { - Phase *p = &(info->phases[i]); - - if (p->start_time < elapsed && p->end_time >= elapsed) - { - current_phase = p; - break; - } - } - - if (current_phase) - { - if (info->first_time) - { - meta_comp_window_show (info->comp_window); - info->first_time = FALSE; - } - - set_geometry (info->comp_window, current_phase, elapsed); - return TRUE; - } - else - { - cm_drawable_node_set_alpha (info->comp_window->node, 1.0); - cm_drawable_node_unset_patch (info->comp_window->node); - comp_window_unref (info->comp_window); -#if 0 - g_print ("done\n"); -#endif - - return FALSE; - } - -} - -static void -start_unminimize (MetaCompWindow *comp_window) -{ - UnminimizeInfo *info = comp_window->unminimize_info; - - if (!info) - return; - - comp_window->unminimize_info = NULL; - - info->timer = g_timer_new (); - info->first_time = TRUE; - - g_idle_add (update_unminimize, info); -} - -void -meta_comp_window_run_unminimize (MetaCompWindow *comp_window, - MetaEffect *effect) -{ - WsRectangle start, end; - UnminimizeInfo *info = g_new0 (UnminimizeInfo, 1); - - meta_rect_to_ws_rect (&(effect->u.unminimize.icon_rect), &start); - meta_rect_to_ws_rect (&(effect->u.unminimize.window_rect), &end); - - generate_unminimize_phases (&start, &end, info->phases); - - info->comp_window = comp_window_ref (comp_window); - - comp_window->unminimize_info = info; - - meta_effect_end (effect); -} - -/* bounce effect */ - -typedef struct -{ - MetaEffect *effect; - MetaCompWindow *window; - GTimer *timer; - Model *model; - MetaRectangle rect; - gdouble last_time; -} FocusInfo; - -static gboolean -update_focus (gpointer data) -{ - FocusInfo *info = data; - CmDrawableNode *node = (CmDrawableNode *)info->window->node; - gdouble elapsed = g_timer_elapsed (info->timer, NULL); - int i; - int n_steps = floor ((elapsed - info->last_time) * 60); - CmPoint points[4][4]; - - if (model_is_calm (info->model) || elapsed > 0.7) - { - cm_drawable_node_unset_patch (node); - meta_effect_end (info->effect); - g_free(info); - return FALSE; - } - - for (i = 0; i < n_steps; ++i) - model_step (info->model); - - if (i > 0) - info->last_time = elapsed; - - get_patch_points (info->model, points); - - cm_drawable_node_set_patch (node, points); - return TRUE; -} - -void -meta_comp_window_run_focus (MetaCompWindow *comp_window, - MetaEffect *effect) -{ - FocusInfo *info = g_new0 (FocusInfo, 1); - MetaWindow *meta_window = - meta_display_lookup_x_window (comp_window->display, - WS_RESOURCE_XID (comp_window->drawable)); - - info->window = comp_window; - info->effect = effect; - info->timer = g_timer_new (); - info->last_time = 0; - - compute_window_rect (meta_window, &info->rect); - info->model = model_new (&info->rect, TRUE); - - g_idle_add (update_focus, info); -} - -void -meta_comp_window_freeze_stack (MetaCompWindow *comp_window) -{ - comp_window->stack_freeze_count++; -} - -void -meta_comp_window_thaw_stack (MetaCompWindow *comp_window) -{ - comp_window->stack_freeze_count--; -} - -gboolean -meta_comp_window_stack_frozen (MetaCompWindow *comp_window) -{ - return comp_window->stack_freeze_count > 0; -} - -#endif - diff --git a/src/c-window.h b/src/c-window.h index c7a574fb7..e69de29bb 100644 --- a/src/c-window.h +++ b/src/c-window.h @@ -1,72 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * Copyright (C) 2006 Red Hat, Inc. - * - * 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 -#include "display.h" -#include "effects.h" - -#ifndef C_WINDOW_H -#define C_WINDOW_H - -typedef struct _MetaCompWindow MetaCompWindow; - -typedef void (* MetaCompWindowDestroy) (MetaCompWindow *window, - gpointer closure); - -MetaCompWindow *meta_comp_window_new (MetaScreen *screen, - WsDrawable *drawable, - MetaCompWindowDestroy destroy, - gpointer data); -CmNode *meta_comp_window_get_node (MetaCompWindow *window); -gboolean meta_comp_window_free (MetaCompWindow *window); -void meta_comp_window_set_size (MetaCompWindow *window, - WsRectangle *size); - -void meta_comp_window_hide (MetaCompWindow *comp_window); -void meta_comp_window_show (MetaCompWindow *comp_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); -void meta_comp_window_shrink (MetaCompWindow *comp_window, - MetaEffect *effect); -void meta_comp_window_unshrink (MetaCompWindow *comp_window, - MetaEffect *effect); -void meta_comp_window_run_focus (MetaCompWindow *comp_window, - MetaEffect *effect); -void meta_comp_window_restack (MetaCompWindow *comp_window, - MetaCompWindow *above); -void meta_comp_window_freeze_stack (MetaCompWindow *comp_window); -void meta_comp_window_thaw_stack (MetaCompWindow *comp_window); -gboolean meta_comp_window_stack_frozen (MetaCompWindow *comp_window); -void meta_comp_window_run_minimize (MetaCompWindow *window, - MetaEffect *effect); -void meta_comp_window_run_unminimize (MetaCompWindow *comp_window, - MetaEffect *effect); - -#if 0 -void meta_comp_window_set_explode (MetaCompWindow *comp_window, - double level); -#endif - -#endif - diff --git a/src/compositor.c b/src/compositor.c index 26f2425c3..1ced8bcac 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1,8 +1,9 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* - * Copyright (C) 2003, 2004, 2005, 2006 Red Hat, Inc. - * Copyright (C) 2003 Keith Packard + * Copyright (C) 2007 Iain Holmes + * Based on xcompmgr - (c) 2003 Keith Packard + * xfwm4 - (c) 2005-2007 Olivier Fourdan * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,660 +22,2243 @@ */ #include -#include "compositor.h" -#include "screen.h" -#include "errors.h" -#include "window.h" -#include "frame.h" -#include "workspace.h" -#include #include +#include +#include +#include -#ifdef HAVE_COMPOSITE_EXTENSIONS -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include +#include +#include "display.h" +#include "screen.h" +#include "frame.h" +#include "errors.h" +#include "compositor.h" +#include "xprops.h" +#include #include #include #include #include #include -#include -#include "effects.h" +#if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2 +#define HAVE_NAME_WINDOW_PIXMAP 1 +#endif -#include "c-screen.h" -#endif /* HAVE_COMPOSITE_EXTENSIONS */ +#define USE_IDLE_REPAINT 1 -#define FRAME_INTERVAL_MILLISECONDS ((int)(1000.0/40.0)) - -#ifdef HAVE_COMPOSITE_EXTENSIONS - -/* Screen specific information */ -typedef struct MoveInfo MoveInfo; - -struct MetaCompositor +typedef enum _MetaCompWindowType { - MetaDisplay *meta_display; - - WsDisplay *display; - - guint repair_idle; - + META_COMP_WINDOW_NORMAL, + META_COMP_WINDOW_DND, + META_COMP_WINDOW_DESKTOP, + META_COMP_WINDOW_DOCK +} MetaCompWindowType; + +struct _MetaCompositor +{ + MetaDisplay *display; + + Atom atom_x_root_pixmap; + Atom atom_x_set_root; + Atom atom_net_wm_window_opacity; + Atom atom_net_wm_window_type_dnd; + +#ifdef USE_IDLE_REPAINT + guint repaint_id; +#endif guint enabled : 1; - guint have_composite : 1; - guint have_damage : 1; - guint have_fixes : 1; - guint have_name_window_pixmap : 1; - guint debug_updates : 1; - - GList *ignored_damage; + guint show_redraw : 1; + guint debug : 1; }; -#endif /* HAVE_COMPOSITE_EXTENSIONS */ -#ifdef HAVE_COMPOSITE_EXTENSIONS - -static WsDisplay *compositor_display; -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS -static void -handle_error (Display *dpy, XErrorEvent *ev, gpointer data) +typedef struct _conv { - WsDisplay *display = data; + int size; + double *data; +} conv; + +typedef struct _MetaCompScreen +{ + MetaScreen *screen; + GList *windows; + GHashTable *windows_by_xid; + + gboolean have_shadows; + conv *gaussian_map; + guchar *shadow_corner; + guchar *shadow_top; + + Picture root_picture; + Picture root_buffer; + Picture black_picture; + Picture trans_black_picture; + Picture root_tile; + XserverRegion all_damage; + + guint overlays; + gboolean compositor_active; + gboolean clip_changed; + + GSList *dock_windows; +} MetaCompScreen; + +typedef struct _MetaCompWindow +{ + MetaScreen *screen; + MetaWindow *window; /* May be NULL if this window isn't managed by Metacity */ + Window id; + XWindowAttributes attrs; + +#ifdef HAVE_NAME_WINDOW_PIXMAP + Pixmap back_pixmap; + + /* When the window is shaded back_pixmap will be replaced with the pixmap + for the shaded window. This is a copy of the original unshaded window + so that we can still see what the window looked like when it is needed + for the _get_window_pixmap function */ + Pixmap shaded_back_pixmap; +#endif + + int mode; + + gboolean damaged; + gboolean shaped; + gboolean needs_shadow; + + MetaCompWindowType type; + + Damage damage; + Picture picture; + Picture alpha_pict; + Picture shadow_pict; + + XserverRegion border_size; + XserverRegion extents; + + Picture shadow; + int shadow_dx; + int shadow_dy; + int shadow_width; + int shadow_height; + + guint opacity; + + XserverRegion border_clip; + + gboolean updates_frozen; + gboolean update_pending; +} MetaCompWindow; + +#define OPAQUE 0xffffffff + +#define WINDOW_SOLID 0 +#define WINDOW_ARGB 1 + +#define SHADOW_RADIUS 6.0 +#define SHADOW_OFFSET_X (SHADOW_RADIUS * -3 / 2) +#define SHADOW_OFFSET_Y (SHADOW_RADIUS * -5 / 4) + +#define SHADOW_OPACITY 0.66 + +#define TRANS_OPACITY 0.75 + +/* Gaussian stuff for creating the shadows */ +static double +gaussian (double r, + double x, + double y) +{ + return ((1 / (sqrt (2 * G_PI * r))) * + exp ((- (x * x + y * y)) / (2 * r * r))); +} + +static conv * +make_gaussian_map (double r) +{ + conv *c; + int size, centre; + int x, y; + double t, g; + + size = ((int) ceil ((r * 3)) + 1) & ~1; + centre = size / 2; + c = g_malloc (sizeof (conv) + size * size * sizeof (double)); + c->size = size; + c->data = (double *) (c + 1); + t = 0.0; + + for (y = 0; y < size; y++) + { + for (x = 0; x < size; x++) + { + g = gaussian (r, (double) (x - centre), (double) (y - centre)); + t += g; + c->data[y * size + x] = g; + } + } + + for (y = 0; y < size; y++) + { + for (x = 0; x < size; x++) + { + c->data[y * size + x] /= t; + } + } + + return c; +} + +static void +dump_xserver_region (const char *location, + MetaDisplay *display, + XserverRegion region) +{ + MetaCompositor *compositor = display->compositor; + Display *dpy = display->xdisplay; + int nrects; + XRectangle *rects; + XRectangle bounds; + + if (!compositor->debug) + return; + + if (region) + { + rects = XFixesFetchRegionAndBounds (dpy, region, &nrects, &bounds); + if (nrects > 0) + { + int i; + fprintf (stderr, "%s (XSR): %d rects, bounds: %d,%d (%d,%d)\n", + location, nrects, bounds.x, bounds.y, bounds.width, bounds.height); + for (i = 1; i < nrects; i++) + fprintf (stderr, "\t%d,%d (%d,%d)\n", + rects[i].x, rects[i].y, rects[i].width, rects[i].height); + } + else + fprintf (stderr, "%s (XSR): empty\n", location); + XFree (rects); + } + else + fprintf (stderr, "%s (XSR): null\n", location); +} + +/* +* A picture will help +* +* -center 0 width width+center +* -center +-----+-------------------+-----+ +* | | | | +* | | | | +* 0 +-----+-------------------+-----+ +* | | | | +* | | | | +* | | | | +* height +-----+-------------------+-----+ +* | | | | +* height+ | | | | +* center +-----+-------------------+-----+ +*/ +static guchar +sum_gaussian (conv *map, + double opacity, + int x, + int y, + int width, + int height) +{ + double *g_data, *g_line; + double v; + int fx, fy; + int fx_start, fx_end; + int fy_start, fy_end; + int g_size, centre; + + g_line = map->data; + g_size = map->size; + centre = g_size / 2; + fx_start = centre - x; + if (fx_start < 0) + fx_start = 0; + + fx_end = width + centre - x; + if (fx_end > g_size) + fx_end = g_size; + + fy_start = centre - y; + if (fy_start < 0) + fy_start = 0; + + fy_end = height + centre - y; + if (fy_end > g_size) + fy_end = g_size; + + g_line = g_line + fy_start * g_size + fx_start; + + v = 0.0; + for (fy = fy_start; fy < fy_end; fy++) + { + g_data = g_line; + g_line += g_size; + + for (fx = fx_start; fx < fx_end; fx++) + v += *g_data++; + } + + if (v > 1.0) + v = 1.0; + + return ((guchar) (v * opacity * 255.0)); +} + +/* precompute shadow corners and sides to save time for large windows */ +static void +presum_gaussian (MetaCompScreen *info) +{ + int centre; + int opacity, x, y; + int msize; + conv *map; + + map = info->gaussian_map; + msize = map->size; + centre = map->size / 2; + + if (info->shadow_corner) + g_free (info->shadow_corner); + if (info->shadow_top) + g_free (info->shadow_top); + + info->shadow_corner = (guchar *)(g_malloc ((msize + 1) * (msize + 1) * 26)); + info->shadow_top = (guchar *) (g_malloc ((msize + 1) * 26)); + + for (x = 0; x <= msize; x++) + { + + info->shadow_top[25 * (msize + 1) + x] = + sum_gaussian (map, 1, x - centre, centre, msize * 2, msize * 2); + for (opacity = 0; opacity < 25; opacity++) + { + info->shadow_top[opacity * (msize + 1) + x] = + info->shadow_top[25 * (msize + 1) + x] * opacity / 25; + } + + for (y = 0; y <= x; y++) + { + info->shadow_corner[25 * (msize + 1) * (msize + 1) + + y * (msize + 1) + + x] + = sum_gaussian (map, 1, x - centre, y - centre, + msize * 2, msize * 2); + + info->shadow_corner[25 * (msize + 1) * (msize + 1) + + x * (msize + 1) + y] = + info->shadow_corner[25 * (msize + 1) * (msize + 1) + + y * (msize + 1) + x]; + + for (opacity = 0; opacity < 25; opacity++) + { + info->shadow_corner[opacity * (msize + 1) * (msize + 1) + + y * (msize + 1) + x] + = info->shadow_corner[opacity * (msize + 1) * (msize + 1) + + x * (msize + 1) + y] + = info->shadow_corner[25 * (msize + 1) * (msize + 1) + + y * (msize + 1) + x] * opacity / 25; + } + } + } +} + +static XImage * +make_shadow (MetaDisplay *display, + MetaScreen *screen, + double opacity, + int width, + int height) +{ + MetaCompScreen *info = screen->compositor_data; + XImage *ximage; + guchar *data; + int msize = info->gaussian_map->size; + int ylimit, xlimit; + int swidth = width + msize; + int sheight = height + msize; + int centre = msize / 2; + int x, y; + guchar d; + int x_diff; + int opacity_int = (int)(opacity * 25); + + data = g_malloc (swidth * sheight * sizeof (guchar)); + + ximage = XCreateImage (display->xdisplay, + DefaultVisual (display->xdisplay, screen->number), + 8, ZPixmap, 0, (char *) data, + swidth, sheight, 8, swidth * sizeof (guchar)); + if (!ximage) + { + g_free (data); + return NULL; + } + + /* + * Build the gaussian in sections + */ + + /* + * centre (fill the complete data array + */ + if (msize > 0) + d = info->shadow_top[opacity_int * (msize + 1) + msize]; + else + d = sum_gaussian (info->gaussian_map, opacity, centre, + centre, width, height); + memset (data, d, sheight * swidth); + + /* + * corners + */ + ylimit = msize; + if (ylimit > sheight / 2) + ylimit = (sheight + 1) / 2; + + xlimit = msize; + if (xlimit > swidth / 2) + xlimit = (swidth + 1) / 2; + + for (y = 0; y < ylimit; y++) + { + for (x = 0; x < xlimit; x++) + { + + if (xlimit == msize && ylimit == msize) + d = info->shadow_corner[opacity_int * (msize + 1) * (msize + 1) + y * (msize + 1) + x]; + else + d = sum_gaussian (info->gaussian_map, opacity, x - centre, + y - centre, width, height); + + data[y * swidth + x] = d; + data[(sheight - y - 1) * swidth + x] = d; + data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + } + + /* top/bottom */ + x_diff = swidth - (msize * 2); + if (x_diff > 0 && ylimit > 0) + { + for (y = 0; y < ylimit; y++) + { + if (ylimit == msize) + d = info->shadow_top[opacity_int * (msize + 1) + y]; + else + d = sum_gaussian (info->gaussian_map, opacity, centre, + y - centre, width, height); + + memset (&data[y * swidth + msize], d, x_diff); + memset (&data[(sheight - y - 1) * swidth + msize], d, x_diff); + } + } + + /* + * sides + */ + for (x = 0; x < xlimit; x++) + { + if (xlimit == msize) + d = info->shadow_top[opacity_int * (msize + 1) + x]; + else + d = sum_gaussian (info->gaussian_map, opacity, x - centre, + centre, width, height); - ws_display_process_xerror (display, ev); + for (y = msize; y < sheight - msize; y++) + { + data[y * swidth + x] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + } + + return ximage; +} + +static Picture +shadow_picture (MetaDisplay *display, + MetaScreen *screen, + double opacity, + Picture alpha_pict, + int width, + int height, + int *wp, + int *hp) +{ + XImage *shadow_image; + Pixmap shadow_pixmap; + Picture shadow_picture; + GC gc; + + shadow_image = make_shadow (display, screen, opacity, width, height); + if (!shadow_image) + return None; + + shadow_pixmap = XCreatePixmap (display->xdisplay, screen->xroot, + shadow_image->width, shadow_image->height, 8); + if (!shadow_pixmap) + { + XDestroyImage (shadow_image); + return None; + } + + shadow_picture = XRenderCreatePicture (display->xdisplay, shadow_pixmap, + XRenderFindStandardFormat (display->xdisplay, PictStandardA8), + 0, 0); + if (!shadow_picture) + { + XDestroyImage (shadow_image); + XFreePixmap (display->xdisplay, shadow_pixmap); + return None; + } + + gc = XCreateGC (display->xdisplay, shadow_pixmap, 0, 0); + if (!gc) + { + XDestroyImage (shadow_image); + XFreePixmap (display->xdisplay, shadow_pixmap); + XRenderFreePicture (display->xdisplay, shadow_picture); + return None; + } + + XPutImage (display->xdisplay, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, + shadow_image->width, shadow_image->height); + *wp = shadow_image->width; + *hp = shadow_image->height; + + XFreeGC (display->xdisplay, gc); + XDestroyImage (shadow_image); + XFreePixmap (display->xdisplay, shadow_pixmap); + + return shadow_picture; +} + +static MetaCompWindow * +find_window_for_screen (MetaScreen *screen, + Window xwindow) +{ + MetaCompScreen *info = screen->compositor_data; + + if (info == NULL) + return NULL; + + return g_hash_table_lookup (info->windows_by_xid, (gpointer) xwindow); +} + +static MetaCompWindow * +find_window_in_display (MetaDisplay *display, + Window xwindow) +{ + GSList *index; + + for (index = display->screens; index; index = index->next) + { + MetaCompWindow *cw = find_window_for_screen (index->data, xwindow); + + if (cw != NULL) + return cw; + } + + return NULL; +} + +static Picture +solid_picture (MetaDisplay *display, + MetaScreen *screen, + gboolean argb, + double a, + double r, + double g, + double b) +{ + Pixmap pixmap; + Picture picture; + XRenderPictureAttributes pa; + XRenderPictFormat *render_format; + XRenderColor c; + + render_format = XRenderFindStandardFormat (display->xdisplay, + argb ? PictStandardARGB32 : PictStandardA8); + + pixmap = XCreatePixmap (display->xdisplay, screen->xroot, + 1, 1, argb ? 32 : 8); + g_return_val_if_fail (pixmap != None, None); + + pa.repeat = TRUE; + picture = XRenderCreatePicture (display->xdisplay, pixmap, render_format, + CPRepeat, &pa); + if (picture == None) + { + XFreePixmap (display->xdisplay, pixmap); + g_warning ("(picture != None) failed"); + return None; + } + + c.alpha = a * 0xffff; + c.red = r * 0xffff; + c.green = g * 0xffff; + c.blue = b * 0xffff; + + XRenderFillRectangle (display->xdisplay, PictOpSrc, picture, &c, 0, 0, 1, 1); + XFreePixmap (display->xdisplay, pixmap); + + return picture; +} + +static Picture +root_tile (MetaScreen *screen) +{ + MetaDisplay *display = screen->display; + Picture picture; + Pixmap pixmap; + gboolean fill = FALSE; + XRenderPictureAttributes pa; + XRenderPictFormat *format; + int p; + Atom background_atoms[2]; + Atom pixmap_atom; + + pixmap = None; + background_atoms[0] = display->compositor->atom_x_root_pixmap; + background_atoms[1] = display->compositor->atom_x_set_root; + + pixmap_atom = XInternAtom (display->xdisplay, "PIXMAP", False); + for (p = 0; p < 2; p++) + { + Atom actual_type; + int actual_format; + gulong nitems, bytes_after; + guchar *prop; + + if (XGetWindowProperty (display->xdisplay, screen->xroot, + background_atoms[p], + 0, 4, FALSE, AnyPropertyType, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop) == Success) + { + if (actual_type == pixmap_atom && + actual_format == 32 && + nitems == 1) + { + memcpy (&pixmap, prop, 4); + XFree (prop); + fill = FALSE; + break; + } + } + } + + if (!pixmap) + { + pixmap = XCreatePixmap (display->xdisplay, screen->xroot, 1, 1, + DefaultDepth (display->xdisplay, screen->number)); + g_return_val_if_fail (pixmap != None, None); + fill = TRUE; + } + + pa.repeat = TRUE; + format = XRenderFindVisualFormat (display->xdisplay, + DefaultVisual (display->xdisplay, + screen->number)); + g_return_val_if_fail (format != NULL, None); + + picture = XRenderCreatePicture (display->xdisplay, pixmap, format, + CPRepeat, &pa); + if ((picture != None) && (fill)) + { + XRenderColor c; + + /* Background default to just plain ugly grey */ + c.red = 0x8080; + c.green = 0x8080; + c.blue = 0x8080; + c.alpha = 0xffff; + + XRenderFillRectangle (display->xdisplay, PictOpSrc, picture, + &c, 0, 0, 1, 1); + XFreePixmap (display->xdisplay, pixmap); + } + + return picture; +} + +static Picture +create_root_buffer (MetaScreen *screen) +{ + MetaDisplay *display = screen->display; + Picture pict; + XRenderPictFormat *format; + Pixmap root_pixmap; + Visual *visual; + int depth, screen_width, screen_height, screen_number; + + screen_width = screen->rect.width; + screen_height = screen->rect.height; + screen_number = screen->number; + visual = DefaultVisual (display->xdisplay, screen_number); + depth = DefaultDepth (display->xdisplay, screen_number); + + format = XRenderFindVisualFormat (display->xdisplay, visual); + g_return_val_if_fail (format != NULL, None); + + root_pixmap = XCreatePixmap (display->xdisplay, + screen->xroot, + screen_width, screen_height, depth); + g_return_val_if_fail (root_pixmap != None, None); + + pict = XRenderCreatePicture (display->xdisplay, root_pixmap, format, 0, NULL); + XFreePixmap (display->xdisplay, root_pixmap); + + return pict; +} + +static void +paint_root (MetaScreen *screen, + Picture root_buffer) +{ + MetaDisplay *display = screen->display; + MetaCompScreen *info = screen->compositor_data; + + g_return_if_fail (root_buffer != None); + + if (info->root_tile == None) + { + info->root_tile = root_tile (screen); + g_return_if_fail (info->root_tile != None); + } + + XRenderComposite (display->xdisplay, PictOpSrc, + info->root_tile, None, root_buffer, + 0, 0, 0, 0, 0, 0, + screen->rect.width, screen->rect.height); +} + +static gboolean +window_has_shadow (MetaCompWindow *cw) +{ + if (((MetaCompScreen *)cw->screen->compositor_data)->have_shadows == FALSE) + return FALSE; + + /* Always put a shadow around windows with a frame */ + if (cw->window) + { + if (cw->window->frame) { + meta_verbose ("Window has shadow because it has a frame\n"); + return TRUE; + } + } + + /* Don't put shadow around DND icon windows */ + if (cw->type == META_COMP_WINDOW_DND || + cw->type == META_COMP_WINDOW_DESKTOP) { + meta_verbose ("Window has no shadow as it is DND or Desktop\n"); + return FALSE; + } + + if (cw->mode != WINDOW_ARGB) { + meta_verbose ("Window has shadow as it is not ARGB\n"); + return TRUE; + } + + meta_verbose ("Window has no shadow as it fell through\n"); + return FALSE; +} + +static XserverRegion +win_extents (MetaCompWindow *cw) +{ + MetaDisplay *display; + MetaScreen *screen; + MetaCompScreen *info; + XRectangle r; + + screen = cw->screen; + display = screen->display; + info = screen->compositor_data; + + r.x = cw->attrs.x; + r.y = cw->attrs.y; + r.width = cw->attrs.width + cw->attrs.border_width * 2; + r.height = cw->attrs.height + cw->attrs.border_width * 2; + + if (cw->needs_shadow) + { + XRectangle sr; + + cw->shadow_dx = SHADOW_OFFSET_X; + cw->shadow_dy = SHADOW_OFFSET_Y; + + if (!cw->shadow) + { + double opacity = SHADOW_OPACITY; + if (cw->opacity != (guint) OPAQUE) + opacity = opacity * ((double) cw->opacity) / ((double) OPAQUE); + + cw->shadow = shadow_picture (display, screen, opacity, cw->alpha_pict, + cw->attrs.width + cw->attrs.border_width * 2, + cw->attrs.height + cw->attrs.border_width * 2, + &cw->shadow_width, &cw->shadow_height); + } + + sr.x = cw->attrs.x + cw->shadow_dx; + sr.y = cw->attrs.y + cw->shadow_dy; + sr.width = cw->shadow_width; + sr.height = cw->shadow_height; + + if (sr.x < r.x) + { + r.width = (r.x + r.width) - sr.x; + r.x = sr.x; + } + + if (sr.y < r.y) + { + r.height = (r.y + r.height) - sr.y; + r.y = sr.y; + } + + if (sr.x + sr.width > r.x + r.width) + r.width = sr.x + sr.width - r.x; + + if (sr.y + sr.height > r.y + r.height) + r.height = sr.y + sr.height - r.y; + } + + return XFixesCreateRegion (display->xdisplay, &r, 1); +} + +static XserverRegion +border_size (MetaCompWindow *cw) +{ + MetaScreen *screen = cw->screen; + MetaDisplay *display = screen->display; + XserverRegion border; + + meta_error_trap_push (display); + border = XFixesCreateRegionFromWindow (display->xdisplay, cw->id, + WindowRegionBounding); + meta_error_trap_pop (display, FALSE); + + g_return_val_if_fail (border != None, None); + XFixesTranslateRegion (display->xdisplay, border, + cw->attrs.x + cw->attrs.border_width, + cw->attrs.y + cw->attrs.border_width); + return border; +} + +static XRenderPictFormat * +get_window_format (MetaCompWindow *cw) +{ + MetaScreen *screen = cw->screen; + MetaDisplay *display = screen->display; + XRenderPictFormat *format; + + format = XRenderFindVisualFormat (display->xdisplay, cw->attrs.visual); + if (!format) + format = XRenderFindVisualFormat (display->xdisplay, + DefaultVisual (display->xdisplay, + screen->number)); + return format; +} + +static Picture +get_window_picture (MetaCompWindow *cw) +{ + MetaScreen *screen = cw->screen; + MetaDisplay *display = screen->display; + XRenderPictureAttributes pa; + XRenderPictFormat *format; + Drawable draw; + + draw = cw->id; + + meta_error_trap_push (display); + +#ifdef HAVE_NAME_WINDOW_PIXMAP + if (cw->back_pixmap == None) + cw->back_pixmap = XCompositeNameWindowPixmap (display->xdisplay, cw->id); + + if (cw->back_pixmap != None) + draw = cw->back_pixmap; +#endif + + format = get_window_format (cw); + if (format) + { + Picture pict; + + pa.subwindow_mode = IncludeInferiors; + + pict = XRenderCreatePicture (display->xdisplay, draw, + format, CPSubwindowMode, &pa); + meta_error_trap_pop (display, FALSE); + + return pict; + } + + meta_error_trap_pop (display, FALSE); + return None; +} + +static void +paint_dock_shadows (MetaScreen *screen, + Picture root_buffer, + XserverRegion region) +{ + MetaDisplay *display = screen->display; + Display *xdisplay = display->xdisplay; + MetaCompScreen *info = screen->compositor_data; + GSList *d; + + for (d = info->dock_windows; d; d = d->next) + { + MetaCompWindow *cw = d->data; + XserverRegion shadow_clip; + + if (cw->shadow) + { + shadow_clip = XFixesCreateRegion (xdisplay, NULL, 0); + XFixesIntersectRegion (xdisplay, shadow_clip, + cw->border_clip, region); + + XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, shadow_clip); + + XRenderComposite (xdisplay, PictOpOver, info->black_picture, + cw->shadow, root_buffer, + 0, 0, 0, 0, + cw->attrs.x + cw->shadow_dx, + cw->attrs.y + cw->shadow_dy, + cw->shadow_width, cw->shadow_height); + XFixesDestroyRegion (xdisplay, shadow_clip); + } + } +} + +static void +paint_windows (MetaScreen *screen, + GList *windows, + Picture root_buffer, + XserverRegion region) +{ + MetaDisplay *display = screen->display; + MetaCompScreen *info = screen->compositor_data; + Display *xdisplay = display->xdisplay; + GList *index, *last; + int screen_width, screen_height, screen_number; + Window xroot; + MetaCompWindow *cw; + XserverRegion paint_region, desktop_region; + + screen_width = screen->rect.width; + screen_height = screen->rect.height; + screen_number = screen->number; + xroot = screen->xroot; + + if (region == None) + { + XRectangle r; + r.x = 0; + r.y = 0; + r.width = screen_width; + r.height = screen_height; + paint_region = XFixesCreateRegion (xdisplay, &r, 1); + } + else + { + paint_region = XFixesCreateRegion (xdisplay, NULL, 0); + XFixesCopyRegion (xdisplay, paint_region, region); + } + + desktop_region = None; + + /* + * Painting from top to bottom, reducing the clipping area at + * each iteration. Only the opaque windows are painted 1st. + */ + last = NULL; + for (index = windows; index; index = index->next) + { + /* Store the last window we dealt with */ + last = index; + + cw = (MetaCompWindow *) index->data; + if (!cw->damaged) + { + /* Not damaged */ + continue; + } + +#if 0 + if ((cw->attrs.x + cw->attrs.width < 1) || + (cw->attrs.y + cw->attrs.height < 1) || + (cw->attrs.x >= screen_width) || (cw->attrs.y >= screen_height)) + { + /* Off screen */ + continue; + } +#endif + + if (cw->picture == None) + cw->picture = get_window_picture (cw); + + /* If the clip region of the screen has been changed + then we need to recreate the extents of the window */ + if (info->clip_changed) + { + if (cw->border_size) + { + XFixesDestroyRegion (xdisplay, cw->border_size); + cw->border_size = None; + } + +#if 0 + if (cw->extents) + { + XFixesDestroyRegion (xdisplay, cw->extents); + cw->extents = None; + } +#endif + } + + if (cw->border_size == None) + cw->border_size = border_size (cw); + + if (cw->extents == None) + cw->extents = win_extents (cw); + + if (cw->mode == WINDOW_SOLID) + { + int x, y, wid, hei; + +#ifdef HAVE_NAME_WINDOW_PIXMAP + x = cw->attrs.x; + y = cw->attrs.y; + wid = cw->attrs.width + cw->attrs.border_width * 2; + hei = cw->attrs.height + cw->attrs.border_width * 2; +#else + x = cw->attrs.x + cw->attrs.border_width; + y = cw->attrs.y + cw->attrs.border_width; + wid = cw->attrs.width; + hei = cw->attrs.height; +#endif + + XFixesSetPictureClipRegion (xdisplay, root_buffer, + 0, 0, paint_region); + XRenderComposite (xdisplay, PictOpSrc, cw->picture, + None, root_buffer, 0, 0, 0, 0, + x, y, wid, hei); + + if (cw->type == META_COMP_WINDOW_DESKTOP) + { + desktop_region = XFixesCreateRegion (xdisplay, 0, 0); + XFixesCopyRegion (xdisplay, desktop_region, paint_region); + } + + XFixesSubtractRegion (xdisplay, paint_region, + paint_region, cw->border_size); + } + + if (!cw->border_clip) + { + cw->border_clip = XFixesCreateRegion (xdisplay, 0, 0); + XFixesCopyRegion (xdisplay, cw->border_clip, paint_region); + } + } + + XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, paint_region); + paint_root (screen, root_buffer); + + paint_dock_shadows (screen, root_buffer, desktop_region == None ? + paint_region : desktop_region); + if (desktop_region != None) + XFixesDestroyRegion (xdisplay, desktop_region); + + /* + * Painting from bottom to top, translucent windows and shadows are painted + */ + for (index = last; index; index = index->prev) + { + cw = (MetaCompWindow *) index->data; + + if (cw->picture) + { + if (cw->shadow && cw->type != META_COMP_WINDOW_DOCK) + { + XserverRegion shadow_clip; + + shadow_clip = XFixesCreateRegion (xdisplay, NULL, 0); + XFixesSubtractRegion (xdisplay, shadow_clip, cw->border_clip, + cw->border_size); + XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, + shadow_clip); + + XRenderComposite (xdisplay, PictOpOver, info->black_picture, + cw->shadow, root_buffer, + 0, 0, 0, 0, + cw->attrs.x + cw->shadow_dx, + cw->attrs.y + cw->shadow_dy, + cw->shadow_width, cw->shadow_height); + if (shadow_clip) + XFixesDestroyRegion (xdisplay, shadow_clip); + } + + if ((cw->opacity != (guint) OPAQUE) && !(cw->alpha_pict)) + { + cw->alpha_pict = solid_picture (display, screen, FALSE, + (double) cw->opacity / OPAQUE, + 0, 0, 0); + } + + XFixesIntersectRegion (xdisplay, cw->border_clip, cw->border_clip, + cw->border_size); + XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, + cw->border_clip); + if (cw->mode == WINDOW_ARGB) + { + int x, y, wid, hei; +#ifdef HAVE_NAME_WINDOW_PIXMAP + x = cw->attrs.x; + y = cw->attrs.y; + wid = cw->attrs.width + cw->attrs.border_width * 2; + hei = cw->attrs.height + cw->attrs.border_width * 2; +#else + x = cw->attrs.x + cw->attrs.border_width; + y = cw->attrs.y + cw->attrs.border_width; + wid = cw->attrs.width; + hei = cw->attrs.height; +#endif + + XRenderComposite (xdisplay, PictOpOver, cw->picture, + cw->alpha_pict, root_buffer, 0, 0, 0, 0, + x, y, wid, hei); + } + } + + if (cw->border_clip) + { + XFixesDestroyRegion (xdisplay, cw->border_clip); + cw->border_clip = None; + } + } + + XFixesDestroyRegion (xdisplay, paint_region); +} + +static void +paint_all (MetaScreen *screen, + XserverRegion region) +{ + MetaCompScreen *info = screen->compositor_data; + Display *xdisplay = screen->display->xdisplay; + int screen_width, screen_height; + + /* Set clipping to the given region */ + XFixesSetPictureClipRegion (xdisplay, info->root_picture, 0, 0, region); + + screen_width = screen->rect.width; + screen_height = screen->rect.height; + + if (screen->display->compositor->show_redraw) + { + Picture overlay; + + dump_xserver_region ("paint_all", screen->display, region); + + /* Make a random colour overlay */ + overlay = solid_picture (screen->display, screen, TRUE, 1, /* 0.3, alpha */ + ((double) (rand () % 100)) / 100.0, + ((double) (rand () % 100)) / 100.0, + ((double) (rand () % 100)) / 100.0); + + XRenderComposite (xdisplay, PictOpOver, overlay, None, info->root_picture, + 0, 0, 0, 0, 0, 0, screen_width, screen_height); + XRenderFreePicture (xdisplay, overlay); + XFlush (xdisplay); + usleep (100 * 1000); + } + + if (info->root_buffer == None) + info->root_buffer = create_root_buffer (screen); + + paint_windows (screen, info->windows, info->root_buffer, region); + + XFixesSetPictureClipRegion (xdisplay, info->root_buffer, 0, 0, region); + XRenderComposite (xdisplay, PictOpSrc, info->root_buffer, None, + info->root_picture, 0, 0, 0, 0, 0, 0, + screen_width, screen_height); +} + +static void +repair_screen (MetaScreen *screen) +{ + MetaCompScreen *info = screen->compositor_data; + MetaDisplay *display = screen->display; + + if (info->all_damage != None) + { + meta_error_trap_push (display); + paint_all (screen, info->all_damage); + XFixesDestroyRegion (display->xdisplay, info->all_damage); + info->all_damage = None; + info->clip_changed = FALSE; + meta_error_trap_pop (display, FALSE); + } +} + +static void +repair_display (MetaDisplay *display) +{ + GSList *screens; + +#ifdef USE_IDLE_REPAINT + if (display->compositor->repaint_id > 0) + { + g_source_remove (display->compositor->repaint_id); + display->compositor->repaint_id = 0; + } +#endif + + for (screens = display->screens; screens; screens = screens->next) + repair_screen ((MetaScreen *) screens->data); +} + +#ifdef USE_IDLE_REPAINT +static gboolean +compositor_idle_cb (gpointer data) +{ + MetaCompositor *compositor = (MetaCompositor *) data; + + compositor->repaint_id = 0; + repair_display (compositor->display); + + return FALSE; +} + +static void +add_repair (MetaDisplay *display) +{ + MetaCompositor *compositor = display->compositor; + + if (compositor->repaint_id > 0) + return; + +#if 0 + compositor->repaint_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, + compositor_idle_cb, compositor, + NULL); +#else + /* Limit it to 50fps */ + compositor->repaint_id = g_timeout_add_full (G_PRIORITY_HIGH, 20, + compositor_idle_cb, compositor, + NULL); +#endif } #endif -#ifdef HAVE_COMPOSITE_EXTENSIONS - -static Window -get_xid (MetaWindow *window) +static void +add_damage (MetaScreen *screen, + XserverRegion damage) { - if (window->frame) - return window->frame->xwindow; - else - return window->xwindow; + MetaDisplay *display = screen->display; + MetaCompScreen *info = screen->compositor_data; + +// dump_xserver_region ("add_damage", display, damage); + + if (info->all_damage) + { + XFixesUnionRegion (display->xdisplay, info->all_damage, + info->all_damage, damage); + XFixesDestroyRegion (display->xdisplay, damage); + } + else + info->all_damage = damage; + +#ifdef USE_IDLE_REPAINT + add_repair (display); +#endif } -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS - -/* This is called by Metacity's effect code when an effect needs to happen. - * In compositor-less Metacity, this includes things like the wireframe - * zoom when a window is minimised. We have a rather larger box of tricks. - */ static void -do_effect (MetaEffect *effect, - gpointer data) +damage_screen (MetaScreen *screen) { - MetaCompScreen *screen; - MetaCompWindow *window; + MetaDisplay *display = screen->display; + XserverRegion region; + XRectangle r; - screen = meta_comp_screen_get_by_xwindow (get_xid (effect->window)); + r.x = 0; + r.y = 0; + r.width = screen->rect.width; + r.height = screen->rect.height; - if (!screen) - { - /* sanity check: if no screen is found, bail */ - meta_warning ("No screen found for %s (%ld); aborting effect.\n", - effect->window->desc, get_xid (effect->window)); - return; + region = XFixesCreateRegion (display->xdisplay, &r, 1); + dump_xserver_region ("damage_screen", display, region); + add_damage (screen, region); +} + +static void +repair_win (MetaCompWindow *cw) +{ + MetaScreen *screen = cw->screen; + MetaDisplay *display = screen->display; + XserverRegion parts; + + meta_error_trap_push (display); + if (!cw->damaged) + { + parts = win_extents (cw); + XDamageSubtract (display->xdisplay, cw->damage, None, None); + } + else + { + parts = XFixesCreateRegion (display->xdisplay, 0, 0); + XDamageSubtract (display->xdisplay, cw->damage, None, parts); + XFixesTranslateRegion (display->xdisplay, parts, + cw->attrs.x + cw->attrs.border_width, + cw->attrs.y + cw->attrs.border_width); + } + + meta_error_trap_pop (display, FALSE); + + dump_xserver_region ("repair_win", display, parts); + add_damage (screen, parts); + cw->damaged = TRUE; +} + +static void +free_win (MetaCompWindow *cw, + gboolean destroy) +{ + MetaDisplay *display = cw->screen->display; + MetaCompScreen *info = cw->screen->compositor_data; + +#ifdef HAVE_NAME_WINDOW_PIXMAP + /* See comment in map_win */ + if (cw->back_pixmap && destroy) + { + XFreePixmap (display->xdisplay, cw->back_pixmap); + cw->back_pixmap = None; + } + + if (cw->shaded_back_pixmap && destroy) + { + XFreePixmap (display->xdisplay, cw->shaded_back_pixmap); + cw->shaded_back_pixmap = None; + } +#endif + + if (cw->picture) + { + XRenderFreePicture (display->xdisplay, cw->picture); + cw->picture = None; + } + + if (cw->shadow) + { + XRenderFreePicture (display->xdisplay, cw->shadow); + cw->shadow = None; + } + + if (cw->alpha_pict) + { + XRenderFreePicture (display->xdisplay, cw->alpha_pict); + cw->alpha_pict = None; + } + + if (cw->shadow_pict) + { + XRenderFreePicture (display->xdisplay, cw->shadow_pict); + cw->shadow_pict = None; + } + + if (cw->border_size) + { + XFixesDestroyRegion (display->xdisplay, cw->border_size); + cw->border_size = None; + } + + if (cw->border_clip) + { + XFixesDestroyRegion (display->xdisplay, cw->border_clip); + cw->border_clip = None; + } + + if (cw->extents) + { + XFixesDestroyRegion (display->xdisplay, cw->extents); + cw->extents = None; + } + + if (destroy) + { + if (cw->damage != None) { + meta_error_trap_push (display); + XDamageDestroy (display->xdisplay, cw->damage); + meta_error_trap_pop (display, FALSE); + + cw->damage = None; } - window = meta_comp_screen_lookup_window (screen, get_xid (effect->window)); + /* The window may not have been added to the list in this case, + but we can check anyway */ + if (cw->type == META_COMP_WINDOW_DOCK) + info->dock_windows = g_slist_remove (info->dock_windows, cw); + + g_free (cw); + } +} + +static void +map_win (MetaDisplay *display, + MetaScreen *screen, + Window id) +{ + MetaCompWindow *cw = find_window_for_screen (screen, id); + + if (cw == NULL) + return; + +#ifdef HAVE_NAME_WINDOW_PIXMAP + /* The reason we deallocate this here and not in unmap + is so that we will still have a valid pixmap for + whenever the window is unmapped */ + if (cw->back_pixmap) + { + XFreePixmap (display->xdisplay, cw->back_pixmap); + cw->back_pixmap = None; + } + + if (cw->shaded_back_pixmap) + { + XFreePixmap (display->xdisplay, cw->shaded_back_pixmap); + cw->shaded_back_pixmap = None; + } +#endif + + cw->attrs.map_state = IsViewable; + cw->damaged = TRUE; +} + +static void +unmap_win (MetaDisplay *display, + MetaScreen *screen, + Window id) +{ + MetaCompWindow *cw = find_window_for_screen (screen, id); + MetaCompScreen *info = screen->compositor_data; + + if (cw == NULL) + { + return; + } + + cw->attrs.map_state = IsUnmapped; + cw->damaged = FALSE; + + if (cw->extents != None) + { + dump_xserver_region ("unmap_win", display, cw->extents); + add_damage (screen, cw->extents); + cw->extents = None; + } + + free_win (cw, FALSE); + info->clip_changed = TRUE; +} + +static void +determine_mode (MetaDisplay *display, + MetaScreen *screen, + MetaCompWindow *cw) +{ + XRenderPictFormat *format; + + if (cw->alpha_pict) + { + XRenderFreePicture (display->xdisplay, cw->alpha_pict); + cw->alpha_pict = None; + } + + if (cw->shadow_pict) + { + XRenderFreePicture (display->xdisplay, cw->shadow_pict); + cw->shadow_pict = None; + } + + if (cw->attrs.class == InputOnly) + format = NULL; + else + format = XRenderFindVisualFormat (display->xdisplay, cw->attrs.visual); + + if ((format && format->type == PictTypeDirect && format->direct.alphaMask) + || cw->opacity != (guint) OPAQUE) + cw->mode = WINDOW_ARGB; + else + cw->mode = WINDOW_SOLID; + + if (cw->extents) + { + XserverRegion damage; + damage = XFixesCreateRegion (display->xdisplay, NULL, 0); + XFixesCopyRegion (display->xdisplay, damage, cw->extents); + + dump_xserver_region ("determine_mode", display, damage); + add_damage (screen, damage); + } +} + +static gboolean +is_shaped (MetaDisplay *display, + Window xwindow) +{ + int xws, yws, xbs, ybs; + unsigned wws, hws, wbs, hbs; + int bounding_shaped, clip_shaped; + + if (META_DISPLAY_HAS_SHAPE (display)) + { + XShapeQueryExtents (display->xdisplay, xwindow, &bounding_shaped, + &xws, &yws, &wws, &hws, &clip_shaped, + &xbs, &ybs, &wbs, &hbs); + return (bounding_shaped != 0); + } + + return FALSE; +} + +static void +get_window_type (MetaDisplay *display, + MetaCompWindow *cw) +{ + MetaCompositor *compositor = display->compositor; + int n_atoms; + Atom *atoms, type_atom; + int i; + + type_atom = None; + n_atoms = 0; + atoms = NULL; + + meta_prop_get_atom_list (display, cw->id, + display->atom_net_wm_window_type, + &atoms, &n_atoms); + + for (i = 0; i < n_atoms; i++) + { + if (atoms[i] == compositor->atom_net_wm_window_type_dnd || + atoms[i] == display->atom_net_wm_window_type_desktop || + atoms[i] == display->atom_net_wm_window_type_dock || + atoms[i] == display->atom_net_wm_window_type_toolbar || + atoms[i] == display->atom_net_wm_window_type_menu || + atoms[i] == display->atom_net_wm_window_type_dialog || + atoms[i] == display->atom_net_wm_window_type_normal || + atoms[i] == display->atom_net_wm_window_type_utility || + atoms[i] == display->atom_net_wm_window_type_splash) + { + type_atom = atoms[i]; + break; + } + } + + meta_XFree (atoms); + + if (type_atom == compositor->atom_net_wm_window_type_dnd) + cw->type = META_COMP_WINDOW_DND; + else if (type_atom == display->atom_net_wm_window_type_desktop) + cw->type = META_COMP_WINDOW_DESKTOP; + else if (type_atom == display->atom_net_wm_window_type_dock) + cw->type = META_COMP_WINDOW_DOCK; + else + cw->type = META_COMP_WINDOW_NORMAL; + +/* meta_verbose ("Window is %d\n", cw->type); */ +} + +/* Must be called with an error trap in place */ +static void +add_win (MetaScreen *screen, + MetaWindow *window, + Window xwindow) +{ + MetaDisplay *display = screen->display; + MetaCompScreen *info = screen->compositor_data; + MetaCompWindow *cw = g_new0 (MetaCompWindow, 1); + gulong event_mask; + + if (info == NULL) + { + g_warning ("Screen not managed"); + g_free (cw); + return; + } + + cw->screen = screen; + cw->window = window; + cw->id = xwindow; + + if (!XGetWindowAttributes (display->xdisplay, xwindow, &cw->attrs)) + { + g_warning ("Could not get attrs"); + g_free (cw); + return; + } + get_window_type (display, cw); + + /* If Metacity has decided not to manage this window then the input events + won't have been set on the window */ + event_mask = cw->attrs.your_event_mask | PropertyChangeMask; + + XSelectInput (display->xdisplay, xwindow, event_mask); + + +#ifdef HAVE_NAME_WINDOW_PIXMAP + cw->back_pixmap = None; + cw->shaded_back_pixmap = None; +#endif + + cw->damaged = FALSE; + cw->shaped = is_shaped (display, xwindow); + + if (cw->attrs.class == InputOnly) + cw->damage = None; + else + cw->damage = XDamageCreate (display->xdisplay, xwindow, + XDamageReportNonEmpty); + + cw->alpha_pict = None; + cw->shadow_pict = None; + cw->border_size = None; + cw->extents = None; + cw->shadow = None; + cw->shadow_dx = 0; + cw->shadow_dy = 0; + cw->shadow_width = 0; + cw->shadow_height = 0; + cw->opacity = OPAQUE; + + cw->border_clip = None; + + determine_mode (display, screen, cw); + cw->needs_shadow = window_has_shadow (cw); + + /* Only add the window to the list of docks if it needs a shadow */ + if (cw->type == META_COMP_WINDOW_DOCK && cw->needs_shadow) + { + meta_verbose ("Appending %p to dock windows\n", cw); + info->dock_windows = g_slist_append (info->dock_windows, cw); + } + + /* Add this to the list at the top of the stack + before it is mapped so that map_win can find it again */ + info->windows = g_list_prepend (info->windows, cw); + g_hash_table_insert (info->windows_by_xid, (gpointer) xwindow, cw); + + if (cw->attrs.map_state == IsViewable) + map_win (display, screen, xwindow); +} + +static void +destroy_win (MetaDisplay *display, + Window xwindow, + gboolean gone) +{ + MetaScreen *screen; + MetaCompScreen *info; + MetaCompWindow *cw; + + cw = find_window_in_display (display, xwindow); + + if (cw == NULL) + return; + + screen = cw->screen; + + if (cw->extents != None) + { + dump_xserver_region ("destroy_win", display, cw->extents); + add_damage (screen, cw->extents); + cw->extents = None; + } + + info = screen->compositor_data; + info->windows = g_list_remove (info->windows, (gconstpointer) cw); + g_hash_table_remove (info->windows_by_xid, (gpointer) xwindow); + + free_win (cw, TRUE); +} + +static void +restack_win (MetaCompWindow *cw, + Window above) +{ + MetaScreen *screen; + MetaCompScreen *info; + Window previous_above; + GList *sibling, *next; + + screen = cw->screen; + info = screen->compositor_data; + + sibling = g_list_find (info->windows, (gconstpointer) cw); + next = g_list_next (sibling); + previous_above = None; + + if (next) + { + MetaCompWindow *ncw = (MetaCompWindow *) next->data; + previous_above = ncw->id; + } + + /* If above is set to None, the window whose state was changed is on + * the bottom of the stack with respect to sibling. + */ + if (above == None) + { + /* Insert at bottom of window stack */ + info->windows = g_list_delete_link (info->windows, sibling); + info->windows = g_list_append (info->windows, cw); + } + else if (previous_above != above) + { + GList *index; + + for (index = info->windows; index; index = index->next) { + MetaCompWindow *cw2 = (MetaCompWindow *) index->data; + if (cw2->id == above) + break; + } + + if (index != NULL) + { + info->windows = g_list_delete_link (info->windows, sibling); + info->windows = g_list_insert_before (info->windows, index, cw); + } + } +} + +static void +resize_win (MetaCompWindow *cw, + int x, + int y, + int width, + int height, + int border_width, + gboolean override_redirect) +{ + MetaScreen *screen; + MetaDisplay *display; + MetaCompScreen *info; + Display *xdisplay; + XserverRegion damage; + gboolean debug; + + screen = cw->screen; + display = screen->display; + xdisplay = display->xdisplay; + info = screen->compositor_data; + + debug = ((MetaCompositor *) display->compositor)->debug; + + if (cw->extents) + { + damage = XFixesCreateRegion (xdisplay, NULL, 0); + XFixesCopyRegion (xdisplay, damage, cw->extents); + } + else + { + damage = None; + if (debug) + fprintf (stderr, "no extents to damage !\n"); + } + + /* { // Damage whole screen each time ! ;-) + XRectangle r; + + r.x = 0; + r.y = 0; + r.width = screen->rect.width; + r.height = screen->rect.height; + fprintf (stderr, "Damage whole screen %d,%d (%d %d)\n", + r.x, r.y, r.width, r.height); - switch (effect->type) + damage = XFixesCreateRegion (display->xdisplay, &r, 1); + } */ + + cw->attrs.x = x; + cw->attrs.y = y; + + if (cw->attrs.width != width || cw->attrs.height != height) { - case META_EFFECT_MINIMIZE: - if (!effect->window->frame) - { - meta_effect_end (effect); - return; - } - - meta_comp_screen_raise_window (screen, effect->window->frame->xwindow); - - meta_comp_window_run_minimize (window, effect); - break; - - case META_EFFECT_UNMINIMIZE: - meta_comp_window_run_unminimize (window, effect); - break; +#ifdef HAVE_NAME_WINDOW_PIXMAP + if (cw->shaded_back_pixmap) + { + XFreePixmap (xdisplay, cw->shaded_back_pixmap); + cw->shaded_back_pixmap = None; + } - case META_EFFECT_FOCUS: - meta_comp_window_run_focus (window, effect); - break; - - case META_EFFECT_CLOSE: - meta_comp_window_freeze_stack (window); - meta_comp_window_set_updates (window, FALSE); - meta_comp_window_explode (window, effect); - break; - default: - g_assert_not_reached(); - break; + if (cw->back_pixmap) + { + /* If the window is shaded, we store the old backing pixmap + so we can return a proper image of the window */ + if (cw->window && cw->window->shaded) + { + cw->shaded_back_pixmap = cw->back_pixmap; + cw->back_pixmap = None; + } + else + { + XFreePixmap (xdisplay, cw->back_pixmap); + cw->back_pixmap = None; + } + } +#endif + if (cw->picture) + { + XRenderFreePicture (xdisplay, cw->picture); + cw->picture = None; + } + + if (cw->shadow) + { + XRenderFreePicture (xdisplay, cw->shadow); + cw->shadow = None; + } } -} -#endif /* HAVE_COMPOSITE_EXTENSIONS */ + cw->attrs.width = width; + cw->attrs.height = height; + cw->attrs.border_width = border_width; + cw->attrs.override_redirect = override_redirect; -/* Constructs a new compositor. The rest of Metacity knows whether the - * compositor is turned on by whether this function returns NULL or not. - */ -MetaCompositor * -meta_compositor_new (MetaDisplay *display) -{ -#ifdef HAVE_COMPOSITE_EXTENSIONS - MetaCompositor *compositor; - - compositor = g_new0 (MetaCompositor, 1); - - if (!compositor_display) + if (cw->extents) + XFixesDestroyRegion (xdisplay, cw->extents); + + cw->extents = win_extents (cw); + + if (damage) { - gboolean has_extensions; - - compositor_display = ws_display_new (NULL); + if (debug) + fprintf (stderr, "Inexplicable intersection with new extents!\n"); - meta_errors_register_foreign_display ( - compositor_display->xdisplay, handle_error, compositor_display); - - has_extensions = - ws_display_init_composite (compositor_display) && - ws_display_init_damage (compositor_display) && - ws_display_init_fixes (compositor_display) && - ws_display_init_test (compositor_display); - - if (!has_extensions) - { - g_warning ("Disabling compositor since the server is missing at " - "least one of the COMPOSITE, DAMAGE, FIXES or TEST " - "extensions"); - - return NULL; - } - - ws_display_set_ignore_grabs (compositor_display, TRUE); + XFixesUnionRegion (xdisplay, damage, damage, cw->extents); } - - compositor->display = compositor_display; - - ws_display_set_synchronize (compositor_display, - getenv ("METACITY_SYNC") != NULL); - - compositor->meta_display = display; - - compositor->enabled = TRUE; - - /* Compositor without bling is the default, but leave the bling - * accessible for now. - */ - if (getenv("METACITY_BLING")!=NULL) - meta_push_effect_handler (do_effect, compositor); - - return compositor; -#else /* HAVE_COMPOSITE_EXTENSIONS */ - return NULL; -#endif /* HAVE_COMPOSITE_EXTENSIONS */ + else + { + damage = XFixesCreateRegion (xdisplay, NULL, 0); + XFixesCopyRegion (xdisplay, damage, cw->extents); + } + + dump_xserver_region ("resize_win", display, damage); + add_damage (screen, damage); + + info->clip_changed = TRUE; } -#if 0 -void -meta_compositor_set_debug_updates (MetaCompositor *compositor, - gboolean debug_updates) -{ -#ifdef HAVE_COMPOSITE_EXTENSIONS - compositor->debug_updates = !!debug_updates; -#endif /* HAVE_COMPOSITE_EXTENSIONS */ -} -#endif /* 0 */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS +/* event processors must all be called with an error trap in place */ static void -remove_repair_idle (MetaCompositor *compositor) +process_circulate_notify (MetaCompositor *compositor, + XCirculateEvent *event) { - if (compositor->repair_idle) - { - meta_topic (META_DEBUG_COMPOSITOR, "Damage idle removed\n"); - - g_source_remove (compositor->repair_idle); - compositor->repair_idle = 0; - } -} -#endif /* HAVE_COMPOSITE_EXTENSIONS */ + MetaCompWindow *cw = find_window_in_display (compositor->display, + event->window); + MetaCompWindow *top; + MetaCompScreen *info; + MetaScreen *screen; + GList *first; + Window above; -void -meta_compositor_unref (MetaCompositor *compositor) -{ -#ifdef HAVE_COMPOSITE_EXTENSIONS - /* There isn't really a refcount at the moment since - * there's no ref() - */ - remove_repair_idle (compositor); - - g_free (compositor); -#endif /* HAVE_COMPOSITE_EXTENSIONS */ + if (!cw) + return; + + screen = cw->screen; + info = screen->compositor_data; + first = info->windows; + top = (MetaCompWindow *) first->data; + + if ((event->place == PlaceOnTop) && top) + above = top->id; + else + above = None; + restack_win (cw, above); + + info->clip_changed = TRUE; + +#ifdef USE_IDLE_REPAINT + add_repair (compositor->display); +#endif } -/**************************************************************************** - * - * HANDLING X EVENTS - * - * Here are several process_* functions, which are all called by - * meta_compositor_process_event at the bottom. - * - ****************************************************************************/ - -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the CirculateNotify XEvent. - */ -static void -process_circulate_notify (MetaCompositor *compositor, - XCirculateEvent* event) -{ - /* FIXME: Do something here. */ -} -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the ConfigureNotify XEvent. - */ static void process_configure_notify (MetaCompositor *compositor, XConfigureEvent *event) { - MetaCompScreen *minfo = meta_comp_screen_get_by_xwindow (event->window); + MetaDisplay *display = compositor->display; + MetaCompWindow *cw = find_window_in_display (display, event->window); + if (cw) + { #if 0 - g_print ("minfo: %lx => %p\n", event->window, minfo); + int x = -1, y = -1, width = -1, height = -1; + int ex = -1, ey = -1, ewidth = -1, eheight = -1; + if (cw->window) { + x = cw->window->rect.x; + y = cw->window->rect.y; + width = cw->window->rect.width; + height = cw->window->rect.height; + } + fprintf (stderr, "configure notify xy (%d %d) -> (%d %d), wh (%d %d) -> (%d %d)\n", + x, y, event->x, event->y, + width, height, event->width, event->height); #endif -#if 0 - g_print ("configure on %lx (above: %lx) %d %d %d %d\n", event->window, event->above, - event->x, event->y, event->width, event->height); + if (compositor->debug) + { + fprintf (stderr, "configure notify %d %d %d\n", cw->damaged, + cw->shaped, cw->needs_shadow); + dump_xserver_region ("\textents", display, cw->extents); + fprintf (stderr, "\txy (%d %d), wh (%d %d)\n", + event->x, event->y, event->width, event->height); + } + + restack_win (cw, event->above); + resize_win (cw, event->x, event->y, event->width, event->height, + event->border_width, event->override_redirect); + } + else + { + MetaScreen *screen; + MetaCompScreen *info; + + /* Might be the root window? */ + screen = meta_display_screen_for_root (display, event->window); + if (screen == NULL) + return; + + info = screen->compositor_data; + if (info->root_buffer) + { + XRenderFreePicture (display->xdisplay, info->root_buffer); + info->root_buffer = None; + } + + damage_screen (screen); + } +} + +static void +process_property_notify (MetaCompositor *compositor, + XPropertyEvent *event) +{ + MetaDisplay *display = compositor->display; + MetaScreen *screen; + int p; + Atom background_atoms[2]; + + /* Check for the background property changing */ + background_atoms[0] = compositor->atom_x_root_pixmap; + background_atoms[1] = compositor->atom_x_set_root; + + for (p = 0; p < 2; p++) + { + if (event->atom == background_atoms[p]) + { + screen = meta_display_screen_for_root (display, event->window); + if (screen) + { + MetaCompScreen *info = screen->compositor_data; + if (info->root_tile) + { + XClearArea (display->xdisplay, screen->xroot, + 0, 0, 0, 0, TRUE); + XRenderFreePicture (display->xdisplay, info->root_tile); + info->root_tile = None; +#ifdef USE_IDLE_REPAINT + add_repair (display); #endif - - if (!minfo) - { -#if 0 - g_print (" --- ignoring configure (no screen info)\n"); + + return; + } + } + } + } + + /* Check for the opacity changing */ + if (event->atom == compositor->atom_net_wm_window_opacity) + { + MetaCompWindow *cw = find_window_in_display (display, event->window); + gulong value; + + if (!cw) + return; + + if (meta_prop_get_cardinal (display, event->window, + compositor->atom_net_wm_window_opacity, + &value) == FALSE) + value = OPAQUE; + + cw->opacity = (guint)value; + determine_mode (display, cw->screen, cw); + cw->needs_shadow = window_has_shadow (cw); + + if (cw->shadow) + { + XRenderFreePicture (display->xdisplay, cw->shadow); + cw->shadow = None; + } + + if (cw->extents) + XFixesDestroyRegion (display->xdisplay, cw->extents); + cw->extents = win_extents (cw); + + cw->damaged = TRUE; +#ifdef USE_IDLE_REPAINT + add_repair (display); #endif + return; + } + + if (event->atom == display->atom_net_wm_window_type) { + MetaCompWindow *cw = find_window_in_display (display, event->window); + + if (!cw) + return; + + get_window_type (display, cw); + cw->needs_shadow = window_has_shadow (cw); + return; } - - meta_comp_screen_restack (minfo, event->window, event->above); - meta_comp_screen_set_size (minfo, - event->window, - event->x, event->y, - event->width, event->height); } -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the Expose XEvent. - * XXX FIXME: This looks like it quite urgently needs looking into. --tthurman - */ static void -process_expose (MetaCompositor *compositor, - XExposeEvent *event) +expose_area (MetaScreen *screen, + XRectangle *rects, + int nrects) { - /* FIXME: queue repaint */ + MetaDisplay *display; + XserverRegion region; + + display = screen->display; + region = XFixesCreateRegion (display->xdisplay, rects, nrects); + + dump_xserver_region ("expose_area", display, region); + add_damage (screen, region); } -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS - -#if 0 - -/* Apparently never used. */ - -typedef struct +static void +process_expose (MetaCompositor *compositor, + XExposeEvent *event) { - CmDrawableNode *node; - GTimer *timer; -} FadeInfo; + MetaCompWindow *cw = find_window_in_display (compositor->display, + event->window); + MetaScreen *screen = NULL; + XRectangle rect[1]; + int origin_x = 0, origin_y = 0; -#define FADE_TIME 0.3 - -static gboolean -fade_out (gpointer data) -{ - FadeInfo *info = data; - gdouble elapsed = g_timer_elapsed (info->timer, NULL); - gdouble alpha; - - if (elapsed > FADE_TIME) - alpha = 0.0; - else - alpha = 1 - (elapsed / FADE_TIME); - - cm_drawable_node_set_alpha (info->node, alpha); - -#if 0 - g_print ("fade out: %f\n", alpha); -#endif - - if (elapsed >= FADE_TIME) + if (cw != NULL) { - g_object_unref (info->node); - - cm_drawable_node_set_viewable (info->node, FALSE); - - return FALSE; + screen = cw->screen; + origin_x = cw->attrs.x; /* + cw->attrs.border_width; ? */ + origin_y = cw->attrs.y; /* + cw->attrs.border_width; ? */ } else { - return TRUE; + screen = meta_display_screen_for_root (compositor->display, + event->window); + if (screen == NULL) + return; } -} -#endif /* 0 */ -#endif -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the MapNotify XEvent. - */ -static void -process_map (MetaCompositor *compositor, - XMapEvent *event) -{ - MetaScreen *screen; + rect[0].x = event->x + origin_x; + rect[0].y = event->y + origin_y; + rect[0].width = event->width; + rect[0].height = event->height; - /* FIXME: do we sometimes get mapnotifies for windows that are - * not (direct) children of the root? - */ - - /* See if window was mapped as child of root */ - screen = meta_display_screen_for_root (compositor->meta_display, - event->event); - - if (screen == NULL) - { - meta_topic (META_DEBUG_COMPOSITOR, - "MapNotify received on non-root 0x%lx for 0x%lx\n", - event->event, event->window); - - /* MapNotify wasn't for a child of the root */ - return; - } - - meta_comp_screen_add_window (screen->compositor_data, - event->window); + expose_area (screen, rect, 1); } -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the UnmapNotify XEvent. - */ static void -process_unmap (MetaCompositor *compositor, - XUnmapEvent *event) +process_unmap (MetaCompositor *compositor, + XUnmapEvent *event) { - MetaScreen *screen; - - /* See if window was unmapped as child of root */ - screen = meta_display_screen_for_root (compositor->meta_display, - event->event); - - if (screen == NULL) + MetaCompWindow *cw; + + if (event->from_configure) { - meta_topic (META_DEBUG_COMPOSITOR, - "UnmapNotify received on non-root 0x%lx for 0x%lx\n", - event->event, event->window); - - /* UnmapNotify wasn't for a child of the root */ + /* Ignore unmap caused by parent's resize */ return; } - - meta_comp_screen_unmap (screen->compositor_data, event->window); + + cw = find_window_in_display (compositor->display, event->window); + if (cw) + unmap_win (compositor->display, cw->screen, event->window); } -#endif /* HAVE_COMPOSITE_EXTENSIONS */ +static void +process_map (MetaCompositor *compositor, + XMapEvent *event) +{ + MetaCompWindow *cw = find_window_in_display (compositor->display, + event->window); + + if (cw) + map_win (compositor->display, cw->screen, event->window); +} + +static void +process_reparent (MetaCompositor *compositor, + XReparentEvent *event, + MetaWindow *window) +{ + MetaScreen *screen; + + screen = meta_display_screen_for_root (compositor->display, event->parent); + if (screen != NULL) + add_win (screen, window, event->window); + else + destroy_win (compositor->display, event->window, FALSE); +} -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the CreateNotify XEvent. - */ static void process_create (MetaCompositor *compositor, - XCreateWindowEvent *event) + XCreateWindowEvent *event, + MetaWindow *window) { MetaScreen *screen; - XWindowAttributes attrs; - - screen = meta_display_screen_for_root (compositor->meta_display, - event->parent); - - if (screen == NULL) - { - meta_topic (META_DEBUG_COMPOSITOR, - "CreateNotify received on non-root 0x%lx for 0x%lx\n", - event->parent, event->window); - return; - } - - meta_error_trap_push_with_return (compositor->meta_display); - - XGetWindowAttributes (compositor->meta_display->xdisplay, - event->window, &attrs); - - if (meta_error_trap_pop_with_return (compositor->meta_display, TRUE) != Success) - { - meta_topic (META_DEBUG_COMPOSITOR, "Failed to get attributes for window 0x%lx\n", - event->window); - } - else - { -#if 0 - g_print (//META_DEBUG_COMPOSITOR, - "Create window 0x%lx, adding\n", event->window); -#endif - meta_compositor_add_window (compositor, - event->window, &attrs); - } -} -#endif /* HAVE_COMPOSITE_EXTENSIONS */ + /* We are only interested in top level windows, others will + be caught by normal metacity functions */ + + screen = meta_display_screen_for_root (compositor->display, event->parent); + if (screen == NULL) + return; + + if (!find_window_in_display (compositor->display, event->window)) + add_win (screen, window, event->window); +} -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the DestroyNotify XEvent. - */ static void process_destroy (MetaCompositor *compositor, XDestroyWindowEvent *event) { - MetaScreen *screen; - - screen = meta_display_screen_for_root (compositor->meta_display, - event->event); - - -#if 0 - g_print ("destroywindow\n"); -#endif - - if (screen == NULL) - { -#if 0 - g_print ("ignoring\n"); -#endif - meta_topic (META_DEBUG_COMPOSITOR, - "DestroyNotify received on non-root 0x%lx for 0x%lx\n", - event->event, event->window); - return; - } - - meta_topic (META_DEBUG_COMPOSITOR, - "Destroy window 0x%lx\n", event->window); - meta_compositor_remove_window (compositor, event->window); + destroy_win (compositor->display, event->window, FALSE); } -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS -/* Handles the ReparentNotify XEvent. - */ static void -process_reparent (MetaCompositor *compositor, - XReparentEvent *event) +process_damage (MetaCompositor *compositor, + XDamageNotifyEvent *event) { - /* Reparent from one screen to another doesn't happen now, but - * it's been suggested as a future extension - */ - MetaScreen *event_screen; - MetaScreen *parent_screen; - - event_screen = meta_display_screen_for_root (compositor->meta_display, - event->event); - - if (event_screen == NULL) - { - meta_topic (META_DEBUG_COMPOSITOR, - "ReparentNotify received on non-root 0x%lx for 0x%lx\n", - event->event, event->window); - return; - } + MetaCompWindow *cw = find_window_in_display (compositor->display, + event->drawable); + if (cw == NULL) + return; - parent_screen = meta_display_screen_for_root (compositor->meta_display, - event->parent); - - if (parent_screen == NULL) - { - meta_topic (META_DEBUG_COMPOSITOR, - "ReparentNotify 0x%lx to a non-screen or unmanaged screen 0x%lx\n", - event->window, event->parent); - - meta_compositor_remove_window (compositor, event->window); - return; - } - else - { - meta_comp_screen_raise_window (parent_screen->compositor_data, - event->window); - } + repair_win (cw); + +#ifdef USE_IDLE_REPAINT + if (event->more == FALSE) + add_repair (compositor->display); +#endif } - -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -/* If the compositor is enabled, this function gets called with any XEvent - * in case we want to deal with it specially. - */ -void -meta_compositor_process_event (MetaCompositor *compositor, - XEvent *event, - MetaWindow *window) -{ -#ifdef HAVE_COMPOSITE_EXTENSIONS - if (!compositor->enabled) - return; /* no extension */ - if (event->type == CirculateNotify) - { - process_circulate_notify (compositor, - (XCirculateEvent*) event); - } - else if (event->type == ConfigureNotify) - { - process_configure_notify (compositor, - (XConfigureEvent*) event); - } - else if (event->type == Expose) - { - process_expose (compositor, - (XExposeEvent*) event); - } - else if (event->type == UnmapNotify) - { - process_unmap (compositor, - (XUnmapEvent*) event); - } - else if (event->type == MapNotify) - { - process_map (compositor, - (XMapEvent*) event); - } - else if (event->type == ReparentNotify) - { - process_reparent (compositor, - (XReparentEvent*) event); - } - else if (event->type == CreateNotify) - { - process_create (compositor, - (XCreateWindowEvent*) event); - } - else if (event->type == DestroyNotify) - { - process_destroy (compositor, - (XDestroyWindowEvent*) event); - } - -#endif /* HAVE_COMPOSITE_EXTENSIONS */ -} - -#ifdef HAVE_COMPOSITE_EXTENSIONS -#if 0 -static GTimer *timer; -#endif /* 0 */ -#endif /* HAVE_COMPOSITE_EXTENSIONS */ - -#ifdef HAVE_COMPOSITE_EXTENSIONS -#if 0 static void -dump_stacking_order (GList *nodes) +process_shape (MetaCompositor *compositor, + XShapeEvent *event) { - GList *list; - - for (list = nodes; list != NULL; list = list->next) + MetaCompWindow *cw = find_window_in_display (compositor->display, + event->window); + + if (cw == NULL) + return; + + if (event->kind == ShapeBounding) { - CmDrawableNode *node = list->data; + if (!event->shaped && cw->shaped) + cw->shaped = FALSE; - g_print ("%lx, ", WS_RESOURCE_XID (node->drawable)); + resize_win (cw, cw->attrs.x, cw->attrs.y, + event->width + event->x, event->height + event->y, + cw->attrs.border_width, cw->attrs.override_redirect); + + if (event->shaped && !cw->shaped) + cw->shaped = TRUE; } - g_print ("\n"); } -#endif /* 0 */ + +static int timeout_debug (MetaCompositor *compositor) +{ + compositor->show_redraw = (g_getenv ("METACITY_DEBUG_REDRAWS") != NULL); + compositor->debug = (g_getenv ("METACITY_DEBUG_COMPOSITOR") != NULL); + + return FALSE; +} + +MetaCompositor * +meta_compositor_new (MetaDisplay *display) +{ +#ifdef HAVE_COMPOSITE_EXTENSIONS + char *atom_names[] = { + "_XROOTPMAP_ID", + "_XSETROOT_ID", + "_NET_WM_WINDOW_OPACITY", + "_NET_WM_WINDOW_TYPE_DND", + }; + Atom atoms[G_N_ELEMENTS(atom_names)]; + MetaCompositor *compositor; + + compositor = g_new (MetaCompositor, 1); + compositor->display = display; + + meta_verbose ("Creating %d atoms\n", G_N_ELEMENTS (atom_names)); + XInternAtoms (display->xdisplay, atom_names, G_N_ELEMENTS (atom_names), + False, atoms); + compositor->atom_x_root_pixmap = atoms[0]; + compositor->atom_x_set_root = atoms[1]; + compositor->atom_net_wm_window_opacity = atoms[2]; + compositor->atom_net_wm_window_type_dnd = atoms[3]; + +#ifdef USE_IDLE_REPAINT + meta_verbose ("Using idle repaint\n"); + compositor->repaint_id = 0; #endif -/* This is called when metacity does its XQueryTree() on startup - * and when a new window is mapped. - */ + compositor->enabled = TRUE; + g_timeout_add (2000, (GSourceFunc) timeout_debug, compositor); + + return compositor; +#else + return NULL; +#endif +} + void meta_compositor_add_window (MetaCompositor *compositor, + MetaWindow *window, Window xwindow, XWindowAttributes *attrs) { #ifdef HAVE_COMPOSITE_EXTENSIONS MetaScreen *screen = meta_screen_for_x_screen (attrs->screen); - MetaCompScreen *minfo = screen->compositor_data; - - meta_comp_screen_add_window (minfo, xwindow); + + meta_error_trap_push (compositor->display); + add_win (screen, window, xwindow); + meta_error_trap_pop (compositor->display, FALSE); #endif } void -meta_compositor_remove_window (MetaCompositor *compositor, - Window xwindow) +meta_compositor_remove_window (MetaCompositor *compositor, + Window xwindow) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MetaCompScreen *minfo; - - minfo = meta_comp_screen_get_by_xwindow (xwindow); - - if (minfo) - meta_comp_screen_remove_window (minfo, xwindow); -#endif /* HAVE_COMPOSITE_EXTENSIONS */ +#endif } void @@ -682,16 +2266,72 @@ meta_compositor_manage_screen (MetaCompositor *compositor, MetaScreen *screen) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MetaCompScreen *info; + MetaCompScreen *info; + MetaDisplay *display = screen->display; + XRenderPictureAttributes pa; + XRenderPictFormat *visual_format; - if (screen->compositor_data) - return; - - info = meta_comp_screen_new (compositor->display, screen); + /* Check if the screen is already managed */ + if (screen->compositor_data) + return; - screen->compositor_data = info; - - meta_comp_screen_redirect (info); + gdk_error_trap_push (); + /* FIXME: Use correct composite mode */ + XCompositeRedirectSubwindows (display->xdisplay, screen->xroot, + CompositeRedirectManual); + XSync (display->xdisplay, FALSE); + + if (gdk_error_trap_pop ()) + { + g_warning ("Another compositing manager is running on screen %i", + screen->number); + return; + } + + info = g_new0 (MetaCompScreen, 1); + info->screen = screen; + + visual_format = XRenderFindVisualFormat (display->xdisplay, + DefaultVisual (display->xdisplay, + screen->number)); + if (!visual_format) + { + g_warning ("Cannot find visual format on screen %i", screen->number); + return; + } + + pa.subwindow_mode = IncludeInferiors; + info->root_picture = XRenderCreatePicture (display->xdisplay, screen->xroot, + visual_format, + CPSubwindowMode, &pa); + if (info->root_picture == None) + { + g_warning ("Cannot create root picture on screen %i", screen->number); + return; + } + + info->root_buffer = None; + info->black_picture = solid_picture (display, screen, TRUE, 1, 0, 0, 0); + + info->root_tile = None; + info->all_damage = None; + + info->windows = NULL; + info->windows_by_xid = g_hash_table_new (g_direct_hash, g_direct_equal); + + info->compositor_active = TRUE; + info->overlays = 0; + info->clip_changed = TRUE; + + info->have_shadows = (g_getenv("META_DEBUG_NO_SHADOW") == NULL); + info->gaussian_map = make_gaussian_map (SHADOW_RADIUS); + presum_gaussian (info); + + XClearArea (display->xdisplay, screen->xroot, 0, 0, 0, 0, TRUE); + + meta_screen_set_cm_selection (screen); + + screen->compositor_data = info; #endif } @@ -700,325 +2340,194 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor, MetaScreen *screen) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MetaCompScreen *info = screen->compositor_data; - - meta_comp_screen_unredirect (info); + MetaDisplay *display = screen->display; + MetaCompScreen *info; + GList *index; + + /* This screen isn't managed */ + if (screen->compositor_data == NULL) + return; + + info = screen->compositor_data; + + /* Destroy the windows */ + for (index = info->windows; index; index = index->next) + { + MetaCompWindow *cw = (MetaCompWindow *) index->data; + free_win (cw, TRUE); + } + g_list_free (info->windows); + g_hash_table_destroy (info->windows_by_xid); + + if (info->root_picture) + XRenderFreePicture (display->xdisplay, info->root_picture); + + if (info->black_picture) + XRenderFreePicture (display->xdisplay, info->black_picture); + + g_free (info->gaussian_map); + + XCompositeUnredirectSubwindows (display->xdisplay, screen->xroot, + CompositeRedirectManual); + meta_screen_unset_cm_selection (screen); + + g_free (info); screen->compositor_data = NULL; #endif } -#ifdef HAVE_COMPOSITE_EXTENSIONS -#endif - -typedef struct -{ - double x; - double y; - double width; - double height; -} DoubleRect; - -#if 0 -static gdouble -interpolate (gdouble t, gdouble begin, gdouble end, double power) -{ - return (begin + (end - begin) * pow (t, power)); -} -#endif - -#if 0 -static gboolean -stop_minimize (gpointer data) -{ - MiniInfo *info = data; - - g_source_remove (info->repaint_id); - - cm_drawable_node_set_deformation_func (info->node, NULL, NULL); - - if (info->finished_func) - info->finished_func (info->finished_data); - - g_free (info); - - return FALSE; -} -#endif - -#if 0 -static void -minimize_deformation (gdouble time, - double in_x, - double in_y, - double *out_x, - double *out_y, - gpointer data) -{ -#define MINIMIZE_TIME 0.5 - MiniInfo *info = data; - gdouble elapsed; - gdouble pos; - - if (info->start_time == -1) - info->start_time = time; - - elapsed = time - info->start_time; - pos = elapsed / MINIMIZE_TIME; - - *out_x = interpolate (pos, in_x, info->target.x + info->target.width * ((in_x - info->start.x) / info->start.width), 10 * in_y); - *out_y = interpolate (pos, in_y, info->target.y + info->target.height * ((in_y - info->start.y) / info->start.height), 1.0); - - if (elapsed > MINIMIZE_TIME) - { - g_assert (info->node); - if (!info->idle_id) - info->idle_id = g_idle_add (stop_minimize, info); - } -} -#endif - void meta_compositor_set_updates (MetaCompositor *compositor, - MetaWindow *window, - gboolean updates) + MetaWindow *window, + gboolean updates) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MetaCompScreen *info = window->screen->compositor_data; - meta_comp_screen_set_updates (info, get_xid (window), updates); #endif } -#ifdef HAVE_COMPOSITE_EXTENSIONS - -#define BALLOON_TIME 2 - -typedef struct -{ - CmDrawableNode *node; - MetaAnimationFinishedFunc finished; - gpointer finished_data; - GTimer *timer; -} BalloonInfo; - -#endif - void meta_compositor_destroy (MetaCompositor *compositor) { -#ifdef HAVE_COMPOSITE_EXTENSIONS +#ifdef HAVE_COMPOSITE_EXTENSIONS g_free (compositor); #endif } -#ifdef HAVE_COMPOSITE_EXTENSIONS - -struct MoveInfo -{ - GTimer *timer; - gboolean finished; - Model *model; - MetaScreen *screen; - MetaWindow *window; - gdouble last_time; - gboolean window_destroyed; - MetaCompositor *compositor; -}; - -#endif - -#ifdef HAVE_COMPOSITE_EXTENSIONS - -void -get_patch_points (Model *model, - CmPoint points[4][4]) -{ - int i, j; - - for (i = 0; i < 4; i++) - { - for (j = 0; j < 4; j++) - { - double obj_x, obj_y; - - model_get_position (model, i, j, &obj_x, &obj_y); - - points[j][i].x = obj_x; - points[j][i].y = obj_y; - } - } -} - -static GList *move_infos; - -static gboolean -wobble (gpointer data) -{ - MoveInfo *info = data; - MetaCompScreen *minfo = info->screen->compositor_data; - double t = g_timer_elapsed (info->timer, NULL); - -#if 0 - g_print ("info->window_destroyed: %d\n", - info->window_destroyed); -#endif - if ((info->finished && model_is_calm (info->model)) || - info->window_destroyed) - { - if (!info->window_destroyed) - meta_comp_screen_unset_patch (minfo, get_xid (info->window)); - - move_infos = g_list_remove (move_infos, info); - g_free (info); -#if 0 - g_print ("stop wobb\n"); -#endif - return FALSE; - } - else - { - int i; - int n_steps; - CmPoint points[4][4]; - n_steps = floor ((t - info->last_time) * 75); - - for (i = 0; i < n_steps; ++i) - model_step (info->model); - - if (i > 0) - info->last_time = t; - - get_patch_points (info->model, points); - meta_comp_screen_set_patch (minfo, - get_xid (info->window), - points); - - return TRUE; - } -} - -#endif - -void -compute_window_rect (MetaWindow *window, - MetaRectangle *rect) -{ - /* FIXME: does metacity include this function somewhere? */ - - if (window->frame) - { - *rect = window->frame->rect; - } - else - { - *rect = window->user_rect; - } -} - void meta_compositor_begin_move (MetaCompositor *compositor, - MetaWindow *window, - MetaRectangle *initial, - int grab_x, int grab_y) + MetaWindow *window, + MetaRectangle *initial, + int grab_x, + int grab_y) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MetaRectangle rect; - MoveInfo *move_info; - -#if 0 - g_print ("begin move\n"); -#endif - - if (!g_getenv ("USE_WOBBLY")) - return; - - move_info = g_new0 (MoveInfo, 1); - - move_infos = g_list_prepend (move_infos, move_info); - - move_info->compositor = compositor; - move_info->last_time = 0.0; - move_info->timer = g_timer_new (); - move_info->window_destroyed = FALSE; - - compute_window_rect (window, &rect); - -#if 0 - g_print ("init: %d %d\n", initial->x, initial->y); - g_print ("window: %d %d\n", window->rect.x, window->rect.y); - g_print ("frame: %d %d\n", rect.x, rect.y); - g_print ("grab: %d %d\n", grab_x, grab_y); -#endif - - move_info->model = model_new (&rect, TRUE); - move_info->window = window; - move_info->screen = window->screen; - - model_begin_move (move_info->model, grab_x, grab_y); - - g_idle_add (wobble, move_info); #endif } -#ifdef HAVE_COMPOSITE_EXTENSIONS -static MoveInfo * -find_info (MetaWindow *window) -{ - GList *list; - - for (list = move_infos; list != NULL; list = list->next) - { - MoveInfo *info = list->data; - - if (info->window == window) - return info; - } - - return NULL; -} -#endif - void meta_compositor_update_move (MetaCompositor *compositor, - MetaWindow *window, - int x, int y) + MetaWindow *window, + int x, + int y) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MoveInfo *move_info = find_info (window); - - if (!g_getenv ("USE_WOBBLY")) - return; - - model_update_move (move_info->model, x, y); #endif } void meta_compositor_end_move (MetaCompositor *compositor, - MetaWindow *window) + MetaWindow *window) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MoveInfo *info = find_info (window); - - if (!g_getenv ("USE_WOBBLY")) - return; - - info->finished = TRUE; #endif } - void meta_compositor_free_window (MetaCompositor *compositor, - MetaWindow *window) + MetaWindow *window) { #ifdef HAVE_COMPOSITE_EXTENSIONS - MoveInfo *info = find_info (window); - - if (!g_getenv ("USE_WOBBLY")) - return; - - if (info) - info->window_destroyed = TRUE; + destroy_win (compositor->display, window->xwindow, FALSE); +#endif +} + +void +meta_compositor_process_event (MetaCompositor *compositor, + XEvent *event, + MetaWindow *window) +{ +#ifdef HAVE_COMPOSITE_EXTENSIONS + /* + * This trap is so that none of the compositor functions cause + * X errors. This is really a hack, but I'm afraid I don't understand + * enough about Metacity/X to know how else you are supposed to do it + */ + meta_error_trap_push (compositor->display); + switch (event->type) + { + case CirculateNotify: + process_circulate_notify (compositor, (XCirculateEvent *) event); + break; + + case ConfigureNotify: + process_configure_notify (compositor, (XConfigureEvent *) event); + break; + + case PropertyNotify: + process_property_notify (compositor, (XPropertyEvent *) event); + break; + + case Expose: + process_expose (compositor, (XExposeEvent *) event); + break; + + case UnmapNotify: + process_unmap (compositor, (XUnmapEvent *) event); + break; + + case MapNotify: + process_map (compositor, (XMapEvent *) event); + break; + + case ReparentNotify: + process_reparent (compositor, (XReparentEvent *) event, window); + break; + + case CreateNotify: + process_create (compositor, (XCreateWindowEvent *) event, window); + break; + + case DestroyNotify: + process_destroy (compositor, (XDestroyWindowEvent *) event); + break; + + default: + if (event->type == compositor->display->damage_event_base + XDamageNotify) + process_damage (compositor, (XDamageNotifyEvent *) event); + else if (event->type == compositor->display->shape_event_base + ShapeNotify) + process_shape (compositor, (XShapeEvent *) event); + else + { + meta_error_trap_pop (compositor->display, FALSE); + return; + } + break; + } + + meta_error_trap_pop (compositor->display, FALSE); +#ifndef USE_IDLE_REPAINT + repair_display (compositor->display); +#endif + + return; +#endif +} + +Pixmap +meta_compositor_get_window_pixmap (MetaCompositor *compositor, + MetaWindow *window) +{ +#ifdef HAVE_COMPOSITE_EXTENSIONS + MetaCompWindow *cw = NULL; + + if (window->frame) + { + cw = find_window_for_screen (window->screen, window->frame->xwindow); + if (cw == NULL) + cw = find_window_for_screen (window->screen, window->xwindow); + } + + if (cw == NULL) + return None; + +#ifdef HAVE_NAME_WINDOW_PIXMAP + if (window->shaded) + return cw->shaded_back_pixmap; + else + return cw->back_pixmap; +#else + return None; +#endif #endif } diff --git a/src/compositor.h b/src/compositor.h index 6b920e99d..0f65dc47e 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -28,23 +28,12 @@ #include "display.h" #include "spring-model.h" -#ifdef HAVE_COMPOSITE_EXTENSIONS -#include "cm/deform.h" -/* FIXME: Needs namespacing. */ -void get_patch_points (Model *model, CmPoint points[4][4]); -#endif - -typedef void (* MetaAnimationFinishedFunc) (gpointer data); - -/* XXX namespace me */ -void compute_window_rect (MetaWindow *window, MetaRectangle *rect); - MetaCompositor* meta_compositor_new (MetaDisplay *display); -void meta_compositor_unref (MetaCompositor *compositor); void meta_compositor_process_event (MetaCompositor *compositor, XEvent *xevent, MetaWindow *window); void meta_compositor_add_window (MetaCompositor *compositor, + MetaWindow *window, Window xwindow, XWindowAttributes *attrs); void meta_compositor_remove_window (MetaCompositor *compositor, @@ -57,23 +46,11 @@ 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, - int y, - int width, - int height, - MetaAnimationFinishedFunc finished_cb, - gpointer finished_data); -#endif +void meta_compositor_set_updates (MetaCompositor *compositor, + MetaWindow *window, + gboolean updates); -void -meta_compositor_set_updates (MetaCompositor *compositor, - MetaWindow *window, - gboolean updates); -void -meta_compositor_destroy (MetaCompositor *compositor); +void meta_compositor_destroy (MetaCompositor *compositor); void meta_compositor_begin_move (MetaCompositor *compositor, MetaWindow *window, @@ -86,7 +63,7 @@ void meta_compositor_end_move (MetaCompositor *compositor, MetaWindow *window); void meta_compositor_free_window (MetaCompositor *compositor, MetaWindow *window); -void meta_compositor_free_window (MetaCompositor *compositor, - MetaWindow *window); +Pixmap meta_compositor_get_window_pixmap (MetaCompositor *compositor, + MetaWindow *window); #endif /* META_COMPOSITOR_H */ diff --git a/src/display.c b/src/display.c index 9a4a6bd20..b0df98231 100644 --- a/src/display.c +++ b/src/display.c @@ -65,6 +65,11 @@ #ifdef HAVE_XCURSOR #include #endif +#ifdef HAVE_COMPOSITE_EXTENSIONS +#include +#include +#include +#endif #include #define GRAB_OP_IS_WINDOW_SWITCH(g) \ @@ -186,10 +191,23 @@ sn_error_trap_pop (SnDisplay *sn_display, #endif static void -enable_compositor (MetaDisplay *display) +enable_compositor (MetaDisplay *display, + gboolean composite_windows) { GSList *list; + if (!META_DISPLAY_HAS_COMPOSITE (display) || + !META_DISPLAY_HAS_DAMAGE (display) || + !META_DISPLAY_HAS_XFIXES (display) || + !META_DISPLAY_HAS_RENDER (display)) + { + meta_warning (_("Missing %s extension required for compositing"), + !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" : + !META_DISPLAY_HAS_DAMAGE (display) ? "damage" : + !META_DISPLAY_HAS_XFIXES (display) ? "xfixes" : "render"); + return; + } + if (!display->compositor) display->compositor = meta_compositor_new (display); @@ -203,7 +221,8 @@ enable_compositor (MetaDisplay *display) meta_compositor_manage_screen (screen->display->compositor, screen); - meta_screen_composite_all_windows (screen); + if (composite_windows) + meta_screen_composite_all_windows (screen); } } @@ -336,7 +355,7 @@ meta_display_open (void) "_NET_WM_VISIBLE_ICON_NAME", "_NET_WM_USER_TIME_WINDOW", "_NET_WM_ACTION_ABOVE", - "_NET_WM_ACTION_BELOW" + "_NET_WM_ACTION_BELOW", }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -398,7 +417,8 @@ meta_display_open (void) update_window_grab_modifiers (display); meta_prefs_add_listener (prefs_changed_callback, display); - + + meta_verbose ("Creating %d atoms\n", G_N_ELEMENTS (atom_names)); XInternAtoms (display->xdisplay, atom_names, G_N_ELEMENTS (atom_names), False, atoms); display->atom_net_wm_name = atoms[0]; @@ -647,6 +667,69 @@ meta_display_open (void) meta_verbose ("Not compiled with Render support\n"); #endif /* !HAVE_RENDER */ +#ifdef HAVE_COMPOSITE_EXTENSIONS + { + display->have_composite = FALSE; + + display->composite_error_base = 0; + display->composite_event_base = 0; + + if (!XCompositeQueryExtension (display->xdisplay, + &display->composite_event_base, + &display->composite_error_base)) + { + display->composite_error_base = 0; + display->composite_event_base = 0; + } + else + display->have_composite = TRUE; + + meta_verbose ("Attempted to init Composite, found error base %d event base %d\n", + display->composite_error_base, + display->composite_event_base); + + display->have_damage = FALSE; + + display->damage_error_base = 0; + display->damage_event_base = 0; + + if (!XDamageQueryExtension (display->xdisplay, + &display->damage_event_base, + &display->damage_error_base)) + { + display->damage_error_base = 0; + display->damage_event_base = 0; + } + else + display->have_damage = TRUE; + + meta_verbose ("Attempted to init Damage, found error base %d event base %d\n", + display->damage_error_base, + display->damage_event_base); + + display->have_xfixes = FALSE; + + display->xfixes_error_base = 0; + display->xfixes_event_base = 0; + + if (!XFixesQueryExtension (display->xdisplay, + &display->xfixes_event_base, + &display->xfixes_error_base)) + { + display->xfixes_error_base = 0; + display->xfixes_event_base = 0; + } + else + display->have_xfixes = TRUE; + + meta_verbose ("Attempted to init XFixes, found error base %d event base %d\n", + display->xfixes_error_base, + display->xfixes_event_base); + } +#else /* HAVE_COMPOSITE_EXTENSIONS */ + meta_verbose ("Not compiled with Composite support\n"); +#endif /* !HAVE_COMPOSITE_EXTENSIONS */ + #ifdef HAVE_XCURSOR { XcursorSetTheme (display->xdisplay, meta_prefs_get_cursor_theme ()); @@ -742,7 +825,13 @@ meta_display_open (void) meta_display_close (display, timestamp); return FALSE; } - + + /* We don't composite the windows here because they will be composited + faster with the call to meta_screen_manage_all_windows further down + the code */ + if (meta_prefs_get_compositing_manager ()) + enable_compositor (display, FALSE); + meta_display_grab (display); /* Now manage all existing windows */ @@ -796,9 +885,6 @@ meta_display_open (void) meta_display_ungrab (display); - if (meta_prefs_get_compositing_manager ()) - enable_compositor (display); - /* Done opening new display */ display->display_opening = FALSE; @@ -939,7 +1025,7 @@ meta_display_close (MetaDisplay *display, meta_display_shutdown_keys (display); if (display->compositor) - meta_compositor_unref (display->compositor); + meta_compositor_destroy (display->compositor); g_free (display); @@ -4830,7 +4916,7 @@ prefs_changed_callback (MetaPreference pref, gboolean cm = meta_prefs_get_compositing_manager (); if (cm) - enable_compositor (display); + enable_compositor (display, TRUE); else disable_compositor (display); } diff --git a/src/display.h b/src/display.h index 14bd4eee8..ed8899232 100644 --- a/src/display.h +++ b/src/display.h @@ -47,7 +47,7 @@ #define meta_XFree(p) do { if ((p)) XFree ((p)); } while (0) -typedef struct MetaCompositor MetaCompositor; +typedef struct _MetaCompositor MetaCompositor; typedef struct _MetaDisplay MetaDisplay; typedef struct _MetaFrame MetaFrame; typedef struct _MetaKeyBinding MetaKeyBinding; @@ -354,6 +354,14 @@ struct _MetaDisplay int render_event_base; int render_error_base; #endif +#ifdef HAVE_COMPOSITE_EXTENSIONS + int composite_event_base; + int composite_error_base; + int damage_event_base; + int damage_error_base; + int xfixes_event_base; + int xfixes_error_base; +#endif #ifdef HAVE_XSYNC unsigned int have_xsync : 1; #define META_DISPLAY_HAS_XSYNC(display) ((display)->have_xsync) @@ -372,6 +380,18 @@ struct _MetaDisplay #else #define META_DISPLAY_HAS_RENDER(display) FALSE #endif +#ifdef HAVE_COMPOSITE_EXTENSIONS + unsigned int have_composite : 1; + unsigned int have_damage : 1; + unsigned int have_xfixes : 1; +#define META_DISPLAY_HAS_COMPOSITE(display) ((display)->have_composite) +#define META_DISPLAY_HAS_DAMAGE(display) ((display)->have_damage) +#define META_DISPLAY_HAS_XFIXES(display) ((display)->have_xfixes) +#else +#define META_DISPLAY_HAS_COMPOSITE(display) FALSE +#define META_DISPLAY_HAS_DAMAGE(display) FALSE +#define META_DISPLAY_HAS_XFIXES(display) FALSE +#endif }; /* Xserver time can wraparound, thus comparing two timestamps needs to take diff --git a/src/screen.c b/src/screen.c index 362397cac..9d965ac1e 100644 --- a/src/screen.c +++ b/src/screen.c @@ -535,7 +535,12 @@ meta_screen_new (MetaDisplay *display, screen->wm_sn_selection_window = new_wm_sn_owner; screen->wm_sn_atom = wm_sn_atom; screen->wm_sn_timestamp = manager_timestamp; - + +#ifdef HAVE_COMPOSITE_EXTENSIONS + screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay, + xroot, + NoEventMask); +#endif screen->work_area_idle = 0; screen->active_workspace = NULL; @@ -807,9 +812,23 @@ meta_screen_manage_all_windows (MetaScreen *screen) for (list = windows; list != NULL; list = list->next) { WindowInfo *info = list->data; + MetaWindow *window; - meta_window_new_with_attrs (screen->display, info->xwindow, TRUE, - &info->attrs); + window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE, + &info->attrs); + if (info->xwindow == screen->no_focus_window || + info->xwindow == screen->flash_window || +#ifdef HAVE_COMPOSITE_EXTENSIONS + info->xwindow == screen->wm_cm_selection_window || +#endif + info->xwindow == screen->wm_sn_selection_window) { + meta_verbose ("Not managing our own windows\n"); + continue; + } + + if (screen->display->compositor) + meta_compositor_add_window (screen->display->compositor, window, + info->xwindow, &info->attrs); } meta_stack_thaw (screen->stack); @@ -822,9 +841,12 @@ meta_screen_manage_all_windows (MetaScreen *screen) void meta_screen_composite_all_windows (MetaScreen *screen) { +#ifdef HAVE_COMPOSITE_EXTENSIONS + MetaDisplay *display; GList *windows, *list; - if (!screen->display->compositor) + display = screen->display; + if (!display->compositor) return; windows = list_windows (screen); @@ -835,7 +857,17 @@ meta_screen_composite_all_windows (MetaScreen *screen) { WindowInfo *info = list->data; - meta_compositor_add_window (screen->display->compositor, + if (info->xwindow == screen->no_focus_window || + info->xwindow == screen->flash_window || + info->xwindow == screen->wm_sn_selection_window || + info->xwindow == screen->wm_cm_selection_window) { + meta_verbose ("Not managing our own windows\n"); + continue; + } + + meta_compositor_add_window (display->compositor, + meta_display_lookup_x_window (display, + info->xwindow), info->xwindow, &info->attrs); } @@ -843,6 +875,7 @@ meta_screen_composite_all_windows (MetaScreen *screen) g_list_foreach (windows, (GFunc)g_free, NULL); g_list_free (windows); +#endif } MetaScreen* @@ -1215,6 +1248,49 @@ meta_screen_update_cursor (MetaScreen *screen) XFreeCursor (screen->display->xdisplay, xcursor); } +#define MAX_PREVIEW_SIZE 150.0 + +static GdkPixbuf * +get_window_pixbuf (MetaWindow *window, + int *width, + int *height) +{ + Pixmap pmap; + GdkPixbuf *pixbuf, *scaled; + double ratio; + + pmap = meta_compositor_get_window_pixmap (window->display->compositor, + window); + if (pmap == None) + return NULL; + + pixbuf = meta_ui_get_pixbuf_from_pixmap (pmap); + if (pixbuf == NULL) + return NULL; + + *width = gdk_pixbuf_get_width (pixbuf); + *height = gdk_pixbuf_get_height (pixbuf); + + /* Scale pixbuf to max dimension MAX_PREVIEW_SIZE */ + if (*width > *height) + { + ratio = ((double) *width) / MAX_PREVIEW_SIZE; + *width = (int) MAX_PREVIEW_SIZE; + *height = (int) (((double) *height) / ratio); + } + else + { + ratio = ((double) *height) / MAX_PREVIEW_SIZE; + *height = (int) MAX_PREVIEW_SIZE; + *width = (int) (((double) *width) / ratio); + } + + scaled = gdk_pixbuf_scale_simple (pixbuf, *width, *height, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + return scaled; +} + void meta_screen_ensure_tab_popup (MetaScreen *screen, MetaTabList list_type, @@ -1247,12 +1323,41 @@ meta_screen_ensure_tab_popup (MetaScreen *screen, { MetaWindow *window; MetaRectangle r; - + GdkPixbuf *win_pixbuf; + int width, height; + window = tmp->data; entries[i].key = (MetaTabEntryKey) window->xwindow; entries[i].title = window->title; - entries[i].icon = window->icon; + + win_pixbuf = get_window_pixbuf (window, &width, &height); + if (win_pixbuf == NULL) + entries[i].icon = g_object_ref (window->icon); + else + { + int icon_width, icon_height, t_width, t_height; +#define ICON_OFFSET 6 + + icon_width = gdk_pixbuf_get_width (window->icon); + icon_height = gdk_pixbuf_get_height (window->icon); + + t_width = width + ICON_OFFSET; + t_height = height + ICON_OFFSET; + + entries[i].icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + t_width, t_height); + gdk_pixbuf_fill (entries[i].icon, 0x00000000); + gdk_pixbuf_copy_area (win_pixbuf, 0, 0, width, height, + entries[i].icon, 0, 0); + g_object_unref (win_pixbuf); + gdk_pixbuf_composite (window->icon, entries[i].icon, + t_width - icon_width, t_height - icon_height, + icon_width, icon_height, + t_width - icon_width, t_height - icon_height, + 1.0, 1.0, GDK_INTERP_BILINEAR, 255); + } + entries[i].blank = FALSE; entries[i].hidden = !meta_window_showing_on_its_workspace (window); entries[i].demands_attention = window->wm_state_demands_attention; @@ -1312,6 +1417,10 @@ meta_screen_ensure_tab_popup (MetaScreen *screen, len, 5, /* FIXME */ TRUE); + + for (i = 0; i < len; i++) + g_object_unref (entries[i].icon); + g_free (entries); g_list_free (tab_list); @@ -2686,3 +2795,28 @@ meta_screen_apply_startup_properties (MetaScreen *screen, return FALSE; } +#ifdef HAVE_COMPOSITE_EXTENSIONS +void +meta_screen_set_cm_selection (MetaScreen *screen) +{ + char selection[32]; + Atom a; + + g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number); + meta_verbose ("Setting selection: %s\n", selection); + a = XInternAtom (screen->display->xdisplay, selection, FALSE); + XSetSelectionOwner (screen->display->xdisplay, a, + screen->wm_cm_selection_window, CurrentTime); +} + +void +meta_screen_unset_cm_selection (MetaScreen *screen) +{ + char selection[32]; + Atom a; + + g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number); + a = XInternAtom (screen->display->xdisplay, selection, FALSE); + XSetSelectionOwner (screen->display->xdisplay, a, None, CurrentTime); +} +#endif /* HAVE_COMPOSITE_EXTENSIONS */ diff --git a/src/screen.h b/src/screen.h index e3a0340dd..c4bc85a03 100644 --- a/src/screen.h +++ b/src/screen.h @@ -102,7 +102,11 @@ struct _MetaScreen GSList *startup_sequences; guint startup_sequence_timeout; #endif - + +#ifdef HAVE_COMPOSITE_EXTENSIONS + Window wm_cm_selection_window; +#endif + guint work_area_idle; int rows_of_workspaces; @@ -211,4 +215,9 @@ gboolean meta_screen_apply_startup_properties (MetaScreen *screen, MetaWindow *window); void meta_screen_composite_all_windows (MetaScreen *screen); +#ifdef HAVE_COMPOSITE_EXTENSIONS +void meta_screen_set_cm_selection (MetaScreen *screen); +void meta_screen_unset_cm_selection (MetaScreen *screen); +#endif + #endif diff --git a/src/theme-parser.c b/src/theme-parser.c index 5e169e6eb..2a98b814f 100644 --- a/src/theme-parser.c +++ b/src/theme-parser.c @@ -1638,8 +1638,10 @@ parse_geometry_element (GMarkupParseContext *context, } } +#if 0 static gboolean -check_expression (const char *expr, +check_expression (PosToken *tokens, + int n_tokens, gboolean has_object, MetaTheme *theme, GMarkupParseContext *context, @@ -1678,7 +1680,7 @@ check_expression (const char *expr, env.mini_icon_height = 0; env.theme = theme; - if (!meta_parse_position_expression (expr, + if (!meta_parse_position_expression (tokens, n_tokens, &env, &x, &y, error)) @@ -1689,16 +1691,7 @@ check_expression (const char *expr, return TRUE; } - -static char* -optimize_expression (MetaTheme *theme, - const char *expr) -{ - /* We aren't expecting an error here, since we already - * did check_expression - */ - return meta_theme_replace_constants (theme, expr, NULL); -} +#endif static void parse_draw_op_element (GMarkupParseContext *context, @@ -1772,6 +1765,7 @@ parse_draw_op_element (GMarkupParseContext *context, return; } +#if 0 if (!check_expression (x1, FALSE, info->theme, context, error)) return; @@ -1783,7 +1777,8 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (y2, FALSE, info->theme, context, error)) return; - +#endif + dash_on_val = 0; if (dash_on_length && !parse_positive_integer (dash_on_length, &dash_on_val, context, info->theme, error)) @@ -1812,10 +1807,12 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_LINE); op->data.line.color_spec = color_spec; - op->data.line.x1 = optimize_expression (info->theme, x1); - op->data.line.y1 = optimize_expression (info->theme, y1); - op->data.line.x2 = optimize_expression (info->theme, x2); - op->data.line.y2 = optimize_expression (info->theme, y2); + + op->data.line.x1 = meta_draw_spec_new (info->theme, x1, NULL); + op->data.line.y1 = meta_draw_spec_new (info->theme, y1, NULL); + op->data.line.x2 = meta_draw_spec_new (info->theme, x2, NULL); + op->data.line.y2 = meta_draw_spec_new (info->theme, y2, NULL); + op->data.line.width = width_val; op->data.line.dash_on_length = dash_on_val; op->data.line.dash_off_length = dash_off_val; @@ -1882,6 +1879,7 @@ parse_draw_op_element (GMarkupParseContext *context, return; } +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -1893,6 +1891,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; +#endif filled_val = FALSE; if (filled && !parse_boolean (filled, &filled_val, context, error)) @@ -1911,10 +1910,12 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_RECTANGLE); op->data.rectangle.color_spec = color_spec; - op->data.rectangle.x = optimize_expression (info->theme, x); - op->data.rectangle.y = optimize_expression (info->theme, y); - op->data.rectangle.width = optimize_expression (info->theme, width); - op->data.rectangle.height = optimize_expression (info->theme, height); + op->data.rectangle.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.rectangle.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.rectangle.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.rectangle.height = meta_draw_spec_new (info->theme, + height, NULL); + op->data.rectangle.filled = filled_val; g_assert (info->op_list); @@ -2022,7 +2023,7 @@ parse_draw_op_element (GMarkupParseContext *context, } } - +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2034,6 +2035,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; +#endif if (start_angle == NULL) { @@ -2078,10 +2080,12 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_ARC); op->data.arc.color_spec = color_spec; - op->data.arc.x = optimize_expression (info->theme, x); - op->data.arc.y = optimize_expression (info->theme, y); - op->data.arc.width = optimize_expression (info->theme, width); - op->data.arc.height = optimize_expression (info->theme, height); + + op->data.arc.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.arc.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.arc.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.arc.height = meta_draw_spec_new (info->theme, height, NULL); + op->data.arc.filled = filled_val; op->data.arc.start_angle = start_angle_val; op->data.arc.extent_angle = extent_angle_val; @@ -2135,6 +2139,7 @@ parse_draw_op_element (GMarkupParseContext *context, return; } +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2146,13 +2151,13 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - +#endif op = meta_draw_op_new (META_DRAW_CLIP); - op->data.clip.x = optimize_expression (info->theme, x); - op->data.clip.y = optimize_expression (info->theme, y); - op->data.clip.width = optimize_expression (info->theme, width); - op->data.clip.height = optimize_expression (info->theme, height); + op->data.clip.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.clip.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.clip.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.clip.height = meta_draw_spec_new (info->theme, height, NULL); g_assert (info->op_list); @@ -2222,7 +2227,7 @@ parse_draw_op_element (GMarkupParseContext *context, _("No \"alpha\" attribute on element <%s>"), element_name); return; } - +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2234,7 +2239,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - +#endif alpha_spec = NULL; if (!parse_alpha (alpha, &alpha_spec, context, error)) return; @@ -2256,10 +2261,11 @@ parse_draw_op_element (GMarkupParseContext *context, op->data.tint.color_spec = color_spec; op->data.tint.alpha_spec = alpha_spec; - op->data.tint.x = optimize_expression (info->theme, x); - op->data.tint.y = optimize_expression (info->theme, y); - op->data.tint.width = optimize_expression (info->theme, width); - op->data.tint.height = optimize_expression (info->theme, height); + + op->data.tint.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.tint.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.tint.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.tint.height = meta_draw_spec_new (info->theme, height, NULL); g_assert (info->op_list); @@ -2322,6 +2328,7 @@ parse_draw_op_element (GMarkupParseContext *context, return; } +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2333,7 +2340,8 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - +#endif + type_val = meta_gradient_type_from_string (type); if (type_val == META_GRADIENT_LAST) { @@ -2350,10 +2358,12 @@ parse_draw_op_element (GMarkupParseContext *context, g_assert (info->op == NULL); info->op = meta_draw_op_new (META_DRAW_GRADIENT); - info->op->data.gradient.x = optimize_expression (info->theme, x); - info->op->data.gradient.y = optimize_expression (info->theme, y); - info->op->data.gradient.width = optimize_expression (info->theme, width); - info->op->data.gradient.height = optimize_expression (info->theme, height); + info->op->data.gradient.x = meta_draw_spec_new (info->theme, x, NULL); + info->op->data.gradient.y = meta_draw_spec_new (info->theme, y, NULL); + info->op->data.gradient.width = meta_draw_spec_new (info->theme, + width, NULL); + info->op->data.gradient.height = meta_draw_spec_new (info->theme, + height, NULL); info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val); @@ -2426,7 +2436,7 @@ parse_draw_op_element (GMarkupParseContext *context, _("No \"filename\" attribute on element <%s>"), element_name); return; } - +#if 0 if (!check_expression (x, TRUE, info->theme, context, error)) return; @@ -2438,7 +2448,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, TRUE, info->theme, context, error)) return; - +#endif fill_type_val = META_IMAGE_FILL_SCALE; if (fill_type) { @@ -2490,10 +2500,12 @@ parse_draw_op_element (GMarkupParseContext *context, op->data.image.pixbuf = pixbuf; op->data.image.colorize_spec = colorize_spec; - op->data.image.x = optimize_expression (info->theme, x); - op->data.image.y = optimize_expression (info->theme, y); - op->data.image.width = optimize_expression (info->theme, width); - op->data.image.height = optimize_expression (info->theme, height); + + op->data.image.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.image.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.image.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.image.height = meta_draw_spec_new (info->theme, height, NULL); + op->data.image.alpha_spec = alpha_spec; op->data.image.fill_type = fill_type_val; @@ -2639,7 +2651,7 @@ parse_draw_op_element (GMarkupParseContext *context, _("No \"height\" attribute on element <%s>"), element_name); return; } - +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2651,7 +2663,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - +#endif filled_val = TRUE; if (filled && !parse_boolean (filled, &filled_val, context, error)) return; @@ -2688,10 +2700,12 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_GTK_ARROW); - op->data.gtk_arrow.x = optimize_expression (info->theme, x); - op->data.gtk_arrow.y = optimize_expression (info->theme, y); - op->data.gtk_arrow.width = optimize_expression (info->theme, width); - op->data.gtk_arrow.height = optimize_expression (info->theme, height); + op->data.gtk_arrow.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.gtk_arrow.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.gtk_arrow.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.gtk_arrow.height = meta_draw_spec_new (info->theme, + height, NULL); + op->data.gtk_arrow.filled = filled_val; op->data.gtk_arrow.state = state_val; op->data.gtk_arrow.shadow = shadow_val; @@ -2765,7 +2779,7 @@ parse_draw_op_element (GMarkupParseContext *context, _("No \"height\" attribute on element <%s>"), element_name); return; } - +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2777,7 +2791,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - +#endif state_val = meta_gtk_state_from_string (state); if (((int) state_val) == -1) { @@ -2800,10 +2814,11 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_GTK_BOX); - op->data.gtk_box.x = optimize_expression (info->theme, x); - op->data.gtk_box.y = optimize_expression (info->theme, y); - op->data.gtk_box.width = optimize_expression (info->theme, width); - op->data.gtk_box.height = optimize_expression (info->theme, height); + op->data.gtk_box.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.gtk_box.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.gtk_box.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.gtk_box.height = meta_draw_spec_new (info->theme, height, NULL); + op->data.gtk_box.state = state_val; op->data.gtk_box.shadow = shadow_val; @@ -2857,6 +2872,7 @@ parse_draw_op_element (GMarkupParseContext *context, return; } +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2865,6 +2881,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (y2, FALSE, info->theme, context, error)) return; +#endif state_val = meta_gtk_state_from_string (state); if (((int) state_val) == -1) @@ -2878,9 +2895,10 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_GTK_VLINE); - op->data.gtk_vline.x = optimize_expression (info->theme, x); - op->data.gtk_vline.y1 = optimize_expression (info->theme, y1); - op->data.gtk_vline.y2 = optimize_expression (info->theme, y2); + op->data.gtk_vline.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.gtk_vline.y1 = meta_draw_spec_new (info->theme, y1, NULL); + op->data.gtk_vline.y2 = meta_draw_spec_new (info->theme, y2, NULL); + op->data.gtk_vline.state = state_val; g_assert (info->op_list); @@ -2937,7 +2955,7 @@ parse_draw_op_element (GMarkupParseContext *context, _("No \"height\" attribute on element <%s>"), element_name); return; } - +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; @@ -2949,7 +2967,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - +#endif fill_type_val = META_IMAGE_FILL_SCALE; if (fill_type) { @@ -2969,11 +2987,12 @@ parse_draw_op_element (GMarkupParseContext *context, return; op = meta_draw_op_new (META_DRAW_ICON); + + op->data.icon.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.icon.y = meta_draw_spec_new (info->theme, y, NULL); + op->data.icon.width = meta_draw_spec_new (info->theme, width, NULL); + op->data.icon.height = meta_draw_spec_new (info->theme, height, NULL); - op->data.icon.x = optimize_expression (info->theme, x); - op->data.icon.y = optimize_expression (info->theme, y); - op->data.icon.width = optimize_expression (info->theme, width); - op->data.icon.height = optimize_expression (info->theme, height); op->data.icon.alpha_spec = alpha_spec; op->data.icon.fill_type = fill_type_val; @@ -3019,12 +3038,14 @@ parse_draw_op_element (GMarkupParseContext *context, return; } +#if 0 if (!check_expression (x, FALSE, info->theme, context, error)) return; if (!check_expression (y, FALSE, info->theme, context, error)) return; - +#endif + /* Check last so we don't have to free it when other * stuff fails */ @@ -3038,8 +3059,9 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_TITLE); op->data.title.color_spec = color_spec; - op->data.title.x = optimize_expression (info->theme, x); - op->data.title.y = optimize_expression (info->theme, y); + + op->data.title.x = meta_draw_spec_new (info->theme, x, NULL); + op->data.title.y = meta_draw_spec_new (info->theme, y, NULL); g_assert (info->op_list); @@ -3075,7 +3097,7 @@ parse_draw_op_element (GMarkupParseContext *context, /* x/y/width/height default to 0,0,width,height - should * probably do this for all the draw ops */ - +#if 0 if (x && !check_expression (x, FALSE, info->theme, context, error)) return; @@ -3087,6 +3109,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (height && !check_expression (height, FALSE, info->theme, context, error)) return; +#endif op_list = meta_theme_lookup_draw_op_list (info->theme, name); @@ -3115,15 +3138,16 @@ parse_draw_op_element (GMarkupParseContext *context, meta_draw_op_list_ref (op_list); op->data.op_list.op_list = op_list; - op->data.op_list.x = x ? optimize_expression (info->theme, x) : - g_strdup ("0"); - op->data.op_list.y = y ? optimize_expression (info->theme, y) : - g_strdup ("0"); - op->data.op_list.width = width ? optimize_expression (info->theme, width) : - g_strdup ("width"); - op->data.op_list.height = height ? optimize_expression (info->theme, height) : - g_strdup ("height"); - + + op->data.op_list.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL); + op->data.op_list.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL); + op->data.op_list.width = meta_draw_spec_new (info->theme, + width ? width : "width", + NULL); + op->data.op_list.height = meta_draw_spec_new (info->theme, + height ? height : "height", + NULL); + meta_draw_op_list_append (info->op_list, op); push_state (info, STATE_INCLUDE); @@ -3176,6 +3200,7 @@ parse_draw_op_element (GMarkupParseContext *context, } /* These default to 0 */ +#if 0 if (tile_xoffset && !check_expression (tile_xoffset, FALSE, info->theme, context, error)) return; @@ -3185,7 +3210,6 @@ parse_draw_op_element (GMarkupParseContext *context, /* x/y/width/height default to 0,0,width,height - should * probably do this for all the draw ops */ - if (x && !check_expression (x, FALSE, info->theme, context, error)) return; @@ -3203,7 +3227,7 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (tile_height, FALSE, info->theme, context, error)) return; - +#endif op_list = meta_theme_lookup_draw_op_list (info->theme, name); if (op_list == NULL) @@ -3230,23 +3254,25 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_TILE); meta_draw_op_list_ref (op_list); + + op->data.tile.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL); + op->data.tile.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL); + op->data.tile.width = meta_draw_spec_new (info->theme, + width ? width : "width", + NULL); + op->data.tile.height = meta_draw_spec_new (info->theme, + height ? height : "height", + NULL); + op->data.tile.tile_xoffset = meta_draw_spec_new (info->theme, + tile_xoffset ? tile_xoffset : "0", + NULL); + op->data.tile.tile_yoffset = meta_draw_spec_new (info->theme, + tile_yoffset ? tile_yoffset : "0", + NULL); + op->data.tile.tile_width = meta_draw_spec_new (info->theme, tile_width, NULL); + op->data.tile.tile_height = meta_draw_spec_new (info->theme, tile_height, NULL); + op->data.tile.op_list = op_list; - op->data.tile.x = x ? optimize_expression (info->theme, x) : - g_strdup ("0"); - op->data.tile.y = y ? optimize_expression (info->theme, y) : - g_strdup ("0"); - op->data.tile.width = width ? optimize_expression (info->theme, width) : - g_strdup ("width"); - op->data.tile.height = height ? optimize_expression (info->theme, height) : - g_strdup ("height"); - op->data.tile.tile_xoffset = tile_xoffset ? - optimize_expression (info->theme, tile_xoffset) : - g_strdup ("0"); - op->data.tile.tile_yoffset = tile_yoffset ? - optimize_expression (info->theme, tile_yoffset) : - g_strdup ("0"); - op->data.tile.tile_width = optimize_expression (info->theme, tile_width); - op->data.tile.tile_height = optimize_expression (info->theme, tile_height); meta_draw_op_list_append (info->op_list, op); diff --git a/src/theme-viewer.c b/src/theme-viewer.c index d4a1106b5..4b97de665 100644 --- a/src/theme-viewer.c +++ b/src/theme-viewer.c @@ -1175,6 +1175,7 @@ static const PositionExpressionTest position_expression_tests[] = { static void run_position_expression_tests (void) { +#if 0 int i; MetaPositionExprEnv env; @@ -1184,6 +1185,8 @@ run_position_expression_tests (void) GError *err; gboolean retval; const PositionExpressionTest *test; + PosToken *tokens; + int n_tokens; int x, y; test = &position_expression_tests[i]; @@ -1210,10 +1213,13 @@ run_position_expression_tests (void) env.mini_icon_height = 16; env.theme = NULL; - retval = meta_parse_position_expression (test->expr, - &env, - &x, &y, - &err); + if (err == NULL) + { + retval = meta_parse_position_expression (tokens, n_tokens, + &env, + &x, &y, + &err); + } if (retval && err) g_error (_("position expression test returned TRUE but set error")); @@ -1243,8 +1249,10 @@ run_position_expression_tests (void) if (err) g_error_free (err); + meta_pos_tokens_free (tokens, n_tokens); ++i; } +#endif } #if 0 diff --git a/src/theme.c b/src/theme.c index 92ff558ff..51f88d6e1 100644 --- a/src/theme.c +++ b/src/theme.c @@ -60,6 +60,8 @@ static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s); +static MetaTheme *meta_current_theme = NULL; + static GdkPixbuf * colorize_pixbuf (GdkPixbuf *orig, GdkColor *new_color) @@ -1167,6 +1169,7 @@ meta_color_spec_new_from_string (const char *str, spec->data.blend.alpha = alpha; spec->data.blend.background = bg; spec->data.blend.foreground = fg; + spec->data.blend.color_set = FALSE; } else if (str[0] == 's' && str[1] == 'h' && str[2] == 'a' && str[3] == 'd' && str[4] == 'e' && str[5] == '/') @@ -1225,6 +1228,7 @@ meta_color_spec_new_from_string (const char *str, spec = meta_color_spec_new (META_COLOR_SPEC_SHADE); spec->data.shade.factor = factor; spec->data.shade.base = base; + spec->data.shade.color_set = FALSE; } else { @@ -1312,49 +1316,38 @@ meta_color_spec_render (MetaColorSpec *spec, { GdkColor bg, fg; - meta_color_spec_render (spec->data.blend.background, widget, &bg); - meta_color_spec_render (spec->data.blend.foreground, widget, &fg); + if (spec->data.blend.color_set == FALSE) + { + meta_color_spec_render (spec->data.blend.background, widget, &bg); + meta_color_spec_render (spec->data.blend.foreground, widget, &fg); - color_composite (&bg, &fg, spec->data.blend.alpha, color); + color_composite (&bg, &fg, spec->data.blend.alpha, + &spec->data.blend.color); + spec->data.blend.color_set = TRUE; + } + + *color = spec->data.blend.color; } break; case META_COLOR_SPEC_SHADE: { - GdkColor base; - - meta_color_spec_render (spec->data.shade.base, widget, &base); - - gtk_style_shade (&base, &base, spec->data.shade.factor); + if (spec->data.shade.color_set == FALSE) + { + meta_color_spec_render (spec->data.shade.base, widget, + &spec->data.shade.color); + + gtk_style_shade (&spec->data.shade.color, + &spec->data.shade.color, spec->data.shade.factor); + spec->data.shade.color_set = TRUE; + } - *color = base; + *color = spec->data.shade.color; } break; } } -typedef enum -{ - POS_TOKEN_INT, - POS_TOKEN_DOUBLE, - POS_TOKEN_OPERATOR, - POS_TOKEN_VARIABLE, - POS_TOKEN_OPEN_PAREN, - POS_TOKEN_CLOSE_PAREN -} PosTokenType; - -typedef enum -{ - POS_OP_NONE, - POS_OP_ADD, - POS_OP_SUBTRACT, - POS_OP_MULTIPLY, - POS_OP_DIVIDE, - POS_OP_MOD, - POS_OP_MAX, - POS_OP_MIN -} PosOperatorType; - static const char* op_name (PosOperatorType type) { @@ -1429,33 +1422,6 @@ op_from_string (const char *p, return POS_OP_NONE; } -typedef struct -{ - PosTokenType type; - - union - { - struct { - int val; - } i; - - struct { - double val; - } d; - - struct { - PosOperatorType op; - } o; - - struct { - char *name; - } v; - - } d; - -} PosToken; - - static void free_tokens (PosToken *tokens, int n_tokens) @@ -1550,6 +1516,46 @@ parse_number (const char *p, #define IS_VARIABLE_CHAR(c) (g_ascii_isalpha ((c)) || (c) == '_') +#if 0 +static void +debug_print_tokens (PosToken *tokens, + int n_tokens) +{ + int i; + + for (i = 0; i < n_tokens; i++) + { + PosToken *t = &tokens[i]; + + g_print (" "); + + switch (t->type) + { + case POS_TOKEN_INT: + g_print ("\"%d\"", t->d.i.val); + break; + case POS_TOKEN_DOUBLE: + g_print ("\"%g\"", t->d.d.val); + break; + case POS_TOKEN_OPEN_PAREN: + g_print ("\"(\""); + break; + case POS_TOKEN_CLOSE_PAREN: + g_print ("\")\""); + break; + case POS_TOKEN_VARIABLE: + g_print ("\"%s\"", t->d.v.name); + break; + case POS_TOKEN_OPERATOR: + g_print ("\"%s\"", op_name (t->d.o.op)); + break; + } + } + + g_print ("\n"); +} +#endif + static gboolean pos_tokenize (const char *expr, PosToken **tokens_p, @@ -1675,46 +1681,6 @@ pos_tokenize (const char *expr, return FALSE; } -#if 0 -static void -debug_print_tokens (PosToken *tokens, - int n_tokens) -{ - int i; - - for (i = 0; i < n_tokens; i++) - { - PosToken *t = &tokens[i]; - - g_print (" "); - - switch (t->type) - { - case POS_TOKEN_INT: - g_print ("\"%d\"", t->d.i.val); - break; - case POS_TOKEN_DOUBLE: - g_print ("\"%g\"", t->d.d.val); - break; - case POS_TOKEN_OPEN_PAREN: - g_print ("\"(\""); - break; - case POS_TOKEN_CLOSE_PAREN: - g_print ("\")\""); - break; - case POS_TOKEN_VARIABLE: - g_print ("\"%s\"", t->d.v.name); - break; - case POS_TOKEN_OPERATOR: - g_print ("\"%s\"", op_name (t->d.o.op)); - break; - } - } - - g_print ("\n"); -} -#endif - typedef enum { POS_EXPR_INT, @@ -2010,6 +1976,100 @@ do_operations (PosExpr *exprs, return TRUE; } +static gboolean +pos_eval_get_variable (PosToken *t, + int *result, + const MetaPositionExprEnv *env, + GError **err) +{ + /* In certain circumstances (when the theme parser is used outside + of metacity) env->theme will be NULL so we run the slow variable search */ + if (env->theme) + { + if (t->d.v.name_quark == env->theme->quark_width) + *result = env->rect.width; + else if (t->d.v.name_quark == env->theme->quark_height) + *result = env->rect.height; + else if (env->object_width >= 0 && + t->d.v.name_quark == env->theme->quark_object_width) + *result = env->object_width; + else if (env->object_height >= 0 && + t->d.v.name_quark == env->theme->quark_object_height) + *result = env->object_height; + else if (t->d.v.name_quark == env->theme->quark_left_width) + *result = env->left_width; + else if (t->d.v.name_quark == env->theme->quark_right_width) + *result = env->right_width; + else if (t->d.v.name_quark == env->theme->quark_top_height) + *result = env->top_height; + else if (t->d.v.name_quark == env->theme->quark_bottom_height) + *result = env->bottom_height; + else if (t->d.v.name_quark == env->theme->quark_mini_icon_width) + *result = env->mini_icon_width; + else if (t->d.v.name_quark == env->theme->quark_mini_icon_height) + *result = env->mini_icon_height; + else if (t->d.v.name_quark == env->theme->quark_icon_width) + *result = env->icon_width; + else if (t->d.v.name_quark == env->theme->quark_icon_height) + *result = env->icon_height; + else if (t->d.v.name_quark == env->theme->quark_title_width) + *result = env->title_width; + else if (t->d.v.name_quark == env->theme->quark_title_height) + *result = env->title_height; + else + { + g_set_error (err, META_THEME_ERROR, + META_THEME_ERROR_UNKNOWN_VARIABLE, + _("Coordinate expression had unknown variable or constant \"%s\""), + t->d.v.name); + return FALSE; + } + } + else + { + if (strcmp (t->d.v.name, "width") == 0) + *result = env->rect.width; + else if (strcmp (t->d.v.name, "height") == 0) + *result = env->rect.height; + else if (env->object_width >= 0 && + strcmp (t->d.v.name, "object_width") == 0) + *result = env->object_width; + else if (env->object_height >= 0 && + strcmp (t->d.v.name, "object_height") == 0) + *result = env->object_height; + else if (strcmp (t->d.v.name, "left_width") == 0) + *result = env->left_width; + else if (strcmp (t->d.v.name, "right_width") == 0) + *result = env->right_width; + else if (strcmp (t->d.v.name, "top_height") == 0) + *result = env->top_height; + else if (strcmp (t->d.v.name, "bottom_height") == 0) + *result = env->bottom_height; + else if (strcmp (t->d.v.name, "mini_icon_width") == 0) + *result = env->mini_icon_width; + else if (strcmp (t->d.v.name, "mini_icon_height") == 0) + *result = env->mini_icon_height; + else if (strcmp (t->d.v.name, "icon_width") == 0) + *result = env->icon_width; + else if (strcmp (t->d.v.name, "icon_height") == 0) + *result = env->icon_height; + else if (strcmp (t->d.v.name, "title_width") == 0) + *result = env->title_width; + else if (strcmp (t->d.v.name, "title_height") == 0) + *result = env->title_height; + else + { + g_set_error (err, META_THEME_ERROR, + META_THEME_ERROR_UNKNOWN_VARIABLE, + _("Coordinate expression had unknown variable or constant \"%s\""), + t->d.v.name); + return FALSE; + } + } + + return TRUE; +} + static gboolean pos_eval_helper (PosToken *tokens, int n_tokens, @@ -2024,13 +2084,10 @@ pos_eval_helper (PosToken *tokens, int i; PosExpr exprs[MAX_EXPRS]; int n_exprs; - int ival; - double dval; int precedence; #if 0 g_print ("Pos eval helper on %d tokens:\n", n_tokens); - debug_print_tokens (tokens, n_tokens); #endif /* Our first goal is to get a list of PosExpr, essentially @@ -2087,62 +2144,9 @@ pos_eval_helper (PosToken *tokens, * in a hash, maybe keep width/height out * for optimization purposes */ - if (strcmp (t->d.v.name, "width") == 0) - exprs[n_exprs].d.int_val = env->rect.width; - else if (strcmp (t->d.v.name, "height") == 0) - exprs[n_exprs].d.int_val = env->rect.height; - else if (env->object_width >= 0 && - strcmp (t->d.v.name, "object_width") == 0) - exprs[n_exprs].d.int_val = env->object_width; - else if (env->object_height >= 0 && - strcmp (t->d.v.name, "object_height") == 0) - exprs[n_exprs].d.int_val = env->object_height; - else if (strcmp (t->d.v.name, "left_width") == 0) - exprs[n_exprs].d.int_val = env->left_width; - else if (strcmp (t->d.v.name, "right_width") == 0) - exprs[n_exprs].d.int_val = env->right_width; - else if (strcmp (t->d.v.name, "top_height") == 0) - exprs[n_exprs].d.int_val = env->top_height; - else if (strcmp (t->d.v.name, "bottom_height") == 0) - exprs[n_exprs].d.int_val = env->bottom_height; - else if (strcmp (t->d.v.name, "mini_icon_width") == 0) - exprs[n_exprs].d.int_val = env->mini_icon_width; - else if (strcmp (t->d.v.name, "mini_icon_height") == 0) - exprs[n_exprs].d.int_val = env->mini_icon_height; - else if (strcmp (t->d.v.name, "icon_width") == 0) - exprs[n_exprs].d.int_val = env->icon_width; - else if (strcmp (t->d.v.name, "icon_height") == 0) - exprs[n_exprs].d.int_val = env->icon_height; - else if (strcmp (t->d.v.name, "title_width") == 0) - exprs[n_exprs].d.int_val = env->title_width; - else if (strcmp (t->d.v.name, "title_height") == 0) - exprs[n_exprs].d.int_val = env->title_height; - /* In practice we only hit this code on initial theme - * parse; after that we always optimize constants away - */ - else if (env->theme && - meta_theme_lookup_int_constant (env->theme, - t->d.v.name, - &ival)) - { - exprs[n_exprs].d.int_val = ival; - } - else if (env->theme && - meta_theme_lookup_float_constant (env->theme, - t->d.v.name, - &dval)) - { - exprs[n_exprs].type = POS_EXPR_DOUBLE; - exprs[n_exprs].d.double_val = dval; - } - else - { - g_set_error (err, META_THEME_ERROR, - META_THEME_ERROR_UNKNOWN_VARIABLE, - _("Coordinate expression had unknown variable or constant \"%s\""), - t->d.v.name); - return FALSE; - } + if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err)) + return FALSE; + ++n_exprs; break; @@ -2232,8 +2236,7 @@ pos_eval_helper (PosToken *tokens, * so very not worth fooling with bison, yet so very painful by hand. */ static gboolean -pos_eval (PosToken *tokens, - int n_tokens, +pos_eval (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *val_p, GError **err) @@ -2242,7 +2245,7 @@ pos_eval (PosToken *tokens, *val_p = 0; - if (pos_eval_helper (tokens, n_tokens, env, &expr, err)) + if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err)) { switch (expr.type) { @@ -2269,7 +2272,7 @@ pos_eval (PosToken *tokens, */ gboolean -meta_parse_position_expression (const char *expr, +meta_parse_position_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *x_return, int *y_return, @@ -2281,73 +2284,55 @@ meta_parse_position_expression (const char *expr, * optionally "object_width" and object_height". Negative numbers * aren't allowed. */ - PosToken *tokens; - int n_tokens; int val; - if (!pos_tokenize (expr, &tokens, &n_tokens, err)) - { - g_assert (err == NULL || *err != NULL); - return FALSE; - } - -#if 0 - g_print ("Tokenized \"%s\" to --->\n", expr); - debug_print_tokens (tokens, n_tokens); -#endif - - if (pos_eval (tokens, n_tokens, env, &val, err)) - { - if (x_return) - *x_return = env->rect.x + val; - if (y_return) - *y_return = env->rect.y + val; - free_tokens (tokens, n_tokens); - return TRUE; - } + if (spec->constant) + val = spec->value; else { - g_assert (err == NULL || *err != NULL); - free_tokens (tokens, n_tokens); - return FALSE; + if (pos_eval (spec, env, &spec->value, err) == FALSE) + { + g_assert (err == NULL || *err != NULL); + return FALSE; + } + + val = spec->value; } + + if (x_return) + *x_return = env->rect.x + val; + if (y_return) + *y_return = env->rect.y + val; + + return TRUE; } gboolean -meta_parse_size_expression (const char *expr, +meta_parse_size_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *val_return, GError **err) { - PosToken *tokens; - int n_tokens; int val; - if (!pos_tokenize (expr, &tokens, &n_tokens, err)) + if (spec->constant) + val = spec->value; + else { - g_assert (err == NULL || *err != NULL); - return FALSE; + if (pos_eval (spec, env, &spec->value, err) == FALSE) + { + g_assert (err == NULL || *err != NULL); + return FALSE; + } + + val = spec->value; } -#if 0 - g_print ("Tokenized \"%s\" to --->\n", expr); - debug_print_tokens (tokens, n_tokens); -#endif + if (val_return) + *val_return = MAX (val, 1); /* require that sizes be at least 1x1 */ - if (pos_eval (tokens, n_tokens, env, &val, err)) - { - if (val_return) - *val_return = MAX (val, 1); /* require that sizes be at least 1x1 */ - free_tokens (tokens, n_tokens); - return TRUE; - } - else - { - g_assert (err == NULL || *err != NULL); - free_tokens (tokens, n_tokens); - return FALSE; - } + return TRUE; } /* To do this we tokenize, replace variable tokens @@ -2356,85 +2341,71 @@ meta_parse_size_expression (const char *expr, * lookups to eval them. Obviously it's a tradeoff that * slows down theme load times. */ -char* +gboolean meta_theme_replace_constants (MetaTheme *theme, - const char *expr, + PosToken *tokens, + int n_tokens, GError **err) { - PosToken *tokens; - int n_tokens; int i; - GString *str; - char buf[G_ASCII_DTOSTR_BUF_SIZE]; double dval; int ival; + gboolean is_constant = TRUE; - if (!pos_tokenize (expr, &tokens, &n_tokens, err)) - { - g_assert (err == NULL || *err != NULL); - return NULL; - } - -#if 0 - g_print ("Tokenized \"%s\" to --->\n", expr); - debug_print_tokens (tokens, n_tokens); -#endif - - str = g_string_new (NULL); - + /* Loop through tokenized string looking for variables to replace */ for (i = 0; i < n_tokens; i++) { PosToken *t = &tokens[i]; - /* spaces so we don't accidentally merge variables - * or anything like that - */ - if (i > 0) - g_string_append_c (str, ' '); - - switch (t->type) + if (t->type == POS_TOKEN_VARIABLE) { - case POS_TOKEN_INT: - g_string_append_printf (str, "%d", t->d.i.val); - break; - case POS_TOKEN_DOUBLE: - g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, - "%g", t->d.d.val); - g_string_append (str, buf); - break; - case POS_TOKEN_OPEN_PAREN: - g_string_append_c (str, '('); - break; - case POS_TOKEN_CLOSE_PAREN: - g_string_append_c (str, ')'); - break; - case POS_TOKEN_VARIABLE: if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival)) - g_string_append_printf (str, "%d", ival); + { + t->type = POS_TOKEN_INT; + t->d.i.val = ival; + } else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval)) { - g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, - "%g", dval); - g_string_append (str, buf); + t->type = POS_TOKEN_DOUBLE; + t->d.d.val = dval; } - else + else { - g_string_append (str, t->d.v.name); + /* If we've found a variable that cannot be replaced then the + expression is not a constant expression and we want to + replace it with a GQuark */ + + t->d.v.name_quark = g_quark_from_string (t->d.v.name); + is_constant = FALSE; } - break; - case POS_TOKEN_OPERATOR: - g_string_append (str, op_name (t->d.o.op)); - break; } } + + return is_constant; +} + +static int +parse_x_position_unchecked (MetaDrawSpec *spec, + const MetaPositionExprEnv *env) +{ + int retval; + GError *error; + + retval = 0; + error = NULL; + if (!meta_parse_position_expression (spec, env, &retval, NULL, &error)) + { + meta_warning (_("Theme contained an expression that resulted in an error: %s\n"), + error->message); + + g_error_free (error); + } - free_tokens (tokens, n_tokens); - - return g_string_free (str, FALSE); + return retval; } static int -parse_x_position_unchecked (const char *expr, +parse_y_position_unchecked (MetaDrawSpec *spec, const MetaPositionExprEnv *env) { int retval; @@ -2442,12 +2413,10 @@ parse_x_position_unchecked (const char *expr, retval = 0; error = NULL; - if (!meta_parse_position_expression (expr, env, - &retval, NULL, - &error)) + if (!meta_parse_position_expression (spec, env, NULL, &retval, &error)) { - meta_warning (_("Theme contained an expression \"%s\" that resulted in an error: %s\n"), - expr, error->message); + meta_warning (_("Theme contained an expression that resulted in an error: %s\n"), + error->message); g_error_free (error); } @@ -2456,29 +2425,7 @@ parse_x_position_unchecked (const char *expr, } static int -parse_y_position_unchecked (const char *expr, - const MetaPositionExprEnv *env) -{ - int retval; - GError *error; - - retval = 0; - error = NULL; - if (!meta_parse_position_expression (expr, env, - NULL, &retval, - &error)) - { - meta_warning (_("Theme contained an expression \"%s\" that resulted in an error: %s\n"), - expr, error->message); - - g_error_free (error); - } - - return retval; -} - -static int -parse_size_unchecked (const char *expr, +parse_size_unchecked (MetaDrawSpec *spec, MetaPositionExprEnv *env) { int retval; @@ -2486,11 +2433,10 @@ parse_size_unchecked (const char *expr, retval = 0; error = NULL; - if (!meta_parse_size_expression (expr, env, - &retval, &error)) + if (!meta_parse_size_expression (spec, env, &retval, &error)) { - meta_warning (_("Theme contained an expression \"%s\" that resulted in an error: %s\n"), - expr, error->message); + meta_warning (_("Theme contained an expression that resulted in an error: %s\n"), + error->message); g_error_free (error); } @@ -2498,6 +2444,41 @@ parse_size_unchecked (const char *expr, return retval; } +void +meta_draw_spec_free (MetaDrawSpec *spec) +{ + free_tokens (spec->tokens, spec->n_tokens); + g_slice_free (MetaDrawSpec, spec); +} + +MetaDrawSpec * +meta_draw_spec_new (MetaTheme *theme, + const char *expr, + GError **error) +{ + MetaDrawSpec *spec; + + spec = g_slice_new0 (MetaDrawSpec); + + pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL); + + spec->constant = meta_theme_replace_constants (theme, spec->tokens, + spec->n_tokens, NULL); + if (spec->constant) + { + gboolean result; + + result = pos_eval (spec, NULL, &spec->value, error); + if (result == FALSE) + { + meta_draw_spec_free (spec); + return NULL; + } + } + + return spec; +} + MetaDrawOp* meta_draw_op_new (MetaDrawType type) { @@ -2581,130 +2562,145 @@ meta_draw_op_free (MetaDrawOp *op) case META_DRAW_LINE: if (op->data.line.color_spec) meta_color_spec_free (op->data.line.color_spec); - g_free (op->data.line.x1); - g_free (op->data.line.y1); - g_free (op->data.line.x2); - g_free (op->data.line.y2); + + meta_draw_spec_free (op->data.line.x1); + meta_draw_spec_free (op->data.line.y1); + meta_draw_spec_free (op->data.line.x2); + meta_draw_spec_free (op->data.line.y2); break; case META_DRAW_RECTANGLE: if (op->data.rectangle.color_spec) g_free (op->data.rectangle.color_spec); - g_free (op->data.rectangle.x); - g_free (op->data.rectangle.y); - g_free (op->data.rectangle.width); - g_free (op->data.rectangle.height); + + meta_draw_spec_free (op->data.rectangle.x); + meta_draw_spec_free (op->data.rectangle.y); + meta_draw_spec_free (op->data.rectangle.width); + meta_draw_spec_free (op->data.rectangle.height); break; case META_DRAW_ARC: if (op->data.arc.color_spec) g_free (op->data.arc.color_spec); - g_free (op->data.arc.x); - g_free (op->data.arc.y); - g_free (op->data.arc.width); - g_free (op->data.arc.height); + + meta_draw_spec_free (op->data.arc.x); + meta_draw_spec_free (op->data.arc.y); + meta_draw_spec_free (op->data.arc.width); + meta_draw_spec_free (op->data.arc.height); break; case META_DRAW_CLIP: - g_free (op->data.clip.x); - g_free (op->data.clip.y); - g_free (op->data.clip.width); - g_free (op->data.clip.height); + meta_draw_spec_free (op->data.clip.x); + meta_draw_spec_free (op->data.clip.y); + meta_draw_spec_free (op->data.clip.width); + meta_draw_spec_free (op->data.clip.height); break; case META_DRAW_TINT: if (op->data.tint.color_spec) meta_color_spec_free (op->data.tint.color_spec); + if (op->data.tint.alpha_spec) meta_alpha_gradient_spec_free (op->data.tint.alpha_spec); - g_free (op->data.tint.x); - g_free (op->data.tint.y); - g_free (op->data.tint.width); - g_free (op->data.tint.height); + + meta_draw_spec_free (op->data.tint.x); + meta_draw_spec_free (op->data.tint.y); + meta_draw_spec_free (op->data.tint.width); + meta_draw_spec_free (op->data.tint.height); break; case META_DRAW_GRADIENT: if (op->data.gradient.gradient_spec) meta_gradient_spec_free (op->data.gradient.gradient_spec); + if (op->data.gradient.alpha_spec) meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec); - g_free (op->data.gradient.x); - g_free (op->data.gradient.y); - g_free (op->data.gradient.width); - g_free (op->data.gradient.height); + + meta_draw_spec_free (op->data.gradient.x); + meta_draw_spec_free (op->data.gradient.y); + meta_draw_spec_free (op->data.gradient.width); + meta_draw_spec_free (op->data.gradient.height); break; case META_DRAW_IMAGE: if (op->data.image.alpha_spec) meta_alpha_gradient_spec_free (op->data.image.alpha_spec); + if (op->data.image.pixbuf) g_object_unref (G_OBJECT (op->data.image.pixbuf)); + if (op->data.image.colorize_spec) meta_color_spec_free (op->data.image.colorize_spec); + if (op->data.image.colorize_cache_pixbuf) g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)); - g_free (op->data.image.x); - g_free (op->data.image.y); - g_free (op->data.image.width); - g_free (op->data.image.height); + + meta_draw_spec_free (op->data.image.x); + meta_draw_spec_free (op->data.image.y); + meta_draw_spec_free (op->data.image.width); + meta_draw_spec_free (op->data.image.height); break; case META_DRAW_GTK_ARROW: - g_free (op->data.gtk_arrow.x); - g_free (op->data.gtk_arrow.y); - g_free (op->data.gtk_arrow.width); - g_free (op->data.gtk_arrow.height); + meta_draw_spec_free (op->data.gtk_arrow.x); + meta_draw_spec_free (op->data.gtk_arrow.y); + meta_draw_spec_free (op->data.gtk_arrow.width); + meta_draw_spec_free (op->data.gtk_arrow.height); break; case META_DRAW_GTK_BOX: - g_free (op->data.gtk_box.x); - g_free (op->data.gtk_box.y); - g_free (op->data.gtk_box.width); - g_free (op->data.gtk_box.height); + meta_draw_spec_free (op->data.gtk_box.x); + meta_draw_spec_free (op->data.gtk_box.y); + meta_draw_spec_free (op->data.gtk_box.width); + meta_draw_spec_free (op->data.gtk_box.height); break; case META_DRAW_GTK_VLINE: - g_free (op->data.gtk_vline.x); - g_free (op->data.gtk_vline.y1); - g_free (op->data.gtk_vline.y2); + meta_draw_spec_free (op->data.gtk_vline.x); + meta_draw_spec_free (op->data.gtk_vline.y1); + meta_draw_spec_free (op->data.gtk_vline.y2); break; case META_DRAW_ICON: if (op->data.icon.alpha_spec) meta_alpha_gradient_spec_free (op->data.icon.alpha_spec); - g_free (op->data.icon.x); - g_free (op->data.icon.y); - g_free (op->data.icon.width); - g_free (op->data.icon.height); + + meta_draw_spec_free (op->data.icon.x); + meta_draw_spec_free (op->data.icon.y); + meta_draw_spec_free (op->data.icon.width); + meta_draw_spec_free (op->data.icon.height); break; case META_DRAW_TITLE: if (op->data.title.color_spec) meta_color_spec_free (op->data.title.color_spec); - g_free (op->data.title.x); - g_free (op->data.title.y); + + meta_draw_spec_free (op->data.title.x); + meta_draw_spec_free (op->data.title.y); break; case META_DRAW_OP_LIST: if (op->data.op_list.op_list) meta_draw_op_list_unref (op->data.op_list.op_list); - g_free (op->data.op_list.x); - g_free (op->data.op_list.y); - g_free (op->data.op_list.width); - g_free (op->data.op_list.height); + + meta_draw_spec_free (op->data.op_list.x); + meta_draw_spec_free (op->data.op_list.y); + meta_draw_spec_free (op->data.op_list.width); + meta_draw_spec_free (op->data.op_list.height); break; case META_DRAW_TILE: if (op->data.tile.op_list) meta_draw_op_list_unref (op->data.tile.op_list); - g_free (op->data.tile.x); - g_free (op->data.tile.y); - g_free (op->data.tile.width); - g_free (op->data.tile.height); - g_free (op->data.tile.tile_xoffset); - g_free (op->data.tile.tile_yoffset); - g_free (op->data.tile.tile_width); - g_free (op->data.tile.tile_height); + + meta_draw_spec_free (op->data.tile.x); + meta_draw_spec_free (op->data.tile.y); + meta_draw_spec_free (op->data.tile.width); + meta_draw_spec_free (op->data.tile.height); + meta_draw_spec_free (op->data.tile.tile_xoffset); + meta_draw_spec_free (op->data.tile.tile_yoffset); + meta_draw_spec_free (op->data.tile.tile_width); + meta_draw_spec_free (op->data.tile.tile_height); break; } @@ -3258,7 +3254,7 @@ fill_env (MetaPositionExprEnv *env, env->title_width = info->title_layout_width; env->title_height = info->title_layout_height; - env->theme = NULL; /* not required, constants have been optimized out */ + env->theme = meta_current_theme; } static void @@ -3293,7 +3289,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op, } x1 = parse_x_position_unchecked (op->data.line.x1, env); - y1 = parse_y_position_unchecked (op->data.line.y1, env); + y1 = parse_y_position_unchecked (op->data.line.y1, env); x2 = parse_x_position_unchecked (op->data.line.x2, env); y2 = parse_y_position_unchecked (op->data.line.y2, env); @@ -4463,8 +4459,6 @@ meta_frame_style_set_validate (MetaFrameStyleSet *style_set, return TRUE; } -static MetaTheme *meta_current_theme = NULL; - MetaTheme* meta_theme_get_current (void) { @@ -4542,6 +4536,22 @@ meta_theme_new (void) g_free, (GDestroyNotify) meta_frame_style_set_unref); + /* Create our variable quarks so we can look up variables without + having to strcmp for the names */ + theme->quark_width = g_quark_from_static_string ("width"); + theme->quark_height = g_quark_from_static_string ("height"); + theme->quark_object_width = g_quark_from_static_string ("object_width"); + theme->quark_object_height = g_quark_from_static_string ("object_height"); + theme->quark_left_width = g_quark_from_static_string ("left_width"); + theme->quark_right_width = g_quark_from_static_string ("right_width"); + theme->quark_top_height = g_quark_from_static_string ("top_height"); + theme->quark_bottom_height = g_quark_from_static_string ("bottom_height"); + theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width"); + theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height"); + theme->quark_icon_width = g_quark_from_static_string ("icon_width"); + theme->quark_icon_height = g_quark_from_static_string ("icon_height"); + theme->quark_title_width = g_quark_from_static_string ("title_width"); + theme->quark_title_height = g_quark_from_static_string ("title_height"); return theme; } diff --git a/src/theme.h b/src/theme.h index 005842ec3..58a16c42e 100644 --- a/src/theme.h +++ b/src/theme.h @@ -214,10 +214,16 @@ struct _MetaColorSpec MetaColorSpec *foreground; MetaColorSpec *background; double alpha; + + gboolean color_set; + GdkColor color; } blend; struct { MetaColorSpec *base; double factor; + + gboolean color_set; + GdkColor color; } shade; } data; }; @@ -275,6 +281,64 @@ typedef enum META_DRAW_TILE } MetaDrawType; +typedef enum +{ + POS_TOKEN_INT, + POS_TOKEN_DOUBLE, + POS_TOKEN_OPERATOR, + POS_TOKEN_VARIABLE, + POS_TOKEN_OPEN_PAREN, + POS_TOKEN_CLOSE_PAREN +} PosTokenType; + +typedef enum +{ + POS_OP_NONE, + POS_OP_ADD, + POS_OP_SUBTRACT, + POS_OP_MULTIPLY, + POS_OP_DIVIDE, + POS_OP_MOD, + POS_OP_MAX, + POS_OP_MIN +} PosOperatorType; + +typedef struct +{ + PosTokenType type; + + union + { + struct { + int val; + } i; + + struct { + double val; + } d; + + struct { + PosOperatorType op; + } o; + + struct { + char *name; + GQuark name_quark; + } v; + + } d; +} PosToken; + +typedef struct _MetaDrawSpec +{ + int value; + + PosToken *tokens; + int n_tokens; + + gboolean constant : 1; /* Does the expression contain any variables? */ +} MetaDrawSpec; + struct _MetaDrawOp { MetaDrawType type; @@ -287,65 +351,66 @@ struct _MetaDrawOp int dash_on_length; int dash_off_length; int width; - char *x1; - char *y1; - char *x2; - char *y2; + MetaDrawSpec *x1; + MetaDrawSpec *y1; + MetaDrawSpec *x2; + MetaDrawSpec *y2; } line; struct { MetaColorSpec *color_spec; gboolean filled; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; } rectangle; struct { MetaColorSpec *color_spec; gboolean filled; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; double start_angle; double extent_angle; } arc; struct { - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; } clip; struct { MetaColorSpec *color_spec; MetaAlphaGradientSpec *alpha_spec; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; } tint; struct { MetaGradientSpec *gradient_spec; MetaAlphaGradientSpec *alpha_spec; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; } gradient; struct { MetaColorSpec *colorize_spec; MetaAlphaGradientSpec *alpha_spec; GdkPixbuf *pixbuf; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; + guint32 colorize_cache_pixel; GdkPixbuf *colorize_cache_pixbuf; MetaImageFillType fill_type; @@ -358,61 +423,62 @@ struct _MetaDrawOp GtkShadowType shadow; GtkArrowType arrow; gboolean filled; - char *x; - char *y; - char *width; - char *height; + + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; } gtk_arrow; struct { GtkStateType state; GtkShadowType shadow; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; } gtk_box; struct { GtkStateType state; - char *x; - char *y1; - char *y2; + MetaDrawSpec *x; + MetaDrawSpec *y1; + MetaDrawSpec *y2; } gtk_vline; struct { MetaAlphaGradientSpec *alpha_spec; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; MetaImageFillType fill_type; } icon; struct { MetaColorSpec *color_spec; - char *x; - char *y; + MetaDrawSpec *x; + MetaDrawSpec *y; } title; struct { MetaDrawOpList *op_list; - char *x; - char *y; - char *width; - char *height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; } op_list; struct { MetaDrawOpList *op_list; - char *x; - char *y; - char *width; - char *height; - char *tile_xoffset; - char *tile_yoffset; - char *tile_width; - char *tile_height; + MetaDrawSpec *x; + MetaDrawSpec *y; + MetaDrawSpec *width; + MetaDrawSpec *height; + MetaDrawSpec *tile_xoffset; + MetaDrawSpec *tile_yoffset; + MetaDrawSpec *tile_width; + MetaDrawSpec *tile_height; } tile; } data; @@ -597,6 +663,21 @@ struct _MetaTheme MetaFrameStyleSet *style_sets_by_type[META_FRAME_TYPE_LAST]; GdkPixbuf *fallback_icon, *fallback_mini_icon; + + GQuark quark_width; + GQuark quark_height; + GQuark quark_object_width; + GQuark quark_object_height; + GQuark quark_left_width; + GQuark quark_right_width; + GQuark quark_top_height; + GQuark quark_bottom_height; + GQuark quark_mini_icon_width; + GQuark quark_mini_icon_height; + GQuark quark_icon_width; + GQuark quark_icon_height; + GQuark quark_title_width; + GQuark quark_title_height; }; struct _MetaPositionExprEnv @@ -643,16 +724,21 @@ void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout gboolean meta_frame_layout_validate (const MetaFrameLayout *layout, GError **error); -gboolean meta_parse_position_expression (const char *expr, +gboolean meta_parse_position_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *x_return, int *y_return, GError **err); -gboolean meta_parse_size_expression (const char *expr, +gboolean meta_parse_size_expression (MetaDrawSpec *spec, const MetaPositionExprEnv *env, int *val_return, GError **err); +MetaDrawSpec* meta_draw_spec_new (MetaTheme *theme, + const char *expr, + GError **error); +void meta_draw_spec_free (MetaDrawSpec *spec); + MetaColorSpec* meta_color_spec_new (MetaColorSpecType type); MetaColorSpec* meta_color_spec_new_from_string (const char *str, GError **err); @@ -833,9 +919,10 @@ gboolean meta_theme_lookup_color_constant (MetaTheme *theme, const char *name, char **value); -char* meta_theme_replace_constants (MetaTheme *theme, - const char *expr, - GError **err); +gboolean meta_theme_replace_constants (MetaTheme *theme, + PosToken *tokens, + int n_tokens, + GError **err); /* random stuff */ @@ -877,6 +964,7 @@ const char* meta_image_fill_type_to_string (MetaImageFillType f guint meta_theme_earliest_version_with_button (MetaButtonType type); + #define META_THEME_ALLOWS(theme, feature) (theme->format_version >= feature) /* What version of the theme file format were various features introduced in? */ diff --git a/src/ui.c b/src/ui.c index 452dcbefc..5d35febb7 100644 --- a/src/ui.c +++ b/src/ui.c @@ -961,3 +961,34 @@ meta_ui_get_direction (void) return META_UI_DIRECTION_LTR; } + +GdkPixbuf * +meta_ui_get_pixbuf_from_pixmap (Pixmap pmap) +{ + GdkPixmap *gpmap; + GdkScreen *screen; + GdkPixbuf *pixbuf; + GdkColormap *cmap; + int width, height, depth; + + gpmap = gdk_pixmap_foreign_new (pmap); + screen = gdk_drawable_get_screen (gpmap); + + gdk_drawable_get_size (GDK_DRAWABLE (gpmap), &width, &height); + + depth = gdk_drawable_get_depth (GDK_DRAWABLE (gpmap)); + if (depth <= 24) + cmap = gdk_screen_get_rgb_colormap (screen); + else + cmap = gdk_screen_get_rgba_colormap (screen); + + pixbuf = gdk_pixbuf_get_from_drawable (NULL, gpmap, cmap, 0, 0, 0, 0, + width, height); + + g_object_unref (gpmap); + + return pixbuf; +} + + + diff --git a/src/ui.h b/src/ui.h index 4ca4afcbc..a4d7fea7d 100644 --- a/src/ui.h +++ b/src/ui.h @@ -202,6 +202,8 @@ int meta_ui_get_drag_threshold (MetaUI *ui); MetaUIDirection meta_ui_get_direction (void); +GdkPixbuf *meta_ui_get_pixbuf_from_pixmap (Pixmap pmap); + #include "tabpopup.h" #endif