pidgin/pidgin

2bb66ef1475e
Fix a crash when hovering over an exceptionally long URL (4074 characters,
but it might be different for you) in a gtkimhtml widget (such as the IM
window).

This was reported on the support mailing list:
http://pidgin.im/pipermail/support/2013-March/012980.html
http://pidgin.im/pipermail/support/2013-March/012981.html

Repro steps:
1. "gdb pidgin"

2. "break gdk_x_error"
You'll probably need to type "y" to make breakpoint pending on future shared library load. (Or you could run first then add the breakpoint.)

3. "run --sync"
--sync probably isn't actually necessary. Theoretically it should make the backtrace more useful. Like, maybe it could actually show the Pidgin calls that trigger the problem? Or maybe the problem call starts from the gtk main loop, so there would never be Pidgin code in the backtrace? It's also possible we don't pass our args to the right places to make --sync work.

4. "cont"
I hit the breakpoint at startup for some reason. I've just been continuing past it. Doesn't seem to affect anything.

5. Open an IM window.

6. Paste a long URL.

7. Mouse over the long URL.

8. The breakpoint is hit.

9. "bt"

#0 gdk_x_error (display=0x740e30, error=0x7fffffffbc20)
at /build/buildd/gtk+2.0-2.24.13/gdk/x11/gdkmain-x11.c:458
#1 0x00007ffff73b94f6 in _XError () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#2 0x00007ffff73b6741 in ?? () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#3 0x00007ffff73b6785 in ?? () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#4 0x00007ffff73b7378 in _XReply () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#5 0x00007ffff73b2d3d in XSync () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#6 0x00007ffff73b2dcb in ?? () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#7 0x00007ffff73b9e2f in ?? () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#8 0x00007ffff7395d14 in XCreatePixmap () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#9 0x00007ffff62bd0d2 in _gdk_pixmap_new (drawable=0x186ec60, width=width@entry=32774, height=25, depth=24,
depth@entry=-1) at /build/buildd/gtk+2.0-2.24.13/gdk/x11/gdkpixmap-x11.c:175
#10 0x00007ffff6289617 in IA__gdk_pixmap_new (drawable=drawable@entry=0x186ec60, width=width@entry=32774,
height=, depth=depth@entry=-1) at /build/buildd/gtk+2.0-2.24.13/gdk/gdkpixmap.c:249
#11 0x00007ffff6297036 in gdk_window_begin_implicit_paint (rect=0x7fffffffbed0, window=0x186ec60)
at /build/buildd/gtk+2.0-2.24.13/gdk/gdkwindow.c:2779
#12 gdk_window_process_updates_internal (window=0x186ec60) at /build/buildd/gtk+2.0-2.24.13/gdk/gdkwindow.c:5574
#13 0x00007ffff6299201 in IA__gdk_window_process_all_updates ()
at /build/buildd/gtk+2.0-2.24.13/gdk/gdkwindow.c:5696
#14 0x00007ffff6299269 in gdk_window_update_idle (data=)
at /build/buildd/gtk+2.0-2.24.13/gdk/gdkwindow.c:5322
#15 0x00007ffff6276e77 in gdk_threads_dispatch (data=0x1a45c40) at /build/buildd/gtk+2.0-2.24.13/gdk/gdk.c:512
#16 0x00007ffff53d8ab5 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#17 0x00007ffff53d8de8 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#18 0x00007ffff53d91e2 in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#19 0x00007ffff663ec77 in IA__gtk_main () at /build/buildd/gtk+2.0-2.24.13/gtk/gtkmain.c:1271
#20 0x0000000000499950 in main (argc=1, argv=0x7fffffffe538) at gtkmain.c:933

This is the message it prints when it exits:
The program 'Pidgin' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadAlloc (insufficient resources for operation)'.
(Details: serial 14454 error_code 11 request_code 53 minor_code 0)
(Note to programmers: normally, X errors are reported asynchronously;
that is, you will receive the error a while after causing it.
To debug your program, run it with the --sync command line
option to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)

I think it's kinda lame that gdk/gtk/xlib/whatever barfs when we give it a
ridiculously wide pango layout, but whatever. I'm assuming this problem is
gtkimhtml specific, and so I don't want to spend a whole lot of time fixing
it. As an easy fix I want to just truncate the URL displayed in the tooltip
to 200 characters.

