/* * Xfce4 Messenger Plugin - DBus message notification plugin for Xfce4 Panel * Copyright (C) 2005-2006 Pasi Orovuo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include #include #include "listener.h" #include "iconset.h" #include "history.h" #include "popup.h" #include "preferences.h" #include "preferences-dialog.h" #define BORDER 8 #define FRAME_BORDER 2 #define DEFAULT_HISTORY_LENGTH 200 #define TOOLTIP_TEXT_MAX_LEN 45 typedef struct _MessengerPlugin MessengerPlugin; struct _MessengerPlugin { /* Frame */ GtkWidget *frame; GtkWidget *box; GtkWidget *evbox; /* Icon */ GtkWidget *icon; MessengerIconSet *icons; /* Label */ GtkWidget *label; guint timeout_id; GSList *message_queue; /* Popup window */ GtkWidget *popup_window; /* History */ MessengerHistory *history; GtkWidget *history_dialog; /* Panel */ XfcePanelPlugin *panel_plugin; gint panel_size; GtkOrientation panel_orientation; MessengerPreferences *preferences; gulong notify_handler_id; GtkWidget *prefs_dialog; GtkTooltips *tooltip; /* The messenger itself */ MessengerListener *messenger; }; typedef struct _MessengerMessage MessengerMessage; struct _MessengerMessage { gchar *text; GdkPixbuf *pixbuf; gint timeout; }; /* Inline 1x1 empty GdkPixbuf for clearing the icon */ #ifdef __SUNPRO_C #pragma align 4 (empty_pixbuf_data) #endif #ifdef __GNUC__ static const guint8 empty_pixbuf_data[] __attribute__ ((__aligned__ (4))) = #else static const guint8 empty_pixbuf_data[] = #endif { "GdkP\0\0\0\34\1\1\0\2\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\0" }; static GdkPixbuf *empty_pixbuf = NULL; static void plugin_clear_icon( MessengerPlugin *plugin ) { g_return_if_fail( plugin->icon != NULL ); if ( !empty_pixbuf ) { empty_pixbuf = gdk_pixbuf_new_from_inline( -1, empty_pixbuf_data, FALSE, NULL ); } if ( gtk_image_get_pixbuf( GTK_IMAGE( plugin->icon ) ) != empty_pixbuf ) { xfce_scaled_image_set_from_pixbuf( XFCE_SCALED_IMAGE( plugin->icon ), empty_pixbuf ); } } static gboolean plugin_message_timeout_cb( gpointer user_data ) { MessengerPlugin *plugin = user_data; if ( plugin->message_queue ) { MessengerMessage *message = plugin->message_queue->data; plugin->message_queue = g_slist_remove( plugin->message_queue, message ); if ( message->text ) { gtk_label_set_text( GTK_LABEL( plugin->label ), message->text ); g_free( message->text ); } if ( message->pixbuf ) { xfce_scaled_image_set_from_pixbuf( XFCE_SCALED_IMAGE( plugin->icon ), message->pixbuf ); g_object_unref( G_OBJECT( message->pixbuf ) ); } else if ( plugin->icon ) { plugin_clear_icon( plugin ); } plugin->timeout_id = g_timeout_add( message->timeout, plugin_message_timeout_cb, plugin ); g_free( message ); } else { if ( plugin->label ) { gtk_label_set_text( GTK_LABEL( plugin->label ), "" ); } if ( plugin->icon ) { plugin_clear_icon( plugin ); } plugin->timeout_id = 0; } return ( FALSE ); } static void plugin_message_cb( MessengerListener *messenger, guint timeout, const gchar *msgstr, gpointer user_data ) { MessengerPlugin *plugin = user_data; gchar *msgbuf = NULL, *msg = NULL; GdkPixbuf *pb = NULL; gboolean show_icon, show_label, show_popup; guint duration; g_object_get( G_OBJECT( plugin->preferences ), "message-duration", &duration, "show-icon", &show_icon, "show-label", &show_label, "show-popup", &show_popup, NULL ); timeout = ( timeout > 0 ? timeout : duration ) * 1000; msg = strchr( msgstr, ':' ); if ( msg ) { gchar *id; msg++; id = g_strstrip( g_strndup( msgstr, msg - msgstr - 1 ) ); if ( messenger_icon_set_identifier_is_valid( id ) ) { if ( plugin->icon || plugin->popup_window ) { pb = gtk_widget_render_icon( plugin->icon ? plugin->icon : plugin->popup_window, id, -1, NULL ); } msgbuf = g_strdup( msg ); } g_free( id ); } if ( !msgbuf ) { msgbuf = g_strdup( msgstr ); } msg = g_strstrip( msgbuf ); if ( !plugin->timeout_id ) { plugin->timeout_id = g_timeout_add( timeout, plugin_message_timeout_cb, plugin ); if ( show_label ) { gtk_label_set_text( GTK_LABEL( plugin->label ), msg ); } if ( show_icon && pb ) { xfce_scaled_image_set_from_pixbuf( XFCE_SCALED_IMAGE( plugin->icon ), pb ); } } else { MessengerMessage *message; message = g_new( MessengerMessage, 1 ); message->text = show_label ? g_strdup( msg ) : NULL; message->pixbuf = show_icon && pb ? g_object_ref( G_OBJECT( pb ) ): NULL; message->timeout = timeout; plugin->message_queue = g_slist_append( plugin->message_queue, message ); } messenger_history_message_prepend( plugin->history, msgstr ); /* Truncate string for tooltip and popup */ { glong msglen = g_utf8_strlen( msg, -1 ); if ( msglen > TOOLTIP_TEXT_MAX_LEN ) { gchar *p = g_utf8_offset_to_pointer( msg, MIN( msglen - 3, TOOLTIP_TEXT_MAX_LEN ) - 1 ); gint i; for ( i = 0; i < 3; i++ ) { *p++ = '.'; } *p = '\0'; } } if ( show_popup ) { messenger_popup_text( MESSENGER_POPUP( plugin->popup_window ), msg, pb ); } gtk_tooltips_set_tip( plugin->tooltip, plugin->evbox, msg, NULL ); if ( pb ) { g_object_unref( G_OBJECT( pb ) ); } g_free( msgbuf ); } static void plugin_show_history( MessengerPlugin *plugin, GtkWindow *parent_window ) { if ( plugin->history_dialog ) { gtk_window_present( GTK_WINDOW( plugin->history_dialog ) ); return; } plugin->history_dialog = messenger_history_create_dialog( plugin->history, parent_window ); g_signal_connect( G_OBJECT( plugin->history_dialog ), "destroy", G_CALLBACK( gtk_widget_destroyed ), &plugin->history_dialog ); g_signal_connect_swapped( G_OBJECT( plugin->history_dialog ), "response", G_CALLBACK( gtk_widget_destroy ), plugin->history_dialog ); gtk_widget_show( plugin->history_dialog ); } static void plugin_preferences_view_history_clicked_cb( MessengerPreferencesDialog *dialog, gpointer user_data ) { plugin_show_history( user_data, NULL ); } static gboolean plugin_button_press_cb( GtkWidget *widget, GdkEventButton *event, MessengerPlugin *plugin ) { if ( event->type == GDK_BUTTON_PRESS && event->button == 1 ) { plugin_show_history( plugin, NULL ); return ( TRUE ); } return ( FALSE ); } static void plugin_popup_clicked_cb( MessengerPopup *popup, MessengerPlugin *plugin ) { plugin_show_history( plugin, NULL ); } static void plugin_update_ui( MessengerPlugin *plugin ) { GtkOrientation panel_orientation; gint panel_size, item_size = -1; gboolean show_label, show_popup, show_icon; gboolean orientation_changed, size_changed; panel_orientation = xfce_panel_plugin_get_orientation( plugin->panel_plugin ); panel_size = xfce_panel_plugin_get_size( plugin->panel_plugin ); g_object_get( G_OBJECT( plugin->preferences ), "show-icon", &show_icon, "show-label", &show_label, "show-popup", &show_popup, NULL ); orientation_changed = panel_orientation != plugin->panel_orientation; size_changed = panel_size != plugin->panel_size; if ( !plugin->box ) { plugin->box = ( panel_orientation == GTK_ORIENTATION_HORIZONTAL ? gtk_hbox_new( FALSE, 1 ) : gtk_vbox_new( FALSE, 1 ) ); gtk_widget_show( plugin->box ); gtk_container_add( GTK_CONTAINER( plugin->frame ), plugin->box ); } else { if ( orientation_changed ) { GtkWidget *box = ( panel_orientation == GTK_ORIENTATION_HORIZONTAL ? gtk_hbox_new( FALSE, 1 ) : gtk_vbox_new( FALSE, 1 ) ); gtk_widget_show( box ); if ( show_icon && plugin->icon ) { gtk_widget_reparent( plugin->icon, box ); } if ( show_label && plugin->label ) { gtk_widget_reparent( plugin->label, box ); } gtk_container_remove( GTK_CONTAINER( plugin->frame ), plugin->box ); plugin->box = box; gtk_container_add( GTK_CONTAINER( plugin->frame ), plugin->box ); } } item_size = panel_size - FRAME_BORDER * 2 - ( panel_orientation == GTK_ORIENTATION_HORIZONTAL ? plugin->frame->style->xthickness : plugin->frame->style->ythickness ); /* Icon */ if ( !show_icon && plugin->icon ) { gtk_widget_destroy( plugin->icon ); plugin->icon = NULL; } else if ( show_icon ) { gint w; if ( !plugin->icon ) { plugin->icon = xfce_scaled_image_new(); gtk_widget_show( plugin->icon ); gtk_box_pack_start( GTK_BOX( plugin->box ), plugin->icon, FALSE, FALSE, 0 ); /* Meh, if icons are enabled after label it'll appear after * the label */ gtk_box_reorder_child( GTK_BOX( plugin->box ), plugin->icon, 0 ); } gtk_widget_get_size_request( plugin->icon, &w, NULL ); if ( w != item_size ) { gtk_widget_set_size_request( plugin->icon, item_size, item_size ); } } /* Label */ if ( !show_label && plugin->label ) { gtk_widget_destroy( plugin->label ); plugin->label = NULL; } else if ( show_label ) { gint oldw, oldh; gint neww, newh; if ( !plugin->label ) { plugin->label = gtk_label_new( NULL ); gtk_widget_show( plugin->label ); gtk_box_pack_end( GTK_BOX( plugin->box ), plugin->label, TRUE, TRUE, 0 ); } gtk_widget_get_size_request( plugin->label, &oldw, &oldh ); if ( plugin->panel_orientation == GTK_ORIENTATION_VERTICAL ) { gint tmp = oldw; oldw = oldh; oldh = tmp; } g_object_get( G_OBJECT( plugin->preferences ), "label-width", &neww, NULL ); newh = item_size; if ( orientation_changed || size_changed || oldw != neww ) { if ( panel_orientation == GTK_ORIENTATION_VERTICAL ) { gint tmp = neww; neww = newh; newh = tmp; gtk_misc_set_alignment( GTK_MISC( plugin->label ), 0.5f, 0.0f ); } else { gtk_misc_set_alignment( GTK_MISC( plugin->label ), 0.0f, 0.5f ); } gtk_label_set_angle( GTK_LABEL( plugin->label ), 270 * (int) panel_orientation ); gtk_widget_set_size_request( plugin->label, neww, newh ); } } /* Popup */ if ( !show_popup && plugin->popup_window ) { gtk_widget_destroy( plugin->popup_window ); plugin->popup_window = NULL; } else if ( show_popup && !plugin->popup_window ) { plugin->popup_window = messenger_popup_new(); g_signal_connect( G_OBJECT( plugin->popup_window ), "clicked", G_CALLBACK( plugin_popup_clicked_cb ), plugin ); } if ( plugin->popup_window ) { guint timeout; g_object_get( G_OBJECT( plugin->preferences ), "popup-duration", &timeout, NULL ); if ( timeout != messenger_popup_get_timeout( MESSENGER_POPUP( plugin->popup_window ) ) ) { messenger_popup_set_timeout( MESSENGER_POPUP( plugin->popup_window ), timeout ); } } plugin->panel_size = panel_size; plugin->panel_orientation = panel_orientation; } static void plugin_size_changed( MessengerPlugin *plugin ) { plugin_update_ui( plugin ); } static void plugin_orientation_changed( MessengerPlugin *plugin ) { plugin_update_ui( plugin ); } static void plugin_destroy( MessengerPlugin *plugin ) { if ( plugin->timeout_id ) { g_source_remove( plugin->timeout_id ); plugin->timeout_id = 0; } if ( plugin->history_dialog ) { gtk_widget_destroy( plugin->history_dialog ); } if ( plugin->prefs_dialog ) { gtk_widget_destroy( plugin->prefs_dialog ); } if ( plugin->popup_window ) { gtk_widget_destroy( plugin->popup_window ); } if ( plugin->message_queue ) { GSList *li = plugin->message_queue; for ( li = plugin->message_queue; li != NULL; li = li->next ) { g_free( li->data ); } g_slist_free( plugin->message_queue ); plugin->message_queue = NULL; } if ( plugin->history ) { messenger_history_free( plugin->history ); } g_object_unref( G_OBJECT( plugin->icons ) ); g_object_unref( G_OBJECT( plugin->tooltip ) ); g_object_unref( G_OBJECT( plugin->messenger ) ); g_object_unref( G_OBJECT( plugin->preferences ) ); if ( empty_pixbuf ) { g_object_unref( G_OBJECT( empty_pixbuf ) ); } g_free( plugin ); } static MessengerPlugin * plugin_new( GtkContainer *container ) { MessengerPlugin *plugin; plugin = g_new0( MessengerPlugin, 1 ); plugin->evbox = gtk_event_box_new(); gtk_event_box_set_above_child( GTK_EVENT_BOX( plugin->evbox ), TRUE ); gtk_widget_show( plugin->evbox ); gtk_container_add( container, plugin->evbox ); plugin->frame = gtk_frame_new( NULL ); gtk_container_set_border_width( GTK_CONTAINER( plugin->frame ), FRAME_BORDER ); gtk_widget_show( plugin->frame ); gtk_container_add( GTK_CONTAINER( plugin->evbox ), plugin->frame ); plugin->preferences = messenger_preferences_get(); plugin->history = messenger_history_new(); plugin->icons = messenger_icon_set_new(); plugin->messenger = messenger_listener_new(); g_signal_connect( G_OBJECT( plugin->evbox ), "button-press-event", G_CALLBACK( plugin_button_press_cb ), plugin ); plugin->notify_handler_id = g_signal_connect_swapped( G_OBJECT( plugin->preferences ), "notify", G_CALLBACK( plugin_update_ui ), plugin ); g_signal_connect( G_OBJECT( plugin->messenger ), "message", G_CALLBACK( plugin_message_cb ), plugin ); plugin->tooltip = gtk_tooltips_new(); g_object_ref( G_OBJECT( plugin->tooltip ) ); gtk_object_sink( GTK_OBJECT( plugin->tooltip ) ); return ( plugin ); } static void plugin_show_preferences( MessengerPlugin *plugin ) { if ( plugin->prefs_dialog ) { gtk_window_present( GTK_WINDOW( plugin->prefs_dialog ) ); return; } plugin->prefs_dialog = messenger_preferences_dialog_new( plugin->preferences ); messenger_preferences_dialog_set_icon_set( MESSENGER_PREFERENCES_DIALOG( plugin->prefs_dialog ), plugin->icons ); g_signal_connect( G_OBJECT( plugin->prefs_dialog ), "view-history-clicked", G_CALLBACK( plugin_preferences_view_history_clicked_cb ), plugin ); g_signal_connect( G_OBJECT( plugin->prefs_dialog ), "destroy", G_CALLBACK( gtk_widget_destroyed ), &(plugin->prefs_dialog) ); g_signal_connect_swapped( G_OBJECT( plugin->prefs_dialog ), "response", G_CALLBACK( gtk_widget_destroy ), plugin->prefs_dialog ); gtk_widget_show( plugin->prefs_dialog ); } /* ======================== PANEL SPECIFIC STUFF ========================== */ static void xfce_messenger_plugin_about_cb( XfcePanelPlugin *panel_plugin, gpointer user_data ) { XfceAboutInfo *info; GtkWidget *dialog; GdkPixbuf *pb; info = xfce_about_info_new( PACKAGE_NAME, PACKAGE_VERSION, _( "DBus message notification plugin" ), XFCE_COPYRIGHT_TEXT( "2005-2006", "Pasi Orovuo " ), XFCE_LICENSE_GPL ); pb = xfce_themed_icon_load( "xfce-mouse", 48 ); dialog = xfce_about_dialog_new( NULL, info, pb ); if ( pb ) { g_object_unref( pb ); } g_signal_connect( G_OBJECT( dialog ), "response", G_CALLBACK( gtk_widget_destroy ), NULL ); g_signal_connect_swapped( G_OBJECT( dialog ), "destroy", G_CALLBACK( xfce_about_info_free ), info ); gtk_widget_show( dialog ); } static void xfce_messenger_plugin_configure_cb( XfcePanelPlugin *panel_plugin, gpointer user_data ) { plugin_show_preferences( user_data ); } static void xfce_messenger_plugin_free_data_cb( XfcePanelPlugin *panel_plugin, gpointer user_data ) { plugin_destroy( user_data ); } static void xfce_messenger_plugin_read_config( XfcePanelPlugin *panel_plugin, gpointer user_data ) { MessengerPlugin *plugin = user_data; gchar *fn; XfceRc *rc; gchar **icons; guint i; gboolean show_label, show_popup, save_history, show_icon; guint label_width, message_duration, popup_duration; fn = xfce_panel_plugin_lookup_rc_file( panel_plugin ); if ( !fn ) { return; } rc = xfce_rc_simple_open( fn, TRUE ); g_free( fn ); if ( !rc ) { return; } /* Ass (defaults) */ g_object_get( G_OBJECT( plugin->preferences ), "show-icon", &show_icon, "show-label", &show_label, "label-width", &label_width, "message-duration", &message_duration, "show-popup", &show_popup, "popup-duration", &popup_duration, "save-history", &save_history, NULL ); g_signal_handler_block( plugin->preferences, plugin->notify_handler_id ); xfce_rc_set_group( rc, "General" ); show_icon = xfce_rc_read_bool_entry( rc, "show_icon", show_icon ); show_label = xfce_rc_read_bool_entry( rc, "show_label", show_label ); label_width = xfce_rc_read_int_entry( rc, "label_width", label_width ); message_duration = xfce_rc_read_int_entry( rc, "message_duration", message_duration ); show_popup = xfce_rc_read_bool_entry( rc, "show_popup", show_popup ); popup_duration = xfce_rc_read_int_entry( rc, "popup_duration", popup_duration ); save_history = xfce_rc_read_bool_entry( rc, "save_history", save_history ); g_object_set( G_OBJECT( plugin->preferences ), "show-icon", show_icon, "show-label", show_label, "label-width", label_width, "message-duration", message_duration, "show-popup", show_popup, "popup-duration", popup_duration, "save-history", save_history, NULL ); g_signal_handler_unblock( plugin->preferences, plugin->notify_handler_id ); if ( save_history ) { gchar idxstr[32]; guint index = 0; const gchar *value; gchar **strv; xfce_rc_set_group( rc, "History" ); g_snprintf( idxstr, sizeof( idxstr ), "item%u", index++ ); value = xfce_rc_read_entry( rc, idxstr, NULL ); while ( value ) { strv = g_strsplit( value, ";", 2 ); if ( g_strv_length( strv ) == 2 ) { messenger_history_message_append_raw( plugin->history, strv[1], strv[0] ); } g_strfreev( strv ); g_snprintf( idxstr, sizeof( idxstr ), "item%u", index++ ); value = xfce_rc_read_entry( rc, idxstr, NULL ); } } xfce_rc_set_group( rc, "Icons" ); icons = xfce_rc_get_entries( rc, "Icons" ); if ( icons ) { for ( i = 0; icons[i]; i++ ) { const gchar *value; value = xfce_rc_read_entry( rc, icons[i], NULL ); if ( value ) { messenger_icon_set_add_icon( plugin->icons, icons[i], value ); } } g_strfreev( icons ); } xfce_rc_close( rc ); plugin_update_ui( plugin ); } static void history_foreach_write_rc_cb( guint index, const gchar *message, const gchar *timestr, gpointer user_data ) { XfceRc *rc = user_data; gchar idx[32]; gchar *value; g_snprintf( idx, sizeof( idx ), "item%u", index ); value = g_strdup_printf( "%s;%s", timestr, message ); xfce_rc_write_entry( rc, idx, value ); g_free( value ); } static void icons_foreach_write_rc_cb( const gchar *identifier, const gchar *source, gpointer user_data ) { XfceRc *rc = user_data; xfce_rc_write_entry( rc, identifier, source ); } static void xfce_messenger_plugin_write_config( XfcePanelPlugin *panel_plugin, gpointer user_data ) { MessengerPlugin *plugin = user_data; gchar *fn; XfceRc *rc; gboolean show_label, show_popup, save_history, show_icon; guint label_width, message_duration, popup_duration; fn = xfce_panel_plugin_save_location( panel_plugin, TRUE ); if ( !fn ) { return; } rc = xfce_rc_simple_open( fn, FALSE ); g_free( fn ); if ( !rc ) { return; } g_object_get( G_OBJECT( plugin->preferences ), "show-icon", &show_icon, "show-label", &show_label, "label-width", &label_width, "message-duration", &message_duration, "show-popup", &show_popup, "popup-duration", &popup_duration, "save-history", &save_history, NULL ); xfce_rc_set_group( rc, "General" ); xfce_rc_write_bool_entry( rc, "show_icon", show_icon ); xfce_rc_write_bool_entry( rc, "show_label", show_label ); xfce_rc_write_int_entry( rc, "label_width", (gint) label_width ); xfce_rc_write_int_entry( rc, "message_duration", (gint) message_duration ); xfce_rc_write_bool_entry( rc, "show_popup", show_popup ); xfce_rc_write_int_entry( rc, "popup_duration", popup_duration ); xfce_rc_write_bool_entry( rc, "save_history", save_history ); if ( save_history ) { xfce_rc_set_group( rc, "History" ); messenger_history_foreach( plugin->history, history_foreach_write_rc_cb, rc ); } else { xfce_rc_delete_group( rc, "History", TRUE ); } xfce_rc_set_group( rc, "Icons" ); messenger_icon_set_foreach( plugin->icons, icons_foreach_write_rc_cb, rc ); xfce_rc_close( rc ); } static void xfce_messenger_plugin_orientation_changed_cb( XfcePanelPlugin *plugin, GtkOrientation orientation, gpointer user_data ) { plugin_orientation_changed( user_data ); } static gboolean xfce_messenger_plugin_size_changed_cb( XfcePanelPlugin *plugin, gint size, gpointer user_data ) { plugin_size_changed( user_data ); return ( TRUE ); } static void xfce_messenger_plugin_construct( XfcePanelPlugin *panel_plugin ) { MessengerPlugin *messenger_plugin; messenger_plugin = plugin_new( GTK_CONTAINER( panel_plugin ) ); messenger_plugin->panel_plugin = panel_plugin; xfce_panel_plugin_add_action_widget( panel_plugin, messenger_plugin->evbox ); xfce_messenger_plugin_read_config( panel_plugin, messenger_plugin ); xfce_panel_plugin_menu_show_configure( panel_plugin ); xfce_panel_plugin_menu_show_about( panel_plugin ); g_signal_connect( G_OBJECT( panel_plugin ), "about", G_CALLBACK( xfce_messenger_plugin_about_cb ), messenger_plugin ); g_signal_connect( G_OBJECT( panel_plugin ), "free-data", G_CALLBACK( xfce_messenger_plugin_free_data_cb ), messenger_plugin ); g_signal_connect( G_OBJECT( panel_plugin ), "orientation-changed", G_CALLBACK( xfce_messenger_plugin_orientation_changed_cb ), messenger_plugin ); g_signal_connect( G_OBJECT( panel_plugin ), "size-changed", G_CALLBACK( xfce_messenger_plugin_size_changed_cb ), messenger_plugin ); g_signal_connect( G_OBJECT( panel_plugin ), "configure-plugin", G_CALLBACK( xfce_messenger_plugin_configure_cb ), messenger_plugin ); g_signal_connect( G_OBJECT( panel_plugin ), "save", G_CALLBACK( xfce_messenger_plugin_write_config ), messenger_plugin ); } XFCE_PANEL_PLUGIN_REGISTER_EXTERNAL( xfce_messenger_plugin_construct );