summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2001-09-16 00:30:45 +0000
committerHavoc Pennington <hp@src.gnome.org>2001-09-16 00:30:45 +0000
commit39df21227d00fa4c2d37b413a5432c6a36b61d98 (patch)
tree010a3c220b7c184889aacf973fe8d8aa265d2150
parent2830c9d74862700fdecd19675e8e5d4432afac38 (diff)
downloadmetacity-39df21227d00fa4c2d37b413a5432c6a36b61d98.tar.gz
add support for a mini icon in the titlebar (update_icon): re-enable
2001-09-15 Havoc Pennington <hp@pobox.com> * src/window.c: add support for a mini icon in the titlebar (update_icon): re-enable support for _NET_WM_ICON * src/session.c (save_state): add an ferror check when writing session file
-rw-r--r--ChangeLog13
-rw-r--r--configure.in10
-rw-r--r--src/Makefile.am8
-rw-r--r--src/core.c16
-rw-r--r--src/core.h3
-rw-r--r--src/frames.c71
-rw-r--r--src/main.c2
-rw-r--r--src/msm/client.c30
-rw-r--r--src/msm/gtkdisclosurebox.c359
-rw-r--r--src/msm/gtkdisclosurebox.h76
-rw-r--r--src/msm/props.c141
-rw-r--r--src/msm/props.h28
-rw-r--r--src/msm/session.c272
-rw-r--r--src/screen.h2
-rw-r--r--src/session.c24
-rw-r--r--src/ui.c10
-rw-r--r--src/ui.h1
-rw-r--r--src/window.c142
-rw-r--r--src/window.h1
19 files changed, 1127 insertions, 82 deletions
diff --git a/ChangeLog b/ChangeLog
index 7ff916dd..c567d976 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2001-09-15 Havoc Pennington <hp@pobox.com>
+
+ * src/window.c: add support for a mini icon in the titlebar
+ (update_icon): re-enable support for _NET_WM_ICON
+
+ * src/session.c (save_state): add an ferror check when writing
+ session file
+
+2001-09-11 Havoc Pennington <hp@pobox.com>
+
+ * src/main.c (usage): exit with error code on usage() (kind of
+ wrong for --help, but oh well).
+
2001-09-11 Havoc Pennington <hp@pobox.com>
* src/window.c: fix up handling of text properties, so we
diff --git a/configure.in b/configure.in
index 4ce71e87..2cbb62ca 100644
--- a/configure.in
+++ b/configure.in
@@ -62,8 +62,13 @@ if test "$found_sm" = "true"; then
AC_DEFINE(HAVE_SM)
fi
-# Check for shaped window extension
-AC_CHECK_LIB(Xext, XShapeCombineMask, AC_DEFINE(HAVE_SHAPE_EXT),,$METACITY_LIBS)
+AM_CONDITIONAL(HAVE_SM, test "$found_sm" = "true")
+
+MSM_CFLAGS=$METACITY_CFLAGS
+MSM_LIBS=$METACITY_LIBS
+
+AC_SUBST(MSM_CFLAGS)
+AC_SUBST(MSM_LIBS)
HOST_ALIAS=$host_alias
AC_SUBST(HOST_ALIAS)
@@ -72,6 +77,7 @@ AC_OUTPUT([
Makefile
src/Makefile
src/wm-tester/Makefile
+src/msm/Makefile
])
diff --git a/src/Makefile.am b/src/Makefile.am
index 25d93073..2019534c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,11 @@
-SUBDIRS=wm-tester
+if HAVE_SM
+SM_SUBDIRS=msm
+else
+SM_SUBDIRS=
+endif
+
+SUBDIRS=wm-tester $(SM_SUBDIRS)
INCLUDES=@METACITY_CFLAGS@ -DMETACITY_LIBEXECDIR=\"$(libexecdir)\" -DHOST_ALIAS=\"@HOST_ALIAS@\"
diff --git a/src/core.c b/src/core.c
index ae36b4bc..399fe6d2 100644
--- a/src/core.c
+++ b/src/core.c
@@ -60,6 +60,22 @@ meta_core_get_frame_flags (Display *xdisplay,
return meta_frame_get_flags (window->frame);
}
+GdkPixbuf*
+meta_core_get_mini_icon (Display *xdisplay,
+ Window frame_xwindow)
+{
+ MetaDisplay *display;
+ MetaWindow *window;
+
+ display = meta_display_for_x_display (xdisplay);
+ window = meta_display_lookup_x_window (display, frame_xwindow);
+
+ if (window == NULL || window->frame == NULL)
+ meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
+
+ return window->mini_icon;
+}
+
void
meta_core_queue_frame_resize (Display *xdisplay,
Window frame_xwindow)
diff --git a/src/core.h b/src/core.h
index 24b2c633..bf8ccd11 100644
--- a/src/core.h
+++ b/src/core.h
@@ -36,6 +36,9 @@ void meta_core_get_frame_size (Display *xdisplay,
MetaFrameFlags meta_core_get_frame_flags (Display *xdisplay,
Window frame_xwindow);
+GdkPixbuf* meta_core_get_mini_icon (Display *xdisplay,
+ Window frame_xwindow);
+
void meta_core_queue_frame_resize (Display *xdisplay,
Window frame_xwindow);
diff --git a/src/frames.c b/src/frames.c
index cf006f5b..22d5fd09 100644
--- a/src/frames.c
+++ b/src/frames.c
@@ -1740,11 +1740,78 @@ meta_frames_expose_event (GtkWidget *widget,
if (frame->layout)
{
+ PangoRectangle layout_rect;
+ int x, y, icon_x, icon_y;
+ GdkPixbuf *icon;
+ int icon_w, icon_h;
+ int area_w, area_h;
+
+#define ICON_TEXT_SPACING 2
+
+ icon = meta_core_get_mini_icon (gdk_display,
+ frame->xwindow);
+
+ icon_w = gdk_pixbuf_get_width (icon);
+ icon_h = gdk_pixbuf_get_height (icon);
+
+ pango_layout_get_pixel_extents (frame->layout,
+ NULL,
+ &layout_rect);
+
+ /* corner of whole title area */
+ x = fgeom.title_rect.x + frames->props->text_border.left;
+ y = fgeom.title_rect.y + frames->props->text_border.top;
+
+ area_w = fgeom.title_rect.width -
+ frames->props->text_border.left -
+ frames->props->text_border.right;
+
+ area_h = fgeom.title_rect.height -
+ frames->props->text_border.top -
+ frames->props->text_border.bottom;
+
+ /* center icon vertically */
+ icon_y = y + MAX ((area_h - icon_h) / 2, 0);
+ /* center text vertically */
+ y = y + MAX ((area_h - layout_rect.height) / 2, 0);
+
+ /* Center icon + text combo */
+ icon_x = x + MAX ((area_w - layout_rect.width - icon_w - ICON_TEXT_SPACING) / 2, 0);
+ x = icon_x + icon_w + ICON_TEXT_SPACING;
+
gdk_gc_set_clip_rectangle (layout_gc, &clip);
+
+ {
+ /* grumble, render_to_drawable_alpha does not accept a clip
+ * mask, so we have to go through some BS
+ */
+ GdkRectangle pixbuf_rect;
+ GdkRectangle draw_rect;
+
+ pixbuf_rect.x = icon_x;
+ pixbuf_rect.y = icon_y;
+ pixbuf_rect.width = icon_w;
+ pixbuf_rect.height = icon_h;
+
+ if (gdk_rectangle_intersect (&clip, &pixbuf_rect, &draw_rect))
+ {
+ gdk_pixbuf_render_to_drawable_alpha (icon,
+ frame->window,
+ draw_rect.x - pixbuf_rect.x,
+ draw_rect.y - pixbuf_rect.y,
+ draw_rect.x, draw_rect.y,
+ draw_rect.width,
+ draw_rect.height,
+ GDK_PIXBUF_ALPHA_FULL,
+ 128,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+ }
+ }
+
gdk_draw_layout (frame->window,
layout_gc,
- fgeom.title_rect.x + frames->props->text_border.left,
- fgeom.title_rect.y + frames->props->text_border.top,
+ x, y,
frame->layout);
gdk_gc_set_clip_rectangle (layout_gc, NULL);
}
diff --git a/src/main.c b/src/main.c
index 52a393f1..8f3bb411 100644
--- a/src/main.c
+++ b/src/main.c
@@ -42,7 +42,7 @@ static void
usage (void)
{
g_print ("metacity [--disable-sm] [--sm-client-id=ID] [--display=DISPLAY]\n");
- exit (0);
+ exit (1);
}
int
diff --git a/src/msm/client.c b/src/msm/client.c
index f6a17ed6..3cebf359 100644
--- a/src/msm/client.c
+++ b/src/msm/client.c
@@ -288,25 +288,9 @@ msm_client_set_property_taking_ownership (MsmClient *client,
SmProp *prop)
{
/* we own prop which should be freed with SmFreeProperty() */
- GList *list;
- if (prop->name == NULL)
- {
- SmFreeProperty (prop);
- return;
- }
-
- list = proplist_find_link_by_name (client->properties, prop->name);
- if (list)
- {
- SmFreeProperty (list->data);
- list->data = prop;
- }
- else
- {
- client->properties = g_list_prepend (client->properties,
- prop);
- }
+ /* pass our ownership into the proplist */
+ client->properties = proplist_replace (client->properties, prop);
/* update pieces of the client struct */
if (strcmp (prop->name, "SmRestartStyleHint") == 0)
@@ -323,15 +307,7 @@ void
msm_client_unset_property (MsmClient *client,
const char *name)
{
- GList *list;
-
- list = proplist_find_link_by_name (client->properties, name);
- if (list)
- {
- SmFreeProperty (list->data);
- client->properties = g_list_delete_link (client->properties,
- list);
- }
+ client->properties = proplist_delete (client->properties, name);
/* Return to default values */
if (strcmp (name, "SmRestartStyleHint") == 0)
diff --git a/src/msm/gtkdisclosurebox.c b/src/msm/gtkdisclosurebox.c
new file mode 100644
index 00000000..b26e8694
--- /dev/null
+++ b/src/msm/gtkdisclosurebox.c
@@ -0,0 +1,359 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * this file Copyright (C) 2001 Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+
+
+/* FIXME implementation contains a bunch of cut-and-paste from GtkFrame
+ * that would be easy to avoid by adding an "int space_before_label_widget"
+ * in GtkFrame that was overridden by subclasses.
+ */
+
+/* FIXME the whole GtkFrame derivation idea is fucked since we can't get
+ * the click event on the arrow.
+ */
+
+
+#define ARROW_SIZE 12
+#define ARROW_PAD 2
+
+enum {
+ PROP_0,
+ PROP_DISCLOSED,
+ PROP_LAST
+};
+
+static void gtk_disclosure_box_class_init (GtkDisclosureBoxClass *klass);
+static void gtk_disclosure_box_init (GtkDisclosureBox *box);
+static void gtk_disclosure_box_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_disclosure_box_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gtk_disclosure_box_paint (GtkWidget *widget,
+ GdkRectangle *area);
+static gint gtk_disclosure_box_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+static void gtk_disclosure_box_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void gtk_disclosure_box_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+static void gtk_frame_compute_child_allocation (GtkFrame *frame,
+ GtkAllocation *child_allocation);
+
+GType
+gtk_disclosure_box_get_type (void)
+{
+ static GType disclosure_box_type = 0;
+
+ if (!disclosure_box_type)
+ {
+ static const GtkTypeInfo disclosure_box_info =
+ {
+ "GtkDisclosureBox",
+ sizeof (GtkDisclosureBox),
+ sizeof (GtkDisclosureBoxClass),
+ (GtkClassInitFunc) gtk_disclosure_box_class_init,
+ (GtkObjectInitFunc) gtk_disclosure_box_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ disclosure_box_type = gtk_type_unique (gtk_box_get_type (), &disclosure_box_info);
+ }
+
+ return disclosure_box_type;
+}
+
+static void
+gtk_disclosure_box_class_init (GtkDisclosureBoxClass *class)
+{
+ GtkWidgetClass *widget_class;
+ GObjectClass *gobject_class;
+ GtkContainerClass *container_class;
+ GtkFrameClass *frame_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ widget_class = GTK_WIDGET_CLASS (class);
+ container_class = GTK_CONTAINER_CLASS (class);
+ frame_class = GTK_FRAME_CLASS (class);
+
+ gobject_class->set_property = gtk_disclosure_box_set_property;
+ gobject_class->get_property = gtk_disclosure_box_get_property;
+
+ widget_class->size_request = gtk_disclosure_box_size_request;
+ widget_class->size_allocate = gtk_disclosure_box_size_allocate;
+ widget_class->expose_event = gtk_disclosure_box_expose;
+}
+
+static void
+gtk_disclosure_box_init (GtkDisclosureBox *disclosure_box)
+{
+
+}
+
+GtkWidget*
+gtk_disclosure_box_new (const char *label)
+{
+ return g_object_new (GTK_TYPE_DISCLOSURE_BOX, "label", label, NULL);
+}
+
+static void
+gtk_disclosure_box_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDisclosureBox *box;
+
+ box = GTK_DISCLOSURE_BOX (object);
+
+ switch (prop_id)
+ {
+ case PROP_DISCLOSED:
+ gtk_disclosure_box_set_disclosed (box,
+ g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_disclosure_box_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDisclosureBox *box;
+
+ box = GTK_DISCLOSURE_BOX (object);
+
+ switch (prop_id)
+ {
+ case PROP_DISCLOSED:
+ g_value_set_boolean (value, box->disclosed);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+void
+gtk_disclosure_box_set_disclosed (GtkDisclosureBox *box,
+ gboolean disclosed)
+{
+ g_return_if_fail (GTK_IS_DISCLOSURE_BOX (box));
+
+ disclosed = disclosed != FALSE;
+
+ if (disclosed != box->disclosed)
+ {
+ box->disclosed = disclosed;
+ gtk_widget_queue_resize (GTK_WIDGET (box));
+ }
+}
+
+gboolean
+gtk_disclosure_box_get_disclosed (GtkDisclosureBox *box)
+{
+ g_return_val_if_fail (GTK_IS_DISCLOSURE_BOX (box), FALSE);
+
+ return box->disclosed;
+}
+
+
+static void
+gtk_disclosure_box_paint (GtkWidget *widget,
+ GdkRectangle *area)
+{
+ GtkFrame *frame;
+ gint x, y, width, height;
+
+ if (GTK_WIDGET_DRAWABLE (widget))
+ {
+ frame = GTK_FRAME (widget);
+
+ x = frame->child_allocation.x - widget->style->xthickness;
+ y = frame->child_allocation.y - widget->style->ythickness;
+ width = frame->child_allocation.width + 2 * widget->style->xthickness;
+ height = frame->child_allocation.height + 2 * widget->style->ythickness;
+
+ if (frame->label_widget)
+ {
+ GtkRequisition child_requisition;
+ gfloat xalign;
+ gint height_extra;
+ gint x2;
+
+ gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ xalign = frame->label_xalign;
+ else
+ xalign = 1 - frame->label_xalign;
+
+ height_extra = MAX (0, child_requisition.height - widget->style->xthickness);
+ y -= height_extra * (1 - frame->label_yalign);
+ height += height_extra * (1 - frame->label_yalign);
+
+ x2 = widget->style->xthickness + (frame->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_SIDE_PAD;
+
+
+ gtk_paint_shadow_gap (widget->style, widget->window,
+ GTK_STATE_NORMAL, frame->shadow_type,
+ area, widget, "frame",
+ x, y, width, height,
+ GTK_POS_TOP,
+ x2 + ARROW_SIZE + ARROW_PAD * 2, child_requisition.width + 2 * LABEL_PAD);
+
+ gtk_paint_arrow (widget->style, widget->window,
+ widget->state, GTK_SHADOW_OUT,
+ area, widget, "arrow",
+ GTK_DISCLOSURE_BOX (widget)->disclosed ?
+ GTK_ARROW_RIGHT : GTK_ARROW_DOWN,
+ TRUE,
+ x2 + ARROW_PAD, y, ARROW_SIZE, ARROW_SIZE);
+ }
+ else
+ gtk_paint_shadow (widget->style, widget->window,
+ GTK_STATE_NORMAL, frame->shadow_type,
+ area, widget, "frame",
+ x, y, width, height);
+ }
+}
+
+static gboolean
+gtk_disclosure_box_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ if (GTK_WIDGET_DRAWABLE (widget))
+ {
+ gtk_disclosure_box_paint (widget, &event->area);
+
+ (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_disclosure_box_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkFrame *frame = GTK_FRAME (widget);
+ GtkBin *bin = GTK_BIN (widget);
+ GtkRequisition child_requisition;
+
+ if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
+ {
+ gtk_widget_size_request (frame->label_widget, &child_requisition);
+
+ requisition->width = child_requisition.width + 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD + ARROW_SIZE + ARROW_PAD * 2;
+ requisition->height =
+ MAX (0, child_requisition.height - GTK_WIDGET (widget)->style->xthickness);
+ }
+ else
+ {
+ requisition->width = 0;
+ requisition->height = 0;
+ }
+
+ if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+ {
+ gtk_widget_size_request (bin->child, &child_requisition);
+
+ requisition->width = MAX (requisition->width, child_requisition.width);
+ requisition->height += child_requisition.height;
+ }
+
+ requisition->width += (GTK_CONTAINER (widget)->border_width +
+ GTK_WIDGET (widget)->style->xthickness) * 2;
+ requisition->height += (GTK_CONTAINER (widget)->border_width +
+ GTK_WIDGET (widget)->style->ythickness) * 2;
+}
+
+static void
+gtk_disclosure_box_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkFrame *frame = GTK_FRAME (widget);
+ GtkBin *bin = GTK_BIN (widget);
+ GtkAllocation new_allocation;
+
+ widget->allocation = *allocation;
+
+ gtk_frame_compute_child_allocation (frame, &new_allocation);
+
+ /* If the child allocation changed, that means that the frame is drawn
+ * in a new place, so we must redraw the entire widget.
+ */
+ if (GTK_WIDGET_MAPPED (widget) &&
+ (new_allocation.x != frame->child_allocation.x ||
+ new_allocation.y != frame->child_allocation.y ||
+ new_allocation.width != frame->child_allocation.width ||
+ new_allocation.height != frame->child_allocation.height))
+ gtk_widget_queue_clear (widget);
+
+ if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+ gtk_widget_size_allocate (bin->child, &new_allocation);
+
+ frame->child_allocation = new_allocation;
+
+ if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
+ {
+ GtkRequisition child_requisition;
+ GtkAllocation child_allocation;
+ gfloat xalign;
+
+ gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ xalign = frame->label_xalign;
+ else
+ xalign = 1 - frame->label_xalign;
+
+ child_allocation.x = frame->child_allocation.x + LABEL_SIDE_PAD +
+ (frame->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_PAD + ARROW_SIZE + ARROW_PAD * 2;
+ child_allocation.width = child_requisition.width;
+
+ child_allocation.y = frame->child_allocation.y - child_requisition.height;
+ child_allocation.height = child_requisition.height;
+
+ gtk_widget_size_allocate (frame->label_widget, &child_allocation);
+ }
+}
+
diff --git a/src/msm/gtkdisclosurebox.h b/src/msm/gtkdisclosurebox.h
new file mode 100644
index 00000000..5c5b5803
--- /dev/null
+++ b/src/msm/gtkdisclosurebox.h
@@ -0,0 +1,76 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * this file Copyright (C) 2001 Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GTK_DISCLOSURE_BOX_H__
+#define __GTK_DISCLOSURE_BOX_H__
+
+
+#include <gdk/gdk.h>
+#include <gtk/gtkframe.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_TYPE_DISCLOSURE_BOX (gtk_disclosure_box_get_type ())
+#define GTK_DISCLOSURE_BOX(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_DISCLOSURE_BOX, GtkDisclosureBox))
+#define GTK_DISCLOSURE_BOX_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_DISCLOSURE_BOX, GtkDisclosureBoxClass))
+#define GTK_IS_DISCLOSURE_BOX(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_DISCLOSURE_BOX))
+#define GTK_IS_DISCLOSURE_BOX_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_DISCLOSURE_BOX))
+#define GTK_DISCLOSURE_BOX_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_DISCLOSURE_BOX, GtkDisclosureBoxClass))
+
+typedef struct _GtkDisclosureBox GtkDisclosureBox;
+typedef struct _GtkDisclosureBoxClass GtkDisclosureBoxClass;
+
+struct _GtkDisclosureBox
+{
+ GtkFrame parent_instance;
+
+ guint disclosed : 1;
+};
+
+struct _GtkDisclosureBoxClass
+{
+ GtkFrameClass parent_class;
+};
+
+GType gtk_disclosure_box_get_type (void) G_GNUC_CONST;
+
+GtkWidget* gtk_disclosure_box_new (const char *label);
+
+void gtk_disclosure_box_set_disclosed (GtkDisclosureBox *box,
+ gboolean disclosed);
+gboolean gtk_disclosure_box_get_disclosed (GtkDisclosureBox *box);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_FRAME_H__ */
diff --git a/src/msm/props.c b/src/msm/props.c
index fd0cf860..e88e3e46 100644
--- a/src/msm/props.c
+++ b/src/msm/props.c
@@ -82,6 +82,80 @@ proplist_find_string (GList *list, const char *name,
return smprop_get_string (prop, result);
}
+GList*
+proplist_replace (GList *list,
+ SmProp *new_prop)
+{
+ GList *link;
+
+ link = proplist_find_link_by_name (list, new_prop->name);
+ if (link)
+ {
+ SmFreeProperty (link->data);
+ link->data = new_prop;
+ }
+ else
+ {
+ list = g_list_prepend (list, new_prop);
+ }
+
+ return list;
+}
+
+GList*
+proplist_delete (GList *list,
+ const char *name)
+{
+ GList *link;
+
+ link = proplist_find_link_by_name (list, name);
+ if (link)
+ {
+ SmFreeProperty (link->data);
+ list = g_list_delete_link (list, link);
+ }
+
+ return list;
+}
+
+GList*
+proplist_replace_card8 (GList *list,
+ const char *name,
+ int value)
+{
+ SmProp *prop;
+
+ prop = smprop_new_card8 (name, value);
+
+ return proplist_replace (list, prop);
+}
+
+GList*
+proplist_replace_string (GList *list,
+ const char *name,
+ const char *str,
+ int len)
+{
+ SmProp *prop;
+
+ prop = smprop_new_string (name, str, len);
+
+ return proplist_replace (list, prop);
+}
+
+GList*
+proplist_replace_vector (GList *list,
+ const char *name,
+ int argc,
+ char **argv)
+{
+ SmProp *prop;
+
+ prop = smprop_new_vector (name, argc, argv);
+
+ return proplist_replace (list, prop);
+}
+
gboolean
proplist_find_vector (GList *list, const char *name,
int *argcp, char ***argvp)
@@ -206,5 +280,72 @@ smprop_copy (SmProp *prop)
return copy;
}
+SmProp*
+smprop_new_vector (const char *name,
+ int argc,
+ char **argv)
+{
+ SmProp *prop;
+ int i;
+
+ prop = msm_non_glib_malloc (sizeof (SmProp));
+ prop->name = msm_non_glib_strdup (name);
+ prop->type = msm_non_glib_strdup (SmLISTofARRAY8);
+
+ prop->num_vals = argc;
+ prop->vals = msm_non_glib_malloc (sizeof (SmPropValue) * prop->num_vals);
+ i = 0;
+ while (i < argc)
+ {
+ prop->vals[i].length = strlen (argv[i]);
+ prop->vals[i].value = msm_non_glib_strdup (argv[i]);
+
+ ++i;
+ }
+ return prop;
+}
+SmProp*
+smprop_new_string (const char *name,
+ const char *str,
+ int len)
+{
+ SmProp *prop;
+
+ if (len < 0)
+ len = strlen (str);
+
+ prop = msm_non_glib_malloc (sizeof (SmProp));
+ prop->name = msm_non_glib_strdup (name);
+ prop->type = msm_non_glib_strdup (SmARRAY8);
+
+ prop->num_vals = 1;
+ prop->vals = msm_non_glib_malloc (sizeof (SmPropValue) * prop->num_vals);
+
+ prop->vals[0].length = len;
+ prop->vals[0].value = msm_non_glib_malloc (len);
+ memcpy (prop->vals[0].value, str, len);
+
+ return prop;
+}
+
+SmProp*
+smprop_new_card8 (const char *name,
+ int value)
+{
+ SmProp *prop;
+
+ prop = msm_non_glib_malloc (sizeof (SmProp));
+ prop->name = msm_non_glib_strdup (name);
+ prop->type = msm_non_glib_strdup (SmARRAY8);
+
+ prop->num_vals = 1;
+ prop->vals = msm_non_glib_malloc (sizeof (SmPropValue) * prop->num_vals);
+
+ prop->vals[0].length = 1;
+ prop->vals[0].value = msm_non_glib_malloc (1);
+ (* (char*) prop->vals[0].value) = (char) value;
+
+ return prop;
+}
diff --git a/src/msm/props.h b/src/msm/props.h
index 92a05f94..09f213fc 100644
--- a/src/msm/props.h
+++ b/src/msm/props.h
@@ -41,6 +41,24 @@ gboolean proplist_find_vector (GList *list,
int *argcp,
char ***argvp);
+GList* proplist_replace (GList *list,
+ SmProp *new_prop);
+
+GList* proplist_delete (GList *list,
+ const char *name);
+
+GList* proplist_replace_card8 (GList *list,
+ const char *name,
+ int value);
+GList* proplist_replace_string (GList *list,
+ const char *name,
+ const char *str,
+ int len);
+GList* proplist_replace_vector (GList *list,
+ const char *name,
+ int argc,
+ char **argv);
+
gboolean smprop_get_card8 (SmProp *prop,
int *result);
gboolean smprop_get_string (SmProp *prop,
@@ -49,6 +67,16 @@ gboolean smprop_get_vector (SmProp *prop,
int *argcp,
char ***argvp);
+SmProp* smprop_new_card8 (const char *name,
+ int value);
+SmProp* smprop_new_string (const char *name,
+ const char *str,
+ int len);
+SmProp* smprop_new_vector (const char *name,
+ int argc,
+ char **argv);
+
+
SmProp* smprop_copy (SmProp *prop);
#endif
diff --git a/src/msm/session.c b/src/msm/session.c
index 492d0c30..9bf995f0 100644
--- a/src/msm/session.c
+++ b/src/msm/session.c
@@ -30,6 +30,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
+#include <stdio.h>
#include <gtk/gtk.h>
@@ -38,7 +39,7 @@ typedef struct _MsmSavedClient MsmSavedClient;
struct _MsmSavedClient
{
char *id;
-
+ GList *properties;
};
struct _MsmSession
@@ -71,6 +72,9 @@ static MsmSession* recover_failed_session (MsmSession *session,
static gboolean parse_session_file (MsmSession *session,
GError **error);
+static char* decode_text_from_utf8 (const char *text);
+static char* encode_text_as_utf8 (const char *text);
+
void
msm_session_clear (MsmSession *session)
{
@@ -106,8 +110,10 @@ msm_session_client_id_known (MsmSession *session,
void
msm_session_launch (MsmSession *session)
{
-
-
+ system ("xclock &");
+ system ("xclock &");
+ system ("xclock &");
+ system ("xterm &");
}
MsmSavedClient*
@@ -118,7 +124,8 @@ saved_new (void)
saved = g_new (MsmSavedClient, 1);
saved->id = NULL;
-
+ saved->properties = NULL;
+
return saved;
}
@@ -344,12 +351,201 @@ msm_session_get_failsafe (void)
return msm_session_get_for_filename (_("Failsafe"), "Failsafe.session");
}
+static void
+write_proplist (FILE *fp,
+ GList *properties)
+{
+ GList *tmp;
+
+ tmp = properties;
+ while (tmp != NULL)
+ {
+ SmProp *prop = tmp->data;
+ char *name_encoded;
+ char *type_encoded;
+
+ name_encoded = encode_text_as_utf8 (prop->name);
+ type_encoded = encode_text_as_utf8 (prop->type);
+
+ fprintf (fp, " <prop name=\"%s\" type=\"%s\">\n",
+ name_encoded, type_encoded);
+
+ g_free (name_encoded);
+ g_free (type_encoded);
+
+ if (strcmp (prop->type, SmCARD8) == 0)
+ {
+ int val = 0;
+ smprop_get_card8 (prop, &val);
+ fprintf (fp, " <value>%d</value>\n", val);
+ }
+ else if (strcmp (prop->type, SmARRAY8) == 0)
+ {
+ char *str = NULL;
+ char *encoded = NULL;
+ smprop_get_string (prop, &str);
+ if (str)
+ encoded = encode_text_as_utf8 (str);
+ if (encoded)
+ fprintf (fp, " <value>%s</value>\n", encoded);
+
+ g_free (encoded);
+ g_free (str);
+ }
+ else if (strcmp (prop->type, SmLISTofARRAY8) == 0)
+ {
+ char **vec;
+ int vec_len;
+ int i;
+
+ vec = NULL;
+ vec_len = 0;
+
+ smprop_get_vector (prop, &vec_len, &vec);
+
+ i = 0;
+ while (i < vec_len)
+ {
+ char *encoded;
+
+ encoded = encode_text_as_utf8 (vec[i]);
+
+ fprintf (fp, " <value>%s</value>\n", encoded);
+
+ g_free (encoded);
+
+ ++i;
+ }
+
+ g_strfreev (vec);
+ }
+ else
+ {
+ msm_warning (_("Not saving unknown property type '%s'\n"),
+ prop->type);
+ }
+
+ fputs (" </prop>\n", fp);
+
+ tmp = tmp->next;
+ }
+}
+
void
msm_session_save (MsmSession *session,
MsmServer *server)
{
+ /* We save to a secondary file then copy over, to handle
+ * out-of-disk-space robustly
+ */
+ int new_fd;
+ char *new_filename;
+ char *error;
+ FILE *fp;
+
+ error = NULL;
+ new_fd = -1;
+
+ new_filename = g_strconcat (session->full_filename, ".new", NULL);
+ new_fd = open (session->full_filename, O_RDWR | O_CREAT | O_EXCL, 0700);
+ if (new_fd < 0)
+ {
+ error = g_strdup_printf (_("Failed to open '%s': %s\n"),
+ new_filename, g_strerror (errno));
+ goto out;
+ }
+
+ if (lock_entire_file (new_fd) < 0)
+ {
+ error = g_strdup_printf (_("Failed to lock file '%s': %s"),
+ new_filename,
+ g_strerror (errno));
+ goto out;
+ }
+ fp = fdopen (new_fd, "w");
+ if (fp == NULL)
+ {
+ error = g_strdup_printf (_("Failed to write to new session file '%s': %s"),
+ new_filename, g_strerror (errno));
+ goto out;
+ }
+
+ fputs ("<msm_session>\n", fp);
+
+ {
+ GList *tmp;
+ tmp = session->clients;
+ while (tmp != NULL)
+ {
+ MsmSavedClient *saved = tmp->data;
+ char *encoded;
+
+ encoded = encode_text_as_utf8 (saved->id);
+
+ fprintf (fp, " <client id=\"%s\">\n",
+ encoded);
+
+ g_free (encoded);
+
+ write_proplist (fp, saved->properties);
+
+ fputs (" </client>\n", fp);
+
+ tmp = tmp->next;
+ }
+ }
+
+ fputs ("</msm_session>\n", fp);
+ if (ferror (fp))
+ {
+ error = g_strdup_printf (_("Error writing new session file '%s': %s"),
+ new_filename, g_strerror (errno));
+ fclose (fp);
+ goto out;
+ }
+
+ if (fclose (fp) < 0)
+ {
+ error = g_strdup_printf (_("Failed to close to new session file '%s': %s"),
+ new_filename, g_strerror (errno));
+ goto out;
+ }
+
+ if (rename (new_filename, session->full_filename) < 0)
+ {
+ error = g_strdup_printf (_("Failed to replace the old session file '%s' with the new session contents in the temporary file '%s': %s"),
+ session->full_filename,
+ new_filename, g_strerror (errno));
+ goto out;
+ }
+
+
+
+ out:
+ g_free (new_filename);
+
+ if (error)
+ {
+ if (new_fd >= 0)
+ close (new_fd);
+ }
+ else
+ {
+ if (session->lock_fd >= 0)
+ close (session->lock_fd);
+ session->lock_fd = new_fd;
+ set_close_on_exec (new_fd);
+ }
+}
+
+static void
+add_details_to_dialog (GtkDialog *dialog,
+ const char *details)
+{
+
+
}
static MsmSession*
@@ -368,21 +564,43 @@ recover_failed_session (MsmSession *session,
case MSM_SESSION_FAILURE_OPENING_FILE:
message = g_strdup_printf (_("Could not open the session \"%s.\""),
session->name);
+ /* FIXME recovery options:
+ * - give up and exit; something pathological is going on
+ * - choose another session?
+ * - use default session in read-only mode?
+ * - open xterm to repair the problem, then try again (experts only)
+ */
break;
case MSM_SESSION_FAILURE_LOCKING:
message = g_strdup_printf (_("You are already logged in elsewhere, using the session \"%s.\" You can only use a session from one location at a time."),
session->name);
+ /* FIXME recovery options:
+ * - log in anyhow, with possible weirdness
+ * - try again (after logging out the other session)
+ * - choose another session
+ * - open xterm to repair the problem, then try again (experts only)
+ */
break;
case MSM_SESSION_FAILURE_BAD_FILE:
message = g_strdup_printf (_("The session file for session \"%s\" appears to be invalid or corrupted."),
session->name);
+ /* FIXME recovery options:
+ * - revert session to defaults
+ * - choose another session
+ * - open xterm to repair the problem, then try again (experts only)
+ */
break;
case MSM_SESSION_FAILURE_EMPTY:
message = g_strdup_printf (_("The session \"%s\" contains no applications."),
session->name);
+ /* FIXME recovery options:
+ * - put default applications in the session
+ * - choose another session
+ * - open xterm to repair the problem, then try again (experts only)
+ */
break;
}
@@ -392,6 +610,9 @@ recover_failed_session (MsmSession *session,
GTK_BUTTONS_CLOSE,
message);
+ gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
+ add_details_to_dialog (GTK_DIALOG (dialog), details);
+
g_free (message);
gtk_dialog_run (GTK_DIALOG (dialog));
@@ -445,3 +666,46 @@ parse_session_file (MsmSession *session,
return TRUE;
}
+
+
+static char*
+encode_text_as_utf8 (const char *text)
+{
+ /* text can be any encoding, and is nul-terminated.
+ * we pretend it's Latin-1 and encode as UTF-8
+ */
+ GString *str;
+ const char *p;
+
+ str = g_string_new ("");
+
+ p = text;
+ while (*p)
+ {
+ g_string_append_unichar (str, *p);
+ ++p;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static char*
+decode_text_from_utf8 (const char *text)
+{
+ /* Convert back from the encoded UTF-8 */
+ GString *str;
+ const char *p;
+
+ str = g_string_new ("");
+
+ p = text;
+ while (*p)
+ {
+ /* obviously this barfs if the UTF-8 contains chars > 255 */
+ g_string_append_c (str, g_utf8_get_char (p));
+
+ p = g_utf8_next_char (p);
+ }
+
+ return g_string_free (str, FALSE);
+}
diff --git a/src/screen.h b/src/screen.h
index 5a347fd5..e81abf60 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -30,6 +30,8 @@
/* should investigate changing these to whatever most apps use */
#define META_ICON_WIDTH 32
#define META_ICON_HEIGHT 32
+#define META_MINI_ICON_WIDTH 16
+#define META_MINI_ICON_HEIGHT 16
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
gpointer user_data);
diff --git a/src/session.c b/src/session.c
index 00290e69..de65a513 100644
--- a/src/session.c
+++ b/src/session.c
@@ -97,8 +97,8 @@ new_ice_connection (IceConn connection, IcePointer client_data, Bool opening,
*/
GIOChannel *channel;
- fcntl (IceConnectionNumber(connection),F_SETFD,
- fcntl(IceConnectionNumber(connection),F_GETFD,0) | FD_CLOEXEC);
+ fcntl (IceConnectionNumber (connection), F_SETFD,
+ fcntl (IceConnectionNumber (connection), F_GETFD, 0) | FD_CLOEXEC);
channel = g_io_channel_unix_new (IceConnectionNumber (connection));
@@ -119,15 +119,15 @@ new_ice_connection (IceConn connection, IcePointer client_data, Bool opening,
}
}
-static IceIOErrorHandler gnome_ice_installed_handler;
+static IceIOErrorHandler ice_installed_handler;
/* We call any handler installed before (or after) gnome_ice_init but
avoid calling the default libICE handler which does an exit() */
static void
ice_io_error_handler (IceConn connection)
{
- if (gnome_ice_installed_handler)
- (*gnome_ice_installed_handler) (connection);
+ if (ice_installed_handler)
+ (*ice_installed_handler) (connection);
}
static void
@@ -139,11 +139,11 @@ ice_init (void)
{
IceIOErrorHandler default_handler;
- gnome_ice_installed_handler = IceSetIOErrorHandler (NULL);
+ ice_installed_handler = IceSetIOErrorHandler (NULL);
default_handler = IceSetIOErrorHandler (ice_io_error_handler);
- if (gnome_ice_installed_handler == default_handler)
- gnome_ice_installed_handler = NULL;
+ if (ice_installed_handler == default_handler)
+ ice_installed_handler = NULL;
IceAddConnectionWatch (new_ice_connection, NULL);
@@ -879,11 +879,17 @@ save_state (void)
out:
if (outfile)
{
- if (fclose (outfile) != 0)
+ /* FIXME need a dialog for this */
+ if (ferror (outfile))
{
meta_warning (_("Error writing session file '%s': %s\n"),
session_file, g_strerror (errno));
}
+ if (fclose (outfile))
+ {
+ meta_warning (_("Error closing session file '%s': %s\n"),
+ session_file, g_strerror (errno));
+ }
}
g_free (metacity_dir);
diff --git a/src/ui.c b/src/ui.c
index 48909a63..01b3154b 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -429,6 +429,16 @@ meta_ui_get_default_window_icon (MetaUI *ui)
NULL);
}
+GdkPixbuf*
+meta_ui_get_default_mini_icon (MetaUI *ui)
+{
+ /* FIXME */
+ return gtk_widget_render_icon (GTK_WIDGET (ui->frames),
+ GTK_STOCK_NEW,
+ GTK_ICON_SIZE_MENU,
+ NULL);
+}
+
gboolean
meta_ui_window_should_not_cause_focus (Display *xdisplay,
Window xwindow)
diff --git a/src/ui.h b/src/ui.h
index 7bfdcb60..9fad03e7 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -129,6 +129,7 @@ void meta_ui_push_delay_exposes (MetaUI *ui);
void meta_ui_pop_delay_exposes (MetaUI *ui);
GdkPixbuf* meta_ui_get_default_window_icon (MetaUI *ui);
+GdkPixbuf* meta_ui_get_default_mini_icon (MetaUI *ui);
gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay,
Window xwindow);
diff --git a/src/window.c b/src/window.c
index 8af7d0ba..0e3e8212 100644
--- a/src/window.c
+++ b/src/window.c
@@ -275,6 +275,7 @@ meta_window_new (MetaDisplay *display, Window xwindow,
window->title = NULL;
window->icon_name = NULL;
window->icon = NULL;
+ window->mini_icon = NULL;
window->desc = g_strdup_printf ("0x%lx", window->xwindow);
@@ -689,6 +690,9 @@ meta_window_free (MetaWindow *window)
if (window->icon)
g_object_unref (G_OBJECT (window->icon));
+
+ if (window->mini_icon)
+ g_object_unref (G_OBJECT (window->mini_icon));
g_free (window->sm_client_id);
g_free (window->role);
@@ -3808,6 +3812,8 @@ update_icon_name (MetaWindow *window)
static gboolean
find_best_size (gulong *data,
int nitems,
+ int ideal_width,
+ int ideal_height,
int *width,
int *height,
gulong **start)
@@ -3857,7 +3863,7 @@ find_best_size (gulong *data,
else
{
/* work with averages */
- const int ideal_size = META_ICON_WIDTH * META_ICON_HEIGHT;
+ const int ideal_size = (ideal_width + ideal_height) / 2;
int best_size = (best_w + best_h) / 2;
int this_size = (w + h) / 2;
@@ -3875,7 +3881,7 @@ find_best_size (gulong *data,
else if (best_size > ideal_size &&
this_size >= ideal_size &&
this_size < best_size)
- replace = TRUE;
+ replace = TRUE;
}
if (replace)
@@ -3900,11 +3906,46 @@ find_best_size (gulong *data,
return FALSE;
}
+static void
+argbdata_to_pixdata (gulong *argb_data, int len, guchar **pixdata)
+{
+ guchar *p;
+ int i;
+
+ *pixdata = g_new (guchar, len * 4);
+ p = *pixdata;
+
+ /* One could speed this up a lot. */
+ i = 0;
+ while (i < len)
+ {
+ guint argb;
+ guint rgba;
+
+ argb = argb_data[i];
+ rgba = (argb << 8) | (argb >> 24);
+
+ *p = rgba >> 24;
+ ++p;
+ *p = (rgba >> 16) & 0xff;
+ ++p;
+ *p = (rgba >> 8) & 0xff;
+ ++p;
+ *p = rgba & 0xff;
+ ++p;
+
+ ++i;
+ }
+}
+
static gboolean
read_rgb_icon (MetaWindow *window,
int *width,
int *height,
- guchar **pixdata)
+ guchar **pixdata,
+ int *mini_width,
+ int *mini_height,
+ guchar **mini_pixdata)
{
Atom type;
int format;
@@ -3913,9 +3954,9 @@ read_rgb_icon (MetaWindow *window,
int result;
gulong *data; /* FIXME should be guint? */
gulong *best;
- int i;
int w, h;
- guchar *p;
+ gulong *best_mini;
+ int mini_w, mini_h;
if (sizeof (gulong) != 4)
meta_warning ("%s: Whoops, I think this function may be broken on 64-bit\n",
@@ -3940,39 +3981,28 @@ read_rgb_icon (MetaWindow *window,
return FALSE;
}
- if (!find_best_size (data, nitems, &w, &h, &best))
+ if (!find_best_size (data, nitems, META_ICON_WIDTH, META_ICON_HEIGHT,
+ &w, &h, &best))
{
XFree (data);
return FALSE;
}
+ if (!find_best_size (data, nitems, META_MINI_ICON_WIDTH, META_MINI_ICON_HEIGHT,
+ &mini_w, &mini_h, &best_mini))
+ {
+ XFree (data);
+ return FALSE;
+ }
+
*width = w;
*height = h;
- *pixdata = g_new (guchar, w * h * 4);
- p = *pixdata;
+ *mini_width = mini_w;
+ *mini_height = mini_h;
- /* One could speed this up a lot. */
- i = 0;
- while (i < w * h)
- {
- guint argb;
- guint rgba;
-
- argb = best[i];
- rgba = (argb << 8) | (argb >> 24);
-
- *p = rgba >> 24;
- ++p;
- *p = (rgba >> 16) & 0xff;
- ++p;
- *p = (rgba >> 8) & 0xff;
- ++p;
- *p = rgba & 0xff;
- ++p;
-
- ++i;
- }
+ argbdata_to_pixdata (best, w * h, pixdata);
+ argbdata_to_pixdata (best_mini, mini_w * mini_h, mini_pixdata);
XFree (data);
@@ -3987,6 +4017,12 @@ clear_icon (MetaWindow *window)
g_object_unref (G_OBJECT (window->icon));
window->icon = NULL;
}
+
+ if (window->mini_icon)
+ {
+ g_object_unref (G_OBJECT (window->mini_icon));
+ window->mini_icon = NULL;
+ }
}
static void
@@ -3997,7 +4033,8 @@ free_pixels (guchar *pixels, gpointer data)
static void
replace_icon (MetaWindow *window,
- GdkPixbuf *unscaled)
+ GdkPixbuf *unscaled,
+ GdkPixbuf *unscaled_mini)
{
if (gdk_pixbuf_get_width (unscaled) != META_ICON_WIDTH ||
gdk_pixbuf_get_height (unscaled) != META_ICON_HEIGHT)
@@ -4015,6 +4052,23 @@ replace_icon (MetaWindow *window,
g_object_ref (G_OBJECT (unscaled));
window->icon = unscaled;
}
+
+ if (gdk_pixbuf_get_width (unscaled_mini) != META_MINI_ICON_WIDTH ||
+ gdk_pixbuf_get_height (unscaled_mini) != META_MINI_ICON_HEIGHT)
+ {
+ /* FIXME should keep aspect ratio, but for now assuming
+ * a square source icon
+ */
+ window->mini_icon = gdk_pixbuf_scale_simple (unscaled_mini,
+ META_MINI_ICON_WIDTH,
+ META_MINI_ICON_HEIGHT,
+ GDK_INTERP_BILINEAR);
+ }
+ else
+ {
+ g_object_ref (G_OBJECT (unscaled_mini));
+ window->mini_icon = unscaled_mini;
+ }
}
static void
@@ -4149,7 +4203,7 @@ try_pixmap_and_mask (MetaWindow *window,
if (unscaled)
{
- replace_icon (window, unscaled);
+ replace_icon (window, unscaled, unscaled);
g_object_unref (G_OBJECT (unscaled));
return TRUE;
}
@@ -4162,18 +4216,22 @@ update_icon (MetaWindow *window,
gboolean reload_rgb_icon)
{
- if (FALSE && reload_rgb_icon)
+ if (reload_rgb_icon)
{
guchar *pixdata;
int w, h;
+ guchar *mini_pixdata;
+ int mini_w, mini_h;
pixdata = NULL;
- if (read_rgb_icon (window, &w, &h, &pixdata))
+ if (read_rgb_icon (window, &w, &h, &pixdata,
+ &mini_w, &mini_h, &mini_pixdata))
{
GdkPixbuf *unscaled;
+ GdkPixbuf *unscaled_mini;
- meta_verbose ("successfully read RGBA icon from _NET_WM_ICON, using w = %d h = %d\n", w, h);
+ meta_verbose ("successfully read RGBA icon from _NET_WM_ICON, using w = %d h = %d mini_w = %d mini_h = %d\n", w, h, mini_w, mini_h);
window->using_rgb_icon = TRUE;
@@ -4185,9 +4243,18 @@ update_icon (MetaWindow *window,
free_pixels,
NULL);
- replace_icon (window, unscaled);
+ unscaled_mini = gdk_pixbuf_new_from_data (mini_pixdata,
+ GDK_COLORSPACE_RGB,
+ TRUE,
+ 8,
+ mini_w, mini_h, mini_w * 4,
+ free_pixels,
+ NULL);
+
+ replace_icon (window, unscaled, unscaled_mini);
g_object_unref (G_OBJECT (unscaled));
+ g_object_unref (G_OBJECT (unscaled_mini));
return Success;
}
@@ -4237,7 +4304,10 @@ update_icon (MetaWindow *window,
/* Fallback to a default icon */
if (window->icon == NULL)
- window->icon = meta_ui_get_default_window_icon (window->screen->ui);
+ {
+ window->icon = meta_ui_get_default_window_icon (window->screen->ui);
+ window->mini_icon = meta_ui_get_default_mini_icon (window->screen->ui);
+ }
return Success;
}
diff --git a/src/window.h b/src/window.h
index 6eab6991..9a23a4f1 100644
--- a/src/window.h
+++ b/src/window.h
@@ -55,6 +55,7 @@ struct _MetaWindow
char *icon_name;
GdkPixbuf *icon;
+ GdkPixbuf *mini_icon;
MetaWindowType type;
Atom type_atom;