summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2001-08-20 01:42:44 +0000
committerHavoc Pennington <hp@src.gnome.org>2001-08-20 01:42:44 +0000
commit04e09d4c564dc5efea47b60c24309617c9d961c8 (patch)
treeca8d99de667c01c7b1413dd102df2b7b8fbe12ad
parent78a68f3e10233bb9c7d699456cf7d8ed6445769d (diff)
downloadmetacity-04e09d4c564dc5efea47b60c24309617c9d961c8.tar.gz
we support _NET_WM_ICON
2001-08-19 Havoc Pennington <hp@pobox.com> * src/screen.c (set_supported_hint): we support _NET_WM_ICON * src/wm-tester/main.c: add stuff to test _NET_WM_ICON (but it doesn't work, so it isn't tested yet) * src/window.c (update_icon): read _NET_WM_ICON * src/screen.c (meta_screen_new): set the WM_ICON_SIZE hint * src/tabpopup.c (meta_ui_tab_popup_select): remove assertion * src/window.c (meta_window_get_icon_geometry): fix obscure memleak
-rw-r--r--ChangeLog16
-rw-r--r--src/display.c4
-rw-r--r--src/display.h1
-rwxr-xr-xsrc/run-metacity.sh4
-rw-r--r--src/screen.c28
-rw-r--r--src/screen.h5
-rw-r--r--src/tabpopup.c2
-rw-r--r--src/ui.c35
-rw-r--r--src/ui.h9
-rw-r--r--src/window.c294
-rw-r--r--src/window.h11
-rw-r--r--src/wm-tester/main.c77
12 files changed, 458 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index b595e09d..9852cb0f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
2001-08-19 Havoc Pennington <hp@pobox.com>
+ * src/screen.c (set_supported_hint): we support _NET_WM_ICON
+
+ * src/wm-tester/main.c: add stuff to test _NET_WM_ICON
+ (but it doesn't work, so it isn't tested yet)
+
+ * src/window.c (update_icon): read _NET_WM_ICON
+
+ * src/screen.c (meta_screen_new): set the WM_ICON_SIZE hint
+
+ * src/tabpopup.c (meta_ui_tab_popup_select): remove assertion
+
+ * src/window.c (meta_window_get_icon_geometry): fix obscure
+ memleak
+
+2001-08-19 Havoc Pennington <hp@pobox.com>
+
* src/display.c (meta_display_grab_window_buttons): remove XSync,
error traps already do that
(meta_display_grab_window_buttons): implement
diff --git a/src/display.c b/src/display.c
index bc4b819a..6d7f6e51 100644
--- a/src/display.c
+++ b/src/display.c
@@ -132,7 +132,8 @@ meta_display_open (const char *name)
"_NET_WM_ICON_NAME",
"_NET_WM_ICON",
"_NET_WM_ICON_GEOMETRY",
- "UTF8_STRING"
+ "UTF8_STRING",
+ "WM_ICON_SIZE"
};
Atom atoms[G_N_ELEMENTS(atom_names)];
@@ -216,6 +217,7 @@ meta_display_open (const char *name)
display->atom_net_wm_icon = atoms[37];
display->atom_net_wm_icon_geometry = atoms[38];
display->atom_utf8_string = atoms[39];
+ display->atom_wm_icon_size = atoms[40];
/* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK,
* created in screen_new
diff --git a/src/display.h b/src/display.h
index 1aa47162..b0a5478a 100644
--- a/src/display.h
+++ b/src/display.h
@@ -97,6 +97,7 @@ struct _MetaDisplay
Atom atom_net_wm_icon;
Atom atom_net_wm_icon_geometry;
Atom atom_utf8_string;
+ Atom atom_wm_icon_size;
/* This is the actual window from focus events,
* not the one we last set
diff --git a/src/run-metacity.sh b/src/run-metacity.sh
index 01dd4432..8daa023d 100755
--- a/src/run-metacity.sh
+++ b/src/run-metacity.sh
@@ -22,6 +22,10 @@ if test -n "$EVIL_TEST"; then
TEST_CLIENT='./wm-tester/wm-tester --evil'
fi
+if test -n "$ICON_TEST"; then
+ TEST_CLIENT='./wm-tester/wm-tester --icon-windows'
+fi
+
if test -z "$ONLY_WM"; then
Xnest -ac :1 -scrns $SCREENS -geometry 640x480 -bw 15 &
## usleep 800000
diff --git a/src/screen.c b/src/screen.c
index ffad0e06..b1795f0c 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -72,7 +72,7 @@ set_wm_check_hint (MetaScreen *screen)
static int
set_supported_hint (MetaScreen *screen)
{
-#define N_SUPPORTED 21
+#define N_SUPPORTED 22
#define N_WIN_SUPPORTED 1
Atom atoms[N_SUPPORTED];
@@ -97,6 +97,7 @@ set_supported_hint (MetaScreen *screen)
atoms[18] = screen->display->atom_net_client_list_stacking;
atoms[19] = screen->display->atom_net_wm_state_skip_taskbar;
atoms[20] = screen->display->atom_net_wm_state_skip_pager;
+ atoms[21] = screen->display->atom_net_wm_icon;
XChangeProperty (screen->display->xdisplay, screen->xroot,
screen->display->atom_net_wm_supported,
@@ -115,6 +116,29 @@ set_supported_hint (MetaScreen *screen)
#undef N_SUPPORTED
}
+static int
+set_wm_icon_size_hint (MetaScreen *screen)
+{
+#define N_VALS 6
+ gulong vals[N_VALS];
+
+ /* min width, min height, max w, max h, width inc, height inc */
+ vals[0] = META_ICON_WIDTH;
+ vals[1] = META_ICON_HEIGHT;
+ vals[2] = META_ICON_WIDTH;
+ vals[3] = META_ICON_HEIGHT;
+ vals[4] = 0;
+ vals[5] = 0;
+
+ XChangeProperty (screen->display->xdisplay, screen->xroot,
+ screen->display->atom_wm_icon_size,
+ XA_CARDINAL,
+ 32, PropModeReplace, (guchar*) vals, N_VALS);
+
+ return Success;
+#undef N_VALS
+}
+
MetaScreen*
meta_screen_new (MetaDisplay *display,
int number)
@@ -177,6 +201,8 @@ meta_screen_new (MetaDisplay *display,
display->leader_window = XCreateSimpleWindow (display->xdisplay,
screen->xroot,
-100, -100, 1, 1, 0, 0, 0);
+
+ set_wm_icon_size_hint (screen);
set_supported_hint (screen);
diff --git a/src/screen.h b/src/screen.h
index f04e5bc4..e3126849 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -26,6 +26,11 @@
#include <X11/Xutil.h>
#include "ui.h"
+
+/* should investigate changing these to whatever most apps use */
+#define META_ICON_WIDTH 32
+#define META_ICON_HEIGHT 32
+
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
gpointer user_data);
diff --git a/src/tabpopup.c b/src/tabpopup.c
index 0a1b055e..ca94bbf8 100644
--- a/src/tabpopup.c
+++ b/src/tabpopup.c
@@ -287,6 +287,4 @@ meta_ui_tab_popup_select (MetaTabPopup *popup,
tmp = tmp->next;
}
-
- meta_bug ("Selected nonexistent entry 0x%lx in tab popup\n", xwindow);
}
diff --git a/src/ui.c b/src/ui.c
index fe3de2c2..f11b198c 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -333,6 +333,41 @@ meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
return retval;
}
+GdkPixbuf*
+meta_gdk_pixbuf_get_from_pixmap (GdkPixbuf *dest,
+ Pixmap xpixmap,
+ int src_x,
+ int src_y,
+ int dest_x,
+ int dest_y,
+ int width,
+ int height)
+{
+ GdkDrawable *drawable;
+ GdkPixbuf *retval;
+
+ retval = NULL;
+
+ drawable = gdk_xid_table_lookup (xpixmap);
+
+ if (drawable)
+ g_object_ref (G_OBJECT (drawable));
+ else
+ drawable = gdk_pixmap_foreign_new (xpixmap);
+
+ retval = gdk_pixbuf_get_from_drawable (dest,
+ drawable,
+ /* We assume root window cmap */
+ gdk_colormap_get_system (),
+ src_x, src_y,
+ dest_x, dest_y,
+ width, height);
+
+ g_object_unref (G_OBJECT (drawable));
+
+ return retval;
+}
+
void
meta_ui_push_delay_exposes (MetaUI *ui)
{
diff --git a/src/ui.h b/src/ui.h
index c9ce0b04..9fc354c9 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -110,6 +110,15 @@ GdkPixbuf* meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
int width,
int height);
+GdkPixbuf* meta_gdk_pixbuf_get_from_pixmap (GdkPixbuf *dest,
+ Pixmap xpixmap,
+ int src_x,
+ int src_y,
+ int dest_x,
+ int dest_y,
+ int width,
+ int height);
+
/* Used when we have a server grab and draw all over everything,
* then we need to handle exposes after doing that, instead of
* during it
diff --git a/src/window.c b/src/window.c
index 9e45d46f..591582b4 100644
--- a/src/window.c
+++ b/src/window.c
@@ -59,7 +59,8 @@ static int update_role (MetaWindow *window);
static int update_net_wm_type (MetaWindow *window);
static int update_initial_workspace (MetaWindow *window);
static int update_icon_name (MetaWindow *window);
-static int update_icon (MetaWindow *window);
+static int update_icon (MetaWindow *window,
+ gboolean reread_rgb_icon);
static void recalc_window_type (MetaWindow *window);
static void recalc_window_features (MetaWindow *window);
static int set_wm_state (MetaWindow *window,
@@ -317,6 +318,8 @@ meta_window_new (MetaDisplay *display, Window xwindow,
window->icon_pixmap = None;
window->icon_mask = None;
+
+ window->using_rgb_icon = FALSE;
window->type = META_WINDOW_NORMAL;
window->type_atom = None;
@@ -328,7 +331,7 @@ meta_window_new (MetaDisplay *display, Window xwindow,
update_size_hints (window);
update_title (window);
- update_protocols (window);
+ update_protocols (window);
update_wm_hints (window);
update_net_wm_state (window);
update_mwm_hints (window);
@@ -339,7 +342,8 @@ meta_window_new (MetaDisplay *display, Window xwindow,
update_net_wm_type (window);
update_initial_workspace (window);
update_icon_name (window);
- update_icon (window);
+ /* should come after wm_hints */
+ update_icon (window, TRUE);
if (!window->mapped &&
(window->size_hints.flags & PPosition) == 0 &&
@@ -2331,7 +2335,6 @@ process_property_notify (MetaWindow *window,
meta_verbose ("Property notify on %s for WM_HINTS\n", window->desc);
update_wm_hints (window);
- update_icon (window);
meta_window_queue_move_resize (window);
}
@@ -2395,7 +2398,7 @@ process_property_notify (MetaWindow *window,
else if (event->atom == window->display->atom_net_wm_icon)
{
meta_verbose ("Property notify on %s for NET_WM_ICON\n", window->desc);
- update_icon (window);
+ update_icon (window, TRUE);
}
return TRUE;
@@ -2742,7 +2745,12 @@ static int
update_wm_hints (MetaWindow *window)
{
XWMHints *hints;
+ Pixmap old_icon;
+ Pixmap old_mask;
+ old_icon = window->icon_pixmap;
+ old_mask = window->icon_mask;
+
/* Fill in defaults */
window->input = FALSE;
window->initially_iconic = FALSE;
@@ -2769,6 +2777,14 @@ update_wm_hints (MetaWindow *window)
if (hints->flags & IconMaskHint)
window->icon_mask = hints->icon_mask;
+
+ if (window->icon_pixmap != old_icon ||
+ window->icon_mask != old_mask)
+ {
+ meta_verbose ("Icon pixmap or mask changed in WM_HINTS for %s\n",
+ window->desc);
+ update_icon (window, FALSE);
+ }
meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%ld\n",
window->input, window->initially_iconic,
@@ -3025,8 +3041,14 @@ meta_window_get_icon_geometry (MetaWindow *window,
result = meta_error_trap_pop (window->display);
- if (result != Success || type != XA_CARDINAL || nitems != 4)
- return FALSE;
+ if (result != Success || type != XA_CARDINAL)
+ return FALSE;
+
+ if (nitems != 4)
+ {
+ XFree (geometry);
+ return FALSE;
+ }
if (rect)
{
@@ -3442,7 +3464,7 @@ update_icon_name (MetaWindow *window)
text.format == 8 &&
g_utf8_validate (text.value, text.nitems, NULL))
{
- meta_verbose ("Using _NET_WM_ICON_NAME for new title of %s: '%s'\n",
+ meta_verbose ("Using _NET_WM_ICON_NAME for new icon name of %s: '%s'\n",
window->desc, text.value);
window->icon_name = g_strdup (text.value);
@@ -3498,26 +3520,266 @@ update_icon_name (MetaWindow *window)
return meta_error_trap_pop (window->display);
}
-static int
-update_icon (MetaWindow *window)
-{
+static gboolean
+find_best_size (gulong *data,
+ gulong nitems,
+ int *width,
+ int *height,
+ gulong **start)
+{
+ int best_w;
+ int best_h;
+ gulong *best_start;
+
+ best_w = 0;
+ best_h = 0;
+ best_start = NULL;
+
+ while (nitems > 0)
+ {
+ int w, h;
+ gboolean replace;
+
+ replace = FALSE;
+
+ if (nitems < 3)
+ {
+ meta_verbose ("_NET_WM_ICON contained too little data\n");
+ return FALSE;
+ }
+
+ w = data[0];
+ h = data[1];
+
+ if (nitems < ((w * h) + 2))
+ {
+ meta_verbose ("_NET_WM_ICON contained too little data\n");
+ return FALSE;
+ }
+
+ if (best_start == NULL)
+ {
+ replace = TRUE;
+ }
+ else
+ {
+ /* work with averages */
+ const int ideal_size = META_ICON_WIDTH * META_ICON_HEIGHT;
+ int best_size = (best_w + best_h) / 2;
+ int this_size = (w + h) / 2;
+
+ /* larger than desired is always better than smaller */
+ if (best_size < ideal_size &&
+ this_size >= ideal_size)
+ replace = TRUE;
+ /* if we have too small, pick anything bigger */
+ else if (best_size < ideal_size &&
+ this_size > best_size)
+ replace = TRUE;
+ /* if we have too large, pick anything smaller
+ * but still >= the ideal
+ */
+ else if (best_size > ideal_size &&
+ this_size >= ideal_size &&
+ this_size < best_size)
+ replace = TRUE;
+ }
+
+ if (replace)
+ {
+ best_start = data + 2;
+ best_w = w;
+ best_h = h;
+ }
+
+ nitems -= (w * h) + 2;
+ }
+
+ if (best_start)
+ {
+ *start = best_start;
+ *width = best_w;
+ *height = best_h;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+read_rgb_icon (MetaWindow *window,
+ int *width,
+ int *height,
+ guchar **pixdata)
+{
+ Atom type;
+ int format;
+ gulong nitems;
+ gulong bytes_after;
+ int result;
+ gulong *data; /* FIXME should be guint? */
+ gulong *best;
+ int i;
+ int w, h;
+ guchar *p;
+
+ if (sizeof (gulong) != 4)
+ meta_warning ("%s: Whoops, I think this function may be broken on 64-bit\n",
+ __FUNCTION__);
+
meta_error_trap_push (window->display);
+ type = None;
+ data = NULL;
+ XGetWindowProperty (window->display->xdisplay,
+ window->xwindow,
+ window->display->atom_net_wm_icon,
+ 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, ((guchar **)&data));
+
+ result = meta_error_trap_pop (window->display);
+
+ if (result != Success || type != XA_CARDINAL)
+ {
+ meta_verbose ("%s doesn't seem to set _NET_WM_ICON\n",
+ window->desc);
+ return FALSE;
+ }
+
+ if (!find_best_size (data, nitems, &w, &h, &best))
+ {
+ XFree (data);
+ return FALSE;
+ }
-#if 0
+ *width = w;
+ *height = h;
+
+ *pixdata = g_new (guchar, w * h);
+ p = *pixdata;
+
+ /* 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;
+ }
+
+ XFree (data);
+
+ return TRUE;
+}
+
+static void
+clear_icon (MetaWindow *window)
+{
if (window->icon)
{
g_object_unref (G_OBJECT (window->icon));
window->icon = NULL;
}
-#endif
+}
+
+static void
+free_pixels (guchar *pixels, gpointer data)
+{
+ g_free (pixels);
+}
+
+static int
+update_icon (MetaWindow *window,
+ gboolean reload_rgb_icon)
+{
+
+ if (reload_rgb_icon)
+ {
+ guchar *pixdata;
+ int w, h;
+
+ pixdata = NULL;
+
+ if (read_rgb_icon (window, &w, &h, &pixdata))
+ {
+ GdkPixbuf *unscaled;
+
+ meta_verbose ("successfully read RGBA icon fro _NET_WM_ICON\n");
+
+ window->using_rgb_icon = TRUE;
+
+ clear_icon (window);
+
+ unscaled = gdk_pixbuf_new_from_data (pixdata,
+ GDK_COLORSPACE_RGB,
+ TRUE,
+ 8,
+ w, h, w,
+ free_pixels,
+ NULL);
+
+ if (w != META_ICON_WIDTH || h != META_ICON_HEIGHT)
+ {
+ /* FIXME should keep aspect ratio, but for now assuming
+ * a square source icon
+ */
+ window->icon = gdk_pixbuf_scale_simple (unscaled,
+ META_ICON_WIDTH,
+ META_ICON_HEIGHT,
+ GDK_INTERP_BILINEAR);
+
+ g_object_unref (G_OBJECT (unscaled));
+ }
+ else
+ {
+ window->icon = unscaled;
+ }
+
+ return Success;
+ }
+ else
+ {
+ if (window->using_rgb_icon)
+ clear_icon (window);
+ window->using_rgb_icon = FALSE;
+
+ /* We'll try to fall back to something else below. */
+ }
+ }
+ else if (window->using_rgb_icon)
+ {
+ /* There's no way we want to use the fallbacks,
+ * keep using this.
+ */
+ return Success;
+ }
- /* FIXME */
+ /* Fallback to pixmap + mask */
+ /* FIXME well, I'm not sure how to deal with the mask */
+ /* FIXME for that matter, I don't know how we get the
+ * icon pixmap as pixbuf without knowing if it's a bitmap,
+ * so we may be entirely hosed. I guess we can try to get it
+ * with a nice error trap.
+ */
- /* Fallback */
+ /* Fallback to a default icon */
if (window->icon == NULL)
window->icon = meta_ui_get_default_window_icon (window->screen->ui);
- return meta_error_trap_pop (window->display);
+ return Success;
}
static void
diff --git a/src/window.h b/src/window.h
index 3757d8d4..a70649db 100644
--- a/src/window.h
+++ b/src/window.h
@@ -70,11 +70,14 @@ struct _MetaWindow
Window xgroup_leader;
Window xclient_leader;
- Pixmap icon_pixmap;
- Pixmap icon_mask;
-
/* Initial workspace property */
- int initial_workspace;
+ int initial_workspace;
+
+ Pixmap icon_pixmap;
+ Pixmap icon_mask;
+
+ /* Whether ->icon is from NET_WM_ICON instead of pixmap */
+ guint using_rgb_icon : 1;
/* Whether we're maximized */
guint maximized : 1;
diff --git a/src/wm-tester/main.c b/src/wm-tester/main.c
index 9a2da68f..f58742d6 100644
--- a/src/wm-tester/main.c
+++ b/src/wm-tester/main.c
@@ -28,11 +28,12 @@
#include <unistd.h>
static void set_up_the_evil (void);
+static void set_up_icon_windows (void);
static void
usage (void)
{
- g_print ("wm-tester [--evil]\n");
+ g_print ("wm-tester [--evil] [--icon-windows]\n");
exit (0);
}
@@ -41,10 +42,12 @@ main (int argc, char **argv)
{
int i;
gboolean do_evil;
-
+ gboolean do_icon_windows;
+
gtk_init (&argc, &argv);
do_evil = FALSE;
+ do_icon_windows = FALSE;
i = 1;
while (i < argc)
@@ -57,6 +60,8 @@ main (int argc, char **argv)
usage ();
else if (strcmp (arg, "--evil") == 0)
do_evil = TRUE;
+ else if (strcmp (arg, "--icon-windows") == 0)
+ do_icon_windows = TRUE;
else
usage ();
@@ -64,12 +69,15 @@ main (int argc, char **argv)
}
/* Be sure some option was provided */
- if (! (do_evil))
+ if (! (do_evil || do_icon_windows))
return 1;
if (do_evil)
set_up_the_evil ();
-
+
+ if (do_icon_windows)
+ set_up_icon_windows ();
+
gtk_main ();
return 0;
@@ -156,3 +164,64 @@ set_up_the_evil (void)
g_timeout_add (40, evil_timeout, NULL);
}
+static void
+set_up_icon_windows (void)
+{
+ int i;
+ int n_windows;
+
+ /* Create some windows */
+ n_windows = 9;
+
+ i = 0;
+ while (i < n_windows)
+ {
+ GtkWidget *w;
+ GtkWidget *c;
+ GList *icons;
+ GdkPixbuf *pix;
+
+ w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ c = gtk_button_new_with_label ("Icon window");
+ gtk_container_add (GTK_CONTAINER (w), c);
+
+ gtk_widget_realize (w);
+
+ icons = NULL;
+
+ pix = gtk_widget_render_icon (w,
+ GTK_STOCK_SAVE,
+ GTK_ICON_SIZE_LARGE_TOOLBAR,
+ NULL);
+
+ icons = g_list_append (icons, pix);
+
+ if (i % 2)
+ {
+ pix = gtk_widget_render_icon (w,
+ GTK_STOCK_SAVE,
+ GTK_ICON_SIZE_DIALOG,
+ NULL);
+ icons = g_list_append (icons, pix);
+ }
+
+ if (i % 3)
+ {
+ pix = gtk_widget_render_icon (w,
+ GTK_STOCK_SAVE,
+ GTK_ICON_SIZE_MENU,
+ NULL);
+ icons = g_list_append (icons, pix);
+ }
+
+ if (!gdk_window_set_icon_list (w->window, icons))
+ g_warning ("_NET_WM_ICON not supported?");
+
+ g_list_foreach (icons, (GFunc) g_object_unref, NULL);
+ g_list_free (icons);
+
+ gtk_widget_show_all (w);
+
+ ++i;
+ }
+}