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
This commit is contained in:
Havoc Pennington 2001-09-16 00:30:45 +00:00 committed by Havoc Pennington
parent 2830c9d748
commit 39df21227d
19 changed files with 1127 additions and 82 deletions

View File

@ -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

View File

@ -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
])

View File

@ -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@\"

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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)

359
src/msm/gtkdisclosurebox.c Normal file
View File

@ -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);
}
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -55,6 +55,7 @@ struct _MetaWindow
char *icon_name;
GdkPixbuf *icon;
GdkPixbuf *mini_icon;
MetaWindowType type;
Atom type_atom;