Here's an example URL that I used to trigger the crash:
http://www.example.com/?%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%30123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%3012345678901234567890123456789012345678901234567890123456789012345678
/** @page account-signals Account Signals
@signals
@signal account-created
@signal account-destroying
@signal account-added
@signal account-connecting
@signal account-removed
@signal account-disabled
@signal account-enabled
@signal account-setting-info
@signal account-set-info
@signal account-status-changed
@signal account-actions-changed
@signal account-alias-changed
@signal account-authorization-requested
@signal account-authorization-requested-with-message
@signal account-authorization-denied
@signal account-authorization-granted
@signal account-error-changed
@signal account-signed-on
@signal account-signed-off
@signal account-connection-error
@endsignals
@see account.h
<hr>
@signaldef account-created
@signalproto
void (*account_created)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account is created by calling purple_account_new.
@param account The account.
@since 2.6.0
@endsignaldef
@signaldef account-destroying
@signalproto
void (*account_destroying)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account is about to be destroyed.
@param account The account.
@since 2.6.0
@endsignaldef
@signaldef account-added
@signalproto
void (*account_added)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account is added.
@param account The account that was added.
@see purple_accounts_add
@endsignaldef
@signaldef account-connecting
@signalproto
void (*account_connecting)(PurpleAccount *account);
@endsignalproto
@signaldesc
This is called when an account is in the process of connecting.
@param account The account in the process of connecting.
@endsignaldef
@signaldef account-removed
@signalproto
void (*account_removed)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account is removed.
@param account The account that was removed.
@see purple_accounts_remove
@endsignaldef
@signaldef account-disabled
@signalproto
void (*account_disabled)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account is disabled.
@param account The account that was disabled.
@endsignaldef
@signaldef account-enabled
@signalproto
void (*account_enabled)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account is enabled.
@param account The account that was enabled.
@endsignaldef
@signaldef account-setting-info
@signalproto
void (*account_setting_info)(PurpleAccount *account, const char *new_info);
@endsignalproto
@signaldesc
Emitted when a user is about to send his new user info, or
profile, to the server.
@param account The account that the info will be set on.
@param new_info The new information to set.
@endsignaldef
@signaldef account-set-info
@signalproto
void (*account_set_info)(PurpleAccount *account, const char *new_info);
@endsignalproto
@signaldesc
Emitted when a user sent his new user info, or profile, to the server.
@param account The account that the info was set on.
@param new_info The new information set.
@endsignaldef
@signaldef account-status-changed
@signalproto
void (*account_status_changed)(PurpleAccount *account, PurpleStatus *old, PurpleStatus *new);
@endsignalproto
@signaldesc
Emitted when the status of an account changes (after the change).
@param account The account that changed status.
@param old The status before change.
@param new The status after change.
@endsignaldef
@signaldef account-actions-changed
@signalproto
void (*account_actions_changed)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when the account actions are changed after initial connection.
@param account The account whose actions changed.
@endsignaldef
@signaldef account-alias-changed
@signalproto
void (*account_alias_changed)(PurpleAccount *account, const char *old);
@endsignalproto
@signaldesc
Emitted when the alias of an account changes (after the change).
@param account The account for which the alias was changed.
@param old The alias before change.
@endsignaldef
@signaldef account-authorization-requested
@signalproto
int (*account_authorization_requested)(PurpleAccount *account, const char *user);
@endsignalproto
@signaldesc
Emitted when a user requests authorization.
@param account The account.
@param user The name of the user requesting authorization.
@return Less than zero to deny the request without prompting, greater
than zero if the request should be granted. If zero is returned,
then the user will be prompted with the request.
@since 2.3.0
@endsignaldef
@signaldef account-authorization-requested-with-message
@signalproto
int (*account_authorization_requested)(PurpleAccount *account, const char *user, const char *message);
@endsignalproto
@signaldesc
Emitted when a user requests authorization.
@param account The account.
@param user The name of the user requesting authorization.
@param message The authorization request message
@return PURPLE_ACCOUNT_RESPONSE_IGNORE to silently ignore the request,
PURPLE_ACCOUNT_RESPONSE_DENY to block the request (the sender might
get informed, PURPLE_ACCOUNT_RESPONSE_ACCEPT if the request should be
granted. If PURPLE_ACCOUNT_RESPONSE_PASS is returned, then the user
will be prompted with the request.
@since 2.8.0
@endsignaldef
@signaldef account-authorization-denied
@signalproto
void (*account_authorization_denied)(PurpleAccount *account, const char *user);
@endsignalproto
@signaldesc
Emitted when the authorization request for a buddy is denied.
@param account The account.
@param user The name of the user requesting authorization.
@since 2.3.0
@endsignaldef
@signaldef account-authorization-granted
@signalproto
void (*account_authorization_granted)(PurpleAccount *account, const char *user);
@endsignalproto
@signaldesc
Emitted when the authorization request for a buddy is granted.
@param account The account.
@param user The name of the user requesting authorization.
@since 2.3.0
@endsignaldef
@signaldef account-error-changed
@signalproto
void (*account_error_changed)(PurpleAccount *account, const PurpleConnectionErrorInfo *old_error, const PurpleConnectionErrorInfo *current_error);
@endsignalproto
@signaldesc
Emitted when @a account's error changes. You should not call
purple_account_clear_current_error() while this signal is being emitted.
@param account The account whose error has changed.
@param old_error The account's previous error, or @c NULL if it had no
error. After this signal is emitted, @a old_error is
not guaranteed to be a valid pointer.
@param new_error The account's new error, or @c NULL if it has no error.
If not @c NULL, @a new_error will remain a valid until
pointer just after the next time this signal is emitted
for this @a account.
@see purple_account_get_current_error()
@since 2.3.0
@endsignaldef
@signaldef account-signed-on
@signalproto
void (*signed_on)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account has signed on.
@param account The account that has signed on.
@since 2.7.0
@endsignaldef
@signaldef account-signed-off
@signalproto
void (*signed_off)(PurpleAccount *account);
@endsignalproto
@signaldesc
Emitted when an account has signed off.
@param account The account that has signed off.
@since 2.7.0
@endsignaldef
@signaldef account-connection-error
@signalproto
void (*connection_error)(PurpleAccount *gc, PurpleConnectionError err, const gchar *desc)
@endsignalproto
@signaldesc
Emitted when a connection error occurs, before @ref signed-off.
@param account The account on which the error has occurred
@param err The error that occurred
@param desc A description of the error, giving more information.
@since 2.7.0
@endsignaldef
*/
// vim: syntax=c.doxygen tw=75 et