Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Nov 2003 18:21:25 -0600
From:      Jeremy Messenger <mezz7@cox.net>
To:        Sean Welch <Sean_Welch@alum.wofford.org>
Cc:        freebsd-gnome@freebsd.org
Subject:   Re: Metacity with Expocity
Message-ID:  <opry7xxzf18ckrg5@smtp.central.cox.net>
In-Reply-To: <12675899.1069777110965.JavaMail.root@bigbird.psp.pas.earthlink.net>
References:  <12675899.1069777110965.JavaMail.root@bigbird.psp.pas.earthlink.net>

next in thread | previous in thread | raw e-mail | index | archive | help
------------fdwcsBtuTPpdvuVktwh6R9
Content-Type: text/plain; format=flowed; charset=iso-8859-1
Content-Transfer-Encoding: 8bit

On Tue, 25 Nov 2003 10:18:30 -0600 (GMT-06:00), Sean Welch 
<welchsm@earthlink.net> wrote:

> I just saw this article:
>
> http://slashdot.org/articles/03/11/25/0330208.shtml?tid=131&tid=179&tid=185&tid=189&tid=190
>
> an took a look at the patch here:
>
> http://www.pycage.de/download/expocity-11-24-03.diff
>
> Figuring to give it a try, I got it to compile and install but the 
> keystroke that is supposed to
> activate it (Alt-Tab) doesn't do anything now.  Perhaps someone else 
> might have a better
> idea what to do with it and how to track the problem down???  It did 
> compile cleanly...
<snip>

Because, it never has been patch clean if you read the messages of patch. 
Looks like the diff was created against the CVS or development version of 
Metacity. Or maybe older version of Metacity, I dunno.

That got me curious, I don't understand what's advantage of it. So, I 
cleaned the patch and make it easier for other users. You should be able 
to use this attach and put it in the x11-wm/metacity/files/ and do the 
'make -DFORCE_PKG_REGISTER install', then restart Metacity. I just played 
with it and it works, but I don't really like it thought. Maybe, I will 
like it if they make it more smaller and can stay in the background when I 
am doing with vim, browser or whatever. :-)

BTW: Be sure to your Metacity version is 2.6.3 if you want to use an 
attach of patch-expocity.

Cheers,
Mezz


-- 
bsdforums.org 's moderator, mezz.
------------fdwcsBtuTPpdvuVktwh6R9
Content-Disposition: attachment; filename=patch-expocity
Content-Type: application/octet-stream; name=patch-expocity
Content-Transfer-Encoding: 8bit

diff -urN src/Makefile.am.orig src/Makefile.am
--- src/Makefile.am.orig	Fri Sep 26 12:04:37 2003
+++ src/Makefile.am	Tue Nov 25 17:59:17 2003
@@ -29,6 +29,8 @@
 	errors.h				\
 	eventqueue.c				\
 	eventqueue.h				\
+	expocity.c				\
+	expocity.h				\
 	fixedtip.c				\
 	fixedtip.h				\
 	frame.c					\
diff -urN src/Makefile.in.orig src/Makefile.in
--- src/Makefile.in.orig	Mon Oct 27 18:43:56 2003
+++ src/Makefile.in	Tue Nov 25 18:01:38 2003
@@ -154,6 +154,8 @@
 	errors.h				\
 	eventqueue.c				\
 	eventqueue.h				\
+	expocity.c				\
+	expocity.h				\
 	fixedtip.c				\
 	fixedtip.h				\
 	frame.c					\
@@ -323,7 +325,7 @@
 metacity_OBJECTS =  async-getprop.$(OBJEXT) bell.$(OBJEXT) \
 constraints.$(OBJEXT) core.$(OBJEXT) delete.$(OBJEXT) display.$(OBJEXT) \
 draw-workspace.$(OBJEXT) effects.$(OBJEXT) errors.$(OBJEXT) \
-eventqueue.$(OBJEXT) fixedtip.$(OBJEXT) frame.$(OBJEXT) \
+eventqueue.$(OBJEXT) expocity.$(OBJEXT) fixedtip.$(OBJEXT) frame.$(OBJEXT) \
 frames.$(OBJEXT) gradient.$(OBJEXT) group.$(OBJEXT) \
 group-props.$(OBJEXT) iconcache.$(OBJEXT) keybindings.$(OBJEXT) \
 main.$(OBJEXT) menu.$(OBJEXT) metaaccellabel.$(OBJEXT) place.$(OBJEXT) \
diff -urN src/display.c.orig src/display.c
--- src/display.c.orig	Mon Oct 13 15:15:40 2003
+++ src/display.c	Tue Nov 25 17:52:51 2003
@@ -54,6 +54,8 @@
 #endif
 #include <string.h>
 
+#include "expocity.h"
+
 #define USE_GDK_DISPLAY
 
 typedef struct 
@@ -1286,7 +1288,19 @@
         }
     }
 #endif /* HAVE_SHAPE */
-  
+
+  /* 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 src/expocity.c.orig src/expocity.c
--- src/expocity.c.orig	Wed Dec 31 18:00:00 1969
+++ src/expocity.c	Tue Nov 25 17:54:05 2003
@@ -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 src/expocity.h.orig src/expocity.h
--- src/expocity.h.orig	Wed Dec 31 18:00:00 1969
+++ src/expocity.h	Tue Nov 25 17:54:12 2003
@@ -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 src/keybindings.c.orig src/keybindings.c
--- src/keybindings.c.orig	Mon Sep 29 11:55:25 2003
+++ src/keybindings.c	Tue Nov 25 17:56:20 2003
@@ -28,6 +28,8 @@
 #include "place.h"
 #include "prefs.h"
 
+#include "expocity.h"
+
 #include <X11/keysym.h>
 #include <string.h>
 #include <stdio.h>
@@ -2779,7 +2781,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 src/main.c.orig src/main.c
--- src/main.c.orig	Mon Sep 29 11:55:26 2003
+++ src/main.c	Tue Nov 25 17:57:58 2003
@@ -28,6 +28,8 @@
 #include "session.h"
 #include "prefs.h"
 
+#include "expocity.h"
+
 #include <glib-object.h>
 #include <gmodule.h>
 #ifdef HAVE_GCONF
@@ -388,6 +390,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,
diff -urN src/window.c.orig src/window.c
--- src/window.c.orig	Sun Oct 26 10:22:54 2003
+++ src/window.c	Tue Nov 25 18:00:43 2003
@@ -40,6 +40,8 @@
 #include "window-props.h"
 #include "constraints.h"
 
+#include "expocity.h"
+
 #include <X11/Xatom.h>
 #include <string.h>
 
@@ -1019,7 +1021,8 @@
     g_object_unref (G_OBJECT (window->mini_icon));
 
   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);

------------fdwcsBtuTPpdvuVktwh6R9--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?opry7xxzf18ckrg5>