Mercurial > pidgin.yaz
view plugins/docklet/eggtrayicon.c @ 11719:109ee3bfeac5
[gaim-migrate @ 14010]
SF Patch #1333770 from corfe83
"Many times in gaim we use the function
g_slist_remove(list,node->data) to remove an element
from a GSList. If we already have the pointer to the
node we want to delete, it is faster to send it the
pointer to the node to delete rather than the data of
the node (we can do this by calling
g_slist_delete_link(list,node)). This change was made
while looking at glib's documentation and the code in
glib's gslist.c.
This is because as the remove/delete function traverses
each node in the list, it doesn't need to spend an
extra memory access to retrieve the data for each
element in the node it is traversing and then compare,
it can simply compare the pointer. In my tests outside
of gaim, this makes a big difference if the node you
are deleting is at a high index in the list. However,
even if you're deleting the first node, it about breaks
even.
So, I've found each case in gaim where we are calling
g_slist_remove, and we already have the pointer to the
appropriate node to delete (this is often the case when
we're doing a for or while loop on a GSList). I've then
replaced it with the appropriate call to
g_slist_delete_link. I, however, didn't do this in
situations where we are explicitly removing the first
element in the list, because in those situations it is
an unnecessary change.
There should be no difference in behavior, but just in
case I've tried running it with valgrind, which reports
the same number of memory leaks after my patch as
before my patch. Of course, I can't guarantee that my
normal behavior on gaim is hitting all the functions
I've changed, but in general testing it Works For Me (tm)."
As with the last patch, this one may not have a practical performance impact (or maybe it does, I have no idea), but it's not worse for any case. Given two ways of doing things where one is always at least as fast and may be faster under some cases, I like to prefer that faster way. This doesn't make the code any uglier, so I'm applying.
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Sat, 22 Oct 2005 20:48:18 +0000 |
parents | 57fccea36e36 |
children | e856f985a0b9 |
line wrap: on
line source
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* eggtrayicon.c * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org> * * 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. */ #include <config.h> #include <string.h> #include "eggtrayicon.h" #include <gdk/gdkx.h> #include <X11/Xatom.h> #define _(x) x #define N_(x) x #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 #define SYSTEM_TRAY_ORIENTATION_HORZ 0 #define SYSTEM_TRAY_ORIENTATION_VERT 1 enum { PROP_0, PROP_ORIENTATION }; static GtkPlugClass *parent_class = NULL; static void egg_tray_icon_init (EggTrayIcon *icon); static void egg_tray_icon_class_init (EggTrayIconClass *klass); static void egg_tray_icon_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void egg_tray_icon_realize (GtkWidget *widget); static void egg_tray_icon_unrealize (GtkWidget *widget); static void egg_tray_icon_update_manager_window (EggTrayIcon *icon, gboolean dock_if_realized); static void egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon); GType egg_tray_icon_get_type (void) { static GType our_type = 0; if (our_type == 0) { our_type = g_type_from_name("EggTrayIcon"); if (our_type == 0) { static const GTypeInfo our_info = { sizeof (EggTrayIconClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) egg_tray_icon_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (EggTrayIcon), 0, /* n_preallocs */ (GInstanceInitFunc) egg_tray_icon_init }; our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0); } else if (parent_class == NULL) { /* we're reheating the old class from a previous instance - engage ugly hack =( */ egg_tray_icon_class_init((EggTrayIconClass *)g_type_class_peek(our_type)); } } return our_type; } static void egg_tray_icon_init (EggTrayIcon *icon) { icon->stamp = 1; icon->orientation = GTK_ORIENTATION_HORIZONTAL; gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK); } static void egg_tray_icon_class_init (EggTrayIconClass *klass) { GObjectClass *gobject_class = (GObjectClass *)klass; GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; parent_class = g_type_class_peek_parent (klass); gobject_class->get_property = egg_tray_icon_get_property; widget_class->realize = egg_tray_icon_realize; widget_class->unrealize = egg_tray_icon_unrealize; g_object_class_install_property (gobject_class, PROP_ORIENTATION, g_param_spec_enum ("orientation", _("Orientation"), _("The orientation of the tray."), GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL, G_PARAM_READABLE)); } static void egg_tray_icon_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EggTrayIcon *icon = EGG_TRAY_ICON (object); switch (prop_id) { case PROP_ORIENTATION: g_value_set_enum (value, icon->orientation); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void egg_tray_icon_get_orientation_property (EggTrayIcon *icon) { Display *xdisplay; Atom type; int format; union { gulong *prop; guchar *prop_ch; } prop = { NULL }; gulong nitems; gulong bytes_after; int error, result; g_return_if_fail(icon->manager_window != None); #if GTK_CHECK_VERSION(2,1,0) xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); #else xdisplay = gdk_display; #endif gdk_error_trap_push (); type = None; result = XGetWindowProperty (xdisplay, icon->manager_window, icon->orientation_atom, 0, G_MAXLONG, FALSE, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &(prop.prop_ch)); error = gdk_error_trap_pop (); if (error || result != Success) return; if (type == XA_CARDINAL) { GtkOrientation orientation; orientation = (prop.prop [0] == SYSTEM_TRAY_ORIENTATION_HORZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; if (icon->orientation != orientation) { icon->orientation = orientation; g_object_notify (G_OBJECT (icon), "orientation"); } } if (prop.prop) XFree (prop.prop); } static GdkFilterReturn egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data) { EggTrayIcon *icon = user_data; XEvent *xev = (XEvent *)xevent; if (xev->xany.type == ClientMessage && xev->xclient.message_type == icon->manager_atom && xev->xclient.data.l[1] == icon->selection_atom) { egg_tray_icon_update_manager_window (icon, TRUE); } else if (xev->xany.window == icon->manager_window) { if (xev->xany.type == PropertyNotify && xev->xproperty.atom == icon->orientation_atom) { egg_tray_icon_get_orientation_property (icon); } if (xev->xany.type == DestroyNotify) { egg_tray_icon_manager_window_destroyed (icon); } } return GDK_FILTER_CONTINUE; } static void egg_tray_icon_unrealize (GtkWidget *widget) { EggTrayIcon *icon = EGG_TRAY_ICON (widget); GdkWindow *root_window; if (icon->manager_window != None) { GdkWindow *gdkwin; #if GTK_CHECK_VERSION(2,1,0) gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget), icon->manager_window); #else gdkwin = gdk_window_lookup (icon->manager_window); #endif gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); } #if GTK_CHECK_VERSION(2,1,0) root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); #else root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ()); #endif gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon); if (GTK_WIDGET_CLASS (parent_class)->unrealize) (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } static void egg_tray_icon_send_manager_message (EggTrayIcon *icon, long message, Window window, long data1, long data2, long data3) { XClientMessageEvent ev; Display *display; ev.type = ClientMessage; ev.window = window; ev.message_type = icon->system_tray_opcode_atom; ev.format = 32; ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window); ev.data.l[1] = message; ev.data.l[2] = data1; ev.data.l[3] = data2; ev.data.l[4] = data3; #if GTK_CHECK_VERSION(2,1,0) display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); #else display = gdk_display; #endif gdk_error_trap_push (); XSendEvent (display, icon->manager_window, False, NoEventMask, (XEvent *)&ev); XSync (display, False); gdk_error_trap_pop (); } static void egg_tray_icon_send_dock_request (EggTrayIcon *icon) { egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_REQUEST_DOCK, icon->manager_window, gtk_plug_get_id (GTK_PLUG (icon)), 0, 0); } static void egg_tray_icon_update_manager_window (EggTrayIcon *icon, gboolean dock_if_realized) { Display *xdisplay; if (icon->manager_window != None) return; #if GTK_CHECK_VERSION(2,1,0) xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); #else xdisplay = gdk_display; #endif XGrabServer (xdisplay); icon->manager_window = XGetSelectionOwner (xdisplay, icon->selection_atom); if (icon->manager_window != None) XSelectInput (xdisplay, icon->manager_window, StructureNotifyMask|PropertyChangeMask); XUngrabServer (xdisplay); XFlush (xdisplay); if (icon->manager_window != None) { GdkWindow *gdkwin; #if GTK_CHECK_VERSION(2,1,0) gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), icon->manager_window); #else gdkwin = gdk_window_lookup (icon->manager_window); #endif gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon); if (dock_if_realized && GTK_WIDGET_REALIZED (icon)) egg_tray_icon_send_dock_request (icon); egg_tray_icon_get_orientation_property (icon); } } static void egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon) { GdkWindow *gdkwin; g_return_if_fail (icon->manager_window != None); #if GTK_CHECK_VERSION(2,1,0) gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), icon->manager_window); #else gdkwin = gdk_window_lookup (icon->manager_window); #endif gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); icon->manager_window = None; egg_tray_icon_update_manager_window (icon, TRUE); } static void egg_tray_icon_realize (GtkWidget *widget) { EggTrayIcon *icon = EGG_TRAY_ICON (widget); gint screen; Display *xdisplay; char buffer[256]; GdkWindow *root_window; if (GTK_WIDGET_CLASS (parent_class)->realize) GTK_WIDGET_CLASS (parent_class)->realize (widget); #if GTK_CHECK_VERSION(2,1,0) screen = gdk_screen_get_number (gtk_widget_get_screen (widget)); xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)); #else screen = XScreenNumberOfScreen (DefaultScreenOfDisplay (gdk_display)); xdisplay = gdk_display; #endif /* Now see if there's a manager window around */ g_snprintf (buffer, sizeof (buffer), "_NET_SYSTEM_TRAY_S%d", screen); icon->selection_atom = XInternAtom (xdisplay, buffer, False); icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False); icon->system_tray_opcode_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_OPCODE", False); icon->orientation_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_ORIENTATION", False); egg_tray_icon_update_manager_window (icon, FALSE); egg_tray_icon_send_dock_request (icon); #if GTK_CHECK_VERSION(2,1,0) root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); #else root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ()); #endif /* Add a root window filter so that we get changes on MANAGER */ gdk_window_add_filter (root_window, egg_tray_icon_manager_filter, icon); } #if GTK_CHECK_VERSION(2,1,0) EggTrayIcon * egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name) { g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); return g_object_new (EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL); } #endif EggTrayIcon* egg_tray_icon_new (const gchar *name) { return g_object_new (EGG_TYPE_TRAY_ICON, "title", name, NULL); } guint egg_tray_icon_send_message (EggTrayIcon *icon, gint timeout, const gchar *message, gint len) { guint stamp; g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0); g_return_val_if_fail (timeout >= 0, 0); g_return_val_if_fail (message != NULL, 0); if (icon->manager_window == None) return 0; if (len < 0) len = strlen (message); stamp = icon->stamp++; /* Get ready to send the message */ egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE, (Window)gtk_plug_get_id (GTK_PLUG (icon)), timeout, len, stamp); /* Now to send the actual message */ gdk_error_trap_push (); while (len > 0) { XClientMessageEvent ev; Display *xdisplay; #if GTK_CHECK_VERSION(2,1,0) xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); #else xdisplay = gdk_display; #endif ev.type = ClientMessage; ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon)); ev.format = 8; ev.message_type = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); if (len > 20) { memcpy (&ev.data, message, 20); len -= 20; message += 20; } else { memcpy (&ev.data, message, len); len = 0; } XSendEvent (xdisplay, icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev); XSync (xdisplay, False); } gdk_error_trap_pop (); return stamp; } void egg_tray_icon_cancel_message (EggTrayIcon *icon, guint id) { g_return_if_fail (EGG_IS_TRAY_ICON (icon)); g_return_if_fail (id > 0); egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE, (Window)gtk_plug_get_id (GTK_PLUG (icon)), id, 0, 0); } GtkOrientation egg_tray_icon_get_orientation (EggTrayIcon *icon) { g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL); return icon->orientation; }