expocity -- Exposé implementation for metacity



Hi all,

I have implemented expocity, an Exposé-like feature for metacity.
It would be great if anyone is interested in integrating the
patch into metacity CVS.
The (attached) patch applies on the CVS metacity from today and,
as an addon, doesn't actually touch very much of metacity's
original code.

The window thumbnails appear when pressing Alt+Tab currently,
which replaces the tablist. It would be good if someone with
more knowledge about metacity's code moves it to a free
keystroke.

expocity works without the new XDamage extension and can thus run
on a standard X-Server. XDamage support could be added later
without too many problems, I think.

More information and a screenshot can be found at
http://www.pycage.de/expocity.html

What do you think about this?


Martin

diff -urN metacity/src/display.c metacity.new/src/display.c
--- metacity/src/display.c	2003-11-23 19:16:01.000000000 +0100
+++ metacity.new/src/display.c	2003-11-24 20:15:01.000000000 +0100
@@ -56,6 +56,8 @@
 #endif
 #include <string.h>
 
+#include "expocity.h"
+
 #define USE_GDK_DISPLAY
 
 typedef struct 
@@ -1302,7 +1304,19 @@
   meta_compositor_process_event (display->compositor,
                                  event,
                                  window);
-  
+
+  /* these are the window events at which expocity updates the thumbnail image
+     of the window */
+  switch (event->type)
+    {
+    case CreateNotify:
+    case ButtonRelease:
+    case KeyRelease:
+    case FocusIn:
+    case FocusOut:
+      expocity_grab_window(window);
+    }
+
   switch (event->type)
     {
     case KeyPress:
diff -urN metacity/src/expocity.c metacity.new/src/expocity.c
--- metacity/src/expocity.c	1970-01-01 01:00:00.000000000 +0100
+++ metacity.new/src/expocity.c	2003-11-24 15:16:03.000000000 +0100
@@ -0,0 +1,625 @@
+/* expocity window switching extension for metacity
+ * Copyright (C) 2003 Martin Grimme
+ */
+
+/* 
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2002 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 "expocity.h"
+
+static Thumbnail* thumbnail_new (MetaWindow* window);
+static void thumbnail_set_pixbuf (Thumbnail* thumb, GdkPixbuf* pixbuf);
+static void thumbnail_set_position (Thumbnail* thumb, int x, int y);
+static void thumbnail_set_size (Thumbnail* thumb, int width, int height);
+static void thumbnail_get_position (Thumbnail* thumb, int* x, int* y);
+static void thumbnail_get_size (Thumbnail* thumb, int* width, int* height);
+static GdkPixbuf* thumbnail_get_pixbuf (Thumbnail* thumb);
+static GtkWidget* thumbnail_make_window (Thumbnail* thumb, float scale);
+
+static gboolean on_select_window (GtkWidget* src, GdkEventButton* event,
+				   MetaWindow* window);
+static gboolean on_enter_window (GtkWidget* src, GdkEvent* event,
+				  GtkWidget* tint);
+static gboolean on_leave_window (GtkWidget* src, GdkEvent* event,
+				  GtkWidget* tint);
+
+static GdkRegion* get_uncovered_areas (MetaWindow* window,
+					gboolean is_recursive);
+static void get_window_rectangle (MetaWindow* window, int* x, int* y,
+				   int* width, int* height);
+
+static gboolean attract_point (int* x, int* y, int px, int py,
+			       double strength);
+static void layout_windows (GSList* thumbnails, int* total_width,
+			    int* total_height);
+
+
+static GHashTable* all_thumbnails;
+static GSList* thumbnails = NULL;
+
+/* the list of open thumbnail windows is required for closing the thumbnail
+   windows again */
+static GSList* open_windows = NULL;
+
+/* while this lock is set, expocity may not grab the contents of windows */
+static gboolean grab_lock = FALSE;
+
+/* while this lock is set, user actions are ignored */
+static gboolean action_lock = TRUE;
+
+
+static Thumbnail*
+thumbnail_new (MetaWindow* window)
+{
+  Thumbnail* thumb;
+
+  thumb = g_new(Thumbnail, 1);
+  thumb->window = window;
+  thumb->pixbuf = NULL;
+  thumb->x = 0;
+  thumb->y = 0;
+  thumb->width = 0;
+  thumb->height = 0;
+  return thumb;
+}
+
+static void
+thumbnail_set_pixbuf (Thumbnail* thumb,
+		       GdkPixbuf* pixbuf)
+{
+  if (thumb->pixbuf != NULL) gdk_pixbuf_unref(thumb->pixbuf);
+  thumb->pixbuf = pixbuf;
+}
+
+static void
+thumbnail_set_position (Thumbnail* thumb,
+			 int x,
+			 int y)
+{
+  thumb->x = x;
+  thumb->y = y;
+}
+
+static void
+thumbnail_set_size (Thumbnail* thumb,
+		     int width,
+		     int height)
+{
+  thumb->width = width;
+  thumb->height = height;
+}
+
+static void
+thumbnail_get_position (Thumbnail* thumb,
+			 int* x,
+			 int* y)
+{
+  *x = thumb->x;
+  *y = thumb->y;
+}
+
+static void
+thumbnail_get_size (Thumbnail* thumb,
+		     int* width,
+		     int* height)
+{
+  *width = thumb->width;
+  *height = thumb->height;
+}
+
+static GdkPixbuf*
+thumbnail_get_pixbuf (Thumbnail* thumb)
+{
+  return thumb->pixbuf;
+}
+
+static GtkWidget*
+thumbnail_make_window (Thumbnail* thumb,
+			float scale)
+{
+  GtkTooltips* tooltip;
+  GtkWidget* thumbwin;
+  GtkWidget* frame;
+  GtkWidget* fixed;
+  GdkPixbuf* scaled;
+  GtkWidget* img;
+  GdkPixbuf* tint;
+  GtkWidget* tintimg;
+  int width, height;
+
+  width = gdk_pixbuf_get_width(thumb->pixbuf) * scale;
+  height = gdk_pixbuf_get_height(thumb->pixbuf) * scale;
+
+  thumbwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  frame = gtk_frame_new(NULL);
+  gtk_widget_show(frame);
+  gtk_container_add(GTK_CONTAINER(thumbwin), frame);
+
+  fixed = gtk_fixed_new();
+  gtk_widget_show(fixed);
+  gtk_container_add(GTK_CONTAINER(frame), fixed);
+
+  scaled = gdk_pixbuf_scale_simple(thumb->pixbuf, width, height,
+				   GDK_INTERP_BILINEAR);
+  img = gtk_image_new_from_pixbuf(scaled);
+  gdk_pixbuf_unref(scaled);
+  gtk_widget_show(img);
+  gtk_fixed_put(GTK_FIXED(fixed), img, 0, 0);
+
+  tint = gdk_pixbuf_composite_color_simple(thumb->pixbuf, width, height,
+					   GDK_INTERP_BILINEAR, 200, 20,
+					   0x00ffaa, 0x00ffaa);
+  tintimg = gtk_image_new_from_pixbuf(tint);
+  gdk_pixbuf_unref(tint);
+  gtk_fixed_put(GTK_FIXED(fixed), tintimg, 0, 0);
+  
+  g_signal_connect(thumbwin, "button-press-event",
+		   G_CALLBACK(on_select_window), thumb->window);
+  g_signal_connect(thumbwin, "enter-notify-event",
+		   G_CALLBACK(on_enter_window), tintimg);
+  g_signal_connect(thumbwin, "leave-notify-event",
+		   G_CALLBACK(on_leave_window), tintimg);
+  gtk_widget_add_events(thumbwin,
+			GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
+			GDK_LEAVE_NOTIFY_MASK);
+
+  tooltip = gtk_tooltips_new();
+  gtk_tooltips_set_tip(tooltip, thumbwin, thumb->window->title, "");
+
+  return thumbwin;
+}
+
+
+/* Initializes expocity. This has to be done before calling any other expocity
+ * functions.
+ */
+void
+expocity_init ()
+{
+  all_thumbnails = g_hash_table_new(NULL, NULL);
+}
+
+
+
+/* Returns the uncovered areas of the given window as a GdkRegion.
+ */
+static GdkRegion*
+get_uncovered_areas (MetaWindow* window,
+		     gboolean is_recursive)
+{
+  MetaWindow* above_window;
+  int x, y, width, height;
+  MetaRectangle outer_rect;
+  GdkRectangle* this_rectangle;
+  GdkRegion* this_region;
+  GdkRegion* above_region;
+
+  this_rectangle = g_new(GdkRectangle, 1);
+  if (is_recursive)
+    {
+      meta_window_get_outer_rect(window, &outer_rect);
+      x = outer_rect.x;
+      y = outer_rect.y;
+      width = outer_rect.width;
+      height = outer_rect.height;
+    }
+  else
+    get_window_rectangle(window, &x, &y, &width, &height);
+
+  this_rectangle->x = x;
+  this_rectangle->y = y;
+  this_rectangle->width = width;
+  this_rectangle->height = height;
+  this_region = gdk_region_rectangle(this_rectangle);
+  g_free(this_rectangle);
+
+  above_window = meta_stack_get_above(window->screen->stack, window, FALSE);
+  if (above_window != NULL)
+    {
+      above_region = get_uncovered_areas(above_window, TRUE);
+      if (is_recursive)
+	gdk_region_union(this_region, above_region);
+      else
+	gdk_region_subtract(this_region, above_region);
+      g_free(above_region);
+    }
+
+  return this_region;
+}
+
+
+/* Returns the geometry rectangle of the given window. This does not include
+ * the window's frame.
+ */
+static void
+get_window_rectangle (MetaWindow* window,
+		      int* x,
+		      int* y,
+		      int* width,
+		      int* height)
+{
+  meta_window_get_geometry(window, x, y,
+			   width, height);
+
+  /* ignore the window frame */
+  if (window->frame != NULL)
+    {
+      *x += window->rect.x;
+      *y += window->rect.y;
+    }
+  *width = window->rect.width;
+  *height = window->rect.height;
+}
+
+
+
+/* Grabs the contents of the currently visible parts of the given window.
+ */
+gboolean
+expocity_grab_window (MetaWindow* window)
+{
+  GdkRectangle screen_rect;
+  GdkRegion* screen_region;
+  GdkRegion* uncovered_region;
+  GdkRectangle* region_rects;
+  int region_rects_number;
+  int i;
+  GdkPixbuf* pixbuf = NULL;
+  int window_x, window_y, window_width, window_height;
+  Thumbnail* thumb;
+
+  /* do nothing when there's no window or grabbing is locked */
+  if (window == NULL || window->shaded || window->minimized ||
+      grab_lock == TRUE)
+    return FALSE;
+
+  get_window_rectangle(window, &window_x, &window_y,
+			&window_width, &window_height);
+  if (window_width == 0 || window_height == 0) return FALSE;
+
+
+  thumb = g_hash_table_lookup(all_thumbnails, window);
+  if (thumb == NULL)
+    {
+      thumb = thumbnail_new(window);
+      g_hash_table_insert(all_thumbnails, window, thumb);
+    }
+
+  /* get the uncovered regions and intersect it with the screen to eliminate
+     offscreen areas */
+  uncovered_region = get_uncovered_areas(window, FALSE);
+  screen_rect.x = 0; screen_rect.y = 0;
+  screen_rect.width = gdk_screen_width();
+  screen_rect.height = gdk_screen_height();
+  screen_region = gdk_region_rectangle(&screen_rect);
+  gdk_region_intersect(uncovered_region, screen_region);
+  gdk_region_get_rectangles(uncovered_region, &region_rects,
+			    &region_rects_number);
+  g_free(screen_region);
+  g_free(uncovered_region);
+
+  pixbuf = thumbnail_get_pixbuf(thumb);
+  if (pixbuf == NULL || gdk_pixbuf_get_width(pixbuf) != window_width ||
+      gdk_pixbuf_get_height(pixbuf) != window_height)
+    {
+      /* create a new thumbnail if there's none or if the size has changed */
+      pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
+			      window_width, window_height);
+      thumbnail_set_pixbuf(thumb, pixbuf);
+      thumbnail_set_size(thumb, window_width, window_height);
+    }
+      
+  for (i = 0; i < region_rects_number; i++)
+    {
+      gdk_pixbuf_get_from_drawable(pixbuf, gdk_get_default_root_window(), NULL,
+				   region_rects[i].x, region_rects[i].y,
+				   region_rects[i].x - window_x,
+				   region_rects[i].y - window_y,
+				   region_rects[i].width,
+				   region_rects[i].height);
+    }
+  g_free(region_rects);
+
+  return FALSE;
+}
+
+
+/* Frees the memory that expocity has allocated for the given window.
+ */
+void
+expocity_free_window (MetaWindow* window)
+{
+  Thumbnail* thumb;
+
+  thumb = g_hash_table_lookup(all_thumbnails, window);
+  if (thumb != NULL) {
+    gdk_pixbuf_unref(thumbnail_get_pixbuf(thumb));
+  }
+  g_hash_table_remove(all_thumbnails, window);
+}
+
+
+static gboolean
+on_select_window (GtkWidget* src,
+		   GdkEventButton* event,
+		   MetaWindow* window)
+{
+  GSList* iter;
+  GtkWidget* thumbnail;
+
+  if (action_lock == TRUE) return TRUE;
+
+  meta_screen_unshow_desktop(window->screen);
+  meta_window_activate(window, event->time);
+
+  iter = open_windows;
+  while (iter != NULL)
+    {
+      thumbnail = GTK_WIDGET(iter->data);
+      gtk_widget_hide(thumbnail);
+      gtk_widget_destroy(thumbnail);
+      iter = iter->next;
+    }
+  g_slist_free(open_windows);
+  g_slist_free(thumbnails);
+  thumbnails = NULL;
+
+  grab_lock = FALSE;
+  action_lock = TRUE;
+  return TRUE;
+}
+
+
+static gboolean
+on_enter_window (GtkWidget* src,
+		  GdkEvent* event,
+		  GtkWidget* tint)
+{
+  if (action_lock == FALSE) gtk_widget_show(tint);
+  return TRUE;
+}
+
+
+static gboolean
+on_leave_window (GtkWidget* src,
+		  GdkEvent* event,
+		  GtkWidget* tint)
+{
+  gtk_widget_hide(tint);
+  return TRUE;
+}
+
+
+
+/* Attracts the point (x, y) to the point (px, py) depending on the strength.
+ * Returns if (x, y) has changed.
+ */
+static gboolean
+attract_point (int* x,
+	       int* y,
+	       int px,
+	       int py,
+	       double strength)
+{
+  int prev_x = *x, prev_y = *y;
+  double att_vector[] = {px - *x, py - *y};
+  double length;
+  gboolean changed = TRUE;
+
+  /* normalize the attraction vector and scale it by the strength */
+  length = sqrt(att_vector[0] * att_vector[0] + att_vector[1] * att_vector[1]);
+  if (abs(strength) > length) length = abs(strength);
+  if (length >= 1)
+    {
+      att_vector[0] *= strength / length;
+      att_vector[1] *= strength / length;
+      *x += att_vector[0];
+      *y += att_vector[1];
+    }
+
+  if (abs(prev_x - *x) < 1 && abs(prev_y - *y) < 1) changed = FALSE;
+  
+  return changed;
+}
+
+
+
+/* Computes a layout for the thumbnail windows and returns the total size of
+ * the layout.
+ * The algorithm works like this:
+ * For n elements, you will have ceil(sqrt(n)) elements per line.
+ * Elements are arranged in slots from left to right, top to bottom.
+ * A slot can contain several elements arranged vertically, if the line still
+ * has space left for additional elements.
+ * The highest element in a line determines the space available for the line.
+ */
+static void
+layout_windows (GSList* thumbnails,
+		int* total_width,
+		int* total_height)
+{
+  int slots[g_slist_length(thumbnails)][4];
+  int slots_number = 0;
+  int line_max[(int) sqrt(g_slist_length(thumbnails))];
+  int i, j;
+  int current_line = 0;
+  int line_length = 0;
+  int cx = 0, cy = 0;
+  GSList* iter;
+  Thumbnail* thumbnail;
+  int thumb_x, thumb_y, thumb_width, thumb_height;
+  gboolean have_place;
+  int items_per_line;
+  int DISTANCE = 50;
+
+  *total_width = 0;
+  *total_height = 0;  
+  items_per_line = (int) (sqrt(g_slist_length(thumbnails)) + 0.5);
+  line_max[0] = 0;
+
+  slots[0][0] = 0;
+  slots[0][1] = 0;
+  slots[0][2] = 0;
+  slots[0][3] = 0;
+  for (iter = thumbnails; iter != NULL; iter = iter->next)
+    {
+      thumbnail = (Thumbnail*) iter->data;
+      thumbnail_get_position(thumbnail, &thumb_x, &thumb_y);
+      thumbnail_get_size(thumbnail, &thumb_width, &thumb_height);
+      have_place = FALSE;
+
+      /* find a good place between other elements */
+      for (i = 0; i < slots_number; i++)
+	{
+	  j = slots[i][3];
+	  if (thumb_width < slots[i][2] &&
+	      slots[i][1] + thumb_height <= line_max[j])
+	    {
+	      thumb_x = slots[i][0];
+	      thumb_y = slots[i][1];
+	      slots[i][1] += thumb_height + DISTANCE;
+	      have_place = TRUE;
+	      break;
+	    }  
+	}
+
+      /* otherwise append or start a new line */
+      if (have_place == FALSE && line_length < items_per_line)
+	{
+	  thumb_x = cx;
+	  thumb_y = cy;
+	  line_length++;
+	  slots_number++;
+	  slots[slots_number][0] = thumb_x;
+	  slots[slots_number][1] = thumb_y + thumb_height + DISTANCE;
+	  slots[slots_number][2] = thumb_width;
+	  slots[slots_number][3] = current_line;
+	  cx += thumb_width + DISTANCE;
+	  line_max[current_line] = MAX(line_max[current_line],
+				       cy + thumb_height);
+	
+	}
+      else if (have_place == FALSE)
+	{
+	  current_line++;
+	  line_length = 1;
+	  cx = 0;
+	  cy = line_max[current_line - 1] + DISTANCE;
+	  line_max[current_line] = cy + thumb_height;
+	  thumb_x = cx;
+	  thumb_y = cy;
+	  slots_number++;
+	  slots[slots_number][0] = thumb_x;
+	  slots[slots_number][1] = thumb_y + thumb_height + DISTANCE;
+	  slots[slots_number][2] = thumb_width;
+	  slots[slots_number][3] = current_line;
+	  cx += thumb_width + DISTANCE;
+	}
+
+      thumbnail_set_position(thumbnail, thumb_x, thumb_y);
+      *total_width = MAX(*total_width, thumb_x + thumb_width);
+      *total_height = MAX(*total_height, thumb_y + thumb_height);
+    }
+}
+
+
+/* Layouts and displays the window thumbnails.
+ */
+void
+expocity_run (MetaDisplay* display,
+	      MetaScreen* screen)
+{
+  GtkWidget* thumbwin;
+  GList* windowlist;
+  GList* iter;
+  GSList* iter2;
+  MetaWindow* key;
+  Thumbnail* value;
+  int x, y;
+  float scale;
+  int total_width, total_height;
+  float angle = 0.0;
+  float step;
+  gboolean changed = TRUE;
+
+  if (grab_lock == TRUE) return;
+  grab_lock = TRUE;
+  windowlist = meta_display_get_tab_list(display, META_TAB_LIST_NORMAL,
+					 screen, screen->active_workspace);
+  thumbnails = NULL;
+  open_windows = NULL;
+  for (iter = windowlist; iter != NULL; iter = iter->next)
+    {
+      key = iter->data;
+      value = g_hash_table_lookup(all_thumbnails, key);
+      if (value != NULL) thumbnails = g_slist_append(thumbnails, value);
+    }
+  g_list_free(windowlist);
+
+  if (g_slist_length(thumbnails) == 0)
+    {
+      grab_lock = FALSE;
+      return;
+    }
+  meta_screen_show_desktop(screen);
+
+  if (thumbnails != NULL)
+    layout_windows(thumbnails, &total_width, &total_height);
+
+  scale = MIN(((double) gdk_screen_width() - 24) / total_width,
+	      ((double) gdk_screen_height() - 24) / total_height);
+  scale = MIN(scale, 1.0);
+
+  step = 6.2831853 / g_slist_length(thumbnails);
+  for (iter2 = thumbnails; iter2 != NULL; iter2 = iter2->next)
+    {
+      thumbwin = thumbnail_make_window(iter2->data, scale);
+      thumbnail_get_position(iter2->data, &x, &y);
+      gtk_window_move(GTK_WINDOW(thumbwin),
+	       gdk_screen_width() / 2 - cos(angle) * 2 * gdk_screen_width(),
+	       gdk_screen_height() / 2 - sin(angle) * 2 * gdk_screen_height());
+      g_object_set_data(G_OBJECT(thumbwin), "x",
+	GINT_TO_POINTER((int) ((gdk_screen_width() - total_width * scale) /
+			       2 + x * scale)));
+      g_object_set_data(G_OBJECT(thumbwin), "y",
+        GINT_TO_POINTER((int) ((gdk_screen_height() - total_height * scale) /
+			       2 + y * scale)));
+      gtk_widget_show(thumbwin);
+      open_windows = g_slist_append(open_windows, thumbwin);
+      angle += step;
+    }
+
+  while (changed == TRUE)
+    {
+      changed = FALSE;
+      for (iter2 = open_windows; iter2 != NULL; iter2 = iter2->next)
+	{
+	  gtk_window_get_position(GTK_WINDOW(iter2->data), &x, &y);
+	  changed |= attract_point(&x, &y,
+	       GPOINTER_TO_INT(g_object_get_data(G_OBJECT(iter2->data), "x")),
+	       GPOINTER_TO_INT(g_object_get_data(G_OBJECT(iter2->data), "y")),
+				   30);
+	  gtk_window_move(GTK_WINDOW(iter2->data), x, y);
+	}
+      while (gtk_events_pending()) gtk_main_iteration();
+    }
+
+  action_lock = FALSE;
+}
diff -urN metacity/src/expocity.h metacity.new/src/expocity.h
--- metacity/src/expocity.h	1970-01-01 01:00:00.000000000 +0100
+++ metacity.new/src/expocity.h	2003-11-24 14:41:55.000000000 +0100
@@ -0,0 +1,53 @@
+/* expocity window switching extension for metacity
+ * Copyright (C) 2003 Martin Grimme
+ */
+
+/* 
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2002 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.
+ */
+
+#ifndef EXPOCITY_H
+#define EXPOCITY_H
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include "window.h"
+#include "display.h"
+#include "screen.h"
+#include <math.h>
+
+typedef struct _Thumbnail Thumbnail;
+
+/* structure for storing a thumbnail and its layouted geometry */
+struct _Thumbnail
+{
+  MetaWindow* window;
+  GdkPixbuf* pixbuf;
+  int x;
+  int y;
+  int width;
+  int height;
+};
+
+void expocity_init (void);
+gboolean expocity_grab_window (MetaWindow* window);
+void expocity_free_window (MetaWindow* window);
+void expocity_run (MetaDisplay* display, MetaScreen* screen);
+
+#endif
diff -urN metacity/src/keybindings.c metacity.new/src/keybindings.c
--- metacity/src/keybindings.c	2003-10-12 08:25:38.000000000 +0200
+++ metacity.new/src/keybindings.c	2003-11-24 20:05:12.000000000 +0100
@@ -29,6 +29,8 @@
 #include "prefs.h"
 #include "effects.h"
 
