pidgin/pidgin

propagate from branch 'im.pidgin.pidgin' (head 1edfa83f6ff820fb7904d5bab5b0943f691976f6)
soc.2008.masterpassword
2012-02-28, Elliott Sales de Andrade
9c3c6a138135
propagate from branch 'im.pidgin.pidgin' (head 1edfa83f6ff820fb7904d5bab5b0943f691976f6)
to branch 'im.pidgin.soc.2008.masterpassword' (head 95a3ed96cc2d4de63a86a8c133693758540ef74c)
  • +6 -2
    ChangeLog
  • +7 -0
    ChangeLog.API
  • +20 -0
    finch/gntrequest.c
  • +64 -194
    libpurple/certificate.c
  • +20 -10
    libpurple/certificate.h
  • +6 -3
    libpurple/plugins/autoaccept.c
  • +50 -1
    libpurple/plugins/ssl/ssl-gnutls.c
  • +50 -1
    libpurple/plugins/ssl/ssl-nss.c
  • +8 -2
    libpurple/protocols/jabber/Makefile.am
  • +19 -1
    libpurple/protocols/jabber/Makefile.mingw
  • +326 -0
    libpurple/protocols/jabber/libfacebook.c
  • +334 -0
    libpurple/protocols/jabber/libgtalk.c
  • +53 -0
    libpurple/request.c
  • +63 -1
    libpurple/request.h
  • +9 -27
    pidgin/gtkaccount.c
  • +422 -244
    pidgin/gtkblist.c
  • +1 -1
    pidgin/gtkblist.h
  • +5 -0
    pidgin/gtkcellrendererexpander.c
  • +5 -40
    pidgin/gtkcertmgr.c
  • +340 -285
    pidgin/gtkconv.c
  • +4 -0
    pidgin/gtkconv.h
  • +21 -22
    pidgin/gtkconvwin.h
  • +10 -0
    pidgin/gtkdebug.c
  • +6 -0
    pidgin/gtkdialogs.c
  • +5 -4
    pidgin/gtkdnd-hints.c
  • +1 -1
    pidgin/gtkdocklet.c
  • +4 -2
    pidgin/gtkidle.c
  • +14 -4
    pidgin/gtkimhtml.c
  • +24 -3
    pidgin/gtkimhtmltoolbar.c
  • +4 -0
    pidgin/gtkimhtmltoolbar.h
  • +2 -0
    pidgin/gtklog.c
  • +17 -3
    pidgin/gtkmenutray.c
  • +2 -0
    pidgin/gtkmenutray.h
  • +12 -0
    pidgin/gtknotify.c
  • +4 -0
    pidgin/gtkpounce.c
  • +99 -74
    pidgin/gtkprefs.c
  • +88 -4
    pidgin/gtkrequest.c
  • +4 -0
    pidgin/gtksavedstatuses.c
  • +1 -1
    pidgin/gtkscrollbook.c
  • +14 -4
    pidgin/gtkstatusbox.c
  • +121 -179
    pidgin/gtkutils.c
  • +75 -123
    pidgin/gtkwebview.c
  • +9 -31
    pidgin/gtkwebview.h
  • +16 -19
    pidgin/gtkwebviewtoolbar.c
  • +3 -4
    pidgin/plugins/contact_priority.c
  • +0 -34
    pidgin/plugins/gestures/gestures.c
  • +2 -0
    pidgin/plugins/themeedit.c
  • +14 -17
    pidgin/plugins/ticker/gtkticker.c
  • +2 -2
    pidgin/plugins/vvconfig.c
  • +6 -0
    pidgin/plugins/xmppconsole.c
  • --- a/ChangeLog Thu Feb 23 08:13:29 2012 +0000
    +++ b/ChangeLog Tue Feb 28 05:29:13 2012 +0000
    @@ -24,8 +24,6 @@
    MSN:
    * Fix file transfer with older Mac MSN clients.
    * Support file transfers up to ~9 EiB.
    - * Support new protocol version MSNP18. (#14753)
    - * Fix messages to offline contacts. (#14302)
    MXit:
    * Remove all reference to Hidden Number.
    @@ -70,10 +68,16 @@
    MSN:
    * Fix possible crashes caused by not validating incoming messages as
    UTF-8. (Thijs Alkemade) (#14884)
    + * Support new protocol version MSNP18. (#14753)
    + * Fix messages to offline contacts. (#14302)
    Windows-Specific Changes:
    * Fix compilation of the Bonjour protocol plugin. (#14802)
    + Plugins:
    + * The autoaccept plugin will no longer reset the preference for unknown
    + buddies to "Auto Reject" in certain cases. (#14964)
    +
    version 2.10.1 (12/06/2011):
    Finch:
    * Fix compilation on OpenBSD.
    --- a/ChangeLog.API Thu Feb 23 08:13:29 2012 +0000
    +++ b/ChangeLog.API Tue Feb 28 05:29:13 2012 +0000
    @@ -8,6 +8,8 @@
    * purple_account_get_ui_data
    * purple_account_set_ui_data
    * purple_account_register_completed
    + * purple_certificate_get_der_data
    + * purple_certificate_get_display_string
    * purple_conv_chat_cb_get_alias
    * purple_conv_chat_cb_get_flags
    * purple_conv_chat_cb_is_buddy
    @@ -32,6 +34,9 @@
    * purple_menu_action_set_data
    * purple_menu_action_set_callback
    * purple_menu_action_set_children
    + * purple_request_certificate
    + * purple_request_field_certificate_new
    + * purple_request_field_certificate_get_value
    * purple_request_field_get_tooltip
    * purple_request_field_group_get_fields_list
    * purple_request_field_set_tooltip
    @@ -159,6 +164,8 @@
    * purple_buddy_icons_set_custom_icon
    * purple_certificate_check_signature_chain_with_failing. Use
    purple_certificate_check_signature_chain, instead
    + * purple_certificate_display_x509. Use purple_request_certificate,
    + instead
    * purple_connection_error_reason
    * purple_connection_new
    * purple_connection_new_unregister
    --- a/finch/gntrequest.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/finch/gntrequest.c Tue Feb 28 05:29:13 2012 +0000
    @@ -571,6 +571,22 @@
    return combo;
    }
    +static GntWidget*
    +create_certificate_field(PurpleRequestField *field)
    +{
    + GntWidget *w;
    + PurpleCertificate *cert;
    + char *str;
    +
    + cert = purple_request_field_certificate_get_value(field);
    + str = purple_certificate_get_display_string(cert);
    + w = gnt_label_new(str);
    +
    + g_free(str);
    +
    + return w;
    +}
    +
    static void *
    finch_request_fields(const char *title, const char *primary,
    const char *secondary, PurpleRequestFields *allfields,
    @@ -650,6 +666,10 @@
    accountlist = create_account_field(field);
    purple_request_field_set_ui_data(field, accountlist);
    }
    + else if (type == PURPLE_REQUEST_FIELD_CERTIFICATE)
    + {
    + purple_request_field_set_ui_data(field, create_certificate_field(field));
    + }
    else
    {
    purple_request_field_set_ui_data(field, gnt_label_new_with_format(_("Not implemented yet."),
    --- a/libpurple/certificate.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/certificate.c Tue Feb 28 05:29:13 2012 +0000
    @@ -518,6 +518,24 @@
    }
    gchar *
    +purple_certificate_get_display_string(PurpleCertificate *crt)
    +{
    + PurpleCertificateScheme *scheme;
    + gchar *str;
    +
    + g_return_val_if_fail(crt, NULL);
    + g_return_val_if_fail(crt->scheme, NULL);
    +
    + scheme = crt->scheme;
    +
    + g_return_val_if_fail(scheme->get_display_string, NULL);
    +
    + str = (scheme->get_display_string)(crt);
    +
    + return str;
    +}
    +
    +gchar *
    purple_certificate_pool_mkpath(PurpleCertificatePool *pool, const gchar *id)
    {
    gchar *path;
    @@ -662,77 +680,62 @@
    /****************************************************************************/
    static void
    -x509_singleuse_verify_cb (PurpleCertificateVerificationRequest *vrq, gint id)
    +x509_singleuse_verify_accept_cb(PurpleCertificateVerificationRequest *vrq)
    {
    g_return_if_fail(vrq);
    purple_debug_info("certificate/x509_singleuse",
    - "VRQ on cert from %s gave %d\n",
    - vrq->subject_name, id);
    + "VRQ on cert from %s accepted\n",
    + vrq->subject_name);
    +
    + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID);
    +}
    - /* Signal what happened back to the caller */
    - if (1 == id) {
    - /* Accepted! */
    - purple_certificate_verify_complete(vrq,
    - PURPLE_CERTIFICATE_VALID);
    - } else {
    - /* Not accepted */
    - purple_certificate_verify_complete(vrq,
    - PURPLE_CERTIFICATE_INVALID);
    +static void
    +x509_singleuse_verify_reject_cb(PurpleCertificateVerificationRequest *vrq)
    +{
    + g_return_if_fail(vrq);
    - }
    + purple_debug_info("certificate/x509_singleuse",
    + "VRQ on cert from %s rejected\n",
    + vrq->subject_name);
    +
    + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID);
    }
    static void
    x509_singleuse_start_verify (PurpleCertificateVerificationRequest *vrq)
    {
    - gchar *sha_asc;
    - GByteArray *sha_bin;
    gchar *cn;
    const gchar *cn_match;
    gchar *primary, *secondary;
    - PurpleCertificate *crt = (PurpleCertificate *) vrq->cert_chain->data;
    + PurpleCertificate *crt = (PurpleCertificate *)vrq->cert_chain->data;
    - /* Pull out the SHA1 checksum */
    - sha_bin = purple_certificate_get_fingerprint_sha1(crt);
    - /* Now decode it for display */
    - sha_asc = purple_base16_encode_chunked(sha_bin->data,
    - sha_bin->len);
    -
    - /* Get the cert Common Name */
    cn = purple_certificate_get_subject_name(crt);
    - /* Determine whether the name matches */
    if (purple_certificate_check_subject_name(crt, vrq->subject_name)) {
    - cn_match = "";
    + cn_match = _("(MATCH)");
    } else {
    cn_match = _("(DOES NOT MATCH)");
    }
    - /* Make messages */
    primary = g_strdup_printf(_("%s has presented the following certificate for just-this-once use:"), vrq->subject_name);
    - secondary = g_strdup_printf(_("Common name: %s %s\nFingerprint (SHA1): %s"), cn, cn_match, sha_asc);
    + secondary = g_strdup_printf(_("Common name: %s %s"), cn, cn_match);
    /* Make a semi-pretty display */
    - purple_request_accept_cancel(
    + purple_request_certificate(
    vrq->cb_data, /* TODO: Find what the handle ought to be */
    _("Single-use Certificate Verification"),
    primary,
    secondary,
    - 0, /* Accept by default */
    - NULL, /* No account */
    - NULL, /* No other user */
    - NULL, /* No associated conversation */
    - vrq,
    - x509_singleuse_verify_cb,
    - x509_singleuse_verify_cb );
    + crt,
    + _("Accept"), G_CALLBACK(x509_singleuse_verify_accept_cb),
    + _("Reject"), G_CALLBACK(x509_singleuse_verify_reject_cb),
    + vrq);
    - /* Cleanup */
    g_free(cn);
    g_free(primary);
    g_free(secondary);
    - g_free(sha_asc);
    - g_byte_array_free(sha_bin, TRUE);
    }
    static void
    @@ -1289,102 +1292,34 @@
    static PurpleCertificateVerifier x509_tls_cached;
    -/* The following is several hacks piled together and needs to be fixed.
    - * It exists because show_cert (see its comments) needs the original reason
    - * given to user_auth in order to rebuild the dialog.
    - */
    -/* TODO: This will cause a ua_ctx to become memleaked if the request(s) get
    - closed by handle or otherwise abnormally. */
    -typedef struct {
    - PurpleCertificateVerificationRequest *vrq;
    - gchar *reason;
    -} x509_tls_cached_ua_ctx;
    -
    -static x509_tls_cached_ua_ctx *
    -x509_tls_cached_ua_ctx_new(PurpleCertificateVerificationRequest *vrq,
    - const gchar *reason)
    +static void
    +x509_tls_cached_user_auth_accept_cb(PurpleCertificateVerificationRequest *vrq)
    {
    - x509_tls_cached_ua_ctx *c;
    + PurpleCertificatePool *tls_peers;
    + gchar *cache_id;
    - c = g_new0(x509_tls_cached_ua_ctx, 1);
    - c->vrq = vrq;
    - c->reason = g_strdup(reason);
    + g_return_if_fail(vrq);
    +
    + tls_peers = purple_certificate_find_pool("x509", "tls_peers");
    - return c;
    -}
    -
    + cache_id = vrq->subject_name;
    + purple_debug_info("certificate/x509/tls_cached",
    + "User ACCEPTED cert\nCaching first in chain for future use as %s...\n",
    + cache_id);
    -static void
    -x509_tls_cached_ua_ctx_free(x509_tls_cached_ua_ctx *c)
    -{
    - g_return_if_fail(c);
    - g_free(c->reason);
    - g_free(c);
    + purple_certificate_pool_store(tls_peers, cache_id, vrq->cert_chain->data);
    +
    + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID);
    }
    static void
    -x509_tls_cached_user_auth(PurpleCertificateVerificationRequest *vrq,
    - const gchar *reason);
    -
    -static void
    -x509_tls_cached_show_cert(x509_tls_cached_ua_ctx *c, gint id)
    +x509_tls_cached_user_auth_reject_cb(PurpleCertificateVerificationRequest *vrq)
    {
    - PurpleCertificate *disp_crt = c->vrq->cert_chain->data;
    -
    - /* Since clicking a button closes the request, show it again */
    - x509_tls_cached_user_auth(c->vrq, c->reason);
    -
    - /* Show the certificate AFTER re-opening the dialog so that this
    - appears above the other */
    - purple_certificate_display_x509(disp_crt);
    -
    - x509_tls_cached_ua_ctx_free(c);
    -}
    -
    -static void
    -x509_tls_cached_user_auth_cb (x509_tls_cached_ua_ctx *c, gint id)
    -{
    - PurpleCertificateVerificationRequest *vrq;
    - PurpleCertificatePool *tls_peers;
    -
    - g_return_if_fail(c);
    - g_return_if_fail(c->vrq);
    -
    - vrq = c->vrq;
    -
    - x509_tls_cached_ua_ctx_free(c);
    + g_return_if_fail(vrq);
    - tls_peers = purple_certificate_find_pool("x509","tls_peers");
    -
    - if (2 == id) {
    - gchar *cache_id = vrq->subject_name;
    - purple_debug_info("certificate/x509/tls_cached",
    - "User ACCEPTED cert\nCaching first in chain for future use as %s...\n",
    - cache_id);
    -
    - purple_certificate_pool_store(tls_peers, cache_id,
    - vrq->cert_chain->data);
    + purple_debug_warning("certificate/x509/tls_cached", "User REJECTED cert\n");
    - purple_certificate_verify_complete(vrq,
    - PURPLE_CERTIFICATE_VALID);
    - } else {
    - purple_debug_warning("certificate/x509/tls_cached",
    - "User REJECTED cert\n");
    - purple_certificate_verify_complete(vrq,
    - PURPLE_CERTIFICATE_INVALID);
    - }
    -}
    -
    -static void
    -x509_tls_cached_user_auth_accept_cb(x509_tls_cached_ua_ctx *c, gint ignore)
    -{
    - x509_tls_cached_user_auth_cb(c, 2);
    -}
    -
    -static void
    -x509_tls_cached_user_auth_reject_cb(x509_tls_cached_ua_ctx *c, gint ignore)
    -{
    - x509_tls_cached_user_auth_cb(c, 1);
    + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID);
    }
    /** Validates a certificate by asking the user
    @@ -1398,27 +1333,19 @@
    {
    gchar *primary;
    - /* Make messages */
    primary = g_strdup_printf(_("Accept certificate for %s?"),
    vrq->subject_name);
    - /* Make a semi-pretty display */
    - purple_request_action(
    + purple_request_certificate(
    vrq->cb_data, /* TODO: Find what the handle ought to be */
    _("SSL Certificate Verification"),
    primary,
    reason,
    - 0, /* Accept by default */
    - NULL, /* No account */
    - NULL, /* No other user */
    - NULL, /* No associated conversation */
    - x509_tls_cached_ua_ctx_new(vrq, reason),
    - 3, /* Number of actions */
    - _("Accept"), x509_tls_cached_user_auth_accept_cb,
    - _("Reject"), x509_tls_cached_user_auth_reject_cb,
    - _("_View Certificate..."), x509_tls_cached_show_cert);
    + vrq->cert_chain->data,
    + _("Accept"), G_CALLBACK(x509_tls_cached_user_auth_accept_cb),
    + _("Reject"), G_CALLBACK(x509_tls_cached_user_auth_reject_cb),
    + vrq);
    - /* Cleanup */
    g_free(primary);
    }
    @@ -2165,63 +2092,6 @@
    /* Scheme-specific functions */
    /****************************************************************************/
    -void
    -purple_certificate_display_x509(PurpleCertificate *crt)
    -{
    - gchar *sha_asc;
    - GByteArray *sha_bin;
    - gchar *cn;
    - time_t activation, expiration;
    - gchar *activ_str, *expir_str;
    - gchar *secondary;
    -
    - /* Pull out the SHA1 checksum */
    - sha_bin = purple_certificate_get_fingerprint_sha1(crt);
    - /* Now decode it for display */
    - sha_asc = purple_base16_encode_chunked(sha_bin->data,
    - sha_bin->len);
    -
    - /* Get the cert Common Name */
    - /* TODO: Will break on CA certs */
    - cn = purple_certificate_get_subject_name(crt);
    -
    - /* Get the certificate times */
    - /* TODO: Check the times against localtime */
    - /* TODO: errorcheck? */
    - if (!purple_certificate_get_times(crt, &activation, &expiration)) {
    - purple_debug_error("certificate",
    - "Failed to get certificate times!\n");
    - activation = expiration = 0;
    - }
    - activ_str = g_strdup(ctime(&activation));
    - expir_str = g_strdup(ctime(&expiration));
    -
    - /* Make messages */
    - secondary = g_strdup_printf(_("Common name: %s\n\n"
    - "Fingerprint (SHA1): %s\n\n"
    - "Activation date: %s\n"
    - "Expiration date: %s\n"),
    - cn ? cn : "(null)",
    - sha_asc ? sha_asc : "(null)",
    - activ_str ? activ_str : "(null)",
    - expir_str ? expir_str : "(null)");
    -
    - /* Make a semi-pretty display */
    - purple_notify_info(
    - NULL, /* TODO: Find what the handle ought to be */
    - _("Certificate Information"),
    - "",
    - secondary);
    -
    - /* Cleanup */
    - g_free(cn);
    - g_free(secondary);
    - g_free(sha_asc);
    - g_free(activ_str);
    - g_free(expir_str);
    - g_byte_array_free(sha_bin, TRUE);
    -}
    -
    void purple_certificate_add_ca_search_path(const char *path)
    {
    if (g_list_find_custom(x509_ca_paths, path, (GCompareFunc)strcmp))
    --- a/libpurple/certificate.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/certificate.h Tue Feb 28 05:29:13 2012 +0000
    @@ -261,8 +261,16 @@
    */
    GByteArray * (* get_der_data)(PurpleCertificate *crt);
    + /**
    + * Retrieves a string representation of the certificate suitable for display
    + *
    + * @param crt Certificate instance
    + * @return User-displayable string representation of certificate - must be
    + * freed using g_free().
    + */
    + gchar * (* get_display_string)(PurpleCertificate *crt);
    +
    void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    };
    /** A set of operations used to provide logic for verifying a Certificate's
    @@ -577,6 +585,17 @@
    GByteArray *
    purple_certificate_get_der_data(PurpleCertificate *crt);
    +/**
    + * Retrieves a string suitable for displaying a certificate to the user.
    + *
    + * @param crt Certificate instance
    + *
    + * @return String representing the certificate that may be displayed to the user
    + * - must be freed using g_free().
    + */
    +char *
    +purple_certificate_get_display_string(PurpleCertificate *crt);
    +
    /*@}*/
    /*****************************************************************************/
    @@ -815,15 +834,6 @@
    /**
    - * Displays a window showing X.509 certificate information
    - *
    - * @param crt Certificate under an "x509" Scheme
    - * @todo Will break on CA certs, as they have no Common Name
    - */
    -void
    -purple_certificate_display_x509(PurpleCertificate *crt);
    -
    -/**
    * Add a search path for certificates.
    *
    * @param path Path to search for certificates.
    --- a/libpurple/plugins/autoaccept.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/plugins/autoaccept.c Tue Feb 28 05:29:13 2012 +0000
    @@ -238,8 +238,12 @@
    * between old libpurple clients and new libpurple clients.
    * --Mark Doliner, 2011-01-03
    */
    - if(purple_prefs_get_bool(PREF_STRANGER_OLD))
    - purple_prefs_set_int(PREF_STRANGER, FT_REJECT);
    + if (!purple_prefs_exists(PREF_STRANGER)) {
    + if (purple_prefs_get_bool(PREF_STRANGER_OLD))
    + purple_prefs_add_int(PREF_STRANGER, FT_REJECT);
    + else
    + purple_prefs_set_int(PREF_STRANGER, FT_ASK);
    + }
    purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", plugin,
    PURPLE_CALLBACK(file_recv_request_cb), plugin);
    @@ -345,7 +349,6 @@
    dirname = g_build_filename(purple_user_dir(), "autoaccept", NULL);
    purple_prefs_add_none(PREF_PREFIX);
    purple_prefs_add_string(PREF_PATH, dirname);
    - purple_prefs_add_int(PREF_STRANGER, FT_ASK);
    purple_prefs_add_bool(PREF_NOTIFY, TRUE);
    purple_prefs_add_bool(PREF_NEWDIR, TRUE);
    purple_prefs_add_bool(PREF_ESCAPE, TRUE);
    --- a/libpurple/plugins/ssl/ssl-gnutls.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/plugins/ssl/ssl-gnutls.c Tue Feb 28 05:29:13 2012 +0000
    @@ -1173,6 +1173,55 @@
    return data;
    }
    +static gchar *
    +x509_display_string(PurpleCertificate *crt)
    +{
    + gchar *sha_asc;
    + GByteArray *sha_bin;
    + gchar *cn;
    + time_t activation, expiration;
    + gchar *activ_str, *expir_str;
    + gchar *text;
    +
    + /* Pull out the SHA1 checksum */
    + sha_bin = x509_sha1sum(crt);
    + sha_asc = purple_base16_encode_chunked(sha_bin->data, sha_bin->len);
    +
    + /* Get the cert Common Name */
    + /* TODO: Will break on CA certs */
    + cn = x509_common_name(crt);
    +
    + /* Get the certificate times */
    + /* TODO: Check the times against localtime */
    + /* TODO: errorcheck? */
    + if (!x509_times(crt, &activation, &expiration)) {
    + purple_debug_error("certificate",
    + "Failed to get certificate times!\n");
    + activation = expiration = 0;
    + }
    + activ_str = g_strdup(ctime(&activation));
    + expir_str = g_strdup(ctime(&expiration));
    +
    + /* Make messages */
    + text = g_strdup_printf(_("Common name: %s\n\n"
    + "Fingerprint (SHA1): %s\n\n"
    + "Activation date: %s\n"
    + "Expiration date: %s\n"),
    + cn ? cn : "(null)",
    + sha_asc ? sha_asc : "(null)",
    + activ_str ? activ_str : "(null)",
    + expir_str ? expir_str : "(null)");
    +
    + /* Cleanup */
    + g_free(cn);
    + g_free(sha_asc);
    + g_free(activ_str);
    + g_free(expir_str);
    + g_byte_array_free(sha_bin, TRUE);
    +
    + return text;
    +}
    +
    /* X.509 certificate operations provided by this plugin */
    static PurpleCertificateScheme x509_gnutls = {
    "x509", /* Scheme name */
    @@ -1190,8 +1239,8 @@
    x509_times, /* Activation/Expiration time */
    x509_importcerts_from_file, /* Multiple certificates import function */
    x509_get_der_data, /* Binary DER data */
    + x509_display_string, /* Display representation */
    - NULL,
    NULL
    };
    --- a/libpurple/plugins/ssl/ssl-nss.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/plugins/ssl/ssl-nss.c Tue Feb 28 05:29:13 2012 +0000
    @@ -953,6 +953,55 @@
    return data;
    }
    +static gchar *
    +x509_display_string(PurpleCertificate *crt)
    +{
    + gchar *sha_asc;
    + GByteArray *sha_bin;
    + gchar *cn;
    + time_t activation, expiration;
    + gchar *activ_str, *expir_str;
    + gchar *text;
    +
    + /* Pull out the SHA1 checksum */
    + sha_bin = x509_sha1sum(crt);
    + sha_asc = purple_base16_encode_chunked(sha_bin->data, sha_bin->len);
    +
    + /* Get the cert Common Name */
    + /* TODO: Will break on CA certs */
    + cn = x509_common_name(crt);
    +
    + /* Get the certificate times */
    + /* TODO: Check the times against localtime */
    + /* TODO: errorcheck? */
    + if (!x509_times(crt, &activation, &expiration)) {
    + purple_debug_error("certificate",
    + "Failed to get certificate times!\n");
    + activation = expiration = 0;
    + }
    + activ_str = g_strdup(ctime(&activation));
    + expir_str = g_strdup(ctime(&expiration));
    +
    + /* Make messages */
    + text = g_strdup_printf(_("Common name: %s\n\n"
    + "Fingerprint (SHA1): %s\n\n"
    + "Activation date: %s\n"
    + "Expiration date: %s\n"),
    + cn ? cn : "(null)",
    + sha_asc ? sha_asc : "(null)",
    + activ_str ? activ_str : "(null)",
    + expir_str ? expir_str : "(null)");
    +
    + /* Cleanup */
    + g_free(cn);
    + g_free(sha_asc);
    + g_free(activ_str);
    + g_free(expir_str);
    + g_byte_array_free(sha_bin, TRUE);
    +
    + return text;
    +}
    +
    static PurpleCertificateScheme x509_nss = {
    "x509", /* Scheme name */
    N_("X.509 Certificates"), /* User-visible scheme name */
    @@ -969,8 +1018,8 @@
    x509_times, /* Activation/Expiration time */
    x509_importcerts_from_file, /* Multiple certificate import function */
    x509_get_der_data, /* Binary DER data */
    + x509_display_string, /* Display representation */
    - NULL,
    NULL
    };
    --- a/libpurple/protocols/jabber/Makefile.am Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/protocols/jabber/Makefile.am Tue Feb 28 05:29:13 2012 +0000
    @@ -103,19 +103,25 @@
    st = -DPURPLE_STATIC_PRPL
    noinst_LTLIBRARIES = libjabber.la
    -libjabber_la_SOURCES = $(JABBERSOURCES) libxmpp.c
    +libjabber_la_SOURCES = $(JABBERSOURCES) libfacebook.c libgtalk.c libxmpp.c
    libjabber_la_CFLAGS = $(AM_CFLAGS)
    else
    st =
    -pkg_LTLIBRARIES = libjabber.la libxmpp.la
    +pkg_LTLIBRARIES = libjabber.la libfacebook.la libgtalk.la libxmpp.la
    libjabber_la_SOURCES = $(JABBERSOURCES)
    libjabber_la_LIBADD = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS)\
    $(FARSIGHT_LIBS) \
    $(GSTREAMER_LIBS) \
    $(GSTINTERFACES_LIBS)
    +libfacebook_la_SOURCES = libfacebook.c
    +libfacebook_la_LIBADD = libjabber.la
    +
    +libgtalk_la_SOURCES = libgtalk.c
    +libgtalk_la_LIBADD = libjabber.la
    +
    libxmpp_la_SOURCES = libxmpp.c
    libxmpp_la_LIBADD = libjabber.la
    --- a/libpurple/protocols/jabber/Makefile.mingw Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/protocols/jabber/Makefile.mingw Tue Feb 28 05:29:13 2012 +0000
    @@ -8,6 +8,8 @@
    include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
    TARGET = libjabber
    +FACEBOOK_TARGET = libfacebook
    +GTALK_TARGET = libgtalk
    XMPP_TARGET = libxmpp
    TYPE = PLUGIN
    @@ -90,6 +92,12 @@
    OBJECTS = $(C_SRC:%.c=%.o)
    +FACEBOOK_C_SRC = libfacebook.c
    +FACEBOOK_OBJECTS = $(FACEBOOK_C_SRC:%.c=%.o)
    +
    +GTALK_C_SRC = libgtalk.c
    +GTALK_OBJECTS = $(GTALK_C_SRC:%.c=%.o)
    +
    XMPP_C_SRC = libxmpp.c
    XMPP_OBJECTS = $(XMPP_C_SRC:%.c=%.o)
    @@ -129,9 +137,11 @@
    ##
    .PHONY: all install clean
    -all: $(TARGET).dll $(XMPP_TARGET).dll
    +all: $(TARGET).dll $(FACEBOOK_TARGET).dll $(GTALK_TARGET).dll $(XMPP_TARGET).dll
    install: all $(DLL_INSTALL_DIR)
    + cp $(FACEBOOK_TARGET).dll $(DLL_INSTALL_DIR)
    + cp $(GTALK_TARGET).dll $(DLL_INSTALL_DIR)
    cp $(XMPP_TARGET).dll $(DLL_INSTALL_DIR)
    cp $(TARGET).dll $(PURPLE_INSTALL_DIR)
    ifeq ($(CYRUS_SASL), 1)
    @@ -145,6 +155,12 @@
    $(TARGET).dll $(TARGET).dll.a: $(PURPLE_DLL).a $(OBJECTS)
    $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--out-implib,$(TARGET).dll.a -o $(TARGET).dll
    +$(FACEBOOK_TARGET).dll: $(TARGET).dll.a $(FACEBOOK_OBJECTS)
    + $(CC) -shared $(FACEBOOK_OBJECTS) $(LIB_PATHS) $(LIBS) -ljabber $(DLL_LD_FLAGS) -o $(FACEBOOK_TARGET).dll
    +
    +$(GTALK_TARGET).dll: $(TARGET).dll.a $(GTALK_OBJECTS)
    + $(CC) -shared $(GTALK_OBJECTS) $(LIB_PATHS) $(LIBS) -ljabber $(DLL_LD_FLAGS) -o $(GTALK_TARGET).dll
    +
    $(XMPP_TARGET).dll: $(TARGET).dll.a $(XMPP_OBJECTS)
    $(CC) -shared $(XMPP_OBJECTS) $(LIB_PATHS) $(LIBS) -ljabber $(DLL_LD_FLAGS) -o $(XMPP_TARGET).dll
    @@ -153,6 +169,8 @@
    ##
    clean:
    rm -f $(OBJECTS) $(TARGET).dll $(TARGET).dll.a
    + rm -f $(FACEBOOK_OBJECTS) $(FACEBOOK_TARGET).dll
    + rm -f $(GTALK_OBJECTS) $(GTALK_TARGET).dll
    rm -f $(XMPP_OBJECTS) $(XMPP_TARGET).dll
    include $(PIDGIN_COMMON_TARGETS)
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/jabber/libfacebook.c Tue Feb 28 05:29:13 2012 +0000
    @@ -0,0 +1,326 @@
    +/* purple
    + *
    + * Purple is the legal property of its developers, whose names are too numerous
    + * to list here. Please refer to the COPYRIGHT file distributed with this
    + * source distribution.
    + *
    + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    + *
    + */
    +
    +/* libfacebook is the Facebook XMPP protocol plugin. It is linked against
    + * libjabbercommon, which may be used to support other protocols (Bonjour)
    + * which may need to share code.
    + */
    +
    +#include "internal.h"
    +
    +#include "accountopt.h"
    +#include "core.h"
    +#include "debug.h"
    +#include "version.h"
    +
    +#include "iq.h"
    +#include "jabber.h"
    +#include "chat.h"
    +#include "disco.h"
    +#include "message.h"
    +#include "roster.h"
    +#include "si.h"
    +#include "message.h"
    +#include "presence.h"
    +#include "google/google.h"
    +#include "pep.h"
    +#include "usermood.h"
    +#include "usertune.h"
    +#include "caps.h"
    +#include "data.h"
    +#include "ibb.h"
    +
    +static const char *
    +facebook_list_icon(PurpleAccount *a, PurpleBuddy *b)
    +{
    + return "facebook";
    +}
    +
    +static PurplePlugin *my_protocol = NULL;
    +
    +static PurplePluginProtocolInfo prpl_info =
    +{
    + sizeof(PurplePluginProtocolInfo), /* struct_size */
    + OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK |
    +#ifdef HAVE_CYRUS_SASL
    + OPT_PROTO_PASSWORD_OPTIONAL |
    +#endif
    + OPT_PROTO_SLASH_COMMANDS_NATIVE,
    + NULL, /* user_splits */
    + NULL, /* protocol_options */
    + {"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
    + facebook_list_icon, /* list_icon */
    + jabber_list_emblem, /* list_emblems */
    + jabber_status_text, /* status_text */
    + jabber_tooltip_text, /* tooltip_text */
    + jabber_status_types, /* status_types */
    + jabber_blist_node_menu, /* blist_node_menu */
    + jabber_chat_info, /* chat_info */
    + jabber_chat_info_defaults, /* chat_info_defaults */
    + jabber_login, /* login */
    + jabber_close, /* close */
    + jabber_message_send_im, /* send_im */
    + jabber_set_info, /* set_info */
    + jabber_send_typing, /* send_typing */
    + jabber_buddy_get_info, /* get_info */
    + jabber_set_status, /* set_status */
    + jabber_idle_set, /* set_idle */
    + NULL, /* change_passwd */
    + NULL, /* add_buddy */
    + NULL, /* add_buddies */
    + NULL, /* remove_buddy */
    + NULL, /* remove_buddies */
    + NULL, /* add_permit */
    + NULL, /* add_deny */
    + NULL, /* rem_permit */
    + NULL, /* rem_deny */
    + NULL, /* set_permit_deny */
    + jabber_chat_join, /* join_chat */
    + NULL, /* reject_chat */
    + jabber_get_chat_name, /* get_chat_name */
    + jabber_chat_invite, /* chat_invite */
    + jabber_chat_leave, /* chat_leave */
    + NULL, /* chat_whisper */
    + jabber_message_send_chat, /* chat_send */
    + jabber_keepalive, /* keepalive */
    + NULL, /* register_user */
    + NULL, /* get_cb_info */
    + NULL, /* alias_buddy */
    + NULL, /* group_buddy */
    + NULL, /* rename_group */
    + NULL, /* buddy_free */
    + jabber_convo_closed, /* convo_closed */
    + jabber_normalize, /* normalize */
    + jabber_set_buddy_icon, /* set_buddy_icon */
    + NULL, /* remove_group */
    + jabber_chat_buddy_real_name, /* get_cb_real_name */
    + jabber_chat_set_topic, /* set_chat_topic */
    + jabber_find_blist_chat, /* find_blist_chat */
    + jabber_roomlist_get_list, /* roomlist_get_list */
    + jabber_roomlist_cancel, /* roomlist_cancel */
    + NULL, /* roomlist_expand_category */
    + NULL, /* can_receive_file */
    + NULL, /* send_file */
    + NULL, /* new_xfer */
    + jabber_offline_message, /* offline_message */
    + NULL, /* whiteboard_prpl_ops */
    + jabber_prpl_send_raw, /* send_raw */
    + jabber_roomlist_room_serialize, /* roomlist_room_serialize */
    + NULL, /* unregister_user */
    + NULL, /* send_attention */
    + NULL, /* attention_types */
    + NULL, /* get_account_text_table */
    + NULL, /* initiate_media */
    + NULL, /* get_media_caps */
    + NULL, /* get_moods */
    + NULL, /* set_public_alias */
    + NULL /* get_public_alias */
    +};
    +
    +static gboolean load_plugin(PurplePlugin *plugin)
    +{
    + jabber_plugin_init(plugin);
    +
    + return TRUE;
    +}
    +
    +static gboolean unload_plugin(PurplePlugin *plugin)
    +{
    + jabber_plugin_uninit(plugin);
    +
    + return TRUE;
    +}
    +
    +static PurplePluginInfo info =
    +{
    + PURPLE_PLUGIN_MAGIC,
    + PURPLE_MAJOR_VERSION,
    + PURPLE_MINOR_VERSION,
    + PURPLE_PLUGIN_PROTOCOL, /**< type */
    + NULL, /**< ui_requirement */
    + 0, /**< flags */
    + NULL, /**< dependencies */
    + PURPLE_PRIORITY_DEFAULT, /**< priority */
    +
    + "prpl-facebook-xmpp", /**< id */
    + "Facebook (XMPP)", /**< name */
    + DISPLAY_VERSION, /**< version */
    + /** summary */
    + N_("Facebook XMPP Protocol Plugin"),
    + /** description */
    + N_("Facebook XMPP Protocol Plugin"),
    + NULL, /**< author */
    + PURPLE_WEBSITE, /**< homepage */
    +
    + load_plugin, /**< load */
    + unload_plugin, /**< unload */
    + NULL, /**< destroy */
    +
    + NULL, /**< ui_info */
    + &prpl_info, /**< extra_info */
    + NULL, /**< prefs_info */
    + jabber_actions,
    +
    + /* padding */
    + NULL,
    + NULL,
    + NULL,
    + NULL
    +};
    +
    +static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
    +{
    + PurpleAccount *acct = NULL;
    +
    + /* If we have a specific acct, use it */
    + if (acct_id) {
    + acct = purple_accounts_find(acct_id, prpl);
    + if (acct && !purple_account_is_connected(acct))
    + acct = NULL;
    + } else { /* Otherwise find an active account for the protocol */
    + GList *l = purple_accounts_get_all();
    + while (l) {
    + if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
    + && purple_account_is_connected(l->data)) {
    + acct = l->data;
    + break;
    + }
    + l = l->next;
    + }
    + }
    +
    + return acct;
    +}
    +
    +static gboolean xmpp_uri_handler(const char *proto, const char *user, GHashTable *params)
    +{
    + char *acct_id = params ? g_hash_table_lookup(params, "account") : NULL;
    + PurpleAccount *acct;
    +
    + if (g_ascii_strcasecmp(proto, "xmpp"))
    + return FALSE;
    +
    + acct = find_acct(purple_plugin_get_id(my_protocol), acct_id);
    +
    + if (!acct)
    + return FALSE;
    +
    + /* xmpp:romeo@montague.net?message;subject=Test%20Message;body=Here%27s%20a%20test%20message */
    + /* params is NULL if the URI has no '?' (or anything after it) */
    + if (!params || g_hash_table_lookup_extended(params, "message", NULL, NULL)) {
    + char *body = g_hash_table_lookup(params, "body");
    + if (user && *user) {
    + PurpleConversation *conv =
    + purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, user);
    + purple_conversation_present(conv);
    + if (body && *body)
    + purple_conv_send_confirm(conv, body);
    + }
    + } else if (g_hash_table_lookup_extended(params, "roster", NULL, NULL)) {
    + char *name = g_hash_table_lookup(params, "name");
    + if (user && *user)
    + purple_blist_request_add_buddy(acct, user, NULL, name);
    + } else if (g_hash_table_lookup_extended(params, "join", NULL, NULL)) {
    + PurpleConnection *gc = purple_account_get_connection(acct);
    + if (user && *user) {
    + GHashTable *params = jabber_chat_info_defaults(gc, user);
    + jabber_chat_join(gc, params);
    + }
    + return TRUE;
    + }
    +
    + return FALSE;
    +}
    +
    +
    +static void
    +init_plugin(PurplePlugin *plugin)
    +{
    + PurpleAccountUserSplit *split;
    + PurpleAccountOption *option;
    + GList *encryption_values = NULL;
    +
    + /* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
    + split = purple_account_user_split_new(_("Domain"), "chat.facebook.com", '@');
    + purple_account_user_split_set_reverse(split, FALSE);
    + prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
    +
    + split = purple_account_user_split_new(_("Resource"), "", '/');
    + purple_account_user_split_set_reverse(split, FALSE);
    + prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
    +
    +#define ADD_VALUE(list, desc, v) { \
    + PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \
    + kvp->key = g_strdup((desc)); \
    + kvp->value = g_strdup((v)); \
    + list = g_list_prepend(list, kvp); \
    +}
    +
    + ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls");
    + ADD_VALUE(encryption_values, _("Require encryption"), "require_tls");
    + ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl");
    +#if 0
    + ADD_VALUE(encryption_values, "None", "none");
    +#endif
    + encryption_values = g_list_reverse(encryption_values);
    +
    +#undef ADD_VALUE
    +
    + option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_bool_new(
    + _("Allow plaintext auth over unencrypted streams"),
    + "auth_plain_in_clear", FALSE);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_int_new(_("Connect port"), "port", 5222);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_string_new(_("Connect server"),
    + "connect_server", NULL);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_string_new(_("BOSH URL"),
    + "bosh_url", NULL);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + /* this should probably be part of global smiley theme settings later on,
    + shared with MSN */
    + option = purple_account_option_bool_new(_("Show Custom Smileys"),
    + "custom_smileys", TRUE);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + my_protocol = plugin;
    +
    + purple_signal_connect(purple_get_core(), "uri-handler", plugin,
    + PURPLE_CALLBACK(xmpp_uri_handler), NULL);
    +}
    +
    +PURPLE_INIT_PLUGIN(facebookxmpp, init_plugin, info);
    +
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/jabber/libgtalk.c Tue Feb 28 05:29:13 2012 +0000
    @@ -0,0 +1,334 @@
    +/* purple
    + *
    + * Purple is the legal property of its developers, whose names are too numerous
    + * to list here. Please refer to the COPYRIGHT file distributed with this
    + * source distribution.
    + *
    + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    + *
    + */
    +
    +/* libgtalk is the Google Talk XMPP protocol plugin. It is linked against
    + * libjabbercommon, which may be used to support other protocols (Bonjour) which
    + * may need to share code.
    + */
    +
    +#include "internal.h"
    +
    +#include "accountopt.h"
    +#include "core.h"
    +#include "debug.h"
    +#include "version.h"
    +
    +#include "iq.h"
    +#include "jabber.h"
    +#include "chat.h"
    +#include "disco.h"
    +#include "message.h"
    +#include "roster.h"
    +#include "si.h"
    +#include "message.h"
    +#include "presence.h"
    +#include "google/google.h"
    +#include "pep.h"
    +#include "usermood.h"
    +#include "usertune.h"
    +#include "caps.h"
    +#include "data.h"
    +#include "ibb.h"
    +
    +static const char *
    +gtalk_list_icon(PurpleAccount *a, PurpleBuddy *b)
    +{
    + return "google-talk";
    +}
    +
    +static PurplePlugin *my_protocol = NULL;
    +
    +static PurplePluginProtocolInfo prpl_info =
    +{
    + sizeof(PurplePluginProtocolInfo), /* struct_size */
    + OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK |
    +#ifdef HAVE_CYRUS_SASL
    + OPT_PROTO_PASSWORD_OPTIONAL |
    +#endif
    + OPT_PROTO_SLASH_COMMANDS_NATIVE,
    + NULL, /* user_splits */
    + NULL, /* protocol_options */
    + {"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
    + gtalk_list_icon, /* list_icon */
    + jabber_list_emblem, /* list_emblems */
    + jabber_status_text, /* status_text */
    + jabber_tooltip_text, /* tooltip_text */
    + jabber_status_types, /* status_types */
    + jabber_blist_node_menu, /* blist_node_menu */
    + jabber_chat_info, /* chat_info */
    + jabber_chat_info_defaults, /* chat_info_defaults */
    + jabber_login, /* login */
    + jabber_close, /* close */
    + jabber_message_send_im, /* send_im */
    + jabber_set_info, /* set_info */
    + jabber_send_typing, /* send_typing */
    + jabber_buddy_get_info, /* get_info */
    + jabber_set_status, /* set_status */
    + jabber_idle_set, /* set_idle */
    + NULL, /* change_passwd */
    + jabber_roster_add_buddy, /* add_buddy */
    + NULL, /* add_buddies */
    + jabber_roster_remove_buddy, /* remove_buddy */
    + NULL, /* remove_buddies */
    + NULL, /* add_permit */
    + jabber_add_deny, /* add_deny */
    + NULL, /* rem_permit */
    + jabber_rem_deny, /* rem_deny */
    + NULL, /* set_permit_deny */
    + jabber_chat_join, /* join_chat */
    + NULL, /* reject_chat */
    + jabber_get_chat_name, /* get_chat_name */
    + jabber_chat_invite, /* chat_invite */
    + jabber_chat_leave, /* chat_leave */
    + NULL, /* chat_whisper */
    + jabber_message_send_chat, /* chat_send */
    + jabber_keepalive, /* keepalive */
    + NULL, /* register_user */
    + NULL, /* get_cb_info */
    + jabber_roster_alias_change, /* alias_buddy */
    + jabber_roster_group_change, /* group_buddy */
    + jabber_roster_group_rename, /* rename_group */
    + NULL, /* buddy_free */
    + jabber_convo_closed, /* convo_closed */
    + jabber_normalize, /* normalize */
    + jabber_set_buddy_icon, /* set_buddy_icon */
    + NULL, /* remove_group */
    + jabber_chat_buddy_real_name, /* get_cb_real_name */
    + jabber_chat_set_topic, /* set_chat_topic */
    + jabber_find_blist_chat, /* find_blist_chat */
    + jabber_roomlist_get_list, /* roomlist_get_list */
    + jabber_roomlist_cancel, /* roomlist_cancel */
    + NULL, /* roomlist_expand_category */
    + jabber_can_receive_file, /* can_receive_file */
    + jabber_si_xfer_send, /* send_file */
    + jabber_si_new_xfer, /* new_xfer */
    + jabber_offline_message, /* offline_message */
    + NULL, /* whiteboard_prpl_ops */
    + jabber_prpl_send_raw, /* send_raw */
    + jabber_roomlist_room_serialize, /* roomlist_room_serialize */
    + NULL, /* unregister_user */
    + jabber_send_attention, /* send_attention */
    + jabber_attention_types, /* attention_types */
    + NULL, /* get_account_text_table */
    + jabber_initiate_media, /* initiate_media */
    + jabber_get_media_caps, /* get_media_caps */
    + jabber_get_moods, /* get_moods */
    + NULL, /* set_public_alias */
    + NULL /* get_public_alias */
    +};
    +
    +static gboolean load_plugin(PurplePlugin *plugin)
    +{
    + jabber_plugin_init(plugin);
    +
    + return TRUE;
    +}
    +
    +static gboolean unload_plugin(PurplePlugin *plugin)
    +{
    + jabber_plugin_uninit(plugin);
    +
    + return TRUE;
    +}
    +
    +static PurplePluginInfo info =
    +{
    + PURPLE_PLUGIN_MAGIC,
    + PURPLE_MAJOR_VERSION,
    + PURPLE_MINOR_VERSION,
    + PURPLE_PLUGIN_PROTOCOL, /**< type */
    + NULL, /**< ui_requirement */
    + 0, /**< flags */
    + NULL, /**< dependencies */
    + PURPLE_PRIORITY_DEFAULT, /**< priority */
    +
    + "prpl-gtalk", /**< id */
    + "Google Talk (XMPP)", /**< name */
    + DISPLAY_VERSION, /**< version */
    + /** summary */
    + N_("Google Talk Protocol Plugin"),
    + /** description */
    + N_("Google Talk Protocol Plugin"),
    + NULL, /**< author */
    + PURPLE_WEBSITE, /**< homepage */
    +
    + load_plugin, /**< load */
    + unload_plugin, /**< unload */
    + NULL, /**< destroy */
    +
    + NULL, /**< ui_info */
    + &prpl_info, /**< extra_info */
    + NULL, /**< prefs_info */
    + jabber_actions,
    +
    + /* padding */
    + NULL,
    + NULL,
    + NULL,
    + NULL
    +};
    +
    +static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
    +{
    + PurpleAccount *acct = NULL;
    +
    + /* If we have a specific acct, use it */
    + if (acct_id) {
    + acct = purple_accounts_find(acct_id, prpl);
    + if (acct && !purple_account_is_connected(acct))
    + acct = NULL;
    + } else { /* Otherwise find an active account for the protocol */
    + GList *l = purple_accounts_get_all();
    + while (l) {
    + if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
    + && purple_account_is_connected(l->data)) {
    + acct = l->data;
    + break;
    + }
    + l = l->next;
    + }
    + }
    +
    + return acct;
    +}
    +
    +static gboolean xmpp_uri_handler(const char *proto, const char *user, GHashTable *params)
    +{
    + char *acct_id = params ? g_hash_table_lookup(params, "account") : NULL;
    + PurpleAccount *acct;
    +
    + if (g_ascii_strcasecmp(proto, "xmpp"))
    + return FALSE;
    +
    + acct = find_acct(purple_plugin_get_id(my_protocol), acct_id);
    +
    + if (!acct)
    + return FALSE;
    +
    + /* xmpp:romeo@montague.net?message;subject=Test%20Message;body=Here%27s%20a%20test%20message */
    + /* params is NULL if the URI has no '?' (or anything after it) */
    + if (!params || g_hash_table_lookup_extended(params, "message", NULL, NULL)) {
    + char *body = g_hash_table_lookup(params, "body");
    + if (user && *user) {
    + PurpleConversation *conv =
    + purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, user);
    + purple_conversation_present(conv);
    + if (body && *body)
    + purple_conv_send_confirm(conv, body);
    + }
    + } else if (g_hash_table_lookup_extended(params, "roster", NULL, NULL)) {
    + char *name = g_hash_table_lookup(params, "name");
    + if (user && *user)
    + purple_blist_request_add_buddy(acct, user, NULL, name);
    + } else if (g_hash_table_lookup_extended(params, "join", NULL, NULL)) {
    + PurpleConnection *gc = purple_account_get_connection(acct);
    + if (user && *user) {
    + GHashTable *params = jabber_chat_info_defaults(gc, user);
    + jabber_chat_join(gc, params);
    + }
    + return TRUE;
    + }
    +
    + return FALSE;
    +}
    +
    +
    +static void
    +init_plugin(PurplePlugin *plugin)
    +{
    + PurpleAccountUserSplit *split;
    + PurpleAccountOption *option;
    + GList *encryption_values = NULL;
    +
    + /* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
    + split = purple_account_user_split_new(_("Domain"), "gmail.com", '@');
    + purple_account_user_split_set_reverse(split, FALSE);
    + prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
    +
    + split = purple_account_user_split_new(_("Resource"), "", '/');
    + purple_account_user_split_set_reverse(split, FALSE);
    + prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
    +
    +#define ADD_VALUE(list, desc, v) { \
    + PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \
    + kvp->key = g_strdup((desc)); \
    + kvp->value = g_strdup((v)); \
    + list = g_list_prepend(list, kvp); \
    +}
    +
    + ADD_VALUE(encryption_values, _("Require encryption"), "require_tls");
    + ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls");
    + ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl");
    +#if 0
    + ADD_VALUE(encryption_values, "None", "none");
    +#endif
    + encryption_values = g_list_reverse(encryption_values);
    +
    +#undef ADD_VALUE
    +
    + option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_bool_new(
    + _("Allow plaintext auth over unencrypted streams"),
    + "auth_plain_in_clear", FALSE);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_int_new(_("Connect port"), "port", 5222);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_string_new(_("Connect server"),
    + "connect_server", NULL);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_string_new(_("File transfer proxies"),
    + "ft_proxies",
    + /* TODO: Is this an acceptable default?
    + * Also, keep this in sync as they add more servers */
    + JABBER_DEFAULT_FT_PROXIES);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + option = purple_account_option_string_new(_("BOSH URL"),
    + "bosh_url", NULL);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + /* this should probably be part of global smiley theme settings later on,
    + shared with MSN */
    + option = purple_account_option_bool_new(_("Show Custom Smileys"),
    + "custom_smileys", TRUE);
    + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
    + option);
    +
    + my_protocol = plugin;
    +
    + purple_signal_connect(purple_get_core(), "uri-handler", plugin,
    + PURPLE_CALLBACK(xmpp_uri_handler), NULL);
    +}
    +
    +PURPLE_INIT_PLUGIN(gtalk, init_plugin, info);
    +
    --- a/libpurple/request.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/request.c Tue Feb 28 05:29:13 2012 +0000
    @@ -119,6 +119,11 @@
    gsize size;
    } image;
    + struct
    + {
    + PurpleCertificate *cert;
    + } certificate;
    +
    } u;
    void *ui_data;
    @@ -1329,6 +1334,31 @@
    return field->u.account.filter_func;
    }
    +PurpleRequestField *
    +purple_request_field_certificate_new(const char *id, const char *text, PurpleCertificate *cert)
    +{
    + PurpleRequestField *field;
    +
    + g_return_val_if_fail(id != NULL, NULL);
    + g_return_val_if_fail(text != NULL, NULL);
    + g_return_val_if_fail(cert != NULL, NULL);
    +
    + field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_CERTIFICATE);
    +
    + field->u.certificate.cert = cert;
    +
    + return field;
    +}
    +
    +PurpleCertificate *
    +purple_request_field_certificate_get_value(const PurpleRequestField *field)
    +{
    + g_return_val_if_fail(field != NULL, NULL);
    + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_CERTIFICATE, NULL);
    +
    + return field->u.certificate.cert;
    +}
    +
    /* -- */
    void *
    @@ -1636,6 +1666,29 @@
    return NULL;
    }
    +void *
    +purple_request_certificate(void *handle, const char *title,
    + const char *primary, const char *secondary,
    + PurpleCertificate *cert,
    + const char *ok_text, GCallback ok_cb,
    + const char *cancel_text, GCallback cancel_cb,
    + void *user_data)
    +{
    + PurpleRequestFields *fields;
    + PurpleRequestFieldGroup *group;
    + PurpleRequestField *field;
    +
    + fields = purple_request_fields_new();
    + group = purple_request_field_group_new(NULL);
    + purple_request_fields_add_group(fields, group);
    + field = purple_request_field_certificate_new("certificate", "Certificate", cert);
    + purple_request_field_group_add_field(group, field);
    +
    + return purple_request_fields(handle, title, primary, secondary, fields,
    + ok_text, ok_cb, cancel_text, cancel_cb,
    + NULL, NULL, NULL, user_data);
    +}
    +
    static void
    purple_request_close_info(PurpleRequestInfo *info)
    {
    --- a/libpurple/request.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/libpurple/request.h Tue Feb 28 05:29:13 2012 +0000
    @@ -76,7 +76,8 @@
    PURPLE_REQUEST_FIELD_LIST,
    PURPLE_REQUEST_FIELD_LABEL,
    PURPLE_REQUEST_FIELD_IMAGE,
    - PURPLE_REQUEST_FIELD_ACCOUNT
    + PURPLE_REQUEST_FIELD_ACCOUNT,
    + PURPLE_REQUEST_FIELD_CERTIFICATE
    } PurpleRequestFieldType;
    @@ -1170,6 +1171,36 @@
    /*@}*/
    /**************************************************************************/
    +/** @name Certificate Field API */
    +/**************************************************************************/
    +/*@{*/
    +
    +/**
    + * Creates a certificate field.
    + *
    + * @param id The field ID.
    + * @param text The label of the field.
    + * @param cert The certificate of the field.
    + *
    + * @return The new field.
    + */
    +PurpleRequestField *purple_request_field_certificate_new(const char *id,
    + const char *text,
    + PurpleCertificate *cert);
    +
    +/**
    + * Returns the certificate in a certificate field.
    + *
    + * @param field The field.
    + *
    + * @return The certificate.
    + */
    +PurpleCertificate *purple_request_field_certificate_get_value(
    + const PurpleRequestField *field);
    +
    +/*@}*/
    +
    +/**************************************************************************/
    /** @name Request API */
    /**************************************************************************/
    /*@{*/
    @@ -1500,6 +1531,37 @@
    PurpleAccount *account, const char *who, PurpleConversation *conv,
    void *user_data);
    +/**
    + * Prompts the user for action over a certificate.
    + *
    + * This is often represented as a dialog with a button for each action.
    + *
    + * @param handle The plugin or connection handle. For some things this
    + * is <em>extremely</em> important. See the comments on
    + * purple_request_input().
    + * @param title The title of the message, or @c NULL if it should have
    + * no title.
    + * @param primary The main point of the message, or @c NULL if you're
    + * feeling enigmatic.
    + * @param secondary Secondary information, or @c NULL if there is none.
    + * @param cert The #PurpleCertificate associated with this request.
    + * @param ok_text The text for the @c OK button, which may not be @c NULL.
    + * @param ok_cb The callback for the @c OK button, which may not be
    + * @c NULL.
    + * @param cancel_text The text for the @c Cancel button, which may not be
    + * @c NULL.
    + * @param cancel_cb The callback for the @c Cancel button, which may be
    + * @c NULL.
    + * @param user_data The data to pass to the callback.
    + *
    + * @return A UI-specific handle.
    + */
    +void *purple_request_certificate(void *handle, const char *title,
    + const char *primary, const char *secondary, PurpleCertificate *cert,
    + const char *ok_text, GCallback ok_cb,
    + const char *cancel_text, GCallback cancel_cb,
    + void *user_data);
    +
    /*@}*/
    /**************************************************************************/
    --- a/pidgin/gtkaccount.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkaccount.c Tue Feb 28 05:29:13 2012 +0000
    @@ -221,7 +221,7 @@
    }
    static void
    -set_account_protocol_cb(GtkWidget *item, const char *id,
    +set_account_protocol_cb(GtkWidget *widget, const char *id,
    AccountPrefsDialog *dialog)
    {
    PurplePlugin *new_plugin;
    @@ -248,8 +248,7 @@
    gtk_widget_grab_focus(dialog->protocol_menu);
    - if (!dialog->prpl_info || !dialog->prpl_info->register_user ||
    - g_object_get_data(G_OBJECT(item), "fake")) {
    + if (!dialog->prpl_info || !dialog->prpl_info->register_user) {
    gtk_widget_hide(dialog->register_button);
    } else {
    if (dialog->prpl_info != NULL &&
    @@ -425,8 +424,6 @@
    GtkWidget *hbox;
    GtkWidget *vbox;
    GtkWidget *entry;
    - GtkWidget *menu;
    - GtkWidget *item;
    GList *user_splits;
    GList *l, *l2;
    char *username = NULL;
    @@ -564,17 +561,6 @@
    if (value == NULL)
    value = purple_account_user_split_get_default_value(split);
    - /* Google Talk default domain hackery! */
    - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu));
    - item = gtk_menu_get_active(GTK_MENU(menu));
    - if (value == NULL && g_object_get_data(G_OBJECT(item), "fakegoogle") &&
    - !strcmp(purple_account_user_split_get_text(split), _("Domain")))
    - value = "gmail.com";
    -
    - if (value == NULL && g_object_get_data(G_OBJECT(item), "fakefacebook") &&
    - !strcmp(purple_account_user_split_get_text(split), _("Domain")))
    - value = "chat.facebook.com";
    -
    if (value != NULL)
    gtk_entry_set_text(GTK_ENTRY(entry), value);
    }
    @@ -770,7 +756,7 @@
    {
    PurpleAccountOption *option;
    PurpleAccount *account;
    - GtkWidget *vbox, *check, *entry, *combo, *menu, *item;
    + GtkWidget *vbox, *check, *entry, *combo;
    GList *list, *node;
    gint i, idx, int_value;
    GtkListStore *model;
    @@ -809,9 +795,6 @@
    gtk_label_new_with_mnemonic(_("Ad_vanced")), 1);
    gtk_widget_show(vbox);
    - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu));
    - item = gtk_menu_get_active(GTK_MENU(menu));
    -
    for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next)
    {
    option = (PurpleAccountOption *)l->data;
    @@ -926,10 +909,6 @@
    model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
    opt_entry->widget = combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
    - if (g_object_get_data(G_OBJECT(item), "fakefacebook") &&
    - !strcmp(opt_entry->setting, "connection_security"))
    - str_value = "opportunistic_tls";
    -
    /* Loop through list of PurpleKeyValuePair items */
    for (node = list; node != NULL; node = node->next) {
    if (node->data != NULL) {
    @@ -1214,8 +1193,12 @@
    gtk_widget_show_all(dialog->voice_frame);
    }
    - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check),
    - purple_account_get_silence_suppression(dialog->account));
    + if (dialog->account) {
    + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check),
    + purple_account_get_silence_suppression(dialog->account));
    + } else {
    + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check), FALSE);
    + }
    #endif
    }
    @@ -2745,4 +2728,3 @@
    purple_signals_unregister_by_instance(pidgin_account_get_handle());
    }
    -
    --- a/pidgin/gtkblist.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkblist.c Tue Feb 28 05:29:13 2012 +0000
    @@ -124,6 +124,11 @@
    #define PIDGIN_BUDDY_LIST_GET_PRIVATE(list) \
    ((PidginBuddyListPrivate *)((list)->priv))
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
    +#define gtk_widget_has_focus(x) GTK_WIDGET_HAS_FOCUS(x)
    +#endif
    +
    static GtkWidget *accountmenu = NULL;
    static guint visibility_manager_count = 0;
    @@ -138,6 +143,9 @@
    static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
    static void sort_method_status(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
    static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
    +static guint sort_merge_id;
    +static GtkActionGroup *sort_action_group = NULL;
    +
    static PidginBuddyList *gtkblist = NULL;
    static GList *groups_tree(void);
    @@ -148,7 +156,6 @@
    static void pidgin_blist_update_group(PurpleBuddyList *list, PurpleBlistNode *node);
    static void pidgin_blist_update_contact(PurpleBuddyList *list, PurpleBlistNode *node);
    static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full);
    -static const char *item_factory_translate_func (const char *path, gpointer func_data);
    static gboolean get_iter_from_node(PurpleBlistNode *node, GtkTreeIter *iter);
    static gboolean buddy_is_displayable(PurpleBuddy *buddy);
    static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender);
    @@ -242,7 +249,7 @@
    /* check for visibility because when we aren't visible, this will *
    * give us bogus (0,0) coordinates. - xOr */
    - if (GTK_WIDGET_VISIBLE(w))
    + if (gtk_widget_get_visible(w))
    gtk_window_get_position(GTK_WINDOW(w), &x, &y);
    else
    return FALSE; /* carry on normally */
    @@ -2012,64 +2019,70 @@
    return handled;
    }
    -static void pidgin_blist_buddy_details_cb(gpointer data, guint action, GtkWidget *item)
    +static void gtk_blist_show_xfer_dialog_cb(GtkAction *item, gpointer data)
    +{
    + pidgin_xfer_dialog_show(NULL);
    +}
    +
    +static void pidgin_blist_buddy_details_cb(GtkToggleAction *item, gpointer data)
    {
    pidgin_set_cursor(gtkblist->window, GDK_WATCH);
    purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons",
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
    + gtk_toggle_action_get_active(item));
    pidgin_clear_cursor(gtkblist->window);
    }
    -static void pidgin_blist_show_idle_time_cb(gpointer data, guint action, GtkWidget *item)
    +static void pidgin_blist_show_idle_time_cb(GtkToggleAction *item, gpointer data)
    {
    pidgin_set_cursor(gtkblist->window, GDK_WATCH);
    purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time",
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
    + gtk_toggle_action_get_active(item));
    pidgin_clear_cursor(gtkblist->window);
    }
    -static void pidgin_blist_show_protocol_icons_cb(gpointer data, guint action, GtkWidget *item)
    +static void pidgin_blist_show_protocol_icons_cb(GtkToggleAction *item, gpointer data)
    {
    purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons",
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
    -}
    -
    -static void pidgin_blist_show_empty_groups_cb(gpointer data, guint action, GtkWidget *item)
    + gtk_toggle_action_get_active(item));
    +}
    +
    +static void pidgin_blist_show_empty_groups_cb(GtkToggleAction *item, gpointer data)
    {
    pidgin_set_cursor(gtkblist->window, GDK_WATCH);
    purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups",
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
    + gtk_toggle_action_get_active(item));
    pidgin_clear_cursor(gtkblist->window);
    }
    -static void pidgin_blist_edit_mode_cb(gpointer callback_data, guint callback_action,
    - GtkWidget *checkitem)
    +static void pidgin_blist_edit_mode_cb(GtkToggleAction *checkitem, gpointer data)
    {
    pidgin_set_cursor(gtkblist->window, GDK_WATCH);
    purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies",
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(checkitem)));
    + gtk_toggle_action_get_active(checkitem));
    pidgin_clear_cursor(gtkblist->window);
    }
    -static void pidgin_blist_mute_sounds_cb(gpointer data, guint action, GtkWidget *item)
    -{
    - purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", GTK_CHECK_MENU_ITEM(item)->active);
    -}
    +static void pidgin_blist_mute_sounds_cb(GtkToggleAction *item, gpointer data)
    +{
    + purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute",
    + gtk_toggle_action_get_active(item));
    +}
    +
    static void
    pidgin_blist_mute_pref_cb(const char *name, PurplePrefType type,
    gconstpointer value, gpointer data)
    {
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item(gtkblist->ift,
    - N_("/Tools/Mute Sounds"))), (gboolean)GPOINTER_TO_INT(value));
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui,
    + "/BList/ToolsMenu/MuteSounds")), (gboolean)GPOINTER_TO_INT(value));
    }
    static void
    @@ -2081,7 +2094,7 @@
    if(!strcmp(value, "none"))
    sensitive = FALSE;
    - gtk_widget_set_sensitive(gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Mute Sounds")), sensitive);
    + gtk_action_set_sensitive(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds"), sensitive);
    }
    static void
    @@ -2926,6 +2939,7 @@
    pidgin_blist_paint_tip(GtkWidget *widget, gpointer null)
    {
    GtkStyle *style;
    + cairo_t *cr;
    int current_height, max_width;
    int max_text_width;
    int max_avatar_width;
    @@ -2959,6 +2973,7 @@
    else
    prpl_col = TOOLTIP_BORDER + status_size + SMALL_SPACE + max_text_width - PRPL_SIZE;
    + cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(gtkblist->tipwindow)));
    current_height = 12;
    for(l = gtkblist->tooltipdata; l; l = l->next)
    {
    @@ -2978,30 +2993,37 @@
    }
    if (td->status_icon) {
    - if (dir == GTK_TEXT_DIR_RTL)
    - gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon,
    - 0, 0, max_width - TOOLTIP_BORDER - status_size, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
    - else
    - gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon,
    - 0, 0, TOOLTIP_BORDER, current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
    + if (dir == GTK_TEXT_DIR_RTL) {
    + gdk_cairo_set_source_pixbuf(cr, td->status_icon,
    + max_width - TOOLTIP_BORDER - status_size,
    + current_height);
    + cairo_paint(cr);
    + } else {
    + gdk_cairo_set_source_pixbuf(cr, td->status_icon,
    + TOOLTIP_BORDER, current_height);
    + cairo_paint(cr);
    + }
    }
    if(td->avatar) {
    - if (dir == GTK_TEXT_DIR_RTL)
    - gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL,
    - td->avatar, 0, 0, TOOLTIP_BORDER, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
    - else
    - gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL,
    - td->avatar, 0, 0, max_width - (td->avatar_width + TOOLTIP_BORDER),
    - current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
    - }
    -
    - if (!td->avatar_is_prpl_icon && td->prpl_icon)
    - gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->prpl_icon,
    - 0, 0,
    - prpl_col,
    - current_height + ((td->name_height / 2) - (PRPL_SIZE / 2)),
    - -1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
    + if (dir == GTK_TEXT_DIR_RTL) {
    + gdk_cairo_set_source_pixbuf(cr, td->avatar,
    + TOOLTIP_BORDER, current_height);
    + cairo_paint(cr);
    + } else {
    + gdk_cairo_set_source_pixbuf(cr, td->avatar,
    + max_width - (td->avatar_width + TOOLTIP_BORDER),
    + current_height);
    + cairo_paint(cr);
    + }
    + }
    +
    + if (!td->avatar_is_prpl_icon && td->prpl_icon) {
    + gdk_cairo_set_source_pixbuf(cr, td->prpl_icon, prpl_col,
    + current_height +
    + (td->name_height - PRPL_SIZE) / 2);
    + cairo_paint(cr);
    + }
    if (td->name_layout) {
    if (dir == GTK_TEXT_DIR_RTL) {
    @@ -3032,6 +3054,8 @@
    current_height += MAX(td->name_height + td->height, td->avatar_height) + td->padding;
    }
    +
    + cairo_destroy(cr);
    return FALSE;
    }
    @@ -3595,64 +3619,121 @@
    /***************************************************
    * Crap *
    ***************************************************/
    -static GtkItemFactoryEntry blist_menu[] =
    -{
    +/* TODO: fill out tooltips... */
    +static const GtkActionEntry blist_menu_entries[] = {
    /* NOTE: Do not set any accelerator to Control+O. It is mapped by
    gtk_blist_key_press_cb to "Get User Info" on the selected buddy. */
    -
    /* Buddies menu */
    - { N_("/_Buddies"), NULL, NULL, 0, "<Branch>", NULL },
    - { N_("/Buddies/New Instant _Message..."), "<CTL>M", pidgin_dialogs_im, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW },
    - { N_("/Buddies/Join a _Chat..."), "<CTL>C", pidgin_blist_joinchat_show, 0, "<StockItem>", PIDGIN_STOCK_CHAT },
    - { N_("/Buddies/Get User _Info..."), "<CTL>I", pidgin_dialogs_info, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_USER_INFO },
    - { N_("/Buddies/View User _Log..."), "<CTL>L", pidgin_dialogs_log, 0, "<Item>", NULL },
    - { "/Buddies/sep1", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Buddies/Sh_ow"), NULL, NULL, 0, "<Branch>", NULL},
    - { N_("/Buddies/Show/_Offline Buddies"), NULL, pidgin_blist_edit_mode_cb, 1, "<CheckItem>", NULL },
    - { N_("/Buddies/Show/_Empty Groups"), NULL, pidgin_blist_show_empty_groups_cb, 1, "<CheckItem>", NULL },
    - { N_("/Buddies/Show/Buddy _Details"), NULL, pidgin_blist_buddy_details_cb, 1, "<CheckItem>", NULL },
    - { N_("/Buddies/Show/Idle _Times"), NULL, pidgin_blist_show_idle_time_cb, 1, "<CheckItem>", NULL },
    - { N_("/Buddies/Show/_Protocol Icons"), NULL, pidgin_blist_show_protocol_icons_cb, 1, "<CheckItem>", NULL },
    - { N_("/Buddies/_Sort Buddies"), NULL, NULL, 0, "<Branch>", NULL },
    - { "/Buddies/sep2", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Buddies/_Add Buddy..."), "<CTL>B", pidgin_blist_add_buddy_cb, 0, "<StockItem>", GTK_STOCK_ADD },
    - { N_("/Buddies/Add C_hat..."), NULL, pidgin_blist_add_chat_cb, 0, "<StockItem>", GTK_STOCK_ADD },
    - { N_("/Buddies/Add _Group..."), NULL, purple_blist_request_add_group, 0, "<StockItem>", GTK_STOCK_ADD },
    - { "/Buddies/sep3", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Buddies/_Quit"), "<CTL>Q", purple_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT },
    + { "BuddiesMenu", NULL, N_("_Buddies"), NULL, NULL, NULL },
    + { "NewInstantMessage", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, N_("New Instant _Message..."), "<control>M", NULL, pidgin_dialogs_im },
    + { "JoinAChat", PIDGIN_STOCK_CHAT, N_("Join a _Chat..."), "<control>C", NULL, pidgin_blist_joinchat_show },
    + { "GetUserInfo", PIDGIN_STOCK_TOOLBAR_USER_INFO, N_("Get User _Info..."), "<control>I", NULL, pidgin_dialogs_info },
    + { "ViewUserLog", NULL, N_("View User _Log..."), "<control>L", NULL, pidgin_dialogs_log },
    + { "ShowMenu", NULL, N_("Sh_ow"), NULL, NULL, NULL },
    + { "SortMenu", NULL, N_("_Sort Buddies"), NULL, NULL, NULL },
    + { "AddBuddy", GTK_STOCK_ADD, N_("_Add Buddy..."), "<control>B", NULL, pidgin_blist_add_buddy_cb },
    + { "AddChat", GTK_STOCK_ADD, N_("Add C_hat..."), NULL, NULL, pidgin_blist_add_chat_cb },
    + { "AddGroup", GTK_STOCK_ADD, N_("Add _Group..."), NULL, NULL, purple_blist_request_add_group },
    + { "Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", NULL, purple_core_quit },
    /* Accounts menu */
    - { N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL },
    - { N_("/Accounts/Manage Accounts"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL },
    + { "AccountsMenu", NULL, N_("_Accounts"), NULL, NULL, NULL },
    + { "ManageAccounts", NULL, N_("Manage Accounts"), "<control>A", NULL, pidgin_accounts_window_show },
    /* Tools */
    - { N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL },
    - { N_("/Tools/Buddy _Pounces"), NULL, pidgin_pounces_manager_show, 1, "<Item>", NULL },
    - { N_("/Tools/_Certificates"), NULL, pidgin_certmgr_show, 0, "<Item>", NULL },
    - { N_("/Tools/Custom Smile_ys"), "<CTL>Y", pidgin_smiley_manager_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SMILEY },
    - { N_("/Tools/Plu_gins"), "<CTL>U", pidgin_plugin_dialog_show, 2, "<StockItem>", PIDGIN_STOCK_TOOLBAR_PLUGINS },
    - { N_("/Tools/Pr_eferences"), "<CTL>P", pidgin_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
    - { N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "<Item>", NULL },
    - { N_("/Tools/Set _Mood"), "<CTL>D", set_mood_show, 0, "<Item>", NULL },
    - { "/Tools/sep2", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_TRANSFER },
    - { N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL },
    - { N_("/Tools/System _Log"), NULL, gtk_blist_show_systemlog_cb, 3, "<Item>", NULL },
    - { "/Tools/sep3", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Tools/Mute _Sounds"), NULL, pidgin_blist_mute_sounds_cb, 0, "<CheckItem>", NULL },
    + { "ToolsMenu", NULL, N_("_Tools"), NULL, NULL, NULL },
    + { "BuddyPounces", NULL, N_("Buddy _Pounces"), NULL, NULL, pidgin_pounces_manager_show },
    + { "Certificates", NULL, N_("_Certificates"), NULL, NULL, pidgin_certmgr_show },
    + { "CustomSmileys", PIDGIN_STOCK_TOOLBAR_SMILEY, N_("Custom Smile_ys"), "<control>Y", NULL, pidgin_smiley_manager_show },
    + { "Plugins", PIDGIN_STOCK_TOOLBAR_PLUGINS, N_("Plu_gins"), "<control>U", NULL, pidgin_plugin_dialog_show },
    + { "Preferences", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), "<control>P", NULL, pidgin_prefs_show },
    + { "Privacy", NULL, N_("Pr_ivacy"), NULL, NULL, pidgin_privacy_dialog_show },
    + { "SetMood", NULL, N_("Set _Mood"), "<control>D", NULL, set_mood_show },
    + { "FileTransfers", PIDGIN_STOCK_TOOLBAR_TRANSFER, N_("_File Transfers"), "<control>T", NULL, G_CALLBACK(gtk_blist_show_xfer_dialog_cb) },
    + { "RoomList", NULL, N_("R_oom List"), NULL, NULL, pidgin_roomlist_dialog_show },
    + { "SystemLog", NULL, N_("System _Log"), NULL, NULL, gtk_blist_show_systemlog_cb },
    +
    /* Help */
    - { N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL },
    - { N_("/Help/Online _Help"), "F1", gtk_blist_show_onlinehelp_cb, 0, "<StockItem>", GTK_STOCK_HELP },
    - { "/Help/sep1", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Help/_Build Information"), NULL, pidgin_dialogs_buildinfo, 0, "<Item>", NULL },
    - { N_("/Help/_Debug Window"), NULL, toggle_debug, 0, "<Item>", NULL },
    - { N_("/Help/De_veloper Information"), NULL, pidgin_dialogs_developers, 0, "<Item>", NULL },
    - { N_("/Help/_Plugin Information"), NULL, pidgin_dialogs_plugins_info, 0, "<Item>", NULL },
    - { N_("/Help/_Translator Information"), NULL, pidgin_dialogs_translators, 0, "<Item>", NULL },
    - { "/Help/sep2", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Help/_About"), NULL, pidgin_dialogs_about, 4, "<StockItem>", GTK_STOCK_ABOUT },
    + { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
    + { "OnlineHelp", GTK_STOCK_HELP, N_("Online _Help"), "F1", NULL, gtk_blist_show_onlinehelp_cb },
    + { "BuildInformation", NULL, N_("_Build Information"), NULL, NULL, pidgin_dialogs_buildinfo },
    + { "DebugWindow", NULL, N_("_Debug Window"), NULL, NULL, toggle_debug },
    + { "DeveloperInformation", NULL, N_("De_veloper Information"), NULL, NULL, pidgin_dialogs_developers },
    + { "PluginInformation", NULL, N_("_Plugin Information"), NULL, NULL, pidgin_dialogs_plugins_info },
    + { "TranslatorInformation", NULL, N_("_Translator Information"), NULL, NULL, pidgin_dialogs_translators },
    + { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, pidgin_dialogs_about },
    +};
    +
    +/* Toggle items */
    +static const GtkToggleActionEntry blist_menu_toggle_entries[] = {
    + /* Buddies->Show menu */
    + { "ShowOffline", NULL, N_("_Offline Buddies"), NULL, NULL, G_CALLBACK(pidgin_blist_edit_mode_cb), FALSE },
    + { "ShowEmptyGroups", NULL, N_("_Empty Groups"), NULL, NULL, G_CALLBACK(pidgin_blist_show_empty_groups_cb), FALSE },
    + { "ShowBuddyDetails", NULL, N_("Buddy _Details"), NULL, NULL, G_CALLBACK(pidgin_blist_buddy_details_cb), FALSE },
    + { "ShowIdleTimes", NULL, N_("Idle _Times"), NULL, NULL, G_CALLBACK(pidgin_blist_show_idle_time_cb), FALSE },
    + { "ShowProtocolIcons", NULL, N_("_Protocol Icons"), NULL, NULL, G_CALLBACK(pidgin_blist_show_protocol_icons_cb), FALSE },
    +
    + /* Tools menu */
    + { "MuteSounds", NULL, N_("Mute _Sounds"), NULL, NULL, G_CALLBACK(pidgin_blist_mute_sounds_cb), FALSE },
    };
    +static const char *blist_menu =
    +"<ui>"
    + "<menubar name='BList'>"
    + "<menu action='BuddiesMenu'>"
    + "<menuitem action='NewInstantMessage'/>"
    + "<menuitem action='JoinAChat'/>"
    + "<menuitem action='GetUserInfo'/>"
    + "<menuitem action='ViewUserLog'/>"
    + "<separator/>"
    + "<menu action='ShowMenu'>"
    + "<menuitem action='ShowOffline'/>"
    + "<menuitem action='ShowEmptyGroups'/>"
    + "<menuitem action='ShowBuddyDetails'/>"
    + "<menuitem action='ShowIdleTimes'/>"
    + "<menuitem action='ShowProtocolIcons'/>"
    + "</menu>"
    + "<menu action='SortMenu'/>"
    + "<separator/>"
    + "<menuitem action='AddBuddy'/>"
    + "<menuitem action='AddChat'/>"
    + "<menuitem action='AddGroup'/>"
    + "<separator/>"
    + "<menuitem action='Quit'/>"
    + "</menu>"
    + "<menu action='AccountsMenu'>"
    + "<menuitem action='ManageAccounts'/>"
    + "</menu>"
    + "<menu action='ToolsMenu'>"
    + "<menuitem action='BuddyPounces'/>"
    + "<menuitem action='Certificates'/>"
    + "<menuitem action='CustomSmileys'/>"
    + "<menuitem action='Plugins'/>"
    + "<menuitem action='Preferences'/>"
    + "<menuitem action='Privacy'/>"
    + "<menuitem action='SetMood'/>"
    + "<separator/>"
    + "<menuitem action='FileTransfers'/>"
    + "<menuitem action='RoomList'/>"
    + "<menuitem action='SystemLog'/>"
    + "<separator/>"
    + "<menuitem action='MuteSounds'/>"
    + "<placeholder name='PluginActions'/>"
    + "</menu>"
    + "<menu action='HelpMenu'>"
    + "<menuitem action='OnlineHelp'/>"
    + "<separator/>"
    + "<menuitem action='BuildInformation'/>"
    + "<menuitem action='DebugWindow'/>"
    + "<menuitem action='DeveloperInformation'/>"
    + "<menuitem action='PluginInformation'/>"
    + "<menuitem action='TranslatorInformation'/>"
    + "<separator/>"
    + "<menuitem action='About'/>"
    + "</menu>"
    + "</menubar>"
    +"</ui>";
    +
    /*********************************************************
    * Private Utility functions *
    *********************************************************/
    @@ -4386,7 +4467,7 @@
    /* if the window exists, is hidden, we're saving positions, and the
    * position is sane... */
    if (gtkblist && gtkblist->window &&
    - !GTK_WIDGET_VISIBLE(gtkblist->window) && blist_width != 0) {
    + !gtk_widget_get_visible(gtkblist->window) && blist_width != 0) {
    blist_x = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/x");
    blist_y = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/y");
    @@ -4416,7 +4497,7 @@
    PurpleBlistNode *gnode, *cnode;
    if (gtk_blist_visibility == GDK_VISIBILITY_FULLY_OBSCURED
    - || !GTK_WIDGET_VISIBLE(gtkblist->window))
    + || !gtk_widget_get_visible(gtkblist->window))
    return TRUE;
    for(gnode = list->root; gnode; gnode = gnode->next) {
    @@ -4462,12 +4543,13 @@
    static const char *require_connection[] =
    {
    - N_("/Buddies/New Instant Message..."),
    - N_("/Buddies/Join a Chat..."),
    - N_("/Buddies/Get User Info..."),
    - N_("/Buddies/Add Buddy..."),
    - N_("/Buddies/Add Chat..."),
    - N_("/Buddies/Add Group..."),
    + "/BList/BuddiesMenu/NewInstantMessage",
    + "/BList/BuddiesMenu/JoinAChat",
    + "/BList/BuddiesMenu/GetUserInfo",
    + "/BList/BuddiesMenu/AddBuddy",
    + "/BList/BuddiesMenu/AddChat",
    + "/BList/BuddiesMenu/AddGroup",
    + "/BList/ToolsMenu/Privacy",
    };
    static const int require_connection_size = sizeof(require_connection)
    @@ -4480,7 +4562,7 @@
    static void
    update_menu_bar(PidginBuddyList *gtkblist)
    {
    - GtkWidget *widget;
    + GtkAction *action;
    gboolean sensitive;
    int i;
    @@ -4492,21 +4574,18 @@
    for (i = 0; i < require_connection_size; i++)
    {
    - widget = gtk_item_factory_get_widget(gtkblist->ift, require_connection[i]);
    - gtk_widget_set_sensitive(widget, sensitive);
    - }
    -
    - widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Buddies/Join a Chat..."));
    - gtk_widget_set_sensitive(widget, pidgin_blist_joinchat_is_showable());
    -
    - widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Buddies/Add Chat..."));
    - gtk_widget_set_sensitive(widget, pidgin_blist_joinchat_is_showable());
    -
    - widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Privacy"));
    - gtk_widget_set_sensitive(widget, sensitive);
    -
    - widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Room List"));
    - gtk_widget_set_sensitive(widget, pidgin_roomlist_is_showable());
    + action = gtk_ui_manager_get_action(gtkblist->ui, require_connection[i]);
    + gtk_action_set_sensitive(action, sensitive);
    + }
    +
    + action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/JoinAChat");
    + gtk_action_set_sensitive(action, pidgin_blist_joinchat_is_showable());
    +
    + action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/AddChat");
    + gtk_action_set_sensitive(action, pidgin_blist_joinchat_is_showable());
    +
    + action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/RoomList");
    + gtk_action_set_sensitive(action, pidgin_roomlist_is_showable());
    }
    static void
    @@ -4798,12 +4877,6 @@
    NUM_TARGETS
    };
    -static const char *
    -item_factory_translate_func (const char *path, gpointer func_data)
    -{
    - return _((char *)path);
    -}
    -
    void pidgin_blist_setup_sort_methods()
    {
    const char *id;
    @@ -5453,8 +5526,28 @@
    headline_style_set (GtkWidget *widget,
    GtkStyle *prev_style)
    {
    + GtkStyle *style;
    +#if GTK_CHECK_VERSION(2,12,0)
    + GtkWidget *window;
    +
    + if (gtkblist->changing_style)
    + return;
    +
    + /* This is a hack needed to use the tooltip background colour */
    + window = gtk_window_new(GTK_WINDOW_POPUP);
    + gtk_widget_set_name(window, "gtk-tooltip");
    + gtk_widget_ensure_style(window);
    + style = gtk_widget_get_style(window);
    +
    + gtkblist->changing_style = TRUE;
    + gtk_widget_set_style(gtkblist->headline_hbox, style);
    + gtkblist->changing_style = FALSE;
    +
    + gtk_widget_destroy(window);
    +
    + gtk_widget_queue_draw(gtkblist->headline_hbox);
    +#else
    GtkTooltips *tooltips;
    - GtkStyle *style;
    if (gtkblist->changing_style)
    return;
    @@ -5463,9 +5556,6 @@
    g_object_ref_sink (tooltips);
    gtk_tooltips_force_window (tooltips);
    -#if GTK_CHECK_VERSION(2, 12, 0)
    - gtk_widget_set_name (tooltips->tip_window, "gtk-tooltips");
    -#endif
    gtk_widget_ensure_style (tooltips->tip_window);
    style = gtk_widget_get_style (tooltips->tip_window);
    @@ -5474,6 +5564,7 @@
    gtkblist->changing_style = FALSE;
    g_object_unref (tooltips);
    +#endif
    }
    /******************************************/
    @@ -5710,6 +5801,8 @@
    GtkWidget *close;
    char *pretty, *tmp;
    const char *theme_name;
    + GtkActionGroup *action_group;
    + GError *error;
    GtkAccelGroup *accel_group;
    GtkTreeSelection *selection;
    GtkTargetEntry dte[] = {{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW},
    @@ -5759,27 +5852,45 @@
    gtk_widget_add_events(gtkblist->window, GDK_VISIBILITY_NOTIFY_MASK);
    /******************************* Menu bar *************************************/
    - accel_group = gtk_accel_group_new();
    - gtk_window_add_accel_group(GTK_WINDOW (gtkblist->window), accel_group);
    - g_object_unref(accel_group);
    - gtkblist->ift = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<PurpleMain>", accel_group);
    - gtk_item_factory_set_translate_func(gtkblist->ift,
    - (GtkTranslateFunc)item_factory_translate_func,
    - NULL, NULL);
    - gtk_item_factory_create_items(gtkblist->ift, sizeof(blist_menu) / sizeof(*blist_menu),
    - blist_menu, NULL);
    + action_group = gtk_action_group_new("BListActions");
    + gtk_action_group_add_actions(action_group,
    + blist_menu_entries,
    + G_N_ELEMENTS(blist_menu_entries),
    + GTK_WINDOW(gtkblist->window));
    + gtk_action_group_add_toggle_actions(action_group,
    + blist_menu_toggle_entries,
    + G_N_ELEMENTS(blist_menu_toggle_entries),
    + GTK_WINDOW(gtkblist->window));
    +#ifdef ENABLE_NLS
    + gtk_action_group_set_translation_domain(action_group,
    + PACKAGE);
    +#endif
    +
    + gtkblist->ui = gtk_ui_manager_new();
    + gtk_ui_manager_insert_action_group(gtkblist->ui, action_group, 0);
    +
    + accel_group = gtk_ui_manager_get_accel_group(gtkblist->ui);
    + gtk_window_add_accel_group(GTK_WINDOW(gtkblist->window), accel_group);
    pidgin_load_accels();
    g_signal_connect(G_OBJECT(accel_group), "accel-changed", G_CALLBACK(pidgin_save_accels_cb), NULL);
    - menu = gtk_item_factory_get_widget(gtkblist->ift, "<PurpleMain>");
    + error = NULL;
    + if (!gtk_ui_manager_add_ui_from_string(gtkblist->ui, blist_menu, -1, &error))
    + {
    + g_message("building menus failed: %s", error->message);
    + g_error_free(error);
    + exit(EXIT_FAILURE);
    + }
    +
    + menu = gtk_ui_manager_get_widget(gtkblist->ui, "/BList");
    gtkblist->menutray = pidgin_menu_tray_new();
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtkblist->menutray);
    gtk_widget_show(gtkblist->menutray);
    gtk_widget_show(menu);
    gtk_box_pack_start(GTK_BOX(gtkblist->main_vbox), menu, FALSE, FALSE, 0);
    - accountmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts"));
    -
    + menu = gtk_ui_manager_get_widget(gtkblist->ui, "/BList/AccountsMenu");
    + accountmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
    /****************************** Notebook *************************************/
    gtkblist->notebook = gtk_notebook_new();
    @@ -5967,26 +6078,26 @@
    /* set the Show Offline Buddies option. must be done
    * after the treeview or faceprint gets mad. -Robot101
    */
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Offline Buddies"))),
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowOffline")),
    purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies"));
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Empty Groups"))),
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowEmptyGroups")),
    purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups"));
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Tools/Mute Sounds"))),
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds")),
    purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute"));
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Buddy Details"))),
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowBuddyDetails")),
    purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"));
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Idle Times"))),
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowIdleTimes")),
    purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time"));
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Protocol Icons"))),
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowProtocolIcons")),
    purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"));
    if(!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), "none"))
    - gtk_widget_set_sensitive(gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Mute Sounds")), FALSE);
    + gtk_action_set_sensitive(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds"), FALSE);
    /* Update some dynamic things */
    update_menu_bar(gtkblist);
    @@ -6843,7 +6954,7 @@
    purple_signals_disconnect_by_handle(gtkblist);
    if (gtkblist->headline_close)
    - gdk_pixbuf_unref(gtkblist->headline_close);
    + g_object_unref(G_OBJECT(gtkblist->headline_close));
    gtk_widget_destroy(gtkblist->window);
    @@ -6862,7 +6973,7 @@
    gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL;
    g_object_unref(G_OBJECT(gtkblist->treemodel));
    gtkblist->treemodel = NULL;
    - g_object_unref(G_OBJECT(gtkblist->ift));
    + g_object_unref(G_OBJECT(gtkblist->ui));
    g_object_unref(G_OBJECT(gtkblist->empty_avatar));
    gdk_cursor_unref(gtkblist->hand_cursor);
    @@ -6887,7 +6998,7 @@
    return;
    if (show) {
    - if(!PIDGIN_WINDOW_ICONIFIED(gtkblist->window) && !GTK_WIDGET_VISIBLE(gtkblist->window))
    + if(!PIDGIN_WINDOW_ICONIFIED(gtkblist->window) && !gtk_widget_get_visible(gtkblist->window))
    purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-unhiding", gtkblist);
    pidgin_blist_restore_position();
    gtk_window_present(GTK_WINDOW(gtkblist->window));
    @@ -6896,7 +7007,7 @@
    purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-hiding", gtkblist);
    gtk_widget_hide(gtkblist->window);
    } else {
    - if (!GTK_WIDGET_VISIBLE(gtkblist->window))
    + if (!gtk_widget_get_visible(gtkblist->window))
    gtk_widget_show(gtkblist->window);
    gtk_window_iconify(GTK_WINDOW(gtkblist->window));
    }
    @@ -7302,7 +7413,7 @@
    pidgin_blist_toggle_visibility()
    {
    if (gtkblist && gtkblist->window) {
    - if (GTK_WIDGET_VISIBLE(gtkblist->window)) {
    + if (gtk_widget_get_visible(gtkblist->window)) {
    /* make the buddy list visible if it is iconified or if it is
    * obscured and not currently focused (the focus part ensures
    * that we do something reasonable if the buddy list is obscured
    @@ -7367,7 +7478,7 @@
    static void
    set_urgent(void)
    {
    - if (gtkblist->window && !GTK_WIDGET_HAS_FOCUS(gtkblist->window))
    + if (gtkblist->window && !gtk_widget_has_focus(gtkblist->window))
    pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE);
    }
    @@ -7902,40 +8013,43 @@
    }
    static void
    -build_plugin_actions(GtkWidget *menu, PurplePlugin *plugin,
    - gpointer context)
    -{
    - GtkWidget *menuitem;
    +build_plugin_actions(GtkActionGroup *action_group, GString *ui, char *parent,
    + PurplePlugin *plugin, gpointer context)
    +{
    + GtkAction *menuaction;
    PurplePluginAction *action = NULL;
    GList *actions, *l;
    + char *name;
    + int count = 0;
    actions = PURPLE_PLUGIN_ACTIONS(plugin, context);
    - for (l = actions; l != NULL; l = l->next)
    - {
    - if (l->data)
    - {
    - action = (PurplePluginAction *) l->data;
    + for (l = actions; l != NULL; l = l->next) {
    + if (l->data) {
    + action = (PurplePluginAction *)l->data;
    action->plugin = plugin;
    action->context = context;
    - menuitem = gtk_menu_item_new_with_label(action->label);
    - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    -
    - g_signal_connect(G_OBJECT(menuitem), "activate",
    + name = g_strdup_printf("%s-action-%d", parent, count++);
    + menuaction = gtk_action_new(name, action->label, NULL, NULL);
    + gtk_action_group_add_action(action_group, menuaction);
    + g_string_append_printf(ui, "<menuitem action='%s'/>", name);
    +
    + g_signal_connect(G_OBJECT(menuaction), "activate",
    G_CALLBACK(plugin_act), action);
    - g_object_set_data_full(G_OBJECT(menuitem), "plugin_action",
    + g_object_set_data_full(G_OBJECT(menuaction), "plugin_action",
    action,
    (GDestroyNotify)purple_plugin_action_free);
    - gtk_widget_show(menuitem);
    + g_free(name);
    }
    else
    - pidgin_separator(menu);
    + g_string_append(ui, "<separator/>");
    }
    g_list_free(actions);
    }
    +
    static void
    modify_account_cb(GtkWidget *widget, gpointer data)
    {
    @@ -7962,14 +8076,12 @@
    purple_account_set_enabled(account, PIDGIN_UI, FALSE);
    }
    -
    -
    void
    pidgin_blist_update_accounts_menu(void)
    {
    - GtkWidget *menuitem = NULL, *submenu = NULL;
    - GtkAccelGroup *accel_group = NULL;
    - GList *l = NULL, *accounts = NULL;
    + GtkWidget *menuitem, *submenu;
    + GtkAccelGroup *accel_group;
    + GList *l, *accounts;
    gboolean disabled_accounts = FALSE;
    gboolean enabled_accounts = FALSE;
    @@ -7980,10 +8092,12 @@
    for (l = gtk_container_get_children(GTK_CONTAINER(accountmenu)); l; l = g_list_delete_link(l, l)) {
    menuitem = l->data;
    - if (menuitem != gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts/Manage Accounts")))
    + if (menuitem != gtk_ui_manager_get_widget(gtkblist->ui, "/BList/AccountsMenu/ManageAccounts"))
    gtk_widget_destroy(menuitem);
    }
    + accel_group = gtk_menu_get_accel_group(GTK_MENU(accountmenu));
    +
    for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) {
    char *buf = NULL;
    GtkWidget *image = NULL;
    @@ -7992,14 +8106,14 @@
    account = accounts->data;
    - if(!purple_account_get_enabled(account, PIDGIN_UI)) {
    + if (!purple_account_get_enabled(account, PIDGIN_UI)) {
    if (!disabled_accounts) {
    menuitem = gtk_menu_item_new_with_label(_("Enable Account"));
    gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem);
    submenu = gtk_menu_new();
    gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group);
    - gtk_menu_set_accel_path(GTK_MENU(submenu), N_("<PurpleMain>/Accounts/Enable Account"));
    + gtk_menu_set_accel_path(GTK_MENU(submenu), "<Actions>/BListActions/EnableAccount");
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
    disabled_accounts = TRUE;
    @@ -8009,9 +8123,9 @@
    purple_account_get_protocol_name(account), ")", NULL);
    menuitem = gtk_image_menu_item_new_with_label(buf);
    g_free(buf);
    +
    pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
    - if (pixbuf != NULL)
    - {
    + if (pixbuf != NULL) {
    if (!purple_account_is_connected(account))
    gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
    image = gtk_image_new_from_pixbuf(pixbuf);
    @@ -8019,9 +8133,11 @@
    gtk_widget_show(image);
    gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
    }
    +
    g_signal_connect(G_OBJECT(menuitem), "activate",
    G_CALLBACK(enable_account_cb), account);
    gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
    +
    } else {
    enabled_accounts = TRUE;
    }
    @@ -8033,7 +8149,6 @@
    }
    pidgin_separator(accountmenu);
    - accel_group = gtk_menu_get_accel_group(GTK_MENU(accountmenu));
    for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) {
    char *buf = NULL;
    @@ -8053,8 +8168,9 @@
    buf = g_strconcat(purple_account_get_username(account), " (",
    purple_account_get_protocol_name(account), ")", NULL);
    menuitem = gtk_image_menu_item_new_with_label(buf);
    - accel_path_buf = g_strconcat(N_("<PurpleMain>/Accounts/"), buf, NULL);
    + accel_path_buf = g_strconcat("<Actions>/AccountActions/", buf, NULL);
    g_free(buf);
    +
    pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
    if (pixbuf != NULL) {
    if (!purple_account_is_connected(account))
    @@ -8065,6 +8181,7 @@
    gtk_widget_show(image);
    gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
    }
    +
    gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem);
    submenu = gtk_menu_new();
    @@ -8073,7 +8190,6 @@
    g_free(accel_path_buf);
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
    -
    menuitem = gtk_menu_item_new_with_mnemonic(_("_Edit Account"));
    g_signal_connect(G_OBJECT(menuitem), "activate",
    G_CALLBACK(modify_account_cb), account);
    @@ -8098,8 +8214,37 @@
    gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
    }
    }
    +
    if (PURPLE_PLUGIN_HAS_ACTIONS(plugin)) {
    - build_plugin_actions(submenu, plugin, gc);
    + GtkWidget *menuitem;
    + PurplePluginAction *action = NULL;
    + GList *actions, *l;
    +
    + actions = PURPLE_PLUGIN_ACTIONS(plugin, gc);
    +
    + for (l = actions; l != NULL; l = l->next)
    + {
    + if (l->data)
    + {
    + action = (PurplePluginAction *) l->data;
    + action->plugin = plugin;
    + action->context = gc;
    +
    + menuitem = gtk_menu_item_new_with_label(action->label);
    + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
    +
    + g_signal_connect(G_OBJECT(menuitem), "activate",
    + G_CALLBACK(plugin_act), action);
    + g_object_set_data_full(G_OBJECT(menuitem), "plugin_action",
    + action,
    + (GDestroyNotify)purple_plugin_action_free);
    + gtk_widget_show(menuitem);
    + }
    + else
    + pidgin_separator(submenu);
    + }
    +
    + g_list_free(actions);
    }
    } else {
    menuitem = gtk_menu_item_new_with_label(_("No actions available"));
    @@ -8114,36 +8259,45 @@
    G_CALLBACK(disable_account_cb), account);
    gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
    }
    +
    gtk_widget_show_all(accountmenu);
    }
    -static GList *plugin_submenus = NULL;
    +static guint plugins_merge_id;
    +static GtkActionGroup *plugins_action_group = NULL;
    void
    pidgin_blist_update_plugin_actions(void)
    {
    - GtkWidget *menuitem, *submenu;
    PurplePlugin *plugin = NULL;
    GList *l;
    - GtkAccelGroup *accel_group;
    -
    - GtkWidget *pluginmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools"));
    -
    - g_return_if_fail(pluginmenu != NULL);
    -
    - /* Remove old plugin action submenus from the Tools menu */
    - for (l = plugin_submenus; l; l = l->next)
    - gtk_widget_destroy(GTK_WIDGET(l->data));
    - g_list_free(plugin_submenus);
    - plugin_submenus = NULL;
    -
    - accel_group = gtk_menu_get_accel_group(GTK_MENU(pluginmenu));
    +
    + GtkAction *action;
    + GString *plugins_ui;
    + gchar *ui_string;
    + int count = 0;
    +
    + if ((gtkblist == NULL) || (gtkblist->ui == NULL))
    + return;
    +
    + /* Clear the old menu */
    + if (plugins_action_group) {
    + gtk_ui_manager_remove_ui(gtkblist->ui, plugins_merge_id);
    + gtk_ui_manager_remove_action_group(gtkblist->ui, plugins_action_group);
    + g_object_unref(G_OBJECT(plugins_action_group));
    + }
    +
    + plugins_action_group = gtk_action_group_new("PluginActions");
    +#ifdef ENABLE_NLS
    + gtk_action_group_set_translation_domain(plugins_action_group, PACKAGE);
    +#endif
    + plugins_ui = g_string_new(NULL);
    /* Add a submenu for each plugin with custom actions */
    for (l = purple_plugins_get_loaded(); l; l = l->next) {
    - char *path;
    -
    - plugin = (PurplePlugin *) l->data;
    + char *name;
    +
    + plugin = (PurplePlugin *)l->data;
    if (PURPLE_IS_PROTOCOL_PLUGIN(plugin))
    continue;
    @@ -8151,28 +8305,34 @@
    if (!PURPLE_PLUGIN_HAS_ACTIONS(plugin))
    continue;
    - menuitem = gtk_image_menu_item_new_with_label(_(plugin->info->name));
    - gtk_menu_shell_append(GTK_MENU_SHELL(pluginmenu), menuitem);
    -
    - plugin_submenus = g_list_append(plugin_submenus, menuitem);
    -
    - submenu = gtk_menu_new();
    - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
    -
    - gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group);
    - path = g_strdup_printf("%s/Tools/%s", gtkblist->ift->path, plugin->info->name);
    - gtk_menu_set_accel_path(GTK_MENU(submenu), path);
    - g_free(path);
    -
    - build_plugin_actions(submenu, plugin, NULL);
    - }
    - gtk_widget_show_all(pluginmenu);
    + name = g_strdup_printf("plugin%d", count);
    + action = gtk_action_new(name, plugin->info->name, NULL, NULL);
    + gtk_action_group_add_action(plugins_action_group, action);
    + g_string_append_printf(plugins_ui, "<menu action='%s'>", name);
    +
    + build_plugin_actions(plugins_action_group, plugins_ui, name, plugin, NULL);
    +
    + g_string_append(plugins_ui, "</menu>");
    + count++;
    +
    + g_free(name);
    + }
    +
    + ui_string = g_strconcat("<ui><menubar action='BList'><menu action='ToolsMenu'><placeholder name='PluginActions'>",
    + plugins_ui->str,
    + "</placeholder></menu></menubar></ui>",
    + NULL);
    + gtk_ui_manager_insert_action_group(gtkblist->ui, plugins_action_group, 1);
    + plugins_merge_id = gtk_ui_manager_add_ui_from_string(gtkblist->ui, ui_string, -1, NULL);
    +
    + g_string_free(plugins_ui, TRUE);
    + g_free(ui_string);
    }
    static void
    -sortmethod_act(GtkCheckMenuItem *checkmenuitem, char *id)
    -{
    - if (gtk_check_menu_item_get_active(checkmenuitem))
    +sortmethod_act(GtkRadioAction *action, GtkRadioAction *current, char *id)
    +{
    + if (action == current)
    {
    pidgin_set_cursor(gtkblist->window, GDK_WATCH);
    /* This is redundant. I think. */
    @@ -8186,40 +8346,58 @@
    void
    pidgin_blist_update_sort_methods(void)
    {
    - GtkWidget *menuitem = NULL, *activeitem = NULL;
    PidginBlistSortMethod *method = NULL;
    GList *l;
    GSList *sl = NULL;
    - GtkWidget *sortmenu;
    const char *m = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/sort_type");
    - if ((gtkblist == NULL) || (gtkblist->ift == NULL))
    - return;
    -
    - g_return_if_fail(m != NULL);
    -
    - sortmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Buddies/Sort Buddies"));
    -
    - if (sortmenu == NULL)
    + GtkRadioAction *action;
    + GString *ui_string;
    +
    + if ((gtkblist == NULL) || (gtkblist->ui == NULL))
    return;
    /* Clear the old menu */
    - for (l = gtk_container_get_children(GTK_CONTAINER(sortmenu)); l; l = g_list_delete_link(l, l)) {
    - menuitem = l->data;
    - gtk_widget_destroy(GTK_WIDGET(menuitem));
    - }
    + if (sort_action_group) {
    + gtk_ui_manager_remove_ui(gtkblist->ui, sort_merge_id);
    + gtk_ui_manager_remove_action_group(gtkblist->ui, sort_action_group);
    + g_object_unref(G_OBJECT(sort_action_group));
    + }
    +
    + sort_action_group = gtk_action_group_new("SortMethods");
    +#ifdef ENABLE_NLS
    + gtk_action_group_set_translation_domain(sort_action_group, PACKAGE);
    +#endif
    + ui_string = g_string_new("<ui><menubar name='BList'>"
    + "<menu action='BuddiesMenu'><menu action='SortMenu'>");
    for (l = pidgin_blist_sort_methods; l; l = l->next) {
    - method = (PidginBlistSortMethod *) l->data;
    - menuitem = gtk_radio_menu_item_new_with_label(sl, _(method->name));
    - if (g_str_equal(m, method->id))
    - activeitem = menuitem;
    - sl = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
    - gtk_menu_shell_append(GTK_MENU_SHELL(sortmenu), menuitem);
    - g_signal_connect(G_OBJECT(menuitem), "toggled",
    - G_CALLBACK(sortmethod_act), method->id);
    - gtk_widget_show(menuitem);
    - }
    - if (activeitem)
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(activeitem), TRUE);
    -}
    + method = (PidginBlistSortMethod *)l->data;
    +
    + g_string_append_printf(ui_string, "<menuitem action='%s'/>", method->id);
    + action = gtk_radio_action_new(method->id,
    + method->name,
    + NULL,
    + NULL,
    + 0);
    + gtk_action_group_add_action_with_accel(sort_action_group, GTK_ACTION(action), NULL);
    +
    + gtk_radio_action_set_group(action, sl);
    + sl = gtk_radio_action_get_group(action);
    +
    + if (!strcmp(m, method->id))
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
    + else
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), FALSE);
    +
    + g_signal_connect(G_OBJECT(action), "changed",
    + G_CALLBACK(sortmethod_act), method->id);
    + }
    +
    + g_string_append(ui_string, "</menu></menu></menubar></ui>");
    + gtk_ui_manager_insert_action_group(gtkblist->ui, sort_action_group, 1);
    + sort_merge_id = gtk_ui_manager_add_ui_from_string(gtkblist->ui, ui_string->str, -1, NULL);
    +
    + g_string_free(ui_string, TRUE);
    +}
    +
    --- a/pidgin/gtkblist.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkblist.h Tue Feb 28 05:29:13 2012 +0000
    @@ -82,7 +82,7 @@
    GtkCellRenderer *text_rend;
    - GtkItemFactory *ift;
    + GtkUIManager *ui;
    GtkWidget *menutray; /**< The menu tray widget. */
    GtkWidget *menutrayicon; /**< The menu tray icon. */
    --- a/pidgin/gtkcellrendererexpander.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkcellrendererexpander.c Tue Feb 28 05:29:13 2012 +0000
    @@ -250,8 +250,13 @@
    state = GTK_STATE_INSENSITIVE;
    else if (flags & GTK_CELL_RENDERER_PRELIT)
    state = GTK_STATE_PRELIGHT;
    +#if GTK_CHECK_VERSION(2,18,0)
    + else if (gtk_widget_has_focus (widget) && flags & GTK_CELL_RENDERER_SELECTED)
    + state = GTK_STATE_ACTIVE;
    +#else
    else if (GTK_WIDGET_HAS_FOCUS (widget) && flags & GTK_CELL_RENDERER_SELECTED)
    state = GTK_STATE_ACTIVE;
    +#endif
    else
    state = GTK_STATE_NORMAL;
    --- a/pidgin/gtkcertmgr.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkcertmgr.c Tue Feb 28 05:29:13 2012 +0000
    @@ -40,12 +40,6 @@
    #include "gtkcertmgr.h"
    -#ifdef ENABLE_GCR
    -#define GCR_API_SUBJECT_TO_CHANGE
    -#include <gcr/gcr.h>
    -#include <gcr/gcr-simple-certificate.h>
    -#endif
    -
    /*****************************************************************************
    * X.509 tls_peers management interface *
    *****************************************************************************/
    @@ -316,13 +310,7 @@
    GtkTreeModel *model;
    gchar *id;
    PurpleCertificate *crt;
    -#ifdef ENABLE_GCR
    - GByteArray *der;
    - GcrCertificate *gcrt;
    char *title;
    - GtkWidget *dialog;
    - GcrCertificateBasicsWidget *cert_widget;
    -#endif
    /* See if things are selected */
    if (!gtk_tree_selection_get_selected(select, &model, &iter)) {
    @@ -338,38 +326,15 @@
    crt = purple_certificate_pool_retrieve(tpm_dat->tls_peers, id);
    g_return_if_fail(crt);
    -#ifdef ENABLE_GCR
    - der = purple_certificate_get_der_data(crt);
    - g_return_if_fail(der);
    -
    - gcrt = gcr_simple_certificate_new(der->data, der->len);
    - g_return_if_fail(gcrt);
    -
    /* Fire the notification */
    title = g_strdup_printf(_("Certificate Information for %s"), id);
    - dialog = gtk_dialog_new_with_buttons(title,
    - NULL,
    - 0,
    - GTK_STOCK_OK,
    - GTK_RESPONSE_ACCEPT,
    - NULL);
    - cert_widget = gcr_certificate_basics_widget_new(gcrt);
    - gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
    - GTK_WIDGET(cert_widget), TRUE, TRUE, 0);
    - g_signal_connect_swapped(dialog, "response",
    - G_CALLBACK(gtk_widget_destroy),
    - dialog);
    - gtk_widget_show_all(dialog);
    -
    - g_byte_array_free(der, TRUE);
    - g_object_unref(G_OBJECT(gcrt));
    -#else
    - /* Fire the notification */
    - purple_certificate_display_x509(crt);
    + purple_request_certificate(tpm_dat, title, NULL, NULL, crt,
    + _("OK"), G_CALLBACK(purple_certificate_destroy),
    + _("Cancel"), G_CALLBACK(purple_certificate_destroy),
    + crt);
    g_free(id);
    - purple_certificate_destroy(crt);
    -#endif
    + g_free(title);
    }
    static void
    --- a/pidgin/gtkconv.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkconv.c Tue Feb 28 05:29:13 2012 +0000
    @@ -80,6 +80,15 @@
    #include "gtknickcolors.h"
    +#if !GTK_CHECK_VERSION(2,20,0)
    +#define gtk_widget_get_realized(x) GTK_WIDGET_REALIZED(x)
    +
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
    +#define gtk_widget_is_drawable(x) GTK_WIDGET_DRAWABLE(x)
    +#endif
    +#endif
    +
    /**
    * A GTK+ Instant Message pane.
    */
    @@ -198,7 +207,6 @@
    static void gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state);
    static void update_typing_icon(PidginConversation *gtkconv);
    static void update_typing_message(PidginConversation *gtkconv, const char *message);
    -static const char *item_factory_translate_func (const char *path, gpointer func_data);
    gboolean pidgin_conv_has_focus(PurpleConversation *conv);
    static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background);
    static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast);
    @@ -943,7 +951,9 @@
    GTK_RESPONSE_OK);
    gtk_container_set_border_width(GTK_CONTAINER(invite_dialog), PIDGIN_HIG_BOX_SPACE);
    gtk_window_set_resizable(GTK_WINDOW(invite_dialog), FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(invite_dialog), FALSE);
    +#endif
    info->window = GTK_WIDGET(invite_dialog);
    @@ -1040,13 +1050,13 @@
    }
    static void
    -menu_new_conv_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_new_conv_cb(GtkAction *action, gpointer data)
    {
    pidgin_dialogs_im();
    }
    static void
    -menu_join_chat_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_join_chat_cb(GtkAction *action, gpointer data)
    {
    pidgin_blist_joinchat_show();
    }
    @@ -1090,7 +1100,7 @@
    * plaintext v. HTML file.
    */
    static void
    -menu_save_as_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_save_as_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
    @@ -1121,7 +1131,7 @@
    }
    static void
    -menu_view_log_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_view_log_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1148,7 +1158,6 @@
    gdk_window_set_cursor(gtkblist->window->window, cursor);
    gdk_window_set_cursor(win->window->window, cursor);
    gdk_cursor_unref(cursor);
    - gdk_display_flush(gdk_drawable_get_display(GDK_DRAWABLE(widget->window)));
    name = purple_conversation_get_name(conv);
    account = purple_conversation_get_account(conv);
    @@ -1175,7 +1184,7 @@
    }
    static void
    -menu_clear_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_clear_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1185,7 +1194,7 @@
    }
    static void
    -menu_find_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_find_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *gtkwin = data;
    PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(gtkwin);
    @@ -1195,7 +1204,7 @@
    #ifdef USE_VV
    static void
    -menu_initiate_media_call_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_initiate_media_call_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = (PidginWindow *)data;
    PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
    @@ -1203,15 +1212,15 @@
    purple_prpl_initiate_media(account,
    purple_conversation_get_name(conv),
    - action == 0 ? PURPLE_MEDIA_AUDIO :
    - action == 1 ? PURPLE_MEDIA_VIDEO :
    - action == 2 ? PURPLE_MEDIA_AUDIO |
    + action == win->audio_call ? PURPLE_MEDIA_AUDIO :
    + action == win->video_call ? PURPLE_MEDIA_VIDEO :
    + action == win->audio_video_call ? PURPLE_MEDIA_AUDIO |
    PURPLE_MEDIA_VIDEO : PURPLE_MEDIA_NONE);
    }
    #endif
    static void
    -menu_send_file_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_send_file_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
    @@ -1223,24 +1232,24 @@
    }
    static void
    -menu_get_attention_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_get_attention_cb(GObject *obj, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
    if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
    int index;
    - if (widget == win->menu.get_attention)
    + if ((GtkAction *)obj == win->menu.get_attention)
    index = 0;
    else
    - index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "index"));
    + index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(obj), "index"));
    purple_prpl_send_attention(purple_conversation_get_connection(conv),
    purple_conversation_get_name(conv), index);
    }
    }
    static void
    -menu_add_pounce_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_add_pounce_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1252,7 +1261,7 @@
    }
    static void
    -menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_insert_link_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PidginConversation *gtkconv;
    @@ -1266,7 +1275,7 @@
    }
    static void
    -menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_insert_image_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PidginConversation *gtkconv;
    @@ -1281,7 +1290,7 @@
    static void
    -menu_alias_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_alias_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1308,7 +1317,7 @@
    }
    static void
    -menu_get_info_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_get_info_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1319,7 +1328,7 @@
    }
    static void
    -menu_invite_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_invite_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1330,7 +1339,7 @@
    }
    static void
    -menu_block_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_block_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1341,7 +1350,7 @@
    }
    static void
    -menu_unblock_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_unblock_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1352,7 +1361,7 @@
    }
    static void
    -menu_add_remove_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_add_remove_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1397,7 +1406,7 @@
    }
    static void
    -menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_close_conv_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    @@ -1405,7 +1414,7 @@
    }
    static void
    -menu_logging_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_logging_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1417,7 +1426,7 @@
    if (conv == NULL)
    return;
    - logging = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
    + logging = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
    if (logging == purple_conversation_is_logging(conv))
    return;
    @@ -1468,14 +1477,14 @@
    }
    static void
    -menu_toolbar_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_toolbar_cb(GtkAction *action, gpointer data)
    {
    purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar",
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
    -}
    -
    -static void
    -menu_sounds_cb(gpointer data, guint action, GtkWidget *widget)
    + gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
    +}
    +
    +static void
    +menu_sounds_cb(GtkAction *action, gpointer data)
    {
    PidginWindow *win = data;
    PurpleConversation *conv;
    @@ -1490,17 +1499,17 @@
    gtkconv = PIDGIN_CONVERSATION(conv);
    gtkconv->make_sound =
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
    + gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
    node = get_conversation_blist_node(conv);
    if (node)
    purple_blist_node_set_bool(node, "gtk-mute-sound", !gtkconv->make_sound);
    }
    static void
    -menu_timestamps_cb(gpointer data, guint action, GtkWidget *widget)
    +menu_timestamps_cb(GtkAction *action, gpointer data)
    {
    purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps",
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
    + gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
    }
    static void
    @@ -2299,7 +2308,7 @@
    gtkconv->active_conv = conv;
    purple_conversation_set_logging(conv,
    - gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging)));
    + gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(gtkconv->win->menu.logging)));
    entry = GTK_IMHTML(gtkconv->entry);
    protocol_name = purple_account_get_protocol_name(purple_conversation_get_account(conv));
    @@ -3114,91 +3123,98 @@
    return gtkconv->win;
    }
    -static GtkItemFactoryEntry menu_items[] =
    +static GtkActionEntry menu_entries[] =
    +/* TODO: fill out tooltips... */
    {
    /* Conversation menu */
    - { N_("/_Conversation"), NULL, NULL, 0, "<Branch>", NULL },
    -
    - { N_("/Conversation/New Instant _Message..."), "<CTL>M", menu_new_conv_cb,
    - 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW },
    - { N_("/Conversation/Join a _Chat..."), NULL, menu_join_chat_cb,
    - 0, "<StockItem>", PIDGIN_STOCK_CHAT },
    -
    - { "/Conversation/sep0", NULL, NULL, 0, "<Separator>", NULL },
    -
    - { N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
    - "<StockItem>", GTK_STOCK_FIND },
    - { N_("/Conversation/View _Log"), NULL, menu_view_log_cb, 0, "<Item>", NULL },
    - { N_("/Conversation/_Save As..."), NULL, menu_save_as_cb, 0,
    - "<StockItem>", GTK_STOCK_SAVE_AS },
    - { N_("/Conversation/Clea_r Scrollback"), "<CTL>L", menu_clear_cb, 0, "<StockItem>", GTK_STOCK_CLEAR },
    -
    - { "/Conversation/sep1", NULL, NULL, 0, "<Separator>", NULL },
    + { "ConversationMenu", NULL, N_("_Conversation"), NULL, NULL, NULL },
    + { "NewInstantMessage", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, N_("New Instant _Message..."), "<control>M", NULL, G_CALLBACK(menu_new_conv_cb) },
    + { "JoinAChat", PIDGIN_STOCK_CHAT, N_("Join a _Chat..."), NULL, NULL, G_CALLBACK(menu_join_chat_cb) },
    + { "Find", GTK_STOCK_FIND, N_("_Find..."), NULL, NULL, G_CALLBACK(menu_find_cb) },
    + { "ViewLog", NULL, N_("View _Log"), NULL, NULL, G_CALLBACK(menu_view_log_cb) },
    + { "SaveAs", GTK_STOCK_SAVE_AS, N_("_Save As..."), NULL, NULL, G_CALLBACK(menu_save_as_cb) },
    + { "ClearScrollback", GTK_STOCK_CLEAR, N_("Clea_r Scrollback"), "<control>L", NULL, G_CALLBACK(menu_clear_cb) },
    #ifdef USE_VV
    - { N_("/Conversation/M_edia"), NULL, NULL, 0, "<Branch>", NULL },
    -
    - { N_("/Conversation/Media/_Audio Call"), NULL, menu_initiate_media_call_cb, 0,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_AUDIO_CALL },
    - { N_("/Conversation/Media/_Video Call"), NULL, menu_initiate_media_call_cb, 1,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL },
    - { N_("/Conversation/Media/Audio\\/Video _Call"), NULL, menu_initiate_media_call_cb, 2,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL },
    + { "MediaMenu", NULL, N_("M_edia"), NULL, NULL, NULL },
    + { "AudioCall", PIDGIN_STOCK_TOOLBAR_AUDIO_CALL, N_("_Audio Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) },
    + { "VideoCall", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL, N_("_Video Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) },
    + { "AudioVideoCall", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL, N_("Audio/Video _Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) },
    #endif
    - { N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_FILE },
    - { N_("/Conversation/Get _Attention"), NULL, menu_get_attention_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION },
    - { N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
    - 0, "<Item>", NULL },
    - { N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_USER_INFO },
    - { N_("/Conversation/In_vite..."), NULL, menu_invite_cb, 0,
    - "<Item>", NULL },
    - { N_("/Conversation/M_ore"), NULL, NULL, 0, "<Branch>", NULL },
    -
    - { "/Conversation/sep2", NULL, NULL, 0, "<Separator>", NULL },
    -
    - { N_("/Conversation/Al_ias..."), NULL, menu_alias_cb, 0,
    - "<Item>", NULL },
    - { N_("/Conversation/_Block..."), NULL, menu_block_cb, 0,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_BLOCK },
    - { N_("/Conversation/_Unblock..."), NULL, menu_unblock_cb, 0,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_UNBLOCK },
    - { N_("/Conversation/_Add..."), NULL, menu_add_remove_cb, 0,
    - "<StockItem>", GTK_STOCK_ADD },
    - { N_("/Conversation/_Remove..."), NULL, menu_add_remove_cb, 0,
    - "<StockItem>", GTK_STOCK_REMOVE },
    -
    - { "/Conversation/sep3", NULL, NULL, 0, "<Separator>", NULL },
    -
    - { N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_LINK },
    - { N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0,
    - "<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE },
    -
    - { "/Conversation/sep4", NULL, NULL, 0, "<Separator>", NULL },
    -
    -
    - { N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0,
    - "<StockItem>", GTK_STOCK_CLOSE },
    + { "SendFile", PIDGIN_STOCK_TOOLBAR_SEND_FILE, N_("Se_nd File..."), NULL, NULL, G_CALLBACK(menu_send_file_cb) },
    + { "GetAttention", PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION, N_("Get _Attention"), NULL, NULL, G_CALLBACK(menu_get_attention_cb) },
    + { "AddBuddyPounce", NULL, N_("Add Buddy _Pounce..."), NULL, NULL, G_CALLBACK(menu_add_pounce_cb) },
    + { "GetInfo", PIDGIN_STOCK_TOOLBAR_USER_INFO, N_("_Get Info"), "<control>O", NULL, G_CALLBACK(menu_get_info_cb) },
    + { "Invite", NULL, N_("In_vite..."), NULL, NULL, G_CALLBACK(menu_invite_cb) },
    + { "MoreMenu", NULL, N_("M_ore"), NULL, NULL, NULL },
    + { "Alias", NULL, N_("Al_ias..."), NULL, NULL, G_CALLBACK(menu_alias_cb) },
    + { "Block", PIDGIN_STOCK_TOOLBAR_BLOCK, N_("_Block..."), NULL, NULL, G_CALLBACK(menu_block_cb) },
    + { "Unblock", PIDGIN_STOCK_TOOLBAR_UNBLOCK, N_("_Unblock..."), NULL, NULL, G_CALLBACK(menu_unblock_cb) },
    + { "Add", GTK_STOCK_ADD, N_("_Add..."), NULL, NULL, G_CALLBACK(menu_add_remove_cb) },
    + { "Remove", GTK_STOCK_REMOVE, N_("_Remove..."), NULL, NULL, G_CALLBACK(menu_add_remove_cb) },
    + { "InsertLink", PIDGIN_STOCK_TOOLBAR_INSERT_LINK, N_("Insert Lin_k..."), NULL, NULL, G_CALLBACK(menu_insert_link_cb) },
    + { "InsertImage", PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE, N_("Insert Imag_e..."), NULL, NULL, G_CALLBACK(menu_insert_image_cb) },
    + { "Close", GTK_STOCK_CLOSE, N_("_Close"), NULL, NULL, G_CALLBACK(menu_close_conv_cb) },
    /* Options */
    - { N_("/_Options"), NULL, NULL, 0, "<Branch>", NULL },
    - { N_("/Options/Enable _Logging"), NULL, menu_logging_cb, 0, "<CheckItem>", NULL },
    - { N_("/Options/Enable _Sounds"), NULL, menu_sounds_cb, 0, "<CheckItem>", NULL },
    - { "/Options/sep0", NULL, NULL, 0, "<Separator>", NULL },
    - { N_("/Options/Show Formatting _Toolbars"), NULL, menu_toolbar_cb, 0, "<CheckItem>", NULL },
    - { N_("/Options/Show Ti_mestamps"), NULL, menu_timestamps_cb, 0, "<CheckItem>", NULL },
    + { "OptionsMenu", NULL, N_("_Options"), NULL, NULL, NULL },
    +};
    +
    +/* Toggle items */
    +static const GtkToggleActionEntry menu_toggle_entries[] = {
    + { "EnableLogging", NULL, N_("Enable _Logging"), NULL, NULL, G_CALLBACK(menu_logging_cb), FALSE },
    + { "EnableSounds", NULL, N_("Enable _Sounds"), NULL, NULL, G_CALLBACK(menu_sounds_cb), FALSE },
    + { "ShowFormattingToolbars", NULL, N_("Show Formatting _Toolbars"), NULL, NULL, G_CALLBACK(menu_toolbar_cb), FALSE },
    + { "ShowTimestamps", NULL, N_("Show Ti_mestamps"), NULL, NULL, G_CALLBACK(menu_timestamps_cb), FALSE },
    };
    -static const int menu_item_count =
    -sizeof(menu_items) / sizeof(*menu_items);
    -
    -static const char *
    -item_factory_translate_func (const char *path, gpointer func_data)
    -{
    - return _(path);
    -}
    +static const char *conversation_menu =
    +"<ui>"
    + "<menubar name='Conversation'>"
    + "<menu action='ConversationMenu'>"
    + "<menuitem action='NewInstantMessage'/>"
    + "<menuitem action='JoinAChat'/>"
    + "<separator/>"
    + "<menuitem action='Find'/>"
    + "<menuitem action='ViewLog'/>"
    + "<menuitem action='SaveAs'/>"
    + "<menuitem action='ClearScrollback'/>"
    + "<separator/>"
    +#ifdef USE_VV
    + "<menu action='MediaMenu'>"
    + "<menuitem action='AudioCall'/>"
    + "<menuitem action='VideoCall'/>"
    + "<menuitem action='AudioVideoCall'/>"
    + "</menu>"
    +#endif
    + "<menuitem action='SendFile'/>"
    + "<menuitem action='GetAttention'/>"
    + "<menuitem action='AddBuddyPounce'/>"
    + "<menuitem action='GetInfo'/>"
    + "<menuitem action='Invite'/>"
    + "<menu action='MoreMenu'/>"
    + "<separator/>"
    + "<menuitem action='Alias'/>"
    + "<menuitem action='Block'/>"
    + "<menuitem action='Unblock'/>"
    + "<menuitem action='Add'/>"
    + "<menuitem action='Remove'/>"
    + "<separator/>"
    + "<menuitem action='InsertLink'/>"
    + "<menuitem action='InsertImage'/>"
    + "<separator/>"
    + "<menuitem action='Close'/>"
    + "</menu>"
    + "<menu action='OptionsMenu'>"
    + "<menuitem action='EnableLogging'/>"
    + "<menuitem action='EnableSounds'/>"
    + "<separator/>"
    + "<menuitem action='ShowFormattingToolbars'/>"
    + "<menuitem action='ShowTimestamps'/>"
    + "</menu>"
    + "</menubar>"
    +"</ui>";
    static void
    sound_method_pref_changed_cb(const char *name, PurplePrefType type,
    @@ -3209,19 +3225,18 @@
    if (!strcmp(method, "none"))
    {
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
    - FALSE);
    - gtk_widget_set_sensitive(win->menu.sounds, FALSE);
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
    + FALSE);
    + gtk_action_set_sensitive(win->menu.sounds, FALSE);
    }
    else
    {
    PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win);
    if (gtkconv != NULL)
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
    - gtkconv->make_sound);
    - gtk_widget_set_sensitive(win->menu.sounds, TRUE);
    -
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
    + gtkconv->make_sound);
    + gtk_action_set_sensitive(win->menu.sounds, TRUE);
    }
    }
    @@ -3351,25 +3366,25 @@
    purple_prpl_get_media_caps(account,
    purple_conversation_get_name(conv));
    - gtk_widget_set_sensitive(win->audio_call,
    + gtk_action_set_sensitive(win->audio_call,
    caps & PURPLE_MEDIA_CAPS_AUDIO
    ? TRUE : FALSE);
    - gtk_widget_set_sensitive(win->video_call,
    + gtk_action_set_sensitive(win->video_call,
    caps & PURPLE_MEDIA_CAPS_VIDEO
    ? TRUE : FALSE);
    - gtk_widget_set_sensitive(win->audio_video_call,
    + gtk_action_set_sensitive(win->audio_video_call,
    caps & PURPLE_MEDIA_CAPS_AUDIO_VIDEO
    ? TRUE : FALSE);
    } else if (purple_conversation_get_type(conv)
    == PURPLE_CONV_TYPE_CHAT) {
    /* for now, don't care about chats... */
    - gtk_widget_set_sensitive(win->audio_call, FALSE);
    - gtk_widget_set_sensitive(win->video_call, FALSE);
    - gtk_widget_set_sensitive(win->audio_video_call, FALSE);
    + gtk_action_set_sensitive(win->audio_call, FALSE);
    + gtk_action_set_sensitive(win->video_call, FALSE);
    + gtk_action_set_sensitive(win->audio_video_call, FALSE);
    } else {
    - gtk_widget_set_sensitive(win->audio_call, FALSE);
    - gtk_widget_set_sensitive(win->video_call, FALSE);
    - gtk_widget_set_sensitive(win->audio_video_call, FALSE);
    + gtk_action_set_sensitive(win->audio_call, FALSE);
    + gtk_action_set_sensitive(win->video_call, FALSE);
    + gtk_action_set_sensitive(win->audio_video_call, FALSE);
    }
    #endif
    }
    @@ -3377,6 +3392,7 @@
    static void
    regenerate_attention_items(PidginWindow *win)
    {
    + GtkWidget *attention;
    GtkWidget *menu;
    PurpleConversation *conv;
    PurpleConnection *pc;
    @@ -3388,8 +3404,11 @@
    if (!conv)
    return;
    + attention = gtk_ui_manager_get_widget(win->menu.ui,
    + "/Conversation/ConversationMenu/GetAttention");
    +
    /* Remove the previous entries */
    - gtk_menu_item_set_submenu(GTK_MENU_ITEM(win->menu.get_attention), NULL);
    + gtk_menu_item_set_submenu(GTK_MENU_ITEM(attention), NULL);
    pc = purple_conversation_get_connection(conv);
    if (pc != NULL)
    @@ -3422,7 +3441,7 @@
    list = g_list_delete_link(list, list);
    }
    - gtk_menu_item_set_submenu(GTK_MENU_ITEM(win->menu.get_attention), menu);
    + gtk_menu_item_set_submenu(GTK_MENU_ITEM(attention), menu);
    gtk_widget_show_all(menu);
    }
    }
    @@ -3434,9 +3453,13 @@
    GtkWidget *menu;
    PidginConversation *gtkconv;
    GList *list;
    + GtkWidget *more_menu;
    gtkconv = pidgin_conv_window_get_active_gtkconv(win);
    - menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Conversation/More"));
    + more_menu = gtk_ui_manager_get_widget(win->menu.ui,
    + "/Conversation/ConversationMenu/MoreMenu");
    + gtk_widget_show(more_menu);
    + menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(more_menu));
    /* Remove the previous entries */
    for (list = gtk_container_get_children(GTK_CONTAINER(menu)); list; )
    @@ -3492,7 +3515,8 @@
    action_items = g_list_delete_link(action_items, action_items);
    }
    - menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Options"));
    + item = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/OptionsMenu");
    + menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item));
    list = purple_conversation_get_extended_menu(conv);
    if (list) {
    @@ -3529,7 +3553,7 @@
    {
    /* The menubar has been deactivated. Make sure the 'More' submenu is regenerated next time
    * the 'Conversation' menu pops up. */
    - GtkWidget *menuitem = gtk_item_factory_get_item(win->menu.item_factory, N_("/Conversation"));
    + GtkWidget *menuitem = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/ConversationMenu");
    g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), G_CALLBACK(menubar_activated), win);
    g_signal_handlers_disconnect_by_func(G_OBJECT(win->menu.menubar),
    G_CALLBACK(focus_out_from_menubar), win);
    @@ -3540,130 +3564,145 @@
    {
    GtkAccelGroup *accel_group;
    const char *method;
    + GtkActionGroup *action_group;
    + GError *error;
    GtkWidget *menuitem;
    - accel_group = gtk_accel_group_new ();
    + action_group = gtk_action_group_new("ConversationActions");
    + gtk_action_group_add_actions(action_group,
    + menu_entries,
    + G_N_ELEMENTS(menu_entries),
    + win);
    + gtk_action_group_add_toggle_actions(action_group,
    + menu_toggle_entries,
    + G_N_ELEMENTS(menu_toggle_entries),
    + win);
    +#ifdef ENABLE_NLS
    + gtk_action_group_set_translation_domain(action_group,
    + PACKAGE);
    +#endif
    +
    + win->menu.ui = gtk_ui_manager_new();
    + gtk_ui_manager_insert_action_group(win->menu.ui, action_group, 0);
    +
    + accel_group = gtk_ui_manager_get_accel_group(win->menu.ui);
    gtk_window_add_accel_group(GTK_WINDOW(win->window), accel_group);
    - g_object_unref(accel_group);
    -
    - win->menu.item_factory =
    - gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
    -
    - gtk_item_factory_set_translate_func(win->menu.item_factory,
    - (GtkTranslateFunc)item_factory_translate_func,
    - NULL, NULL);
    -
    - gtk_item_factory_create_items(win->menu.item_factory, menu_item_count,
    - menu_items, win);
    g_signal_connect(G_OBJECT(accel_group), "accel-changed",
    G_CALLBACK(pidgin_save_accels_cb), NULL);
    + error = NULL;
    + if (!gtk_ui_manager_add_ui_from_string(win->menu.ui, conversation_menu, -1, &error))
    + {
    + g_message("building menus failed: %s", error->message);
    + g_error_free(error);
    + exit(EXIT_FAILURE);
    + }
    +
    + win->menu.menubar =
    + gtk_ui_manager_get_widget(win->menu.ui, "/Conversation");
    +
    /* Make sure the 'Conversation -> More' menuitems are regenerated whenever
    * the 'Conversation' menu pops up because the entries can change after the
    * conversation is created. */
    - menuitem = gtk_item_factory_get_item(win->menu.item_factory, N_("/Conversation"));
    + menuitem = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/ConversationMenu");
    g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menubar_activated), win);
    - win->menu.menubar =
    - gtk_item_factory_get_widget(win->menu.item_factory, "<main>");
    -
    win->menu.view_log =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/View Log"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/ViewLog");
    #ifdef USE_VV
    win->audio_call =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Media/Audio Call"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/MediaMenu/AudioCall");
    win->video_call =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Media/Video Call"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/MediaMenu/VideoCall");
    win->audio_video_call =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Media/Audio\\/Video Call"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/MediaMenu/AudioVideoCall");
    #endif
    /* --- */
    win->menu.send_file =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Send File..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/SendFile");
    win->menu.get_attention =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Get Attention"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/GetAttention");
    win->menu.add_pounce =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Add Buddy Pounce..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/AddBuddyPounce");
    /* --- */
    win->menu.get_info =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Get Info"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/GetInfo");
    win->menu.invite =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Invite..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/Invite");
    /* --- */
    win->menu.alias =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Alias..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/Alias");
    win->menu.block =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Block..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/Block");
    win->menu.unblock =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Unblock..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/Unblock");
    win->menu.add =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Add..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/Add");
    win->menu.remove =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Remove..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/Remove");
    /* --- */
    win->menu.insert_link =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Insert Link..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/InsertLink");
    win->menu.insert_image =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Conversation/Insert Image..."));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/ConversationMenu/InsertImage");
    /* --- */
    win->menu.logging =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Options/Enable Logging"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/OptionsMenu/EnableLogging");
    win->menu.sounds =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Options/Enable Sounds"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/OptionsMenu/EnableSounds");
    method = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method");
    if (method != NULL && !strcmp(method, "none"))
    {
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
    FALSE);
    - gtk_widget_set_sensitive(win->menu.sounds, FALSE);
    + gtk_action_set_sensitive(win->menu.sounds, FALSE);
    }
    purple_prefs_connect_callback(win, PIDGIN_PREFS_ROOT "/sound/method",
    sound_method_pref_changed_cb, win);
    win->menu.show_formatting_toolbar =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Options/Show Formatting Toolbars"));
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/OptionsMenu/ShowFormattingToolbars");
    win->menu.show_timestamps =
    - gtk_item_factory_get_widget(win->menu.item_factory,
    - N_("/Options/Show Timestamps"));
    - win->menu.show_icon = NULL;
    + gtk_ui_manager_get_action(win->menu.ui,
    + "/Conversation/OptionsMenu/ShowTimestamps");
    win->menu.tray = pidgin_menu_tray_new();
    gtk_menu_shell_append(GTK_MENU_SHELL(win->menu.menubar),
    @@ -3846,7 +3885,6 @@
    if (!(b = purple_find_buddy(account, purple_conversation_get_name(conv))))
    return FALSE;
    -
    gtk_widget_show(win->menu.send_to);
    menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(win->menu.send_to));
    @@ -5017,8 +5055,12 @@
    close = pidgin_create_small_button(gtk_label_new("×"));
    gtk_box_pack_start(GTK_BOX(widget), close, FALSE, FALSE, 0);
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(close, _("Close Find bar"));
    +#else
    gtk_tooltips_set_tip(gtkconv->tooltips, close,
    _("Close Find bar"), NULL);
    +#endif
    label = gtk_label_new(_("Find:"));
    gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 10);
    @@ -5691,7 +5733,9 @@
    gtkconv->send_history = g_list_append(NULL, NULL);
    /* Setup some initial variables. */
    +#if !GTK_CHECK_VERSION(2,12,0)
    gtkconv->tooltips = gtk_tooltips_new();
    +#endif
    gtkconv->unseen_state = PIDGIN_UNSEEN_NONE;
    gtkconv->unseen_count = 0;
    theme = purple_theme_manager_find_theme(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/theme"), "conversation");
    @@ -5890,7 +5934,9 @@
    g_free(gtkconv->u.chat);
    }
    +#if !GTK_CHECK_VERSION(2,12,0)
    gtk_object_sink(GTK_OBJECT(gtkconv->tooltips));
    +#endif
    gtkconv->send_history = g_list_first(gtkconv->send_history);
    g_list_foreach(gtkconv->send_history, (GFunc)g_free, NULL);
    @@ -7005,57 +7051,57 @@
    /* Show stuff that applies to IMs, hide stuff that applies to chats */
    /* Deal with menu items */
    - gtk_widget_show(win->menu.view_log);
    - gtk_widget_show(win->menu.send_file);
    - gtk_widget_show(win->menu.get_attention);
    - gtk_widget_show(win->menu.add_pounce);
    - gtk_widget_show(win->menu.get_info);
    - gtk_widget_hide(win->menu.invite);
    - gtk_widget_show(win->menu.alias);
    + gtk_action_set_visible(win->menu.view_log, TRUE);
    + gtk_action_set_visible(win->menu.send_file, TRUE);
    + gtk_action_set_visible(win->menu.get_attention, TRUE);
    + gtk_action_set_visible(win->menu.add_pounce, TRUE);
    + gtk_action_set_visible(win->menu.get_info, TRUE);
    + gtk_action_set_visible(win->menu.invite, FALSE);
    + gtk_action_set_visible(win->menu.alias, TRUE);
    if (purple_privacy_check(account, purple_conversation_get_name(conv))) {
    - gtk_widget_hide(win->menu.unblock);
    - gtk_widget_show(win->menu.block);
    + gtk_action_set_visible(win->menu.unblock, FALSE);
    + gtk_action_set_visible(win->menu.block, TRUE);
    } else {
    - gtk_widget_hide(win->menu.block);
    - gtk_widget_show(win->menu.unblock);
    + gtk_action_set_visible(win->menu.block, FALSE);
    + gtk_action_set_visible(win->menu.unblock, TRUE);
    }
    if ((account == NULL) || purple_find_buddy(account, purple_conversation_get_name(conv)) == NULL) {
    - gtk_widget_show(win->menu.add);
    - gtk_widget_hide(win->menu.remove);
    + gtk_action_set_visible(win->menu.add, TRUE);
    + gtk_action_set_visible(win->menu.remove, FALSE);
    } else {
    - gtk_widget_show(win->menu.remove);
    - gtk_widget_hide(win->menu.add);
    - }
    -
    - gtk_widget_show(win->menu.insert_link);
    - gtk_widget_show(win->menu.insert_image);
    + gtk_action_set_visible(win->menu.remove, TRUE);
    + gtk_action_set_visible(win->menu.add, FALSE);
    + }
    +
    + gtk_action_set_visible(win->menu.insert_link, TRUE);
    + gtk_action_set_visible(win->menu.insert_image, TRUE);
    } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
    /* Show stuff that applies to Chats, hide stuff that applies to IMs */
    /* Deal with menu items */
    - gtk_widget_show(win->menu.view_log);
    - gtk_widget_hide(win->menu.send_file);
    - gtk_widget_hide(win->menu.get_attention);
    - gtk_widget_hide(win->menu.add_pounce);
    - gtk_widget_hide(win->menu.get_info);
    - gtk_widget_show(win->menu.invite);
    - gtk_widget_show(win->menu.alias);
    - gtk_widget_hide(win->menu.block);
    - gtk_widget_hide(win->menu.unblock);
    + gtk_action_set_visible(win->menu.view_log, TRUE);
    + gtk_action_set_visible(win->menu.send_file, FALSE);
    + gtk_action_set_visible(win->menu.get_attention, FALSE);
    + gtk_action_set_visible(win->menu.add_pounce, FALSE);
    + gtk_action_set_visible(win->menu.get_info, FALSE);
    + gtk_action_set_visible(win->menu.invite, TRUE);
    + gtk_action_set_visible(win->menu.alias, TRUE);
    + gtk_action_set_visible(win->menu.block, FALSE);
    + gtk_action_set_visible(win->menu.unblock, FALSE);
    if ((account == NULL) || purple_blist_find_chat(account, purple_conversation_get_name(conv)) == NULL) {
    /* If the chat is NOT in the buddy list */
    - gtk_widget_show(win->menu.add);
    - gtk_widget_hide(win->menu.remove);
    + gtk_action_set_visible(win->menu.add, TRUE);
    + gtk_action_set_visible(win->menu.remove, FALSE);
    } else {
    /* If the chat IS in the buddy list */
    - gtk_widget_hide(win->menu.add);
    - gtk_widget_show(win->menu.remove);
    - }
    -
    - gtk_widget_show(win->menu.insert_link);
    - gtk_widget_show(win->menu.insert_image);
    + gtk_action_set_visible(win->menu.add, FALSE);
    + gtk_action_set_visible(win->menu.remove, TRUE);
    + }
    +
    + gtk_action_set_visible(win->menu.insert_link, TRUE);
    + gtk_action_set_visible(win->menu.insert_image, TRUE);
    }
    /*
    @@ -7104,30 +7150,30 @@
    gtk_imhtmltoolbar_associate_smileys(GTK_IMHTMLTOOLBAR(gtkconv->toolbar), purple_account_get_protocol_id(account));
    /* Deal with menu items */
    - gtk_widget_set_sensitive(win->menu.view_log, TRUE);
    - gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
    - gtk_widget_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL));
    - gtk_widget_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL));
    - gtk_widget_set_sensitive(win->menu.insert_link, (features & PURPLE_CONNECTION_HTML));
    - gtk_widget_set_sensitive(win->menu.insert_image, !(features & PURPLE_CONNECTION_NO_IMAGES));
    + gtk_action_set_sensitive(win->menu.view_log, TRUE);
    + gtk_action_set_sensitive(win->menu.add_pounce, TRUE);
    + gtk_action_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL));
    + gtk_action_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL));
    + gtk_action_set_sensitive(win->menu.insert_link, (features & PURPLE_CONNECTION_HTML));
    + gtk_action_set_sensitive(win->menu.insert_image, !(features & PURPLE_CONNECTION_NO_IMAGES));
    if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
    {
    - gtk_widget_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL));
    - gtk_widget_set_sensitive(win->menu.remove, (prpl_info->remove_buddy != NULL));
    - gtk_widget_set_sensitive(win->menu.send_file,
    + gtk_action_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL));
    + gtk_action_set_sensitive(win->menu.remove, (prpl_info->remove_buddy != NULL));
    + gtk_action_set_sensitive(win->menu.send_file,
    (prpl_info->send_file != NULL && (!prpl_info->can_receive_file ||
    prpl_info->can_receive_file(gc, purple_conversation_get_name(conv)))));
    - gtk_widget_set_sensitive(win->menu.get_attention, (prpl_info->send_attention != NULL));
    - gtk_widget_set_sensitive(win->menu.alias,
    + gtk_action_set_sensitive(win->menu.get_attention, (prpl_info->send_attention != NULL));
    + gtk_action_set_sensitive(win->menu.alias,
    (account != NULL) &&
    (purple_find_buddy(account, purple_conversation_get_name(conv)) != NULL));
    }
    else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
    {
    - gtk_widget_set_sensitive(win->menu.add, (prpl_info->join_chat != NULL));
    - gtk_widget_set_sensitive(win->menu.remove, (prpl_info->join_chat != NULL));
    - gtk_widget_set_sensitive(win->menu.alias,
    + gtk_action_set_sensitive(win->menu.add, (prpl_info->join_chat != NULL));
    + gtk_action_set_sensitive(win->menu.remove, (prpl_info->join_chat != NULL));
    + gtk_action_set_sensitive(win->menu.alias,
    (account != NULL) &&
    (purple_blist_find_chat(account, purple_conversation_get_name(conv)) != NULL));
    }
    @@ -7137,17 +7183,17 @@
    /* Or it's a chat that we've left. */
    /* Then deal with menu items */
    - gtk_widget_set_sensitive(win->menu.view_log, TRUE);
    - gtk_widget_set_sensitive(win->menu.send_file, FALSE);
    - gtk_widget_set_sensitive(win->menu.get_attention, FALSE);
    - gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
    - gtk_widget_set_sensitive(win->menu.get_info, FALSE);
    - gtk_widget_set_sensitive(win->menu.invite, FALSE);
    - gtk_widget_set_sensitive(win->menu.alias, FALSE);
    - gtk_widget_set_sensitive(win->menu.add, FALSE);
    - gtk_widget_set_sensitive(win->menu.remove, FALSE);
    - gtk_widget_set_sensitive(win->menu.insert_link, TRUE);
    - gtk_widget_set_sensitive(win->menu.insert_image, FALSE);
    + gtk_action_set_sensitive(win->menu.view_log, TRUE);
    + gtk_action_set_sensitive(win->menu.send_file, FALSE);
    + gtk_action_set_sensitive(win->menu.get_attention, FALSE);
    + gtk_action_set_sensitive(win->menu.add_pounce, TRUE);
    + gtk_action_set_sensitive(win->menu.get_info, FALSE);
    + gtk_action_set_sensitive(win->menu.invite, FALSE);
    + gtk_action_set_sensitive(win->menu.alias, FALSE);
    + gtk_action_set_sensitive(win->menu.add, FALSE);
    + gtk_action_set_sensitive(win->menu.remove, FALSE);
    + gtk_action_set_sensitive(win->menu.insert_link, TRUE);
    + gtk_action_set_sensitive(win->menu.insert_image, FALSE);
    }
    /*
    @@ -7228,8 +7274,13 @@
    topic = purple_conv_chat_get_topic(chat);
    gtk_entry_set_text(GTK_ENTRY(gtkchat->topic_text), topic ? topic : "");
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(gtkchat->topic_text,
    + topic ? topic : "");
    +#else
    gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text,
    topic ? topic : "", NULL);
    +#endif
    }
    }
    @@ -7291,7 +7342,7 @@
    if (title != markup)
    g_free(markup);
    - if (!GTK_WIDGET_REALIZED(gtkconv->tab_label))
    + if (!gtk_widget_get_realized(gtkconv->tab_label))
    gtk_widget_realize(gtkconv->tab_label);
    accessibility_obj = gtk_widget_get_accessible(gtkconv->tab_cont);
    @@ -7685,7 +7736,7 @@
    tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(notebook), page);
    /* Make sure the tab is not hidden beyond an arrow */
    - if (!GTK_WIDGET_DRAWABLE(tab) && gtk_notebook_get_show_tabs(notebook))
    + if (!gtk_widget_is_drawable(tab) && gtk_notebook_get_show_tabs(notebook))
    continue;
    if (horiz) {
    @@ -7810,8 +7861,8 @@
    gtkconv = PIDGIN_CONVERSATION(conv);
    win = gtkconv->win;
    - gtk_check_menu_item_set_active(
    - GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
    + gtk_toggle_action_set_active(
    + GTK_TOGGLE_ACTION(win->menu.show_timestamps),
    (gboolean)GPOINTER_TO_INT(value));
    /* TODO WEBKIT: Use WebKit version of this. */
    @@ -7841,8 +7892,8 @@
    gtkconv = PIDGIN_CONVERSATION(conv);
    win = gtkconv->win;
    - gtk_check_menu_item_set_active(
    - GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
    + gtk_toggle_action_set_active(
    + GTK_TOGGLE_ACTION(win->menu.show_formatting_toolbar),
    (gboolean)GPOINTER_TO_INT(value));
    if ((gboolean)GPOINTER_TO_INT(value))
    @@ -8810,8 +8861,9 @@
    gtk_container_set_border_width(GTK_CONTAINER(warn_close_dialog),
    6);
    gtk_window_set_resizable(GTK_WINDOW(warn_close_dialog), FALSE);
    - gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog),
    - FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    + gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog), FALSE);
    +#endif
    /* Setup the outside spacing. */
    vbox = GTK_DIALOG(warn_close_dialog)->vbox;
    @@ -9113,9 +9165,9 @@
    /* Right click was pressed. Popup the context menu. */
    GtkWidget *menu = gtk_menu_new(), *sub;
    gboolean populated = populate_menu_with_options(menu, gtkconv, TRUE);
    +
    sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to));
    -
    - if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) {
    + if (sub && gtk_widget_is_sensitive(gtkconv->win->menu.send_to)) {
    GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("S_end To"));
    if (populated)
    pidgin_separator(menu);
    @@ -9548,7 +9600,7 @@
    PurpleConversation *conv = gtkconv->active_conv;
    const char *text = NULL;
    - if (!GTK_WIDGET_VISIBLE(gtkconv->infopane)) {
    + if (!gtk_widget_get_visible(gtkconv->infopane)) {
    /* There's already an entry for alias. Let's not create another one. */
    return FALSE;
    }
    @@ -9632,8 +9684,8 @@
    /* Update the menubar */
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging),
    - purple_conversation_is_logging(conv));
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtkconv->win->menu.logging),
    + purple_conversation_is_logging(conv));
    generate_send_to_items(win);
    regenerate_options_items(win);
    @@ -9643,14 +9695,14 @@
    sound_method = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method");
    if (strcmp(sound_method, "none") != 0)
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
    - gtkconv->make_sound);
    -
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
    - purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar"));
    -
    - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
    - purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps"));
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
    + gtkconv->make_sound);
    +
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.show_formatting_toolbar),
    + purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar"));
    +
    + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.show_timestamps),
    + purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps"));
    /*
    * We pause icons when they are not visible. If this icon should
    @@ -9708,7 +9760,7 @@
    static gboolean gtk_conv_configure_cb(GtkWidget *w, GdkEventConfigure *event, gpointer data) {
    int x, y;
    - if (GTK_WIDGET_VISIBLE(w))
    + if (gtk_widget_get_visible(w))
    gtk_window_get_position(GTK_WINDOW(w), &x, &y);
    else
    return FALSE; /* carry on normally */
    @@ -9743,7 +9795,7 @@
    /* if the window exists, is hidden, we're saving positions, and the
    * position is sane... */
    if (win && win->window &&
    - !GTK_WIDGET_VISIBLE(win->window) && conv_width != 0) {
    + !gtk_widget_get_visible(win->window) && conv_width != 0) {
    #ifdef _WIN32 /* only override window manager placement on Windows */
    /* ...check position is on screen... */
    @@ -9898,7 +9950,7 @@
    }
    gtk_widget_destroy(win->window);
    - g_object_unref(G_OBJECT(win->menu.item_factory));
    + g_object_unref(G_OBJECT(win->menu.ui));
    purple_notify_close_with_handle(win);
    purple_signals_disconnect_by_handle(win);
    @@ -9976,8 +10028,12 @@
    /* Close button. */
    gtkconv->close = pidgin_create_small_button(gtk_label_new("×"));
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(gtkconv->close, _("Close conversation"));
    +#else
    gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close,
    _("Close conversation"), NULL);
    +#endif
    g_signal_connect(gtkconv->close, "clicked", G_CALLBACK (close_conv_cb), gtkconv);
    @@ -10113,9 +10169,9 @@
    gtk_notebook_set_tab_label(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont, ebox);
    }
    - gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont,
    - !tabs_side && !angle,
    - TRUE, GTK_PACK_START);
    + gtk_container_child_set(GTK_CONTAINER(win->notebook), gtkconv->tab_cont,
    + "tab-expand", !tabs_side && !angle,
    + "tab-fill", TRUE, NULL);
    if (pidgin_conv_window_get_gtkconv_count(win) == 1)
    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
    @@ -10139,8 +10195,7 @@
    index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont);
    - g_object_ref(gtkconv->tab_cont);
    - gtk_object_sink(GTK_OBJECT(gtkconv->tab_cont));
    + g_object_ref_sink(G_OBJECT(gtkconv->tab_cont));
    gtk_notebook_remove_page(GTK_NOTEBOOK(win->notebook), index);
    @@ -10345,7 +10400,7 @@
    PurpleConversationType type = purple_conversation_get_type(conv->active_conv);
    GList *all;
    - if (GTK_WIDGET_VISIBLE(w))
    + if (gtk_widget_get_visible(w))
    gtk_window_get_position(GTK_WINDOW(w), &x, &y);
    else
    return FALSE; /* carry on normally */
    --- a/pidgin/gtkconv.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkconv.h Tue Feb 28 05:29:13 2012 +0000
    @@ -90,7 +90,11 @@
    gboolean make_sound;
    +#if GTK_CHECK_VERSION(2,12,0)
    + gpointer depr2;
    +#else
    GtkTooltips *tooltips;
    +#endif
    GtkWidget *tab_cont;
    GtkWidget *tabby;
    --- a/pidgin/gtkconvwin.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkconvwin.h Tue Feb 28 05:29:13 2012 +0000
    @@ -48,28 +48,27 @@
    {
    GtkWidget *menubar;
    - GtkWidget *view_log;
    + GtkAction *view_log;
    - GtkWidget *send_file;
    - GtkWidget *get_attention;
    - GtkWidget *add_pounce;
    - GtkWidget *get_info;
    - GtkWidget *invite;
    + GtkAction *send_file;
    + GtkAction *get_attention;
    + GtkAction *add_pounce;
    + GtkAction *get_info;
    + GtkAction *invite;
    - GtkWidget *alias;
    - GtkWidget *block;
    - GtkWidget *unblock;
    - GtkWidget *add;
    - GtkWidget *remove;
    + GtkAction *alias;
    + GtkAction *block;
    + GtkAction *unblock;
    + GtkAction *add;
    + GtkAction *remove;
    - GtkWidget *insert_link;
    - GtkWidget *insert_image;
    + GtkAction *insert_link;
    + GtkAction *insert_image;
    - GtkWidget *logging;
    - GtkWidget *sounds;
    - GtkWidget *show_formatting_toolbar;
    - GtkWidget *show_timestamps;
    - GtkWidget *show_icon;
    + GtkAction *logging;
    + GtkAction *sounds;
    + GtkAction *show_formatting_toolbar;
    + GtkAction *show_timestamps;
    GtkWidget *send_to;
    @@ -77,7 +76,7 @@
    GtkWidget *typing_icon;
    - GtkItemFactory *item_factory;
    + GtkUIManager *ui;
    } menu;
    @@ -99,9 +98,9 @@
    gint drag_leave_signal;
    /* Media menu options. */
    - GtkWidget *audio_call;
    - GtkWidget *video_call;
    - GtkWidget *audio_video_call;
    + GtkAction *audio_call;
    + GtkAction *video_call;
    + GtkAction *audio_video_call;
    };
    /*@}*/
    --- a/pidgin/gtkdebug.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkdebug.c Tue Feb 28 05:29:13 2012 +0000
    @@ -128,7 +128,11 @@
    static gboolean
    configure_cb(GtkWidget *w, GdkEventConfigure *event, DebugWindow *win)
    {
    +#if GTK_CHECK_VERSION(2,18,0)
    + if (gtk_widget_get_visible(w)) {
    +#else
    if (GTK_WIDGET_VISIBLE(w)) {
    +#endif
    purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/width", event->width);
    purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/height", event->height);
    }
    @@ -186,7 +190,9 @@
    gtk_container_set_border_width(GTK_CONTAINER(win->find), PIDGIN_HIG_BOX_SPACE);
    gtk_window_set_resizable(GTK_WINDOW(win->find), FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(win->find), FALSE);
    +#endif
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(win->find)->vbox), PIDGIN_HIG_BORDER);
    gtk_container_set_border_width(
    GTK_CONTAINER(GTK_DIALOG(win->find)->vbox), PIDGIN_HIG_BOX_SPACE);
    @@ -623,7 +629,11 @@
    static void
    regex_key_release_cb(GtkWidget *w, GdkEventKey *e, DebugWindow *win) {
    if(e->keyval == GDK_Return &&
    +#if GTK_CHECK_VERSION(2,18,0)
    + gtk_widget_is_sensitive(win->filter) &&
    +#else
    GTK_WIDGET_IS_SENSITIVE(win->filter) &&
    +#endif
    !gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter)))
    {
    gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), TRUE);
    --- a/pidgin/gtkdialogs.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkdialogs.c Tue Feb 28 05:29:13 2012 +0000
    @@ -466,7 +466,11 @@
    button = pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CLOSE,
    G_CALLBACK(destroy_win), win);
    +#if GTK_CHECK_VERSION(2,18,0)
    + gtk_widget_set_can_default(button, TRUE);
    +#else
    GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
    +#endif
    gtk_widget_grab_default(button);
    gtk_widget_show_all(win);
    @@ -972,7 +976,9 @@
    gtk_container_set_border_width (GTK_CONTAINER(window), PIDGIN_HIG_BOX_SPACE);
    gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(window), FALSE);
    +#endif
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(window)->vbox), PIDGIN_HIG_BORDER);
    gtk_container_set_border_width (GTK_CONTAINER(GTK_DIALOG(window)->vbox), PIDGIN_HIG_BOX_SPACE);
    --- a/pidgin/gtkdnd-hints.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkdnd-hints.c Tue Feb 28 05:29:13 2012 +0000
    @@ -62,19 +62,20 @@
    GdkBitmap *bitmap;
    GtkWidget *pix;
    GtkWidget *win;
    + GdkColormap *colormap;
    pixbuf = gdk_pixbuf_new_from_file(fname, NULL);
    g_return_val_if_fail(pixbuf, NULL);
    - gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, &bitmap, 128);
    + win = gtk_window_new(GTK_WINDOW_POPUP);
    + colormap = gtk_widget_get_colormap(win);
    + gdk_pixbuf_render_pixmap_and_mask_for_colormap(pixbuf, colormap,
    + &pixmap, &bitmap, 128);
    g_object_unref(G_OBJECT(pixbuf));
    - gtk_widget_push_colormap(gdk_rgb_get_colormap());
    - win = gtk_window_new(GTK_WINDOW_POPUP);
    pix = gtk_image_new_from_pixmap(pixmap, bitmap);
    gtk_container_add(GTK_CONTAINER(win), pix);
    gtk_widget_shape_combine_mask(win, bitmap, 0, 0);
    - gtk_widget_pop_colormap();
    g_object_unref(G_OBJECT(pixmap));
    g_object_unref(G_OBJECT(bitmap));
    --- a/pidgin/gtkdocklet.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkdocklet.c Tue Feb 28 05:29:13 2012 +0000
    @@ -564,7 +564,7 @@
    new_menu_item_with_status_icon(menu,
    purple_status_type_get_name(status_type),
    prim, G_CALLBACK(activate_status_account_cb),
    - status_type, 0, 0, NULL);
    + GINT_TO_POINTER(status_type), 0, 0, NULL);
    }
    }
    --- a/pidgin/gtkidle.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkidle.c Tue Feb 28 05:29:13 2012 +0000
    @@ -107,14 +107,16 @@
    int event_base, error_base;
    if (has_extension == -1)
    - has_extension = XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base);
    + has_extension = XScreenSaverQueryExtension(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
    + &event_base, &error_base);
    if (has_extension)
    {
    if (mit_info == NULL)
    mit_info = XScreenSaverAllocInfo();
    - XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), mit_info);
    + XScreenSaverQueryInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
    + GDK_ROOT_WINDOW(), mit_info);
    return (mit_info->idle) / 1000;
    }
    else
    --- a/pidgin/gtkimhtml.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkimhtml.c Tue Feb 28 05:29:13 2012 +0000
    @@ -65,6 +65,16 @@
    #define TOOLTIP_TIMEOUT 500
    +#if !GTK_CHECK_VERSION(2,20,0)
    +#define gtk_widget_get_realized(x) GTK_WIDGET_REALIZED(x)
    +
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_get_has_window(x) !GTK_WIDGET_NO_WINDOW(x)
    +#define gtk_widget_get_state(x) GTK_WIDGET_STATE(x)
    +#define gtk_widget_is_drawable(x) GTK_WIDGET_DRAWABLE(x)
    +#endif
    +#endif
    +
    static GtkTextViewClass *parent_class = NULL;
    struct scalable_data {
    @@ -458,7 +468,7 @@
    /* Don't scroll here if we're in the middle of a smooth scroll */
    if (scroll && imhtml->scroll_time == NULL &&
    - GTK_WIDGET_REALIZED(imhtml))
    + gtk_widget_get_realized(GTK_WIDGET(imhtml)))
    gtk_imhtml_scroll_to_end(imhtml, FALSE);
    }
    @@ -575,7 +585,7 @@
    g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE);
    - if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) {
    + if (!imhtml->tip || !gtk_widget_is_drawable (GTK_WIDGET(imhtml))) {
    imhtml->tip_timer = 0;
    return FALSE;
    }
    @@ -628,7 +638,7 @@
    h = 8 + baseline_skip;
    gdk_window_get_pointer (NULL, &x, &y, NULL);
    - if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml)))
    + if (!gtk_widget_get_has_window (GTK_WIDGET(imhtml)))
    y += GTK_WIDGET(imhtml)->allocation.y;
    scr_w = gdk_screen_width();
    @@ -824,7 +834,7 @@
    gdk_color_parse(GTK_IMHTML(widget)->edit.background, &gcolor);
    gdk_cairo_set_source_color(cr, &gcolor);
    } else {
    - gdk_cairo_set_source_color(cr, &(widget->style->base[GTK_WIDGET_STATE(widget)]));
    + gdk_cairo_set_source_color(cr, &(widget->style->base[gtk_widget_get_state(widget)]));
    }
    cairo_rectangle(cr,
    --- a/pidgin/gtkimhtmltoolbar.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkimhtmltoolbar.c Tue Feb 28 05:29:13 2012 +0000
    @@ -43,6 +43,11 @@
    #include <gdk/gdkkeysyms.h>
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
    +#define gtk_widget_is_sensitive(x) GTK_WIDGET_IS_SENSITIVE(x)
    +#endif
    +
    static GtkHBoxClass *parent_class = NULL;
    static void toggle_button_set_active_block(GtkToggleButton *button,
    @@ -658,7 +663,11 @@
    g_object_set_data(G_OBJECT(button), "smiley_text", face);
    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(insert_smiley_text), toolbar);
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(button, face);
    +#else
    gtk_tooltips_set_tip(toolbar->tooltips, button, face, NULL);
    +#endif
    /* these look really weird with borders */
    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
    @@ -672,7 +681,11 @@
    g_snprintf(tip, sizeof(tip),
    _("This smiley is disabled because a custom smiley exists for this shortcut:\n %s"),
    face);
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(button, tip);
    +#else
    gtk_tooltips_set_tip(toolbar->tooltips, button, tip, NULL);
    +#endif
    gtk_widget_set_sensitive(button, FALSE);
    } else if (psmiley) {
    /* Remove the button if the smiley is destroyed */
    @@ -1155,7 +1168,9 @@
    }
    g_free(toolbar->sml);
    +#if !GTK_CHECK_VERSION(2,12,0)
    gtk_object_sink(GTK_OBJECT(toolbar->tooltips));
    +#endif
    menu = g_object_get_data(object, "font_menu");
    if (menu)
    @@ -1186,7 +1201,7 @@
    if (event->button != 3)
    return FALSE;
    - wide = GTK_WIDGET_VISIBLE(toolbar->bold);
    + wide = gtk_widget_get_visible(toolbar->bold);
    menu = gtk_menu_new();
    item = gtk_menu_item_new_with_mnemonic(wide ? _("Group Items") : _("Ungroup Items"));
    @@ -1253,7 +1268,11 @@
    g_signal_connect(G_OBJECT(button), "clicked",
    G_CALLBACK(buttons[iter].callback), toolbar);
    *(buttons[iter].button) = button;
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(button, buttons[iter].tooltip);
    +#else
    gtk_tooltips_set_tip(toolbar->tooltips, button, buttons[iter].tooltip, NULL);
    +#endif
    } else
    button = gtk_vseparator_new();
    gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
    @@ -1266,7 +1285,7 @@
    static void
    button_visibility_changed(GtkWidget *button, gpointer dontcare, GtkWidget *item)
    {
    - if (GTK_WIDGET_VISIBLE(button))
    + if (gtk_widget_get_visible(button))
    gtk_widget_hide(item);
    else
    gtk_widget_show(item);
    @@ -1275,7 +1294,7 @@
    static void
    button_sensitiveness_changed(GtkWidget *button, gpointer dontcare, GtkWidget *item)
    {
    - gtk_widget_set_sensitive(item, GTK_WIDGET_IS_SENSITIVE(button));
    + gtk_widget_set_sensitive(item, gtk_widget_is_sensitive(button));
    }
    static void
    @@ -1353,7 +1372,9 @@
    toolbar->smiley_dialog = NULL;
    toolbar->image_dialog = NULL;
    +#if !GTK_CHECK_VERSION(2,12,0)
    toolbar->tooltips = gtk_tooltips_new();
    +#endif
    gtk_box_set_spacing(GTK_BOX(toolbar), 3);
    --- a/pidgin/gtkimhtmltoolbar.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkimhtmltoolbar.h Tue Feb 28 05:29:13 2012 +0000
    @@ -44,7 +44,11 @@
    GtkWidget *imhtml;
    +#if GTK_CHECK_VERSION(2,12,0)
    + gpointer depr1;
    +#else
    GtkTooltips *tooltips;
    +#endif
    GtkWidget *bold;
    GtkWidget *italic;
    --- a/pidgin/gtklog.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtklog.c Tue Feb 28 05:29:13 2012 +0000
    @@ -575,7 +575,9 @@
    gtk_dialog_add_button(GTK_DIALOG(lv->window), _("_Browse logs folder"), GTK_RESPONSE_HELP);
    #endif
    gtk_container_set_border_width (GTK_CONTAINER(lv->window), PIDGIN_HIG_BOX_SPACE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE);
    +#endif
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(lv->window)->vbox), 0);
    g_signal_connect(G_OBJECT(lv->window), "response",
    G_CALLBACK(destroy_cb), ht);
    --- a/pidgin/gtkmenutray.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkmenutray.c Tue Feb 28 05:29:13 2012 +0000
    @@ -40,6 +40,10 @@
    * Internal Stuff
    *****************************************************************************/
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_get_has_window(x) !GTK_WIDGET_NO_WINDOW(x)
    +#endif
    +
    /******************************************************************************
    * Item Stuff
    *****************************************************************************/
    @@ -92,7 +96,9 @@
    static void
    pidgin_menu_tray_finalize(GObject *obj)
    {
    +#if !GTK_CHECK_VERSION(2,12,0)
    PidginMenuTray *tray = PIDGIN_MENU_TRAY(obj);
    +#endif
    #if 0
    /* This _might_ be leaking, but I have a sneaking suspicion that the widget is
    * getting destroyed in GtkContainer's finalize function. But if were are
    @@ -104,9 +110,11 @@
    gtk_widget_destroy(GTK_WIDGET(tray->tray));
    #endif
    +#if !GTK_CHECK_VERSION(2,12,0)
    if (tray->tooltips) {
    gtk_object_sink(GTK_OBJECT(tray->tooltips));
    }
    +#endif
    G_OBJECT_CLASS(parent_class)->finalize(obj);
    }
    @@ -205,7 +213,7 @@
    g_return_if_fail(PIDGIN_IS_MENU_TRAY(menu_tray));
    g_return_if_fail(GTK_IS_WIDGET(widget));
    - if (GTK_WIDGET_NO_WINDOW(widget))
    + if (!gtk_widget_get_has_window(widget))
    {
    GtkWidget *event;
    @@ -238,21 +246,27 @@
    void
    pidgin_menu_tray_set_tooltip(PidginMenuTray *menu_tray, GtkWidget *widget, const char *tooltip)
    {
    +#if !GTK_CHECK_VERSION(2,12,0)
    if (!menu_tray->tooltips)
    menu_tray->tooltips = gtk_tooltips_new();
    +#endif
    /* Should we check whether widget is a child of menu_tray? */
    /*
    - * If the widget does not have it's own window, then it
    + * If the widget does not have its own window, then it
    * must have automatically been added to an event box
    * when it was added to the menu tray. If this is the
    * case, we want to set the tooltip on the widget's parent,
    * not on the widget itself.
    */
    - if (GTK_WIDGET_NO_WINDOW(widget))
    + if (!gtk_widget_get_has_window(widget))
    widget = widget->parent;
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(widget, tooltip);
    +#else
    gtk_tooltips_set_tip(menu_tray->tooltips, widget, tooltip, NULL);
    +#endif
    }
    --- a/pidgin/gtkmenutray.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkmenutray.h Tue Feb 28 05:29:13 2012 +0000
    @@ -40,7 +40,9 @@
    struct _PidginMenuTray {
    GtkMenuItem gparent; /**< The parent instance */
    GtkWidget *tray; /**< The tray */
    +#if !GTK_CHECK_VERSION(2,12,0)
    GtkTooltips *tooltips; /**< Tooltips */
    +#endif
    };
    /** A PidginMenuTrayClass */
    --- a/pidgin/gtknotify.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtknotify.c Tue Feb 28 05:29:13 2012 +0000
    @@ -534,7 +534,9 @@
    gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER);
    gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
    @@ -784,7 +786,11 @@
    gtk_tree_selection_select_iter(sel, &iter);
    }
    +#if GTK_CHECK_VERSION(2,18,0)
    + if (!gtk_widget_get_visible(mail_dialog->dialog)) {
    +#else
    if (!GTK_WIDGET_VISIBLE(mail_dialog->dialog)) {
    +#endif
    GdkPixbuf *pixbuf = gtk_widget_render_icon(mail_dialog->dialog, PIDGIN_STOCK_DIALOG_MAIL,
    gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL), NULL);
    char *label_text = g_strdup_printf(ngettext("<b>%d new email.</b>",
    @@ -800,7 +806,11 @@
    g_free(label_text);
    if (pixbuf)
    g_object_unref(pixbuf);
    +#if GTK_CHECK_VERSION(2,18,0)
    + } else if (!gtk_widget_has_focus(mail_dialog->dialog))
    +#else
    } else if (!GTK_WIDGET_HAS_FOCUS(mail_dialog->dialog))
    +#endif
    pidgin_set_urgent(GTK_WINDOW(mail_dialog->dialog), TRUE);
    return data;
    @@ -1503,7 +1513,9 @@
    /* Setup the dialog */
    gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE);
    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
    /* Vertical box */
    --- a/pidgin/gtkpounce.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkpounce.c Tue Feb 28 05:29:13 2012 +0000
    @@ -1018,7 +1018,11 @@
    static gboolean
    pounces_manager_configure_cb(GtkWidget *widget, GdkEventConfigure *event, PouncesManager *dialog)
    {
    +#if GTK_CHECK_VERSION(2,18,0)
    + if (gtk_widget_get_visible(widget)) {
    +#else
    if (GTK_WIDGET_VISIBLE(widget)) {
    +#endif
    purple_prefs_set_int(PIDGIN_PREFS_ROOT "/pounces/dialog/width", event->width);
    purple_prefs_set_int(PIDGIN_PREFS_ROOT "/pounces/dialog/height", event->height);
    }
    --- a/pidgin/gtkprefs.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkprefs.c Tue Feb 28 05:29:13 2012 +0000
    @@ -188,29 +188,49 @@
    return pidgin_add_widget_to_vbox(GTK_BOX(page), title, sg, entry, TRUE, NULL);
    }
    +/* TODO: Maybe move this up somewheres... */
    +enum {
    + PREF_DROPDOWN_TEXT,
    + PREF_DROPDOWN_VALUE,
    + PREF_DROPDOWN_COUNT
    +};
    static void
    dropdown_set(GObject *w, const char *key)
    {
    const char *str_value;
    int int_value;
    + gboolean bool_value;
    PurplePrefType type;
    + GtkTreeIter iter;
    + GtkTreeModel *tree_model;
    +
    + tree_model = gtk_combo_box_get_model(GTK_COMBO_BOX(w));
    + if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w), &iter))
    + return;
    type = GPOINTER_TO_INT(g_object_get_data(w, "type"));
    if (type == PURPLE_PREF_INT) {
    - int_value = GPOINTER_TO_INT(g_object_get_data(w, "value"));
    + gtk_tree_model_get(tree_model, &iter,
    + PREF_DROPDOWN_VALUE, &int_value,
    + -1);
    purple_prefs_set_int(key, int_value);
    }
    else if (type == PURPLE_PREF_STRING) {
    - str_value = (const char *)g_object_get_data(w, "value");
    + gtk_tree_model_get(tree_model, &iter,
    + PREF_DROPDOWN_VALUE, &str_value,
    + -1);
    purple_prefs_set_string(key, str_value);
    }
    else if (type == PURPLE_PREF_BOOLEAN) {
    - purple_prefs_set_bool(key,
    - GPOINTER_TO_INT(g_object_get_data(w, "value")));
    + gtk_tree_model_get(tree_model, &iter,
    + PREF_DROPDOWN_VALUE, &bool_value,
    + -1);
    +
    + purple_prefs_set_bool(key, bool_value);
    }
    }
    @@ -218,69 +238,89 @@
    pidgin_prefs_dropdown_from_list(GtkWidget *box, const gchar *title,
    PurplePrefType type, const char *key, GList *menuitems)
    {
    - GtkWidget *dropdown, *opt, *menu;
    + GtkWidget *dropdown;
    GtkWidget *label = NULL;
    gchar *text;
    const char *stored_str = NULL;
    int stored_int = 0;
    + gboolean stored_bool = FALSE;
    int int_value = 0;
    const char *str_value = NULL;
    - int o = 0;
    + gboolean bool_value = FALSE;
    + GtkListStore *store = NULL;
    + GtkTreeIter iter;
    + GtkTreeIter active;
    + GtkCellRenderer *renderer;
    g_return_val_if_fail(menuitems != NULL, NULL);
    - dropdown = gtk_option_menu_new();
    - menu = gtk_menu_new();
    -
    - if (type == PURPLE_PREF_INT)
    + if (type == PURPLE_PREF_INT) {
    + store = gtk_list_store_new(PREF_DROPDOWN_COUNT, G_TYPE_STRING, G_TYPE_INT);
    stored_int = purple_prefs_get_int(key);
    - else if (type == PURPLE_PREF_STRING)
    + } else if (type == PURPLE_PREF_STRING) {
    + store = gtk_list_store_new(PREF_DROPDOWN_COUNT, G_TYPE_STRING, G_TYPE_STRING);
    stored_str = purple_prefs_get_string(key);
    -
    - while (menuitems != NULL && (text = (char *) menuitems->data) != NULL) {
    + } else if (type == PURPLE_PREF_BOOLEAN) {
    + store = gtk_list_store_new(PREF_DROPDOWN_COUNT, G_TYPE_STRING, G_TYPE_BOOLEAN);
    + stored_bool = purple_prefs_get_bool(key);
    + } else {
    + g_warn_if_reached();
    + return NULL;
    + }
    +
    + dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
    + g_object_set_data(G_OBJECT(dropdown), "type", GINT_TO_POINTER(type));
    +
    + while (menuitems != NULL && (text = (char *)menuitems->data) != NULL) {
    menuitems = g_list_next(menuitems);
    g_return_val_if_fail(menuitems != NULL, NULL);
    - opt = gtk_menu_item_new_with_label(text);
    -
    - g_object_set_data(G_OBJECT(opt), "type", GINT_TO_POINTER(type));
    + gtk_list_store_append(store, &iter);
    + gtk_list_store_set(store, &iter,
    + PREF_DROPDOWN_TEXT, text,
    + -1);
    if (type == PURPLE_PREF_INT) {
    int_value = GPOINTER_TO_INT(menuitems->data);
    - g_object_set_data(G_OBJECT(opt), "value",
    - GINT_TO_POINTER(int_value));
    + gtk_list_store_set(store, &iter,
    + PREF_DROPDOWN_VALUE, int_value,
    + -1);
    }
    else if (type == PURPLE_PREF_STRING) {
    str_value = (const char *)menuitems->data;
    -
    - g_object_set_data(G_OBJECT(opt), "value", (char *)str_value);
    + gtk_list_store_set(store, &iter,
    + PREF_DROPDOWN_VALUE, str_value,
    + -1);
    }
    else if (type == PURPLE_PREF_BOOLEAN) {
    - g_object_set_data(G_OBJECT(opt), "value",
    - menuitems->data);
    + bool_value = (gboolean)GPOINTER_TO_INT(menuitems->data);
    + gtk_list_store_set(store, &iter,
    + PREF_DROPDOWN_VALUE, bool_value,
    + -1);
    }
    - g_signal_connect(G_OBJECT(opt), "activate",
    - G_CALLBACK(dropdown_set), (char *)key);
    -
    - gtk_widget_show(opt);
    - gtk_menu_shell_append(GTK_MENU_SHELL(menu), opt);
    -
    if ((type == PURPLE_PREF_INT && stored_int == int_value) ||
    (type == PURPLE_PREF_STRING && stored_str != NULL &&
    !strcmp(stored_str, str_value)) ||
    (type == PURPLE_PREF_BOOLEAN &&
    - (purple_prefs_get_bool(key) == GPOINTER_TO_INT(menuitems->data)))) {
    -
    - gtk_menu_set_active(GTK_MENU(menu), o);
    + (stored_bool == bool_value))) {
    +
    + active = iter;
    }
    menuitems = g_list_next(menuitems);
    -
    - o++;
    }
    - gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu);
    + renderer = gtk_cell_renderer_text_new();
    + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE);
    + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer,
    + "text", 0,
    + NULL);
    +
    + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(dropdown), &active);
    +
    + g_signal_connect(G_OBJECT(dropdown), "changed",
    + G_CALLBACK(dropdown_set), (char *)key);
    pidgin_add_widget_to_vbox(GTK_BOX(box), title, NULL, dropdown, FALSE, &label);
    @@ -1307,50 +1347,36 @@
    purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/font_size",
    gtk_webview_get_current_fontsize(webview));
    if (buttons & GTK_WEBVIEW_FACE) {
    - const char *face = gtk_webview_get_current_fontface(webview);
    - if (!face)
    - face = "";
    -
    - purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/font_face", face);
    + char *face = gtk_webview_get_current_fontface(webview);
    +
    + if (face)
    + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/font_face", face);
    + else
    + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/font_face", "");
    +
    + g_free(face);
    }
    if (buttons & GTK_WEBVIEW_FORECOLOR) {
    - const char *color = gtk_webview_get_current_forecolor(webview);
    - if (!color)
    - color = "";
    -
    - purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor", color);
    + char *color = gtk_webview_get_current_forecolor(webview);
    +
    + if (color)
    + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor", color);
    + else
    + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor", "");
    +
    + g_free(color);
    }
    if (buttons & GTK_WEBVIEW_BACKCOLOR) {
    - const char *color;
    - GObject *object;
    -
    - color = gtk_webview_get_current_backcolor(webview);
    - if (!color)
    - color = "";
    -
    - /* Block the signal to prevent a loop. */
    - object = g_object_ref(G_OBJECT(webview));
    - g_signal_handlers_block_matched(object, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
    - NULL, toolbar);
    - /* Clear the backcolor. */
    - gtk_webview_toggle_backcolor(webview, "");
    - /* Unblock the signal. */
    - g_signal_handlers_unblock_matched(object, G_SIGNAL_MATCH_DATA, 0, 0,
    - NULL, NULL, toolbar);
    - g_object_unref(object);
    -
    - /* This will fire a toggle signal and get saved below. */
    - gtk_webview_toggle_background(webview, color);
    - }
    -
    - if (buttons & GTK_WEBVIEW_BACKGROUND) {
    - const char *color = gtk_webview_get_current_background(webview);
    - if (!color)
    - color = "";
    -
    - purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor", color);
    + char *color = gtk_webview_get_current_backcolor(webview);
    +
    + if (color)
    + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor", color);
    + else
    + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor", "");
    +
    + g_free(color);
    }
    }
    @@ -1704,8 +1730,7 @@
    GTK_WEBVIEW_SHRINK |
    GTK_WEBVIEW_FACE |
    GTK_WEBVIEW_FORECOLOR |
    - GTK_WEBVIEW_BACKCOLOR |
    - GTK_WEBVIEW_BACKGROUND);
    + GTK_WEBVIEW_BACKCOLOR);
    gtk_webview_append_html(GTK_WEBVIEW(webview),
    _("This is how your outgoing message text will "
    --- a/pidgin/gtkrequest.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkrequest.c Tue Feb 28 05:29:13 2012 +0000
    @@ -39,6 +39,27 @@
    #include <gdk/gdkkeysyms.h>
    +#ifdef ENABLE_GCR
    +#define GCR_API_SUBJECT_TO_CHANGE
    +#include <gcr/gcr.h>
    +#include <gcr/gcr-simple-certificate.h>
    +#endif
    +
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_set_can_default(x,y) do {\
    + if (y) \
    + GTK_WIDGET_SET_FLAGS(x, GTK_CAN_DEFAULT); \
    + else \
    + GTK_WIDGET_UNSET_FLAGS(x, GTK_CAN_DEFAULT); \
    +} while(0)
    +#define gtk_widget_set_can_focus(x,y) do {\
    + if (y) \
    + GTK_WIDGET_SET_FLAGS(x, GTK_CAN_FOCUS); \
    + else \
    + GTK_WIDGET_UNSET_FLAGS(x, GTK_CAN_FOCUS); \
    +} while(0)
    +#endif
    +
    static GtkWidget * create_account_field(PurpleRequestField *field);
    typedef struct
    @@ -86,7 +107,9 @@
    {
    GtkWidget *image;
    GdkPixbuf *pixbuf;
    +#if !GTK_CHECK_VERSION(2,12,0)
    GtkTooltips *tips;
    +#endif
    if (!account)
    return;
    @@ -95,8 +118,12 @@
    image = gtk_image_new_from_pixbuf(pixbuf);
    g_object_unref(G_OBJECT(pixbuf));
    +#if GTK_CHECK_VERSION(2,12,0)
    + gtk_widget_set_tooltip_text(image, purple_account_get_username(account));
    +#else
    tips = gtk_tooltips_new();
    gtk_tooltips_set_tip(tips, image, purple_account_get_username(account), NULL);
    +#endif
    if (GTK_IS_DIALOG(cont)) {
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cont)->action_area), image, FALSE, TRUE, 0);
    @@ -257,7 +284,11 @@
    {
    generic_response_start(data);
    +#if GTK_CHECK_VERSION(2,18,0)
    + if (!gtk_widget_has_focus(button))
    +#else
    if (!GTK_WIDGET_HAS_FOCUS(button))
    +#endif
    gtk_widget_grab_focus(button);
    if (data->cbs[0] != NULL)
    @@ -356,7 +387,9 @@
    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2);
    if (!multiline)
    gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0);
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
    @@ -522,7 +555,9 @@
    gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2);
    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2);
    gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
    /* Setup the main horizontal box */
    @@ -644,7 +679,9 @@
    gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2);
    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2);
    gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
    /* Setup the main horizontal box */
    @@ -715,8 +752,8 @@
    if (default_action == PURPLE_DEFAULT_ACTION_NONE) {
    - GTK_WIDGET_SET_FLAGS(img, GTK_CAN_DEFAULT);
    - GTK_WIDGET_SET_FLAGS(img, GTK_CAN_FOCUS);
    + gtk_widget_set_can_default(img, TRUE);
    + gtk_widget_set_can_focus(img, TRUE);
    gtk_widget_grab_focus(img);
    gtk_widget_grab_default(img);
    } else
    @@ -1191,6 +1228,51 @@
    return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1);
    }
    +static GtkWidget *
    +create_certificate_field(PurpleRequestField *field)
    +{
    + PurpleCertificate *cert;
    +#ifdef ENABLE_GCR
    + GcrCertificateBasicsWidget *cert_widget;
    + GByteArray *der;
    + GcrCertificate *gcrt;
    +#else
    + GtkWidget *cert_label;
    + char *str;
    + char *escaped;
    +#endif
    +
    + cert = purple_request_field_certificate_get_value(field);
    +
    +#ifdef ENABLE_GCR
    + der = purple_certificate_get_der_data(cert);
    + g_return_val_if_fail(der, NULL);
    +
    + gcrt = gcr_simple_certificate_new(der->data, der->len);
    + g_return_val_if_fail(gcrt, NULL);
    +
    + cert_widget = gcr_certificate_basics_widget_new(gcrt);
    +
    + g_byte_array_free(der, TRUE);
    + g_object_unref(G_OBJECT(gcrt));
    +
    + return GTK_WIDGET(cert_widget);
    +#else
    + str = purple_certificate_get_display_string(cert);
    + escaped = g_markup_escape_text(str, -1);
    +
    + cert_label = gtk_label_new(NULL);
    + gtk_label_set_markup(GTK_LABEL(cert_label), escaped);
    + gtk_label_set_line_wrap(GTK_LABEL(cert_label), TRUE);
    + gtk_misc_set_alignment(GTK_MISC(cert_label), 0, 0);
    +
    + g_free(str);
    + g_free(escaped);
    +
    + return cert_label;
    +#endif
    +}
    +
    static void *
    pidgin_request_fields(const char *title, const char *primary,
    const char *secondary, PurpleRequestFields *fields,
    @@ -1254,12 +1336,12 @@
    /* Cancel button */
    button = pidgin_dialog_add_button(GTK_DIALOG(win), text_to_stock(cancel_text), G_CALLBACK(multifield_cancel_cb), data);
    - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
    + gtk_widget_set_can_default(button, TRUE);
    /* OK button */
    button = pidgin_dialog_add_button(GTK_DIALOG(win), text_to_stock(ok_text), G_CALLBACK(multifield_ok_cb), data);
    data->ok_button = button;
    - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
    + gtk_widget_set_can_default(button, TRUE);
    gtk_window_set_default(GTK_WINDOW(win), button);
    pidgin_widget_decorate_account(hbox, account);
    @@ -1478,6 +1560,8 @@
    widget = create_image_field(field);
    else if (type == PURPLE_REQUEST_FIELD_ACCOUNT)
    widget = create_account_field(field);
    + else if (type == PURPLE_REQUEST_FIELD_CERTIFICATE)
    + widget = create_certificate_field(field);
    else
    continue;
    }
    --- a/pidgin/gtksavedstatuses.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtksavedstatuses.c Tue Feb 28 05:29:13 2012 +0000
    @@ -524,7 +524,11 @@
    static gboolean
    configure_cb(GtkWidget *widget, GdkEventConfigure *event, StatusWindow *dialog)
    {
    +#if GTK_CHECK_VERSION(2,18,0)
    + if (gtk_widget_get_visible(widget))
    +#else
    if (GTK_WIDGET_VISIBLE(widget))
    +#endif
    {
    purple_prefs_set_int(PIDGIN_PREFS_ROOT "/status/dialog/width", event->width);
    purple_prefs_set_int(PIDGIN_PREFS_ROOT "/status/dialog/height", event->height);
    --- a/pidgin/gtkscrollbook.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkscrollbook.c Tue Feb 28 05:29:13 2012 +0000
    @@ -147,7 +147,7 @@
    }
    static void
    -switch_page_cb(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, PidginScrollBook *scroll_book)
    +switch_page_cb(GtkNotebook *notebook, GtkWidget *page, guint page_num, PidginScrollBook *scroll_book)
    {
    int count;
    count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(scroll_book->notebook));
    --- a/pidgin/gtkstatusbox.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkstatusbox.c Tue Feb 28 05:29:13 2012 +0000
    @@ -70,6 +70,16 @@
    /* Timeout for typing notifications in seconds */
    #define TYPING_TIMEOUT 4
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_is_sensitive(x) GTK_WIDGET_IS_SENSITIVE(x)
    +#define gtk_widget_set_has_window(x, y) do { \
    + if (y) \
    + GTK_WIDGET_UNSET_FLAGS(x, GTK_WIDGET_NO_WINDOW); \
    + else \
    + GTK_WIDGET_SET_FLAGS(x, GTK_WIDGET_NO_WINDOW); \
    +} while (0)
    +#endif
    +
    static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data);
    static void imhtml_format_changed_cb(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons, void *data);
    static void remove_typing_cb(PidginStatusBox *box);
    @@ -1749,7 +1759,7 @@
    GtkWidget *toplevel;
    GtkTreeSelection *sel;
    - GTK_WIDGET_SET_FLAGS (status_box, GTK_NO_WINDOW);
    + gtk_widget_set_has_window(GTK_WIDGET(status_box), FALSE);
    status_box->imhtml_visible = FALSE;
    status_box->network_available = purple_network_is_available();
    status_box->connecting = FALSE;
    @@ -2625,7 +2635,7 @@
    purple_timeout_remove(status_box->typing);
    status_box->typing = 0;
    - if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box)))
    + if (gtk_widget_is_sensitive(GTK_WIDGET(status_box)))
    {
    if (type == PIDGIN_STATUS_BOX_TYPE_POPULAR || type == PIDGIN_STATUS_BOX_TYPE_SAVED_POPULAR)
    {
    @@ -2687,7 +2697,7 @@
    }
    g_list_free(accounts);
    - if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box)))
    + if (gtk_widget_is_sensitive(GTK_WIDGET(status_box)))
    {
    if (status_box->imhtml_visible)
    {
    @@ -2743,7 +2753,7 @@
    static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data)
    {
    PidginStatusBox *status_box = (PidginStatusBox*)data;
    - if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box)))
    + if (gtk_widget_is_sensitive(GTK_WIDGET(status_box)))
    {
    if (status_box->typing != 0) {
    pidgin_status_box_pulse_typing(status_box);
    --- a/pidgin/gtkutils.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkutils.c Tue Feb 28 05:29:13 2012 +0000
    @@ -71,8 +71,20 @@
    #include "gtkwebviewtoolbar.h"
    #include "pidgin/minidialog.h"
    +#if !GTK_CHECK_VERSION(2,18,0)
    +#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
    +#define gtk_widget_is_sensitive(x) GTK_WIDGET_IS_SENSITIVE(x)
    +#endif
    +
    +enum {
    + AOP_ICON_COLUMN,
    + AOP_NAME_COLUMN,
    + AOP_DATA_COLUMN,
    + AOP_COLUMN_COUNT
    +};
    +
    typedef struct {
    - GtkWidget *menu;
    + GtkTreeModel *model;
    gint default_item;
    } AopMenu;
    @@ -381,7 +393,7 @@
    if (to_toggle == NULL)
    return;
    - sensitivity = GTK_WIDGET_IS_SENSITIVE(to_toggle);
    + sensitivity = gtk_widget_is_sensitive(to_toggle);
    gtk_widget_set_sensitive(to_toggle, !sensitivity);
    }
    @@ -398,7 +410,7 @@
    if (element == NULL)
    continue;
    - sensitivity = GTK_WIDGET_IS_SENSITIVE(element);
    + sensitivity = gtk_widget_is_sensitive(element);
    gtk_widget_set_sensitive(element, !sensitivity);
    }
    @@ -410,7 +422,7 @@
    if (to_toggle == NULL)
    return;
    - if (GTK_WIDGET_VISIBLE(to_toggle))
    + if (gtk_widget_get_visible(to_toggle))
    gtk_widget_hide(to_toggle);
    else
    gtk_widget_show(to_toggle);
    @@ -611,68 +623,36 @@
    }
    static gpointer
    -aop_option_menu_get_selected(GtkWidget *optmenu, GtkWidget **p_item)
    +aop_option_menu_get_selected(GtkWidget *optmenu)
    {
    - GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu));
    - GtkWidget *item = gtk_menu_get_active(GTK_MENU(menu));
    - if (p_item)
    - (*p_item) = item;
    - return item ? g_object_get_data(G_OBJECT(item), "aop_per_item_data") : NULL;
    + gpointer data = NULL;
    + GtkTreeIter iter;
    +
    + g_return_val_if_fail(optmenu != NULL, NULL);
    +
    + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(optmenu), &iter))
    + gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(optmenu)),
    + &iter, AOP_DATA_COLUMN, &data, -1);
    +
    + return data;
    }
    static void
    aop_menu_cb(GtkWidget *optmenu, GCallback cb)
    {
    - GtkWidget *item;
    - gpointer per_item_data;
    -
    - per_item_data = aop_option_menu_get_selected(optmenu, &item);
    -
    if (cb != NULL) {
    - ((void (*)(GtkWidget *, gpointer, gpointer))cb)(item, per_item_data, g_object_get_data(G_OBJECT(optmenu), "user_data"));
    + ((void (*)(GtkWidget *, gpointer, gpointer))cb)(optmenu,
    + aop_option_menu_get_selected(optmenu),
    + g_object_get_data(G_OBJECT(optmenu), "user_data"));
    }
    }
    -static GtkWidget *
    -aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer per_item_data, const char *data)
    +static void
    +aop_option_menu_replace_menu(GtkWidget *optmenu, AopMenu *new_aop_menu)
    {
    - GtkWidget *item;
    - GtkWidget *hbox;
    - GtkWidget *image;
    - GtkWidget *label;
    -
    - item = gtk_menu_item_new();
    - gtk_widget_show(item);
    -
    - hbox = gtk_hbox_new(FALSE, 4);
    - gtk_widget_show(hbox);
    -
    - /* Create the image */
    - if (pixbuf == NULL)
    - image = gtk_image_new();
    - else
    - image = gtk_image_new_from_pixbuf(pixbuf);
    - gtk_widget_show(image);
    -
    - if (sg)
    - gtk_size_group_add_widget(sg, image);
    -
    - /* Create the label */
    - label = gtk_label_new (lbl);
    - gtk_widget_show (label);
    - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
    - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    -
    - gtk_container_add(GTK_CONTAINER(item), hbox);
    - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
    - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
    -
    - g_object_set_data(G_OBJECT (item), data, per_item_data);
    - g_object_set_data(G_OBJECT (item), "aop_per_item_data", per_item_data);
    -
    - pidgin_set_accessible_label(item, label);
    -
    - return item;
    + gtk_combo_box_set_model(GTK_COMBO_BOX(optmenu), new_aop_menu->model);
    + gtk_combo_box_set_active(GTK_COMBO_BOX(optmenu), new_aop_menu->default_item);
    + g_free(new_aop_menu);
    }
    static GdkPixbuf *
    @@ -713,16 +693,17 @@
    static GtkWidget *
    aop_option_menu_new(AopMenu *aop_menu, GCallback cb, gpointer user_data)
    {
    - GtkWidget *optmenu;
    -
    - optmenu = gtk_option_menu_new();
    + GtkWidget *optmenu = NULL;
    + GtkCellRenderer *cr = NULL;
    +
    + optmenu = gtk_combo_box_new();
    gtk_widget_show(optmenu);
    - gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), aop_menu->menu);
    -
    - if (aop_menu->default_item != -1)
    - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), aop_menu->default_item);
    -
    - g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", aop_menu, (GDestroyNotify)g_free);
    + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(optmenu), cr = gtk_cell_renderer_pixbuf_new(), FALSE);
    + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(optmenu), cr, "pixbuf", AOP_ICON_COLUMN);
    + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(optmenu), cr = gtk_cell_renderer_text_new(), TRUE);
    + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(optmenu), cr, "text", AOP_NAME_COLUMN);
    +
    + aop_option_menu_replace_menu(optmenu, aop_menu);
    g_object_set_data(G_OBJECT(optmenu), "user_data", user_data);
    g_signal_connect(G_OBJECT(optmenu), "changed", G_CALLBACK(aop_menu_cb), cb);
    @@ -731,32 +712,20 @@
    }
    static void
    -aop_option_menu_replace_menu(GtkWidget *optmenu, AopMenu *new_aop_menu)
    -{
    - if (gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))
    - gtk_option_menu_remove_menu(GTK_OPTION_MENU(optmenu));
    -
    - gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), new_aop_menu->menu);
    -
    - if (new_aop_menu->default_item != -1)
    - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), new_aop_menu->default_item);
    -
    - g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", new_aop_menu, (GDestroyNotify)g_free);
    -}
    -
    -static void
    aop_option_menu_select_by_data(GtkWidget *optmenu, gpointer data)
    {
    - guint idx;
    - GList *llItr = NULL;
    -
    - for (idx = 0, llItr = GTK_MENU_SHELL(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))->children;
    - llItr != NULL;
    - llItr = llItr->next, idx++) {
    - if (data == g_object_get_data(G_OBJECT(llItr->data), "aop_per_item_data")) {
    - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), idx);
    - break;
    - }
    + GtkTreeModel *model;
    + GtkTreeIter iter;
    + gpointer iter_data;
    + model = gtk_combo_box_get_model(GTK_COMBO_BOX(optmenu));
    + if (gtk_tree_model_get_iter_first(model, &iter)) {
    + do {
    + gtk_tree_model_get(model, &iter, AOP_DATA_COLUMN, &iter_data, -1);
    + if (iter_data == data) {
    + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(optmenu), &iter);
    + return;
    + }
    + } while (gtk_tree_model_iter_next(model, &iter));
    }
    }
    @@ -766,21 +735,16 @@
    AopMenu *aop_menu = NULL;
    PurplePlugin *plugin;
    GdkPixbuf *pixbuf = NULL;
    - GtkSizeGroup *sg;
    + GtkTreeIter iter;
    + GtkListStore *ls;
    GList *p;
    - const char *gtalk_name = NULL, *facebook_name = NULL;
    int i;
    + ls = gtk_list_store_new(AOP_COLUMN_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
    +
    aop_menu = g_malloc0(sizeof(AopMenu));
    - aop_menu->default_item = -1;
    - aop_menu->menu = gtk_menu_new();
    - gtk_widget_show(aop_menu->menu);
    - sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
    -
    - if (purple_find_prpl("prpl-jabber")) {
    - gtalk_name = _("Google Talk");
    - facebook_name = _("Facebook (XMPP)");
    - }
    + aop_menu->default_item = 0;
    + aop_menu->model = GTK_TREE_MODEL(ls);
    for (p = purple_plugins_get_protocols(), i = 0;
    p != NULL;
    @@ -788,48 +752,14 @@
    plugin = (PurplePlugin *)p->data;
    - if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0) {
    - char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
    - "16", "google-talk.png", NULL);
    - GtkWidget *item;
    -
    - pixbuf = pidgin_pixbuf_new_from_file(filename);
    - g_free(filename);
    -
    - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
    - item = aop_menu_item_new(sg, pixbuf, gtalk_name, "prpl-jabber", "protocol"));
    - g_object_set_data(G_OBJECT(item), "fakegoogle", GINT_TO_POINTER(1));
    -
    - if (pixbuf)
    - g_object_unref(pixbuf);
    -
    - gtalk_name = NULL;
    - i++;
    - }
    -
    - if (facebook_name && strcmp(facebook_name, plugin->info->name) < 0) {
    - char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
    - "16", "facebook.png", NULL);
    - GtkWidget *item;
    -
    - pixbuf = pidgin_pixbuf_new_from_file(filename);
    - g_free(filename);
    -
    - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
    - item = aop_menu_item_new(sg, pixbuf, facebook_name, "prpl-jabber", "protocol"));
    - g_object_set_data(G_OBJECT(item), "fakefacebook", GINT_TO_POINTER(1));
    -
    - if (pixbuf)
    - g_object_unref(pixbuf);
    -
    - facebook_name = NULL;
    - i++;
    - }
    -
    pixbuf = pidgin_create_prpl_icon_from_prpl(plugin, PIDGIN_PRPL_ICON_SMALL, NULL);
    - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
    - aop_menu_item_new(sg, pixbuf, plugin->info->name, plugin->info->id, "protocol"));
    + gtk_list_store_append(ls, &iter);
    + gtk_list_store_set(ls, &iter,
    + AOP_ICON_COLUMN, pixbuf,
    + AOP_NAME_COLUMN, plugin->info->name,
    + AOP_DATA_COLUMN, plugin->info->id,
    + -1);
    if (pixbuf)
    g_object_unref(pixbuf);
    @@ -838,8 +768,6 @@
    aop_menu->default_item = i;
    }
    - g_object_unref(sg);
    -
    return aop_menu;
    }
    @@ -853,13 +781,13 @@
    const char *
    pidgin_protocol_option_menu_get_selected(GtkWidget *optmenu)
    {
    - return (const char *)aop_option_menu_get_selected(optmenu, NULL);
    + return (const char *)aop_option_menu_get_selected(optmenu);
    }
    PurpleAccount *
    pidgin_account_option_menu_get_selected(GtkWidget *optmenu)
    {
    - return (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL);
    + return (PurpleAccount *)aop_option_menu_get_selected(optmenu);
    }
    static AopMenu *
    @@ -871,7 +799,8 @@
    GdkPixbuf *pixbuf = NULL;
    GList *list;
    GList *p;
    - GtkSizeGroup *sg;
    + GtkListStore *ls;
    + GtkTreeIter iter;
    int i;
    char buf[256];
    @@ -880,11 +809,11 @@
    else
    list = purple_connections_get_all();
    + ls = gtk_list_store_new(AOP_COLUMN_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
    +
    aop_menu = g_malloc0(sizeof(AopMenu));
    - aop_menu->default_item = -1;
    - aop_menu->menu = gtk_menu_new();
    - gtk_widget_show(aop_menu->menu);
    - sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
    + aop_menu->default_item = 0;
    + aop_menu->model = GTK_TREE_MODEL(ls);
    for (p = list, i = 0; p != NULL; p = p->next, i++) {
    if (show_all)
    @@ -919,8 +848,12 @@
    purple_account_get_protocol_name(account));
    }
    - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
    - aop_menu_item_new(sg, pixbuf, buf, account, "account"));
    + gtk_list_store_append(ls, &iter);
    + gtk_list_store_set(ls, &iter,
    + AOP_ICON_COLUMN, pixbuf,
    + AOP_NAME_COLUMN, buf,
    + AOP_DATA_COLUMN, account,
    + -1);
    if (pixbuf)
    g_object_unref(pixbuf);
    @@ -929,8 +862,6 @@
    aop_menu->default_item = i;
    }
    - g_object_unref(sg);
    -
    return aop_menu;
    }
    @@ -941,7 +872,7 @@
    PurpleAccount *account;
    PurpleFilterAccountFunc filter_func;
    - account = (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL);
    + account = (PurpleAccount *)aop_option_menu_get_selected(optmenu);
    show_all = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(optmenu), "show_all"));
    filter_func = g_object_get_data(G_OBJECT(optmenu), "filter_func");
    @@ -1965,6 +1896,15 @@
    return menuitem;
    }
    +enum {
    + COMPLETION_DISPLAYED_COLUMN, /* displayed completion value */
    + COMPLETION_BUDDY_COLUMN, /* buddy name */
    + COMPLETION_NORMALIZED_COLUMN, /* UTF-8 normalized & casefolded buddy name */
    + COMPLETION_COMPARISON_COLUMN, /* UTF-8 normalized & casefolded value for comparison */
    + COMPLETION_ACCOUNT_COLUMN, /* account */
    + COMPLETION_COLUMN_COUNT
    +};
    +
    typedef struct
    {
    GtkWidget *entry;
    @@ -1984,10 +1924,10 @@
    GValue val2;
    const char *tmp;
    - model = gtk_entry_completion_get_model (completion);
    + model = gtk_entry_completion_get_model(completion);
    val1.g_type = 0;
    - gtk_tree_model_get_value(model, iter, 2, &val1);
    + gtk_tree_model_get_value(model, iter, COMPLETION_NORMALIZED_COLUMN, &val1);
    tmp = g_value_get_string(&val1);
    if (tmp != NULL && purple_str_has_prefix(tmp, key))
    {
    @@ -1997,7 +1937,7 @@
    g_value_unset(&val1);
    val2.g_type = 0;
    - gtk_tree_model_get_value(model, iter, 3, &val2);
    + gtk_tree_model_get_value(model, iter, COMPLETION_COMPARISON_COLUMN, &val2);
    tmp = g_value_get_string(&val2);
    if (tmp != NULL && purple_str_has_prefix(tmp, key))
    {
    @@ -2017,11 +1957,11 @@
    PurpleAccount *account;
    val.g_type = 0;
    - gtk_tree_model_get_value(model, iter, 1, &val);
    + gtk_tree_model_get_value(model, iter, COMPLETION_BUDDY_COLUMN, &val);
    gtk_entry_set_text(GTK_ENTRY(data->entry), g_value_get_string(&val));
    g_value_unset(&val);
    - gtk_tree_model_get_value(model, iter, 4, &val);
    + gtk_tree_model_get_value(model, iter, COMPLETION_ACCOUNT_COLUMN, &val);
    account = g_value_get_pointer(&val);
    g_value_unset(&val);
    @@ -2058,11 +1998,11 @@
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter,
    - 0, completion_entry,
    - 1, buddyname,
    - 2, normalized_buddyname,
    - 3, tmp,
    - 4, account,
    + COMPLETION_DISPLAYED_COLUMN, completion_entry,
    + COMPLETION_BUDDY_COLUMN, buddyname,
    + COMPLETION_NORMALIZED_COLUMN, normalized_buddyname,
    + COMPLETION_COMPARISON_COLUMN, tmp,
    + COMPLETION_ACCOUNT_COLUMN, account,
    -1);
    g_free(completion_entry);
    g_free(tmp);
    @@ -2083,11 +2023,11 @@
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter,
    - 0, completion_entry,
    - 1, buddyname,
    - 2, normalized_buddyname,
    - 3, tmp,
    - 4, account,
    + COMPLETION_DISPLAYED_COLUMN, completion_entry,
    + COMPLETION_BUDDY_COLUMN, buddyname,
    + COMPLETION_NORMALIZED_COLUMN, normalized_buddyname,
    + COMPLETION_COMPARISON_COLUMN, tmp,
    + COMPLETION_ACCOUNT_COLUMN, account,
    -1);
    g_free(completion_entry);
    g_free(tmp);
    @@ -2099,11 +2039,11 @@
    /* Add the buddy's name. */
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter,
    - 0, buddyname,
    - 1, buddyname,
    - 2, normalized_buddyname,
    - 3, NULL,
    - 4, account,
    + COMPLETION_DISPLAYED_COLUMN, buddyname,
    + COMPLETION_BUDDY_COLUMN, buddyname,
    + COMPLETION_NORMALIZED_COLUMN, normalized_buddyname,
    + COMPLETION_COMPARISON_COLUMN, NULL,
    + COMPLETION_ACCOUNT_COLUMN, account,
    -1);
    }
    @@ -2201,7 +2141,9 @@
    GtkEntryCompletion *completion;
    data = g_new0(PidginCompletionData, 1);
    - store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
    + store = gtk_list_store_new(COMPLETION_COLUMN_COUNT, G_TYPE_STRING,
    + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    + G_TYPE_POINTER);
    data->entry = entry;
    data->accountopt = accountopt;
    @@ -2218,7 +2160,8 @@
    /* Sort the completion list by buddy name */
    gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
    - 1, GTK_SORT_ASCENDING);
    + COMPLETION_BUDDY_COLUMN,
    + GTK_SORT_ASCENDING);
    completion = gtk_entry_completion_new();
    gtk_entry_completion_set_match_func(completion, buddyname_completion_match_func, NULL, NULL);
    @@ -2232,7 +2175,7 @@
    gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store));
    g_object_unref(store);
    - gtk_entry_completion_set_text_column(completion, 0);
    + gtk_entry_completion_set_text_column(completion, COMPLETION_DISPLAYED_COLUMN);
    purple_signal_connect(purple_connections_get_handle(), "signed-on", entry,
    PURPLE_CALLBACK(repopulate_autocomplete), data);
    @@ -3067,7 +3010,7 @@
    windows = g_list_delete_link(windows, windows);
    if (window == widget ||
    - !GTK_WIDGET_VISIBLE(window))
    + !gtk_widget_get_visible(window))
    continue;
    if (!gdk_property_get(window->window, _WindowTime, _Cardinal, 0, sizeof(time_t), FALSE,
    @@ -3121,7 +3064,7 @@
    windows = g_list_delete_link(windows, windows);
    if (window == widget ||
    - !GTK_WIDGET_VISIBLE(window)) {
    + !gtk_widget_get_visible(window)) {
    continue;
    }
    @@ -3762,4 +3705,3 @@
    gtk_imhtml_class_register_protocol("mailto:", NULL, NULL);
    gtk_imhtml_class_register_protocol("gopher://", NULL, NULL);
    }
    -
    --- a/pidgin/gtkwebview.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkwebview.c Tue Feb 28 05:29:13 2012 +0000
    @@ -68,16 +68,6 @@
    GtkWebViewButtons format_functions;
    struct {
    gboolean wbfo:1; /* Whole buffer formatting only. */
    - gboolean bold:1;
    - gboolean italic:1;
    - gboolean underline:1;
    - gboolean strike:1;
    - gchar *forecolor;
    - gchar *backcolor;
    - gchar *background;
    - gchar *fontface;
    - int fontsize;
    - /*GtkTextTag *link;*/
    } edit;
    } GtkWebViewPriv;
    @@ -313,28 +303,13 @@
    static void
    webview_clear_formatting(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    + WebKitDOMDocument *dom;
    if (!webkit_web_view_get_editable(WEBKIT_WEB_VIEW(webview)))
    return;
    - priv->edit.bold = FALSE;
    - priv->edit.italic = FALSE;
    - priv->edit.underline = FALSE;
    - priv->edit.strike = FALSE;
    - priv->edit.fontsize = 0;
    -
    - g_free(priv->edit.fontface);
    - priv->edit.fontface = NULL;
    -
    - g_free(priv->edit.forecolor);
    - priv->edit.forecolor = NULL;
    -
    - g_free(priv->edit.backcolor);
    - priv->edit.backcolor = NULL;
    -
    - g_free(priv->edit.background);
    - priv->edit.background = NULL;
    + dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    + webkit_dom_document_exec_command(dom, "removeFormat", FALSE, "");
    }
    static void
    @@ -541,6 +516,7 @@
    return g_string_free(str, FALSE);
    }
    +
    void
    gtk_webview_safe_execute_script(GtkWebView *webview, const char *script)
    {
    @@ -607,7 +583,8 @@
    }
    }
    -void gtk_webview_page_up(GtkWebView *webview)
    +void
    +gtk_webview_page_up(GtkWebView *webview)
    {
    GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    GtkAdjustment *vadj = priv->vadj;
    @@ -624,7 +601,8 @@
    gtk_adjustment_set_value(vadj, scroll_val);
    }
    -void gtk_webview_page_down(GtkWebView *webview)
    +void
    +gtk_webview_page_down(GtkWebView *webview)
    {
    GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    GtkAdjustment *vadj = priv->vadj;
    @@ -653,12 +631,12 @@
    void
    gtk_webview_setup_entry(GtkWebView *webview, PurpleConnectionFlags flags)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    GtkWebViewButtons buttons;
    if (flags & PURPLE_CONNECTION_HTML) {
    char color[8];
    GdkColor fg_color, bg_color;
    + gboolean bold, italic, underline, strike;
    buttons = GTK_WEBVIEW_ALL;
    @@ -672,17 +650,19 @@
    if (flags & PURPLE_CONNECTION_NO_URLDESC)
    buttons &= ~GTK_WEBVIEW_LINKDESC;
    + gtk_webview_get_current_format(webview, &bold, &italic, &underline, &strike);
    +
    gtk_webview_set_format_functions(webview, GTK_WEBVIEW_ALL);
    - if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold") != priv->edit.bold)
    + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold") != bold)
    gtk_webview_toggle_bold(webview);
    - if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic") != priv->edit.italic)
    + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic") != italic)
    gtk_webview_toggle_italic(webview);
    - if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline") != priv->edit.underline)
    + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline") != underline)
    gtk_webview_toggle_underline(webview);
    - if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_strike") != priv->edit.strike)
    + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_strike") != strike)
    gtk_webview_toggle_strike(webview);
    gtk_webview_toggle_fontface(webview,
    @@ -701,28 +681,30 @@
    {
    gdk_color_parse(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor"),
    &fg_color);
    - g_snprintf(color, sizeof(color), "#%02x%02x%02x",
    - fg_color.red / 256,
    - fg_color.green / 256,
    - fg_color.blue / 256);
    + g_snprintf(color, sizeof(color),
    + "#%02x%02x%02x",
    + fg_color.red / 256,
    + fg_color.green / 256,
    + fg_color.blue / 256);
    } else
    strcpy(color, "");
    gtk_webview_toggle_forecolor(webview, color);
    - if(!(flags & PURPLE_CONNECTION_NO_BGCOLOR) &&
    - strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor"), "") != 0)
    + if (!(flags & PURPLE_CONNECTION_NO_BGCOLOR) &&
    + strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor"), "") != 0)
    {
    gdk_color_parse(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor"),
    &bg_color);
    - g_snprintf(color, sizeof(color), "#%02x%02x%02x",
    - bg_color.red / 256,
    - bg_color.green / 256,
    - bg_color.blue / 256);
    + g_snprintf(color, sizeof(color),
    + "#%02x%02x%02x",
    + bg_color.red / 256,
    + bg_color.green / 256,
    + bg_color.blue / 256);
    } else
    strcpy(color, "");
    - gtk_webview_toggle_background(webview, color);
    + gtk_webview_toggle_backcolor(webview, color);
    if (flags & PURPLE_CONNECTION_FORMATTING_WBFO)
    gtk_webview_set_whole_buffer_formatting_only(webview, TRUE);
    @@ -773,50 +755,56 @@
    gboolean *italic, gboolean *underline,
    gboolean *strike)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    + WebKitDOMDocument *dom;
    + dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    +
    if (bold)
    - *bold = priv->edit.bold;
    + *bold = webkit_dom_document_query_command_state(dom, "bold");
    if (italic)
    - *italic = priv->edit.italic;
    + *italic = webkit_dom_document_query_command_state(dom, "italic");
    if (underline)
    - *underline = priv->edit.underline;
    + *underline = webkit_dom_document_query_command_state(dom, "underline");
    if (strike)
    - *strike = priv->edit.strike;
    -}
    -
    -const char *
    -gtk_webview_get_current_fontface(GtkWebView *webview)
    -{
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    - return priv->edit.fontface;
    + *strike = webkit_dom_document_query_command_state(dom, "strikethrough");
    }
    -const char *
    +char *
    +gtk_webview_get_current_fontface(GtkWebView *webview)
    +{
    + WebKitDOMDocument *dom;
    + dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    + return webkit_dom_document_query_command_value(dom, "fontName");
    +}
    +
    +char *
    gtk_webview_get_current_forecolor(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    - return priv->edit.forecolor;
    + WebKitDOMDocument *dom;
    + dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    + return webkit_dom_document_query_command_value(dom, "foreColor");
    }
    -const char *
    +char *
    gtk_webview_get_current_backcolor(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    - return priv->edit.backcolor;
    -}
    -
    -const char *
    -gtk_webview_get_current_background(GtkWebView *webview)
    -{
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    - return priv->edit.background;
    + WebKitDOMDocument *dom;
    + dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    + return webkit_dom_document_query_command_value(dom, "backColor");
    }
    gint
    gtk_webview_get_current_fontsize(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    - return priv->edit.fontsize;
    + WebKitDOMDocument *dom;
    + gchar *text;
    + gint size;
    +
    + dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    + text = webkit_dom_document_query_command_value(dom, "fontSize");
    + size = atoi(text);
    + g_free(text);
    +
    + return size;
    }
    gboolean
    @@ -841,11 +829,8 @@
    void
    gtk_webview_toggle_bold(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    - priv->edit.bold = !priv->edit.bold;
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    webkit_dom_document_exec_command(dom, "bold", FALSE, "");
    }
    @@ -853,11 +838,8 @@
    void
    gtk_webview_toggle_italic(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    - priv->edit.italic = !priv->edit.italic;
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    webkit_dom_document_exec_command(dom, "italic", FALSE, "");
    }
    @@ -865,11 +847,8 @@
    void
    gtk_webview_toggle_underline(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    - priv->edit.underline = !priv->edit.underline;
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    webkit_dom_document_exec_command(dom, "underline", FALSE, "");
    }
    @@ -877,11 +856,8 @@
    void
    gtk_webview_toggle_strike(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    - priv->edit.strike = !priv->edit.strike;
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    webkit_dom_document_exec_command(dom, "strikethrough", FALSE, "");
    }
    @@ -889,14 +865,10 @@
    gboolean
    gtk_webview_toggle_forecolor(GtkWebView *webview, const char *color)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    - g_free(priv->edit.forecolor);
    - priv->edit.forecolor = g_strdup(color);
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    - webkit_dom_document_exec_command(dom, "forecolor", FALSE, color);
    + webkit_dom_document_exec_command(dom, "foreColor", FALSE, color);
    return FALSE;
    }
    @@ -904,25 +876,10 @@
    gboolean
    gtk_webview_toggle_backcolor(GtkWebView *webview, const char *color)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    - g_free(priv->edit.backcolor);
    - priv->edit.backcolor = g_strdup(color);
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    - webkit_dom_document_exec_command(dom, "backcolor", FALSE, color);
    -
    - return FALSE;
    -}
    -
    -gboolean
    -gtk_webview_toggle_background(GtkWebView *webview, const char *color)
    -{
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    -
    - g_free(priv->edit.background);
    - priv->edit.background = g_strdup(color);
    + webkit_dom_document_exec_command(dom, "backColor", FALSE, color);
    return FALSE;
    }
    @@ -930,14 +887,10 @@
    gboolean
    gtk_webview_toggle_fontface(GtkWebView *webview, const char *face)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    - g_free(priv->edit.fontface);
    - priv->edit.fontface = g_strdup(face);
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    - webkit_dom_document_exec_command(dom, "fontname", FALSE, face);
    + webkit_dom_document_exec_command(dom, "fontName", FALSE, face);
    return FALSE;
    }
    @@ -945,45 +898,44 @@
    void
    gtk_webview_font_set_size(GtkWebView *webview, gint size)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    char *tmp;
    - priv->edit.fontsize = size;
    -
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    tmp = g_strdup_printf("%d", size);
    - webkit_dom_document_exec_command(dom, "fontsize", FALSE, tmp);
    + webkit_dom_document_exec_command(dom, "fontSize", FALSE, tmp);
    g_free(tmp);
    }
    void
    gtk_webview_font_shrink(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    + gint fontsize;
    char *tmp;
    - priv->edit.fontsize = MAX(priv->edit.fontsize - 1, 1);
    + fontsize = gtk_webview_get_current_fontsize(webview);
    + fontsize = MAX(fontsize - 1, 1);
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    - tmp = g_strdup_printf("%d", priv->edit.fontsize);
    - webkit_dom_document_exec_command(dom, "fontsize", FALSE, tmp);
    + tmp = g_strdup_printf("%d", fontsize);
    + webkit_dom_document_exec_command(dom, "fontSize", FALSE, tmp);
    g_free(tmp);
    }
    void
    gtk_webview_font_grow(GtkWebView *webview)
    {
    - GtkWebViewPriv *priv = GTK_WEBVIEW_GET_PRIVATE(webview);
    WebKitDOMDocument *dom;
    + gint fontsize;
    char *tmp;
    - priv->edit.fontsize = MIN(priv->edit.fontsize + 1, MAX_FONT_SIZE);
    + fontsize = gtk_webview_get_current_fontsize(webview);
    + fontsize = MIN(fontsize + 1, MAX_FONT_SIZE);
    dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(webview));
    - tmp = g_strdup_printf("%d", priv->edit.fontsize);
    - webkit_dom_document_exec_command(dom, "fontsize", FALSE, tmp);
    + tmp = g_strdup_printf("%d", fontsize);
    + webkit_dom_document_exec_command(dom, "fontSize", FALSE, tmp);
    g_free(tmp);
    }
    --- a/pidgin/gtkwebview.h Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkwebview.h Tue Feb 28 05:29:13 2012 +0000
    @@ -48,14 +48,13 @@
    GTK_WEBVIEW_FACE = 1 << 5,
    GTK_WEBVIEW_FORECOLOR = 1 << 6,
    GTK_WEBVIEW_BACKCOLOR = 1 << 7,
    - GTK_WEBVIEW_BACKGROUND = 1 << 8,
    - GTK_WEBVIEW_LINK = 1 << 9,
    - GTK_WEBVIEW_IMAGE = 1 << 10,
    - GTK_WEBVIEW_SMILEY = 1 << 11,
    - GTK_WEBVIEW_LINKDESC = 1 << 12,
    - GTK_WEBVIEW_STRIKE = 1 << 13,
    + GTK_WEBVIEW_LINK = 1 << 8,
    + GTK_WEBVIEW_IMAGE = 1 << 9,
    + GTK_WEBVIEW_SMILEY = 1 << 10,
    + GTK_WEBVIEW_LINKDESC = 1 << 11,
    + GTK_WEBVIEW_STRIKE = 1 << 12,
    /** Show custom smileys when appropriate. */
    - GTK_WEBVIEW_CUSTOM_SMILEY = 1 << 14,
    + GTK_WEBVIEW_CUSTOM_SMILEY = 1 << 13,
    GTK_WEBVIEW_ALL = -1
    } GtkWebViewButtons;
    @@ -242,7 +241,7 @@
    *
    * @return A string containing the font face or @c NULL if none is set.
    */
    -const char *gtk_webview_get_current_fontface(GtkWebView *webview);
    +char *gtk_webview_get_current_fontface(GtkWebView *webview);
    /**
    * Returns a string containing the selected foreground color at the current
    @@ -252,7 +251,7 @@
    *
    * @return A string containing the foreground color or @c NULL if none is set.
    */
    -const char *gtk_webview_get_current_forecolor(GtkWebView *webview);
    +char *gtk_webview_get_current_forecolor(GtkWebView *webview);
    /**
    * Returns a string containing the selected font background color at the current
    @@ -262,17 +261,7 @@
    *
    * @return A string containing the background color or @c NULL if none is set.
    */
    -const char *gtk_webview_get_current_backcolor(GtkWebView *webview);
    -
    -/**
    - * Returns a string containing the selected background color at the current
    - * position in a GtkWebView.
    - *
    - * @param webview The GtkWebView
    - *
    - * @return A string containg the background color or @c NULL if none is set.
    - */
    -const char *gtk_webview_get_current_background(GtkWebView *webview);
    +char *gtk_webview_get_current_backcolor(GtkWebView *webview);
    /**
    * Returns a integer containing the selected HTML font size at the current
    @@ -351,17 +340,6 @@
    gboolean gtk_webview_toggle_backcolor(GtkWebView *webview, const char *color);
    /**
    - * Toggles a background color at the current location or selection in a
    - * GtkWebView.
    - *
    - * @param webview The GtkWebView
    - * @param color The HTML-style color, or @c NULL or "" to clear the color.
    - *
    - * @return @c TRUE if a color was set, or @c FALSE if it was cleared.
    - */
    -gboolean gtk_webview_toggle_background(GtkWebView *webview, const char *color);
    -
    -/**
    * Toggles a font face at the current location or selection in a GtkWebView.
    *
    * @param webview The GtkWebView
    --- a/pidgin/gtkwebviewtoolbar.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/gtkwebviewtoolbar.c Tue Feb 28 05:29:13 2012 +0000
    @@ -253,7 +253,7 @@
    priv = GTK_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar);
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(font))) {
    - const char *fontname = gtk_webview_get_current_fontface(GTK_WEBVIEW(toolbar->webview));
    + char *fontname = gtk_webview_get_current_fontface(GTK_WEBVIEW(toolbar->webview));
    if (!priv->font_dialog) {
    priv->font_dialog = gtk_font_selection_dialog_new(_("Select Font"));
    @@ -279,6 +279,8 @@
    }
    gtk_window_present(GTK_WINDOW(priv->font_dialog));
    +
    + g_free(fontname);
    } else {
    cancel_toolbar_font(font, toolbar);
    }
    @@ -341,7 +343,7 @@
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(color))) {
    GtkWidget *colorsel;
    GdkColor fgcolor;
    - const char *color = gtk_webview_get_current_forecolor(GTK_WEBVIEW(toolbar->webview));
    + char *color = gtk_webview_get_current_forecolor(GTK_WEBVIEW(toolbar->webview));
    if (!priv->fgcolor_dialog) {
    priv->fgcolor_dialog = gtk_color_selection_dialog_new(_("Select Text Color"));
    @@ -360,6 +362,8 @@
    }
    gtk_window_present(GTK_WINDOW(priv->fgcolor_dialog));
    +
    + g_free(color);
    } else {
    cancel_toolbar_fgcolor(color, toolbar);
    }
    @@ -373,12 +377,7 @@
    {
    GtkWebViewToolbarPriv *priv = GTK_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar);
    if (widget != NULL) {
    -#if 0
    - if (gtk_text_buffer_get_selection_bounds(GTK_WEBVIEW(toolbar->webview)->text_buffer, NULL, NULL))
    - gtk_webview_toggle_backcolor(GTK_WEBVIEW(toolbar->webview), "");
    - else
    -#endif
    - gtk_webview_toggle_background(GTK_WEBVIEW(toolbar->webview), "");
    + gtk_webview_toggle_backcolor(GTK_WEBVIEW(toolbar->webview), "");
    }
    if (priv->bgcolor_dialog != NULL)
    @@ -414,12 +413,7 @@
    text_color.red / 256,
    text_color.green / 256,
    text_color.blue / 256);
    -#if 0
    - if (gtk_text_buffer_get_selection_bounds(GTK_WEBVIEW(toolbar->webview)->text_buffer, NULL, NULL))
    - gtk_webview_toggle_backcolor(GTK_WEBVIEW(toolbar->webview), open_tag);
    - else
    -#endif
    - gtk_webview_toggle_background(GTK_WEBVIEW(toolbar->webview), open_tag);
    + gtk_webview_toggle_backcolor(GTK_WEBVIEW(toolbar->webview), open_tag);
    g_free(open_tag);
    cancel_toolbar_bgcolor(NULL, toolbar);
    @@ -432,7 +426,7 @@
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(color))) {
    GtkWidget *colorsel;
    GdkColor bgcolor;
    - const char *color = gtk_webview_get_current_backcolor(GTK_WEBVIEW(toolbar->webview));
    + char *color = gtk_webview_get_current_backcolor(GTK_WEBVIEW(toolbar->webview));
    if (!priv->bgcolor_dialog) {
    priv->bgcolor_dialog = gtk_color_selection_dialog_new(_("Select Background Color"));
    @@ -451,6 +445,8 @@
    }
    gtk_window_present(GTK_WINDOW(priv->bgcolor_dialog));
    +
    + g_free(color);
    } else {
    cancel_toolbar_bgcolor(color, toolbar);
    }
    @@ -1098,8 +1094,7 @@
    {
    GtkWebViewToolbarPriv *priv = GTK_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar);
    gboolean bold, italic, underline, strike;
    - const char *tmp;
    - const char *tmp2;
    + char *tmp;
    GtkLabel *label = GTK_LABEL(priv->font_label);
    gtk_label_set_label(label, _("_Font"));
    @@ -1158,6 +1153,7 @@
    gtk_label_set_markup_with_mnemonic(label, markup);
    g_free(markup);
    }
    + g_free(tmp);
    tmp = gtk_webview_get_current_forecolor(GTK_WEBVIEW(toolbar->webview));
    toggle_button_set_active_block(GTK_TOGGLE_BUTTON(priv->fgcolor),
    @@ -1168,17 +1164,18 @@
    gtk_label_set_markup_with_mnemonic(label, markup);
    g_free(markup);
    }
    + g_free(tmp);
    tmp = gtk_webview_get_current_backcolor(GTK_WEBVIEW(toolbar->webview));
    - tmp2 = gtk_webview_get_current_background(GTK_WEBVIEW(toolbar->webview));
    toggle_button_set_active_block(GTK_TOGGLE_BUTTON(priv->bgcolor),
    - (tmp != NULL || tmp2 != NULL), toolbar);
    + (tmp != NULL), toolbar);
    if (tmp != NULL) {
    gchar *markup = g_strdup_printf("<span background=\"%s\">%s</span>",
    tmp, gtk_label_get_label(label));
    gtk_label_set_markup_with_mnemonic(label, markup);
    g_free(markup);
    }
    + g_free(tmp);
    }
    static void
    --- a/pidgin/plugins/contact_priority.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/plugins/contact_priority.c Tue Feb 28 05:29:13 2012 +0000
    @@ -35,11 +35,11 @@
    }
    static void
    -account_update(GtkWidget *widget, GtkOptionMenu *optmenu)
    +account_update(GtkWidget *widget, GtkWidget *optmenu)
    {
    PurpleAccount *account = NULL;
    - account = g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(optmenu)))), "account");
    + account = pidgin_account_option_menu_get_selected(optmenu);
    purple_account_set_int(account, "score", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)));
    }
    @@ -147,8 +147,7 @@
    gtk_box_pack_start(GTK_BOX(hbox), optmenu, FALSE, FALSE, 0);
    /* this is where we set up the spin button we made above */
    - account = g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu))))),
    - "account");
    + account = pidgin_account_option_menu_get_selected(optmenu);
    gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
    (gdouble)purple_account_get_int(account, "score", 0));
    gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(spin), GTK_ADJUSTMENT(adj));
    --- a/pidgin/plugins/gestures/gestures.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/plugins/gestures/gestures.c Tue Feb 28 05:29:13 2012 +0000
    @@ -145,7 +145,6 @@
    }
    #if 0
    -#if GTK_CHECK_VERSION(2,4,0)
    static void
    mouse_button_menu_cb(GtkComboBox *opt, gpointer data)
    {
    @@ -153,15 +152,6 @@
    gstroke_set_mouse_button(button + 2);
    }
    -#else
    -static void
    -mouse_button_menu_cb(GtkMenuItem *item, gpointer data)
    -{
    - int button = (int)data;
    -
    - gstroke_set_mouse_button(button + 2);
    -}
    -#endif
    #endif
    static void
    @@ -230,9 +220,6 @@
    GtkWidget *toggle;
    #if 0
    GtkWidget *opt;
    -#if GTK_CHECK_VERSION(2,4,0)
    - GtkWidget *menu, *item;
    -#endif
    #endif
    /* Outside container */
    @@ -243,7 +230,6 @@
    vbox = pidgin_make_frame(ret, _("Mouse Gestures Configuration"));
    #if 0
    -#if GTK_CHECK_VERSION(2,4,0)
    /* Mouse button drop-down menu */
    opt = gtk_combo_box_new_text();
    @@ -255,26 +241,6 @@
    gtk_box_pack_start(GTK_BOX(vbox), opt, FALSE, FALSE, 0);
    gtk_combo_box_set_active(GTK_COMBO_BOX(opt),
    gstroke_get_mouse_button() - 2);
    -#else
    - /* Mouse button drop-down menu */
    - menu = gtk_menu_new();
    - opt = gtk_option_menu_new();
    -
    - item = gtk_menu_item_new_with_label(_("Middle mouse button"));
    - g_signal_connect(G_OBJECT(item), "activate",
    - G_CALLBACK(mouse_button_menu_cb), opt);
    - gtk_menu_append(menu, item);
    -
    - item = gtk_menu_item_new_with_label(_("Right mouse button"));
    - g_signal_connect(G_OBJECT(item), "activate",
    - G_CALLBACK(mouse_button_menu_cb), opt);
    - gtk_menu_append(menu, item);
    -
    - gtk_box_pack_start(GTK_BOX(vbox), opt, FALSE, FALSE, 0);
    - gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
    - gtk_option_menu_set_history(GTK_OPTION_MENU(opt),
    - gstroke_get_mouse_button() - 2);
    -#endif
    #endif
    /* "Visual gesture display" checkbox */
    --- a/pidgin/plugins/themeedit.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/plugins/themeedit.c Tue Feb 28 05:29:13 2012 +0000
    @@ -306,7 +306,9 @@
    }
    }
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), TRUE);
    +#endif
    #ifdef NOT_SADRUL
    pidgin_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_SAVE, G_CALLBACK(save_blist_theme), dialog);
    #endif
    --- a/pidgin/plugins/ticker/gtkticker.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/plugins/ticker/gtkticker.c Tue Feb 28 05:29:13 2012 +0000
    @@ -21,28 +21,24 @@
    * GtkTicker Copyright 2000 Syd Logan
    */
    -/* FIXME: GTK+ deprecated GTK_WIDGET_MAPPED/REALIZED, but don't provide
    - accessor functions yet. */
    -#undef GSEAL_ENABLE
    -
    #include "gtkticker.h"
    #include <gtk/gtk.h>
    -/* These don't seem to be in a release yet. See BZ #69872 */
    -#define gtk_widget_is_mapped(x) GTK_WIDGET_MAPPED(x)
    -#define gtk_widget_is_realized(x) GTK_WIDGET_REALIZED(x)
    +#if !GTK_CHECK_VERSION(2,20,0)
    +#define gtk_widget_get_mapped(x) GTK_WIDGET_MAPPED(x)
    +#define gtk_widget_set_mapped(x,y) do {\
    + if (y) \
    + GTK_WIDGET_SET_FLAGS(x, GTK_MAPPED); \
    + else \
    + GTK_WIDGET_UNSET_FLAGS(x, GTK_MAPPED); \
    +} while(0)
    +#define gtk_widget_get_realized(x) GTK_WIDGET_REALIZED(x)
    #define gtk_widget_set_realized(x,y) do {\
    if (y) \
    GTK_WIDGET_SET_FLAGS(x, GTK_REALIZED); \
    else \
    GTK_WIDGET_UNSET_FLAGS(x, GTK_REALIZED); \
    } while(0)
    -#define gtk_widget_set_mapped(x,y) do {\
    - if (y) \
    - GTK_WIDGET_SET_FLAGS(x, GTK_MAPPED); \
    - else \
    - GTK_WIDGET_UNSET_FLAGS(x, GTK_MAPPED); \
    -} while(0)
    #if !GTK_CHECK_VERSION(2,18,0)
    #define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
    @@ -51,6 +47,7 @@
    #define gtk_widget_get_window(x) x->window
    #endif
    #endif
    +#endif
    static void gtk_ticker_compute_offsets (GtkTicker *ticker);
    static void gtk_ticker_class_init (GtkTickerClass *klass);
    @@ -181,13 +178,13 @@
    ticker->children = g_list_append (ticker->children, child_info);
    - if (gtk_widget_is_realized (ticker))
    + if (gtk_widget_get_realized (GTK_WIDGET (ticker)))
    gtk_widget_realize (widget);
    if (gtk_widget_get_visible (GTK_WIDGET (ticker)) &&
    gtk_widget_get_visible (widget))
    {
    - if (gtk_widget_is_mapped (GTK_WIDGET (ticker)))
    + if (gtk_widget_get_mapped (GTK_WIDGET (ticker)))
    gtk_widget_map (widget);
    gtk_widget_queue_resize (GTK_WIDGET (ticker));
    @@ -298,7 +295,7 @@
    children = children->next;
    if (gtk_widget_get_visible (child->widget) &&
    - !gtk_widget_is_mapped (child->widget))
    + !gtk_widget_get_mapped (child->widget))
    gtk_widget_map (child->widget);
    }
    @@ -474,7 +471,7 @@
    #else
    widget->allocation = *allocation;
    #endif
    - if (gtk_widget_is_realized (widget))
    + if (gtk_widget_get_realized (widget))
    gdk_window_move_resize (gtk_widget_get_window (widget),
    allocation->x,
    allocation->y,
    --- a/pidgin/plugins/vvconfig.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/plugins/vvconfig.c Tue Feb 28 05:29:13 2012 +0000
    @@ -629,7 +629,7 @@
    }
    static void
    -voice_test_frame_destroy_cb(GtkObject *w, GstElement *pipeline)
    +voice_test_frame_destroy_cb(GtkWidget *w, GstElement *pipeline)
    {
    g_return_if_fail(GST_IS_ELEMENT(pipeline));
    @@ -704,7 +704,7 @@
    gtk_range_set_value(GTK_RANGE(volume),
    purple_prefs_get_int("/purple/media/audio/volume/input"));
    - gtk_widget_set(volume, "draw-value", FALSE, NULL);
    + gtk_scale_set_draw_value(GTK_SCALE(volume), FALSE);
    gtk_range_set_value(GTK_RANGE(threshold),
    purple_prefs_get_int("/purple/media/audio/silence_threshold"));
    --- a/pidgin/plugins/xmppconsole.c Thu Feb 23 08:13:29 2012 +0000
    +++ b/pidgin/plugins/xmppconsole.c Tue Feb 28 05:29:13 2012 +0000
    @@ -274,7 +274,9 @@
    GTK_STOCK_OK,
    GTK_RESPONSE_ACCEPT,
    NULL);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
    gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
    #if GTK_CHECK_VERSION(2,14,0)
    @@ -362,7 +364,9 @@
    GTK_STOCK_OK,
    GTK_RESPONSE_ACCEPT,
    NULL);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
    gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
    #if GTK_CHECK_VERSION(2,14,0)
    @@ -520,7 +524,9 @@
    GTK_STOCK_OK,
    GTK_RESPONSE_ACCEPT,
    NULL);
    +#if !GTK_CHECK_VERSION(2,22,0)
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    +#endif
    gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
    gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
    #if GTK_CHECK_VERSION(2,14,0)