+#include "expocity.h"
+
 #include <X11/keysym.h>
 #include <string.h>
 #include <stdio.h>
@@ -2912,7 +2914,10 @@
 {
   MetaTabList type;
   MetaWindow *initial_selection;
-  
+
+  expocity_run(display, screen);
+  return;  
+
   type = GPOINTER_TO_INT (binding->handler->data);
   
   meta_topic (META_DEBUG_KEYBINDINGS,
diff -urN metacity/src/main.c metacity.new/src/main.c
--- metacity/src/main.c	2003-11-16 05:20:17.000000000 +0100
+++ metacity.new/src/main.c	2003-11-24 20:06:10.000000000 +0100
@@ -28,6 +28,8 @@
 #include "session.h"
 #include "prefs.h"
 
+#include "expocity.h"
+
 #include <glib-object.h>
 #include <gmodule.h>
 #ifdef HAVE_GCONF
@@ -389,6 +391,9 @@
   /* must be after UI init so we can override GDK handlers */
   meta_errors_init ();
 
+  /* initialize the expocity addon */
+  expocity_init();
+
 #if 1
   g_log_set_handler (NULL,
                      G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
diff -urN metacity/src/Makefile.am metacity.new/src/Makefile.am
--- metacity/src/Makefile.am	2003-11-16 05:20:17.000000000 +0100
+++ metacity.new/src/Makefile.am	2003-11-24 20:07:55.000000000 +0100
@@ -31,6 +31,8 @@
 	errors.h				\
 	eventqueue.c				\
 	eventqueue.h				\
+        expocity.c                              \
+        expocity.h                              \
 	fixedtip.c				\
 	fixedtip.h				\
 	frame.c					\
diff -urN metacity/src/window.c metacity.new/src/window.c
--- metacity/src/window.c	2003-11-21 03:32:05.000000000 +0100
+++ metacity.new/src/window.c	2003-11-24 20:06:59.000000000 +0100
@@ -40,6 +40,8 @@
 #include "window-props.h"
 #include "constraints.h"
 
+#include "expocity.h"
+
 #include <X11/Xatom.h>
 #include <string.h>
 
@@ -1041,6 +1043,7 @@
 
   meta_icon_cache_free (&window->icon_cache);
   
+  expocity_free_window (window);
   g_free (window->sm_client_id);
   g_free (window->wm_client_machine);
   g_free (window->startup_id);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]