summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Egan <seanegan@pidgin.im>2007-06-15 19:34:24 +0000
committerSean Egan <seanegan@pidgin.im>2007-06-15 19:34:24 +0000
commit5c3672918dc1741d4a2b01817375b26e6e894b64 (patch)
treed77a8792b8e1eb669ec4e8aefeeba78738c9acb2
parent9b7f77bc969db63c4e64638f865887dd1e2396b2 (diff)
parenta8effca1a29c7565d0c982174ee8201fbbc94623 (diff)
downloadpidgin-5c3672918dc1741d4a2b01817375b26e6e894b64.tar.gz
propagate from branch 'im.pidgin.pidgin.2.1.0' (head 6733196cafc60146d92a26565e0d90bd8b43a9ef)
to branch 'im.pidgin.pidgin' (head ed70e92f7c284be8ef382ca84a3b1a8780566bc3)
-rw-r--r--COPYRIGHT2
-rw-r--r--ChangeLog18
-rw-r--r--ChangeLog.API69
-rw-r--r--configure.ac12
-rw-r--r--doc/conversation-signals.dox11
-rw-r--r--doc/finch.1.in36
-rw-r--r--finch/finch.c6
-rw-r--r--finch/gntaccount.c76
-rw-r--r--finch/gntblist.c40
-rw-r--r--finch/gntblist.h10
-rw-r--r--finch/gntconv.c25
-rw-r--r--finch/gntnotify.c9
-rw-r--r--finch/gntplugin.c3
-rw-r--r--finch/gntpounce.c4
-rw-r--r--finch/gntrequest.c2
-rw-r--r--finch/gntstatus.c2
-rw-r--r--finch/libgnt/Makefile.am2
-rw-r--r--finch/libgnt/configure.ac6
-rw-r--r--finch/libgnt/gnt-skel.c22
-rw-r--r--finch/libgnt/gnt-skel.h34
-rw-r--r--finch/libgnt/gnt.h110
-rw-r--r--finch/libgnt/gntbindable.c22
-rw-r--r--finch/libgnt/gntbindable.h74
-rw-r--r--finch/libgnt/gntbox.c26
-rw-r--r--finch/libgnt/gntbox.h107
-rw-r--r--finch/libgnt/gntbutton.c22
-rw-r--r--finch/libgnt/gntbutton.h35
-rw-r--r--finch/libgnt/gntcheckbox.c22
-rw-r--r--finch/libgnt/gntcheckbox.h46
-rw-r--r--finch/libgnt/gntclipboard.c24
-rw-r--r--finch/libgnt/gntclipboard.h40
-rw-r--r--finch/libgnt/gntcolors.c22
-rw-r--r--finch/libgnt/gntcolors.h37
-rw-r--r--finch/libgnt/gntcombobox.c22
-rw-r--r--finch/libgnt/gntcombobox.h62
-rw-r--r--finch/libgnt/gntentry.c22
-rw-r--r--finch/libgnt/gntentry.h91
-rw-r--r--finch/libgnt/gntfilesel.c22
-rw-r--r--finch/libgnt/gntfilesel.h117
-rw-r--r--finch/libgnt/gntkeys.c37
-rw-r--r--finch/libgnt/gntkeys.h49
-rw-r--r--finch/libgnt/gntlabel.c22
-rw-r--r--finch/libgnt/gntlabel.h53
-rw-r--r--finch/libgnt/gntline.c22
-rw-r--r--finch/libgnt/gntline.h35
-rw-r--r--finch/libgnt/gntmain.c43
-rw-r--r--finch/libgnt/gntmenu.c27
-rw-r--r--finch/libgnt/gntmenu.h40
-rw-r--r--finch/libgnt/gntmenuitem.c22
-rw-r--r--finch/libgnt/gntmenuitem.h48
-rw-r--r--finch/libgnt/gntmenuitemcheck.c22
-rw-r--r--finch/libgnt/gntmenuitemcheck.h46
-rw-r--r--finch/libgnt/gntstyle.c78
-rw-r--r--finch/libgnt/gntstyle.h54
-rw-r--r--finch/libgnt/gnttextview.c22
-rw-r--r--finch/libgnt/gnttextview.h92
-rw-r--r--finch/libgnt/gnttree.c29
-rw-r--r--finch/libgnt/gnttree.h253
-rw-r--r--finch/libgnt/gntutils.c22
-rw-r--r--finch/libgnt/gntutils.h88
-rw-r--r--finch/libgnt/gntwidget.c22
-rw-r--r--finch/libgnt/gntwidget.h152
-rw-r--r--finch/libgnt/gntwindow.c60
-rw-r--r--finch/libgnt/gntwindow.h51
-rw-r--r--finch/libgnt/gntwm.c592
-rw-r--r--finch/libgnt/gntwm.h120
-rw-r--r--finch/libgnt/gntws.c168
-rw-r--r--finch/libgnt/gntws.h60
-rw-r--r--finch/libgnt/wms/Makefile.am11
-rw-r--r--finch/libgnt/wms/irssi.c319
-rw-r--r--finch/libgnt/wms/s.c2
-rw-r--r--libpurple/Makefile.am2
-rw-r--r--libpurple/account.c14
-rw-r--r--libpurple/account.h2
-rw-r--r--libpurple/accountopt.c17
-rw-r--r--libpurple/accountopt.h20
-rw-r--r--libpurple/blist.c13
-rw-r--r--libpurple/blist.h9
-rw-r--r--libpurple/buddyicon.c34
-rw-r--r--libpurple/buddyicon.h1
-rw-r--r--libpurple/connection.c8
-rw-r--r--libpurple/connection.h6
-rw-r--r--libpurple/conversation.c95
-rw-r--r--libpurple/conversation.h38
-rw-r--r--libpurple/core.c89
-rw-r--r--libpurple/core.h10
-rw-r--r--libpurple/dbus-analyze-functions.py50
-rw-r--r--libpurple/dbus-bindings.h38
-rw-r--r--libpurple/dbus-server.c93
-rw-r--r--libpurple/dbus-server.h7
-rw-r--r--libpurple/dbus-useful.c2
-rw-r--r--libpurple/eventloop.c11
-rw-r--r--libpurple/eventloop.h42
-rw-r--r--libpurple/example/nullclient.c6
-rw-r--r--libpurple/ft.c10
-rw-r--r--libpurple/ft.h9
-rw-r--r--libpurple/idle.c14
-rw-r--r--libpurple/imgstore.c3
-rw-r--r--libpurple/log.c117
-rw-r--r--libpurple/notify.c2
-rw-r--r--libpurple/notify.h2
-rw-r--r--libpurple/plugins/joinpart.c2
-rw-r--r--libpurple/plugins/perl/common/Account.xs5
-rw-r--r--libpurple/plugins/perl/common/BuddyList.xs18
-rw-r--r--libpurple/plugins/perl/common/Connection.xs4
-rw-r--r--libpurple/plugins/perl/common/Conversation.xs25
-rw-r--r--libpurple/plugins/perl/common/Prefs.xs5
-rw-r--r--libpurple/plugins/perl/common/module.h1
-rw-r--r--libpurple/plugins/perl/common/typemap1
-rw-r--r--libpurple/plugins/perl/perl-handlers.c11
-rw-r--r--libpurple/plugins/tcl/tcl_cmds.c10
-rw-r--r--libpurple/pounce.c2
-rw-r--r--libpurple/prefs.c2
-rw-r--r--libpurple/protocols/irc/irc.c5
-rw-r--r--libpurple/protocols/jabber/jutil.c2
-rw-r--r--libpurple/protocols/jabber/libxmpp.c8
-rw-r--r--libpurple/protocols/msn/msn.c6
-rw-r--r--libpurple/protocols/msn/switchboard.c2
-rw-r--r--libpurple/protocols/oscar/oscar.c2
-rw-r--r--libpurple/protocols/silc/ft.c2
-rw-r--r--libpurple/protocols/silc/silc.c3
-rw-r--r--libpurple/protocols/silc10/silc.c6
-rw-r--r--libpurple/protocols/yahoo/yahoo.c2
-rw-r--r--libpurple/protocols/yahoo/yahoochat.c10
-rw-r--r--libpurple/protocols/yahoo/yahoochat.h2
-rw-r--r--libpurple/prpl.c30
-rw-r--r--libpurple/prpl.h6
-rwxr-xr-xlibpurple/purple-remote6
-rw-r--r--libpurple/savedstatuses.c2
-rw-r--r--libpurple/server.c7
-rw-r--r--libpurple/util.c93
-rw-r--r--libpurple/util.h22
-rw-r--r--libpurple/xmlnode.c17
-rw-r--r--libpurple/xmlnode.h16
-rw-r--r--pidgin/Makefile.am4
-rw-r--r--pidgin/Makefile.mingw1
-rw-r--r--pidgin/gtkaccount.c50
-rw-r--r--pidgin/gtkblist.c53
-rw-r--r--pidgin/gtkconv.c492
-rw-r--r--pidgin/gtkdialogs.c14
-rw-r--r--pidgin/gtkdocklet.c6
-rw-r--r--pidgin/gtkeventloop.c4
-rw-r--r--pidgin/gtkft.c5
-rw-r--r--pidgin/gtkimhtml.c229
-rw-r--r--pidgin/gtkimhtml.h58
-rw-r--r--pidgin/gtkimhtmltoolbar.c316
-rw-r--r--pidgin/gtklog.c2
-rw-r--r--pidgin/gtkmain.c18
-rw-r--r--pidgin/gtknotify.c8
-rw-r--r--pidgin/gtkpounce.c76
-rw-r--r--pidgin/gtkprefs.c22
-rw-r--r--pidgin/gtkprivacy.c6
-rw-r--r--pidgin/gtkrequest.c14
-rw-r--r--pidgin/gtkroomlist.c8
-rw-r--r--pidgin/gtksavedstatuses.c18
-rw-r--r--pidgin/gtksourceundomanager.c1123
-rw-r--r--pidgin/gtksourceundomanager.h83
-rw-r--r--pidgin/gtksourceview-marshal.c95
-rw-r--r--pidgin/gtksourceview-marshal.h32
-rw-r--r--pidgin/gtkstatusbox.c2
-rw-r--r--pidgin/gtkthemes.c2
-rw-r--r--pidgin/gtkutils.c241
-rw-r--r--pidgin/gtkutils.h28
-rw-r--r--pidgin/gtkwhiteboard.c14
-rw-r--r--pidgin/pidginstock.c1
-rw-r--r--pidgin/pidginstock.h1
-rw-r--r--pidgin/pixmaps/toolbar/16/Makefile.am1
-rw-r--r--pidgin/plugins/cap/cap.c6
-rw-r--r--pidgin/plugins/gestures/gestures.c4
-rw-r--r--pidgin/plugins/gevolution/add_buddy_dialog.c7
-rw-r--r--pidgin/plugins/gevolution/assoc-buddy.c4
-rw-r--r--pidgin/plugins/gevolution/gevolution.c5
-rw-r--r--pidgin/plugins/gevolution/new_person_dialog.c6
-rw-r--r--pidgin/plugins/notify.c8
-rw-r--r--pidgin/plugins/relnot.c5
-rw-r--r--pidgin/plugins/spellchk.c4
-rw-r--r--pidgin/plugins/ticker/ticker.c5
-rw-r--r--pidgin/plugins/timestamp.c4
-rw-r--r--pidgin/plugins/xmppconsole.c7
179 files changed, 6911 insertions, 1253 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
index 74a9fb37a0..d150e49f98 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -52,6 +52,7 @@ Matt Brenneke
Jeremy Brooks
Jonathan Brossard
Philip Brown
+Norbert Buchmuller
Sean Burke
Thomas Butter
Trevor Caira
@@ -146,6 +147,7 @@ Michael Golden
Charlie Gordon
Ryan C. Gordon
Miah Gregory
+David Grohmann
Christian Hammond
Erick Hamness
Fred Hampton
diff --git a/ChangeLog b/ChangeLog
index 71250ae70d..5009880cfe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
+version 2.1.0 (??/??/????):
+ libpurple:
+ * Core changes to allow UIs to use second-granularity for scheduling.
+ Pidgin and Finch, which use the glib event loop, were changed to use
+ g_timeout_add_seconds() on glib >= 2.14 when possible. This allows
+ glib to better group our longer timers to increase power efficiency.
+ (Arjan van de Ven with Intel Corporation)
+ * No longer linkifies screennames containing @ signs in join/part
+ notifications in chats
+ * With the HTML logger, images in conversations are now saved.
+ NOTE: Saved images are not yet displayed when loading logs.
+
+ Pidgin:
+ * Ensure only one copy of Pidgin is running with a given configuration
+ directory. The net effect of this is that trying to start Pidgin a
+ second time will raise the buddy list. (Gabriel Schulhof)
+ * Undo capability in the conversation window
+
version 2.0.2 (06/14/2007):
Pidgin:
* Added a custom conversation font option to preferences
diff --git a/ChangeLog.API b/ChangeLog.API
index 307491fb5b..a58304dc11 100644
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -1,5 +1,74 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
+version 2.1.0 (??/??/????):
+ libpurple:
+ Added:
+ * purple-remote: added getstatus command
+ * conversation-extended-menu signal (See Doxygen docs)
+ * OPT_PROTO_SLASH_COMMANDS_NATIVE protocol option to indicate that
+ slash commands are "native" to the protocol
+ * PURPLE_MESSAGE_NO_LINKIFY message flag to indicate that the message
+ should not be auto-linkified
+ * PurpleEventLoopUiOps.timeout_add_seconds
+ UIs can now use better scheduling for whole-second timers. For
+ example, clients based on the glib event loop can now use
+ g_timeout_add_seconds.
+ * gtk_imhtml_setup_entry
+ * pidgin_create_window
+ * purple_blist_node_get_type
+ * purple_conversation_do_command
+ * purple_conversation_get_extended_menu
+ * purple_core_ensure_single_instance
+ This is for UIs to use to ensure only one copy is running.
+ * purple_dbus_is_owner
+ * purple_dbusify_const_GList
+ * purple_dbusify_const_GSList
+ * purple_const_GList_to_array
+ * purple_const_GSList_to_array
+ * purple_image_data_calculate_filename
+ * pidgin_retrieve_user_info, shows immediate feedback when getting
+ information about a user.
+ * purple_timeout_add_seconds
+ Callers should prefer this to purple_timeout_add for timers
+ longer than 1 second away. Be aware of the rounding, though.
+ * purple_timeout_add_seconds
+ Callers should prefer this to purple_timeout_add for timers
+ longer than 1 second away. Be aware of the rounding, though.
+ * purple_xfer_get_remote_user
+ * gtk_imhtml_animation_new
+ Can be used for inserting an animated image into an IMHTML.
+
+ Changed:
+ * Mark some return types const:
+ * purple_accounts_get_all
+ * purple_connections_get_all
+ * purple_connections_get_connecting
+ * purple_conv_chat_get_ignored
+ * purple_conv_chat_get_users
+ * purple_get_chats
+ * purple_get_conversations
+ * purple_get_ims
+ * purple_notify_user_info_get_entries
+
+ Deprecated:
+ * purple_dbusify_GList: Use purple_dbusify_const_GList (and
+ g_list_free if needed) if depending on 2.1.0 is okay.
+ * purple_dbusify_GSList: Use purple_dbusify_const_GSList (and
+ g_slist_free if needed) if depending on 2.1.0 is okay..
+ * purple_GList_to_array: Use purple_const_GList_to_array (and
+ g_list_free if needed) if depending on 2.1.0 is okay..
+ * purple_GSList_to_array: Use purple_const_GSList_to_array (and
+ g_slist_free if needed) if depending on 2.1.0 is okay..
+
+ Pidgin:
+ Changed:
+ * pidgin_append_menu_action returns the menuitem added to the menu.
+ * pidgin_separator returns the separator added to the menu.
+
+ Finch:
+ Added:
+ * finch_retrieve_user_info
+
version 2.0.2 (6/14/2007):
Pidgin:
Deprecated:
diff --git a/configure.ac b/configure.ac
index 084ffa3611..e765b55ca4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,19 +43,19 @@ AC_PREREQ([2.50])
#
# Make sure to update finch/libgnt/configure.ac with libgnt version changes.
#
-m4_define([purple_lt_current], [0])
+m4_define([purple_lt_current], [1])
m4_define([purple_major_version], [2])
-m4_define([purple_minor_version], [0])
-m4_define([purple_micro_version], [2])
+m4_define([purple_minor_version], [1])
+m4_define([purple_micro_version], [0])
m4_define([purple_version_suffix], [])
m4_define([purple_version],
[purple_major_version.purple_minor_version.purple_micro_version])
m4_define([purple_display_version], purple_version[]m4_ifdef([purple_version_suffix],[purple_version_suffix]))
-m4_define([gnt_lt_current], [0])
-m4_define([gnt_major_version], [1])
+m4_define([gnt_lt_current], [1])
+m4_define([gnt_major_version], [2])
m4_define([gnt_minor_version], [0])
-m4_define([gnt_micro_version], [2])
+m4_define([gnt_micro_version], [0])
m4_define([gnt_version_suffix], [])
m4_define([gnt_version],
[gnt_major_version.gnt_minor_version.gnt_micro_version])
diff --git a/doc/conversation-signals.dox b/doc/conversation-signals.dox
index 2aa32fead7..d8adb67abf 100644
--- a/doc/conversation-signals.dox
+++ b/doc/conversation-signals.dox
@@ -29,6 +29,7 @@
@signal chat-joined
@signal chat-left
@signal chat-topic-changed
+ @signal conversation-extended-menu
@endsignals
@signaldef writing-im-msg
@@ -417,5 +418,15 @@ void (*chat_topic_changed)(PurpleConversation *conv, const char *who, const char
@param topic The new topic.
@endsignaldef
+ @signaldef conversation-extended-menu
+ @signalproto
+void (*conversation_extended_menu)(PurpleConversation *conv, GList **list);
+ @endsignalproto
+ @signaldesc
+ Emitted when the UI requests a list of plugin actions for a
+ conversation.
+ @param conv The conversation.
+ @param list A pointer to the list of actions.
+ @endsignaldef
*/
// vim: syntax=c tw=75 et
diff --git a/doc/finch.1.in b/doc/finch.1.in
index 483a813d10..c625792e5c 100644
--- a/doc/finch.1.in
+++ b/doc/finch.1.in
@@ -109,6 +109,15 @@ Jump to the 1st, 2nd ... 10th window.
.B Ctrl \+ o
Bring up the menu (if there is one) for a window. Note that currently only the
buddylist has a menu.
+.TP
+.B Alt \+ Shift \+ .
+Switch to the next workspace
+.TP
+.B Alt \+ Shift \+ ,
+Switch to the previous workspace
+.TP
+.B Alt \+ s
+Show the workspace list
.SH FILES
\fI~/.gntrc\fR: configuration file for gnt applications.
@@ -134,6 +143,33 @@ remember_position = 1
.br
.br
+# Workspaces are created simply by adding Workspace-X groups as follows:
+.br
+[Workspace-1]
+.br
+name = blist
+.br
+# window-names specifies that windows with these semi-colon separated names are placed
+into this workspace
+.br
+window-names = buddylist;debug-window
+.br
+
+.br
+[Workspace-2]
+.br
+name = IM
+.br
+window-names = conversation-window
+.br
+# window-titles specifies that windows with these semi-colon separated titles are placed
+into this workspace. These are matched as substrings. Window titles take precedence over
+names.
+.br
+window-titles = Preferences;Pounce
+.br
+
+.br
[colors]
.br
# The RGB values range in [0, 1000]
diff --git a/finch/finch.c b/finch/finch.c
index 9ff98d0208..d3c337d85b 100644
--- a/finch/finch.c
+++ b/finch/finch.c
@@ -156,11 +156,15 @@ static PurpleEventLoopUiOps eventloop_ops =
gnt_input_add,
g_source_remove,
NULL, /* input_get_error */
+#if GLIB_CHECK_VERSION(2,14,0)
+ g_timeout_add_seconds,
+#else
+ NULL,
+#endif
/* padding */
NULL,
NULL,
- NULL,
NULL
};
diff --git a/finch/gntaccount.c b/finch/gntaccount.c
index 218b8b664a..788452e591 100644
--- a/finch/gntaccount.c
+++ b/finch/gntaccount.c
@@ -31,6 +31,7 @@
#include <gntlabel.h>
#include <gntline.h>
#include <gnttree.h>
+#include <gntwindow.h>
#include <account.h>
#include <accountopt.h>
@@ -40,6 +41,7 @@
#include <request.h>
#include "gntaccount.h"
+#include "gntblist.h"
#include "finch.h"
#include <string.h>
@@ -280,7 +282,11 @@ update_user_splits(AccountEditDialog *dialog)
if (dialog->account)
{
- s = strrchr(username, purple_account_user_split_get_separator(split));
+ if(purple_account_user_split_get_reverse(split))
+ s = strrchr(username, purple_account_user_split_get_separator(split));
+ else
+ s = strchr(username, purple_account_user_split_get_separator(split));
+
if (s != NULL)
{
*s = '\0';
@@ -635,7 +641,7 @@ reset_accounts_win(GntWidget *widget, gpointer null)
void finch_accounts_show_all()
{
- GList *iter;
+ const GList *iter;
GntWidget *box, *button;
if (accounts.window)
@@ -728,7 +734,7 @@ account_abled_cb(PurpleAccount *account, gpointer user_data)
void finch_accounts_init()
{
- GList *iter;
+ const GList *iter;
purple_signal_connect(purple_accounts_get_handle(), "account-added",
finch_accounts_get_handle(), PURPLE_CALLBACK(account_added_callback),
@@ -743,12 +749,18 @@ void finch_accounts_init()
finch_accounts_get_handle(),
PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(TRUE));
- for (iter = purple_accounts_get_all(); iter; iter = iter->next) {
- if (purple_account_get_enabled(iter->data, FINCH_UI))
- break;
- }
- if (!iter)
+ iter = purple_accounts_get_all();
+ if (iter) {
+ for (; iter; iter = iter->next) {
+ if (purple_account_get_enabled(iter->data, FINCH_UI))
+ break;
+ }
+ if (!iter)
+ finch_accounts_show_all();
+ } else {
+ edit_account(NULL);
finch_accounts_show_all();
+ }
}
void finch_accounts_uninit()
@@ -819,7 +831,7 @@ add_user_cb(AddUserData *data)
{
PurpleConnection *gc = purple_account_get_connection(data->account);
- if (g_list_find(purple_connections_get_all(), gc))
+ if (g_list_find((GList *)purple_connections_get_all(), gc))
{
purple_blist_request_add_buddy(data->account, data->username,
NULL, data->alias);
@@ -865,25 +877,25 @@ typedef struct {
} auth_and_add;
static void
+free_auth_and_add(auth_and_add *aa)
+{
+ g_free(aa->username);
+ g_free(aa->alias);
+ g_free(aa);
+}
+
+static void
authorize_and_add_cb(auth_and_add *aa)
{
aa->auth_cb(aa->data);
purple_blist_request_add_buddy(aa->account, aa->username,
NULL, aa->alias);
-
- g_free(aa->username);
- g_free(aa->alias);
- g_free(aa);
}
static void
deny_no_add_cb(auth_and_add *aa)
{
aa->deny_cb(aa->data);
-
- g_free(aa->username);
- g_free(aa->alias);
- g_free(aa);
}
static void *
@@ -912,19 +924,47 @@ finch_request_authorize(PurpleAccount *account, const char *remote_user,
(message != NULL ? ": " : "."),
(message != NULL ? message : ""));
if (!on_list) {
+ GntWidget *widget;
+ GList *iter;
auth_and_add *aa = g_new(auth_and_add, 1);
+
aa->auth_cb = (PurpleAccountRequestAuthorizationCb)auth_cb;
aa->deny_cb = (PurpleAccountRequestAuthorizationCb)deny_cb;
aa->data = user_data;
aa->username = g_strdup(remote_user);
aa->alias = g_strdup(alias);
aa->account = account;
- uihandle = purple_request_action(NULL, _("Authorize buddy?"), buffer, NULL,
+
+ uihandle = gnt_vwindow_new(FALSE);
+ gnt_box_set_title(GNT_BOX(uihandle), _("Authorize buddy?"));
+ gnt_box_set_pad(GNT_BOX(uihandle), 0);
+
+ widget = purple_request_action(NULL, _("Authorize buddy?"), buffer, NULL,
PURPLE_DEFAULT_ACTION_NONE,
account, remote_user, NULL,
aa, 2,
_("Authorize"), authorize_and_add_cb,
_("Deny"), deny_no_add_cb);
+ gnt_screen_release(widget);
+ gnt_box_set_toplevel(GNT_BOX(widget), FALSE);
+ gnt_box_add_widget(GNT_BOX(uihandle), widget);
+
+ gnt_box_add_widget(GNT_BOX(uihandle), gnt_hline_new());
+
+ widget = finch_retrieve_user_info(account->gc, remote_user);
+ for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) {
+ if (GNT_IS_BUTTON(iter->data)) {
+ gnt_widget_destroy(iter->data);
+ gnt_box_remove(GNT_BOX(widget), iter->data);
+ break;
+ }
+ }
+ gnt_box_set_toplevel(GNT_BOX(widget), FALSE);
+ gnt_screen_release(widget);
+ gnt_box_add_widget(GNT_BOX(uihandle), widget);
+ gnt_widget_show(uihandle);
+
+ g_signal_connect_swapped(G_OBJECT(uihandle), "destroy", G_CALLBACK(free_auth_and_add), aa);
} else {
uihandle = purple_request_action(NULL, _("Authorize buddy?"), buffer, NULL,
PURPLE_DEFAULT_ACTION_NONE,
diff --git a/finch/gntblist.c b/finch/gntblist.c
index dee056f511..37b8dad05a 100644
--- a/finch/gntblist.c
+++ b/finch/gntblist.c
@@ -104,6 +104,7 @@ static void add_contact(PurpleContact *contact, FinchBlist *ggblist);
static void add_group(PurpleGroup *group, FinchBlist *ggblist);
static void add_chat(PurpleChat *chat, FinchBlist *ggblist);
static void add_node(PurpleBlistNode *node, FinchBlist *ggblist);
+static void node_update(PurpleBuddyList *list, PurpleBlistNode *node);
static void draw_tooltip(FinchBlist *ggblist);
static gboolean remove_typing_cb(gpointer null);
static void remove_peripherals(FinchBlist *ggblist);
@@ -189,6 +190,8 @@ node_remove(PurpleBuddyList *list, PurpleBlistNode *node)
if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_contact_online(contact)) ||
contact->currentsize < 1)
node_remove(list, (PurpleBlistNode*)contact);
+ else
+ node_update(list, (PurpleBlistNode*)contact);
} else if (!PURPLE_BLIST_NODE_IS_GROUP(node)) {
PurpleGroup *group = (PurpleGroup*)node->parent;
if ((!purple_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) ||
@@ -215,6 +218,9 @@ node_update(PurpleBuddyList *list, PurpleBlistNode *node)
if (list->ui_data == NULL)
return; /* XXX: this is probably the place to auto-join chats */
+ if (ggblist->window == NULL)
+ return;
+
if (node->ui_data != NULL) {
gnt_tree_change_text(GNT_TREE(ggblist->tree), node,
0, get_display_name(node));
@@ -634,9 +640,18 @@ selection_activate(GntWidget *widget, FinchBlist *ggblist)
if (PURPLE_BLIST_NODE_IS_BUDDY(node))
{
PurpleBuddy *buddy = (PurpleBuddy *)node;
- PurpleConversation *conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
- purple_buddy_get_account(buddy),
- purple_buddy_get_name(buddy));
+ PurpleConversation *conv;
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
+ purple_buddy_get_name(buddy),
+ purple_buddy_get_account(buddy));
+ if (!conv) {
+ conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
+ purple_buddy_get_account(buddy),
+ purple_buddy_get_name(buddy));
+ } else {
+ FinchConv *ggconv = conv->ui_data;
+ gnt_window_present(ggconv->window);
+ }
finch_conversation_set_active(conv);
}
else if (PURPLE_BLIST_NODE_IS_CHAT(node))
@@ -824,17 +839,22 @@ create_group_menu(GntMenu *menu, PurpleGroup *group)
PURPLE_CALLBACK(finch_add_group), group);
}
-static void
-finch_blist_get_buddy_info_cb(PurpleBuddy *buddy, PurpleBlistNode *selected)
+gpointer finch_retrieve_user_info(PurpleConnection *conn, const char *name)
{
- /* Add a userinfo with a "Retrieving information", which will later be updated
- * when the server finally returns the information. */
PurpleNotifyUserInfo *info = purple_notify_user_info_new();
+ gpointer uihandle;
purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving..."));
- purple_notify_userinfo(buddy->account->gc, purple_buddy_get_name(buddy), info, NULL, NULL);
+ uihandle = purple_notify_userinfo(conn, name, info, NULL, NULL);
purple_notify_user_info_destroy(info);
- serv_get_info(buddy->account->gc, purple_buddy_get_name(buddy));
+ serv_get_info(conn, name);
+ return uihandle;
+}
+
+static void
+finch_blist_get_buddy_info_cb(PurpleBuddy *buddy, PurpleBlistNode *selected)
+{
+ finch_retrieve_user_info(buddy->account->gc, purple_buddy_get_name(buddy));
}
static void
@@ -2297,6 +2317,8 @@ blist_show(PurpleBuddyList *list)
ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_peripherals),
ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+ g_signal_connect_data(G_OBJECT(ggblist->window), "workspace-hidden", G_CALLBACK(remove_peripherals),
+ ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
g_signal_connect(G_OBJECT(ggblist->tree), "size_changed", G_CALLBACK(size_changed_cb), NULL);
g_signal_connect(G_OBJECT(ggblist->window), "position_set", G_CALLBACK(save_position_cb), NULL);
g_signal_connect(G_OBJECT(ggblist->window), "destroy", G_CALLBACK(reset_blist_window), NULL);
diff --git a/finch/gntblist.h b/finch/gntblist.h
index cce411d7c1..1125264f1d 100644
--- a/finch/gntblist.h
+++ b/finch/gntblist.h
@@ -90,6 +90,16 @@ gboolean finch_blist_get_size(int *width, int *height);
*/
void finch_blist_set_size(int width, int height);
+/**
+ * Get information about a user. Show immediate feedback.
+ *
+ * @param conn The connection to get information fro
+ * @param name The user to get information about.
+ *
+ * @return Returns the ui-handle for the userinfo notification.
+ */
+gpointer finch_retrieve_user_info(PurpleConnection *conn, const char *name);
+
/*@}*/
#endif
diff --git a/finch/gntconv.c b/finch/gntconv.c
index b5bb3d7105..c6ed24d0e8 100644
--- a/finch/gntconv.c
+++ b/finch/gntconv.c
@@ -64,7 +64,7 @@ static void
send_typing_notification(GntWidget *w, FinchConv *ggconv)
{
const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry));
- gboolean empty = (!text || !*text);
+ gboolean empty = (!text || !*text || (*text == '/'));
if (purple_prefs_get_bool("/finch/conversations/notify_typing")) {
PurpleConversation *conv = ggconv->active_conv;
PurpleConvIm *im = PURPLE_CONV_IM(conv);
@@ -313,12 +313,7 @@ static void
get_info_cb(GntMenuItem *item, gpointer ggconv)
{
FinchConv *ggc = ggconv;
- PurpleNotifyUserInfo *info = purple_notify_user_info_new();
- purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving..."));
- purple_notify_userinfo(ggc->active_conv->account->gc, purple_conversation_get_name(ggc->active_conv), info, NULL, NULL);
- purple_notify_user_info_destroy(info);
-
- serv_get_info(purple_conversation_get_gc(ggc->active_conv),
+ finch_retrieve_user_info(purple_conversation_get_gc(ggc->active_conv),
purple_conversation_get_name(ggc->active_conv));
}
@@ -445,6 +440,16 @@ create_conv_from_userlist(GntWidget *widget, FinchConv *fc)
}
static void
+gained_focus_cb(GntWindow *window, FinchConv *fc)
+{
+ GList *iter;
+ for (iter = fc->list; iter; iter = iter->next) {
+ purple_conversation_set_data(iter->data, "unseen-count", 0);
+ purple_conversation_update(iter->data, PURPLE_CONV_UPDATE_UNSEEN);
+ }
+}
+
+static void
finch_create_conversation(PurpleConversation *conv)
{
FinchConv *ggc = conv->ui_data;
@@ -534,6 +539,7 @@ finch_create_conversation(PurpleConversation *conv)
g_free(title);
gnt_box_give_focus_to_child(GNT_BOX(ggc->window), ggc->entry);
+ g_signal_connect(G_OBJECT(ggc->window), "gained-focus", G_CALLBACK(gained_focus_cb), ggc);
}
static void
@@ -627,6 +633,11 @@ finch_write_common(PurpleConversation *conv, const char *who, const char *messag
if (flags & (PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_NICK | PURPLE_MESSAGE_ERROR))
gnt_widget_set_urgent(ggconv->tv);
+ if (flags & PURPLE_MESSAGE_RECV && !gnt_widget_has_focus(ggconv->window)) {
+ int count = GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count"));
+ purple_conversation_set_data(conv, "unseen-count", GINT_TO_POINTER(count + 1));
+ purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
+ }
}
static void
diff --git a/finch/gntnotify.c b/finch/gntnotify.c
index 1fefc8d514..5ae84c182f 100644
--- a/finch/gntnotify.c
+++ b/finch/gntnotify.c
@@ -69,6 +69,7 @@ finch_notify_message(PurpleNotifyMsgType type, const char *title,
gnt_box_set_title(GNT_BOX(window), title);
gnt_box_set_fill(GNT_BOX(window), FALSE);
gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
+ gnt_box_set_pad(GNT_BOX(window), 0);
if (primary)
gnt_box_add_widget(GNT_BOX(window),
@@ -168,7 +169,7 @@ setup_email_dialog()
gnt_label_new_with_format(_("You have mail!"), GNT_TEXT_FLAG_BOLD));
emaildialog.tree = tree = gnt_tree_new_with_columns(3);
- gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("From"), _("Subject"));
+ gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("Sender"), _("Subject"));
gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
gnt_tree_set_col_width(GNT_TREE(tree), 0, 15);
gnt_tree_set_col_width(GNT_TREE(tree), 1, 25);
@@ -268,11 +269,11 @@ finch_notify_userinfo(PurpleConnection *gc, const char *who, PurpleNotifyUserInf
char *strip = purple_markup_strip_html(info);
int tvw, tvh, width, height, ntvw, ntvh;
+ while (GNT_WIDGET(ui_handle)->parent)
+ ui_handle = GNT_WIDGET(ui_handle)->parent;
gnt_widget_get_size(GNT_WIDGET(ui_handle), &width, &height);
gnt_widget_get_size(GNT_WIDGET(msg), &tvw, &tvh);
- /* Ideally, I would replace the information in "info". But replacing tagged text is a
- * bit nasty right now. So clear the view and add the new stuff instead. */
gnt_text_view_clear(msg);
gnt_text_view_append_text_with_flags(msg, strip, GNT_TEXT_FLAG_NORMAL);
gnt_text_view_scroll(msg, 0);
@@ -280,7 +281,7 @@ finch_notify_userinfo(PurpleConnection *gc, const char *who, PurpleNotifyUserInf
ntvw += 3;
ntvh++;
- gnt_screen_resize_widget(GNT_WIDGET(ui_handle), width + (ntvw - tvw), height + (ntvh - tvh));
+ gnt_screen_resize_widget(GNT_WIDGET(ui_handle), width + MAX(0, ntvw - tvw), height + MAX(0, ntvh - tvh));
g_free(strip);
g_free(key);
} else {
diff --git a/finch/gntplugin.c b/finch/gntplugin.c
index 13c7f9b011..ea7e170d71 100644
--- a/finch/gntplugin.c
+++ b/finch/gntplugin.c
@@ -106,6 +106,9 @@ selection_changed(GntWidget *widget, gpointer old, gpointer current, gpointer nu
char *text;
GList *list = NULL, *iter = NULL;
+ if (!plugin)
+ return;
+
/* If the selected plugin was unseen before, mark it as seen. But save the list
* only when the plugin list is closed. So if the user enables a plugin, and it
* crashes, it won't get marked as seen so the user can fix the bug and still
diff --git a/finch/gntpounce.c b/finch/gntpounce.c
index 1b7a292d8a..055cfb02a3 100644
--- a/finch/gntpounce.c
+++ b/finch/gntpounce.c
@@ -288,7 +288,7 @@ finch_pounce_editor_show(PurpleAccount *account, const char *name,
GntWidget *hbox, *vbox;
GntWidget *button;
GntWidget *combo;
- GList *list;
+ const GList *list;
g_return_if_fail((cur_pounce != NULL) ||
(account != NULL) ||
@@ -303,7 +303,7 @@ finch_pounce_editor_show(PurpleAccount *account, const char *name,
dialog->pounce = NULL;
dialog->account = account;
} else {
- GList *connections = purple_connections_get_all();
+ const GList *connections = purple_connections_get_all();
PurpleConnection *gc;
if (connections != NULL) {
diff --git a/finch/gntrequest.c b/finch/gntrequest.c
index a0e0db0942..4971be7c4c 100644
--- a/finch/gntrequest.c
+++ b/finch/gntrequest.c
@@ -490,7 +490,7 @@ finch_request_fields(const char *title, const char *primary,
{
gboolean all;
PurpleAccount *def;
- GList *list;
+ const GList *list;
GntWidget *combo = gnt_combo_box_new();
gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
gnt_box_add_widget(GNT_BOX(hbox), combo);
diff --git a/finch/gntstatus.c b/finch/gntstatus.c
index e423727428..753c1cffce 100644
--- a/finch/gntstatus.c
+++ b/finch/gntstatus.c
@@ -497,7 +497,7 @@ void finch_savedstatus_edit(PurpleSavedStatus *saved)
GntWidget *window, *box, *button, *entry, *combo, *label, *tree;
PurpleStatusPrimitive prims[] = {PURPLE_STATUS_AVAILABLE, PURPLE_STATUS_AWAY,
PURPLE_STATUS_INVISIBLE, PURPLE_STATUS_OFFLINE, PURPLE_STATUS_UNSET}, current;
- GList *iter;
+ const GList *iter;
int i;
if (saved)
diff --git a/finch/libgnt/Makefile.am b/finch/libgnt/Makefile.am
index e948357b08..3079a4148d 100644
--- a/finch/libgnt/Makefile.am
+++ b/finch/libgnt/Makefile.am
@@ -32,6 +32,7 @@ libgnt_la_SOURCES = \
gntutils.c \
gntwindow.c \
gntwm.c \
+ gntws.c \
gntmain.c
libgnt_la_headers = \
@@ -58,6 +59,7 @@ libgnt_la_headers = \
gntutils.h \
gntwindow.h \
gntwm.h \
+ gntws.h \
gnt.h
CLEANFILES = \
diff --git a/finch/libgnt/configure.ac b/finch/libgnt/configure.ac
index eeae6acbdb..7fa570f703 100644
--- a/finch/libgnt/configure.ac
+++ b/finch/libgnt/configure.ac
@@ -24,11 +24,11 @@ AC_PREREQ([2.50])
# Make sure to update ../../configure.ac with libgnt version changes.
#
-m4_define([gnt_lt_current], [0])
-m4_define([gnt_major_version], [1])
+m4_define([gnt_lt_current], [1])
+m4_define([gnt_major_version], [2])
m4_define([gnt_minor_version], [0])
m4_define([gnt_micro_version], [0])
-m4_define([gnt_version_suffix], [beta7])
+m4_define([gnt_version_suffix], [devel])
m4_define([gnt_version],
[gnt_major_version.gnt_minor_version.gnt_micro_version])
m4_define([gnt_display_version], gnt_version[]m4_ifdef([gnt_version_suffix],[gnt_version_suffix]))
diff --git a/finch/libgnt/gnt-skel.c b/finch/libgnt/gnt-skel.c
index 7a208d6a7e..66e790e957 100644
--- a/finch/libgnt/gnt-skel.c
+++ b/finch/libgnt/gnt-skel.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gnt-skel.h"
enum
diff --git a/finch/libgnt/gnt-skel.h b/finch/libgnt/gnt-skel.h
index 5809f4b472..f41ceb2312 100644
--- a/finch/libgnt/gnt-skel.h
+++ b/finch/libgnt/gnt-skel.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_SKEL_H
#define GNT_SKEL_H
@@ -38,9 +60,19 @@ struct _GntSkelClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_skel_get_gtype(void);
-GntWidget *gnt_skel_new();
+/**
+ *
+ *
+ * @return
+ */
+GntWidget * gnt_skel_new();
G_END_DECLS
diff --git a/finch/libgnt/gnt.h b/finch/libgnt/gnt.h
index cc1a11fbad..16b4f02049 100644
--- a/finch/libgnt/gnt.h
+++ b/finch/libgnt/gnt.h
@@ -1,39 +1,141 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include <glib.h>
#include "gntwidget.h"
#include "gntclipboard.h"
#include "gntcolors.h"
#include "gntkeys.h"
+/**
+ *
+ */
void gnt_init(void);
+/**
+ *
+ */
void gnt_main(void);
+/**
+ *
+ *
+ * @return
+ */
gboolean gnt_ascii_only(void);
+void gnt_window_present(GntWidget *window);
+/**
+ *
+ * @param widget
+ */
void gnt_screen_occupy(GntWidget *widget);
+/**
+ *
+ * @param widget
+ */
void gnt_screen_release(GntWidget *widget);
+/**
+ *
+ * @param widget
+ */
void gnt_screen_update(GntWidget *widget);
+/**
+ *
+ * @param widget
+ * @param width
+ * @param height
+ */
void gnt_screen_resize_widget(GntWidget *widget, int width, int height);
+/**
+ *
+ * @param widget
+ * @param x
+ * @param y
+ */
void gnt_screen_move_widget(GntWidget *widget, int x, int y);
+/**
+ *
+ * @param widget
+ * @param text
+ */
void gnt_screen_rename_widget(GntWidget *widget, const char *text);
+/**
+ *
+ * @param widget
+ *
+ * @return
+ */
gboolean gnt_widget_has_focus(GntWidget *widget);
+/**
+ *
+ * @param widget
+ */
void gnt_widget_set_urgent(GntWidget *widget);
+/**
+ *
+ * @param label
+ * @param callback)()
+ */
void gnt_register_action(const char *label, void (*callback)());
+/**
+ *
+ * @param menu
+ *
+ * @return
+ */
gboolean gnt_screen_menu_show(gpointer menu);
+/**
+ *
+ */
void gnt_quit(void);
-GntClipboard *gnt_get_clipboard(void);
-
-gchar *gnt_get_clipboard_string(void);
-
+/**
+ *
+ *
+ * @return
+ */
+GntClipboard * gnt_get_clipboard(void);
+
+/**
+ *
+ *
+ * @return
+ */
+gchar * gnt_get_clipboard_string(void);
+
+/**
+ *
+ * @param string
+ */
void gnt_set_clipboard_string(gchar *string);
+
diff --git a/finch/libgnt/gntbindable.c b/finch/libgnt/gntbindable.c
index 3dfda6ab39..374fa5ffd1 100644
--- a/finch/libgnt/gntbindable.c
+++ b/finch/libgnt/gntbindable.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntbindable.h"
#include "gntstyle.h"
#include "gnt.h"
diff --git a/finch/libgnt/gntbindable.h b/finch/libgnt/gntbindable.h
index 17b143363f..6fc0f4e908 100644
--- a/finch/libgnt/gntbindable.h
+++ b/finch/libgnt/gntbindable.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_BINDABLE_H
#define GNT_BINDABLE_H
@@ -39,6 +61,11 @@ struct _GntBindableClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_bindable_get_gtype(void);
/******************/
@@ -70,18 +97,53 @@ struct _GntBindableActionParam
GList *list;
};
-
/*GntBindableAction *gnt_bindable_action_parse(const char *name);*/
+/**
+ *
+ * @param action
+ */
void gnt_bindable_action_free(GntBindableAction *action);
-void gnt_bindable_action_param_free(GntBindableActionParam *param);
-void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name,
- GntBindableActionCallback callback, const char *trigger, ...);
-void gnt_bindable_register_binding(GntBindableClass *klass, const char *name,
- const char *trigger, ...);
+/**
+ *
+ * @param param
+ */
+void gnt_bindable_action_param_free(GntBindableActionParam *param);
+/**
+ *
+ * @param klass
+ * @param name
+ * @param callback
+ * @param trigger
+ */
+void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name, GntBindableActionCallback callback, const char *trigger, ...);
+
+/**
+ *
+ * @param klass
+ * @param name
+ * @param trigger
+ */
+void gnt_bindable_register_binding(GntBindableClass *klass, const char *name, const char *trigger, ...);
+
+/**
+ *
+ * @param bindable
+ * @param keys
+ *
+ * @return
+ */
gboolean gnt_bindable_perform_action_key(GntBindable *bindable, const char *keys);
+
+/**
+ *
+ * @param bindable
+ * @param name
+ *
+ * @return
+ */
gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...);
G_END_DECLS
diff --git a/finch/libgnt/gntbox.c b/finch/libgnt/gntbox.c
index db78c806ad..902db3fa23 100644
--- a/finch/libgnt/gntbox.c
+++ b/finch/libgnt/gntbox.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntbox.h"
#include "gntutils.h"
@@ -293,6 +315,10 @@ gnt_box_key_pressed(GntWidget *widget, const char *text)
{
find_next_focus(box);
}
+ else if (strcmp(text, GNT_KEY_BACK_TAB) == 0)
+ {
+ find_prev_focus(box);
+ }
}
else if (text[0] == '\t')
{
diff --git a/finch/libgnt/gntbox.h b/finch/libgnt/gntbox.h
index 15beb79534..13cc146100 100644
--- a/finch/libgnt/gntbox.h
+++ b/finch/libgnt/gntbox.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_BOX_H
#define GNT_BOX_H
@@ -61,35 +83,110 @@ struct _GntBoxClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_box_get_gtype(void);
#define gnt_vbox_new(homo) gnt_box_new(homo, TRUE)
#define gnt_hbox_new(homo) gnt_box_new(homo, FALSE)
-GntWidget *gnt_box_new(gboolean homo, gboolean vert);
-
+/**
+ *
+ * @param homo
+ * @param vert
+ *
+ * @return
+ */
+GntWidget * gnt_box_new(gboolean homo, gboolean vert);
+
+/**
+ *
+ * @param box
+ * @param widget
+ */
void gnt_box_add_widget(GntBox *box, GntWidget *widget);
+/**
+ *
+ * @param box
+ * @param title
+ */
void gnt_box_set_title(GntBox *box, const char *title);
+/**
+ *
+ * @param box
+ * @param pad
+ */
void gnt_box_set_pad(GntBox *box, int pad);
+/**
+ *
+ * @param box
+ * @param set
+ */
void gnt_box_set_toplevel(GntBox *box, gboolean set);
+/**
+ *
+ * @param box
+ */
void gnt_box_sync_children(GntBox *box);
+/**
+ *
+ * @param box
+ * @param alignment
+ */
void gnt_box_set_alignment(GntBox *box, GntAlignment alignment);
-void gnt_box_remove(GntBox *box, GntWidget *widget); /* XXX: does NOT destroy widget */
+/**
+ *
+ * @param box
+ * @param widget
+ */
+void gnt_box_remove(GntBox *box, GntWidget *widget);
+
+ /* XXX: does NOT destroy widget */
-void gnt_box_remove_all(GntBox *box); /* Removes AND destroys all the widgets in it */
+/**
+ *
+ * @param box
+ */
+void gnt_box_remove_all(GntBox *box);
+ /* Removes AND destroys all the widgets in it */
+
+/**
+ *
+ * @param box
+ */
void gnt_box_readjust(GntBox *box);
+/**
+ *
+ * @param box
+ * @param fill
+ */
void gnt_box_set_fill(GntBox *box, gboolean fill);
-void gnt_box_move_focus(GntBox *box, int dir); /* +1 to move forward, -1 for backward */
+/**
+ *
+ * @param box
+ * @param dir
+ */
+void gnt_box_move_focus(GntBox *box, int dir);
+
+ /* +1 to move forward, -1 for backward */
+/**
+ *
+ * @param box
+ * @param widget
+ */
void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget);
G_END_DECLS
diff --git a/finch/libgnt/gntbutton.c b/finch/libgnt/gntbutton.c
index 1683818e8f..f4e6f5bfd1 100644
--- a/finch/libgnt/gntbutton.c
+++ b/finch/libgnt/gntbutton.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include <string.h>
#include "gntbutton.h"
diff --git a/finch/libgnt/gntbutton.h b/finch/libgnt/gntbutton.h
index 0088ef8d41..d8fe87856c 100644
--- a/finch/libgnt/gntbutton.h
+++ b/finch/libgnt/gntbutton.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_BUTTON_H
#define GNT_BUTTON_H
@@ -46,9 +68,20 @@ struct _GntButtonClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_button_get_gtype(void);
-GntWidget *gnt_button_new(const char *text);
+/**
+ *
+ * @param text
+ *
+ * @return
+ */
+GntWidget * gnt_button_new(const char *text);
G_END_DECLS
diff --git a/finch/libgnt/gntcheckbox.c b/finch/libgnt/gntcheckbox.c
index e43b967767..893ce099ea 100644
--- a/finch/libgnt/gntcheckbox.c
+++ b/finch/libgnt/gntcheckbox.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntcheckbox.h"
enum
diff --git a/finch/libgnt/gntcheckbox.h b/finch/libgnt/gntcheckbox.h
index db72b0ddaf..12ca8c2650 100644
--- a/finch/libgnt/gntcheckbox.h
+++ b/finch/libgnt/gntcheckbox.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_CHECK_BOX_H
#define GNT_CHECK_BOX_H
@@ -41,12 +63,34 @@ struct _GntCheckBoxClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_check_box_get_gtype(void);
-GntWidget *gnt_check_box_new(const char *text);
+/**
+ *
+ * @param text
+ *
+ * @return
+ */
+GntWidget * gnt_check_box_new(const char *text);
+/**
+ *
+ * @param box
+ * @param set
+ */
void gnt_check_box_set_checked(GntCheckBox *box, gboolean set);
+/**
+ *
+ * @param box
+ *
+ * @return
+ */
gboolean gnt_check_box_get_checked(GntCheckBox *box);
G_END_DECLS
diff --git a/finch/libgnt/gntclipboard.c b/finch/libgnt/gntclipboard.c
index 04c2399ca4..fc6d6d5194 100644
--- a/finch/libgnt/gntclipboard.c
+++ b/finch/libgnt/gntclipboard.c
@@ -1,6 +1,26 @@
-#include "gntclipboard.h"
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
-gchar *string;
+#include "gntclipboard.h"
enum {
SIG_CLIPBOARD = 0,
diff --git a/finch/libgnt/gntclipboard.h b/finch/libgnt/gntclipboard.h
index 7670bc8161..e143185cfb 100644
--- a/finch/libgnt/gntclipboard.h
+++ b/finch/libgnt/gntclipboard.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_CLIPBOARD_H
#define GNT_CLIPBOARD_H
@@ -33,10 +55,26 @@ struct _GntClipboardClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_clipboard_get_gtype(void);
-gchar *gnt_clipboard_get_string(GntClipboard *clip);
+/**
+ *
+ * @param clip
+ *
+ * @return
+ */
+gchar * gnt_clipboard_get_string(GntClipboard *clip);
+/**
+ *
+ * @param clip
+ * @param string
+ */
void gnt_clipboard_set_string(GntClipboard *clip, gchar *string);
G_END_DECLS
diff --git a/finch/libgnt/gntcolors.c b/finch/libgnt/gntcolors.c
index fa4a082fa8..acc50390f0 100644
--- a/finch/libgnt/gntcolors.c
+++ b/finch/libgnt/gntcolors.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "config.h"
#include <ncurses.h>
diff --git a/finch/libgnt/gntcolors.h b/finch/libgnt/gntcolors.h
index d69bde4fe3..a17ad5e3a0 100644
--- a/finch/libgnt/gntcolors.h
+++ b/finch/libgnt/gntcolors.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_COLORS_H
#define GNT_COLORS_H
@@ -33,14 +55,29 @@ enum
};
/* populate some default colors */
+/**
+ *
+ */
void gnt_init_colors(void);
+/**
+ *
+ */
void gnt_uninit_colors(void);
#if GLIB_CHECK_VERSION(2,6,0)
+/**
+ *
+ * @param kfile
+ */
void gnt_colors_parse(GKeyFile *kfile);
+/**
+ *
+ * @param kfile
+ */
void gnt_color_pairs_parse(GKeyFile *kfile);
+
#endif
#endif
diff --git a/finch/libgnt/gntcombobox.c b/finch/libgnt/gntcombobox.c
index b1fcadb9d3..7e71dca932 100644
--- a/finch/libgnt/gntcombobox.c
+++ b/finch/libgnt/gntcombobox.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntbox.h"
#include "gntcombobox.h"
#include "gnttree.h"
diff --git a/finch/libgnt/gntcombobox.h b/finch/libgnt/gntcombobox.h
index ac5991d0d0..3c641d5480 100644
--- a/finch/libgnt/gntcombobox.h
+++ b/finch/libgnt/gntcombobox.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_COMBO_BOX_H
#define GNT_COMBO_BOX_H
@@ -42,18 +64,54 @@ struct _GntComboBoxClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_combo_box_get_gtype(void);
-GntWidget *gnt_combo_box_new(void);
-
+/**
+ *
+ *
+ * @return
+ */
+GntWidget * gnt_combo_box_new(void);
+
+/**
+ *
+ * @param box
+ * @param key
+ * @param text
+ */
void gnt_combo_box_add_data(GntComboBox *box, gpointer key, const char *text);
+/**
+ *
+ * @param box
+ * @param key
+ */
void gnt_combo_box_remove(GntComboBox *box, gpointer key);
+/**
+ *
+ * @param box
+ */
void gnt_combo_box_remove_all(GntComboBox *box);
+/**
+ *
+ * @param box
+ *
+ * @return
+ */
gpointer gnt_combo_box_get_selected_data(GntComboBox *box);
+/**
+ *
+ * @param box
+ * @param key
+ */
void gnt_combo_box_set_selected(GntComboBox *box, gpointer key);
G_END_DECLS
diff --git a/finch/libgnt/gntentry.c b/finch/libgnt/gntentry.c
index 73c0fcd543..ebcc230ffa 100644
--- a/finch/libgnt/gntentry.c
+++ b/finch/libgnt/gntentry.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include <ctype.h>
#include <string.h>
diff --git a/finch/libgnt/gntentry.h b/finch/libgnt/gntentry.h
index 461a156780..58460c8306 100644
--- a/finch/libgnt/gntentry.h
+++ b/finch/libgnt/gntentry.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_ENTRY_H
#define GNT_ENTRY_H
@@ -73,32 +95,97 @@ struct _GntEntryClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_entry_get_gtype(void);
-GntWidget *gnt_entry_new(const char *text);
-
+/**
+ *
+ * @param text
+ *
+ * @return
+ */
+GntWidget * gnt_entry_new(const char *text);
+
+/**
+ *
+ * @param entry
+ * @param max
+ */
void gnt_entry_set_max(GntEntry *entry, int max);
+/**
+ *
+ * @param entry
+ * @param text
+ */
void gnt_entry_set_text(GntEntry *entry, const char *text);
+/**
+ *
+ * @param entry
+ * @param flag
+ */
void gnt_entry_set_flag(GntEntry *entry, GntEntryFlag flag);
const char *gnt_entry_get_text(GntEntry *entry);
+/**
+ *
+ * @param entry
+ */
void gnt_entry_clear(GntEntry *entry);
+/**
+ *
+ * @param entry
+ * @param set
+ */
void gnt_entry_set_masked(GntEntry *entry, gboolean set);
+/**
+ *
+ * @param entry
+ * @param text
+ */
void gnt_entry_add_to_history(GntEntry *entry, const char *text);
+/**
+ *
+ * @param entry
+ * @param num
+ */
void gnt_entry_set_history_length(GntEntry *entry, int num);
+/**
+ *
+ * @param entry
+ * @param word
+ */
void gnt_entry_set_word_suggest(GntEntry *entry, gboolean word);
+/**
+ *
+ * @param entry
+ * @param always
+ */
void gnt_entry_set_always_suggest(GntEntry *entry, gboolean always);
+/**
+ *
+ * @param entry
+ * @param text
+ */
void gnt_entry_add_suggest(GntEntry *entry, const char *text);
+/**
+ *
+ * @param entry
+ * @param text
+ */
void gnt_entry_remove_suggest(GntEntry *entry, const char *text);
G_END_DECLS
diff --git a/finch/libgnt/gntfilesel.c b/finch/libgnt/gntfilesel.c
index 0f325f8b1a..a1601c904d 100644
--- a/finch/libgnt/gntfilesel.c
+++ b/finch/libgnt/gntfilesel.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntbutton.h"
#include "gntentry.h"
#include "gntfilesel.h"
diff --git a/finch/libgnt/gntfilesel.h b/finch/libgnt/gntfilesel.h
index 2a07dfa1e3..5d12aa1366 100644
--- a/finch/libgnt/gntfilesel.h
+++ b/finch/libgnt/gntfilesel.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_FILE_SEL_H
#define GNT_FILE_SEL_H
@@ -71,32 +93,115 @@ struct _GntFile
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_file_sel_get_gtype(void);
-GntWidget *gnt_file_sel_new(void);
-
+/**
+ *
+ *
+ * @return
+ */
+GntWidget * gnt_file_sel_new(void);
+
+/**
+ *
+ * @param sel
+ * @param path
+ *
+ * @return
+ */
gboolean gnt_file_sel_set_current_location(GntFileSel *sel, const char *path);
+/**
+ *
+ * @param sel
+ * @param dirs
+ */
void gnt_file_sel_set_dirs_only(GntFileSel *sel, gboolean dirs);
+/**
+ *
+ * @param sel
+ *
+ * @return
+ */
gboolean gnt_file_sel_get_dirs_only(GntFileSel *sel);
+/**
+ *
+ * @param sel
+ * @param must
+ */
void gnt_file_sel_set_must_exist(GntFileSel *sel, gboolean must);
+/**
+ *
+ * @param sel
+ *
+ * @return
+ */
gboolean gnt_file_sel_get_must_exist(GntFileSel *sel);
-char *gnt_file_sel_get_selected_file(GntFileSel *sel); /* The returned value should be free'd */
-
-GList *gnt_file_sel_get_selected_multi_files(GntFileSel *sel);
-
+/**
+ *
+ * @param sel
+ *
+ * @return
+ */
+char * gnt_file_sel_get_selected_file(GntFileSel *sel);
+
+ /* The returned value should be free'd */
+
+/**
+ *
+ * @param sel
+ *
+ * @return
+ */
+GList * gnt_file_sel_get_selected_multi_files(GntFileSel *sel);
+
+/**
+ *
+ * @param sel
+ * @param set
+ */
void gnt_file_sel_set_multi_select(GntFileSel *sel, gboolean set);
+/**
+ *
+ * @param sel
+ * @param suggest
+ */
void gnt_file_sel_set_suggested_filename(GntFileSel *sel, const char *suggest);
+/**
+ *
+ * @param sel
+ * @param path
+ * @param files
+ * @param error)
+ */
void gnt_file_sel_set_read_fn(GntFileSel *sel, gboolean (*read_fn)(const char *path, GList **files, GError **error));
+/**
+ *
+ * @param name
+ * @param size
+ *
+ * @return
+ */
GntFile* gnt_file_new(const char *name, unsigned long size);
+/**
+ *
+ * @param name
+ *
+ * @return
+ */
GntFile* gnt_file_new_dir(const char *name);
G_END_DECLS
diff --git a/finch/libgnt/gntkeys.c b/finch/libgnt/gntkeys.c
index 59527af99d..d87eb5c7a6 100644
--- a/finch/libgnt/gntkeys.c
+++ b/finch/libgnt/gntkeys.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntkeys.h"
#include <glib.h>
@@ -50,6 +72,7 @@ void gnt_init_keys()
INSERT_KEY("pagedown", GNT_KEY_PGDOWN);
INSERT_KEY("insert", GNT_KEY_INS);
INSERT_KEY("delete", GNT_KEY_DEL);
+ INSERT_KEY("back_tab", GNT_KEY_BACK_TAB);
INSERT_KEY("left", GNT_KEY_LEFT);
INSERT_KEY("right", GNT_KEY_RIGHT);
@@ -183,8 +206,8 @@ static void add_path(struct _node *node, const char *path)
node->flags |= IS_END;
return;
}
- while (*path && node->next[*path]) {
- node = node->next[*path];
+ while (*path && node->next[(unsigned char)*path]) {
+ node = node->next[(unsigned char)*path];
node->ref++;
path++;
}
@@ -192,7 +215,7 @@ static void add_path(struct _node *node, const char *path)
return;
n = g_new0(struct _node, 1);
n->ref = 1;
- node->next[*path++] = n;
+ node->next[(unsigned char)*path++] = n;
add_path(n, path);
}
@@ -207,13 +230,13 @@ static void del_path(struct _node *node, const char *path)
if (!*path)
return;
- next = node->next[*path];
+ next = node->next[(unsigned char)*path];
if (!next)
return;
del_path(next, path + 1);
next->ref--;
if (next->ref == 0) {
- node->next[*path] = NULL;
+ node->next[(unsigned char)*path] = NULL;
g_free(next);
}
}
@@ -229,12 +252,12 @@ int gnt_keys_find_combination(const char *path)
struct _node *n = &root;
root.flags &= ~IS_END;
- while (*path && n->next[*path] && !(n->flags & IS_END)) {
+ while (*path && n->next[(unsigned char)*path] && !(n->flags & IS_END)) {
if (!g_ascii_isspace(*path) &&
!g_ascii_iscntrl(*path) &&
!g_ascii_isgraph(*path))
return 0;
- n = n->next[*path++];
+ n = n->next[(unsigned char)*path++];
depth++;
}
diff --git a/finch/libgnt/gntkeys.h b/finch/libgnt/gntkeys.h
index 0adcaef411..190f69a287 100644
--- a/finch/libgnt/gntkeys.h
+++ b/finch/libgnt/gntkeys.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_KEYS_H
#define GNT_KEYS_H
@@ -39,6 +61,7 @@ extern char *gnt_key_cright;
#define GNT_KEY_BACKSPACE SAFE(key_backspace)
#define GNT_KEY_DEL SAFE(key_dc)
#define GNT_KEY_INS SAFE(key_ic)
+#define GNT_KEY_BACK_TAB SAFE(back_tab)
#define GNT_KEY_CTRL_A "\001"
#define GNT_KEY_CTRL_B "\002"
@@ -79,15 +102,39 @@ extern char *gnt_key_cright;
/**
* This will do stuff with the terminal settings and stuff.
*/
+/**
+ *
+ */
void gnt_init_keys(void);
+
+/**
+ *
+ * @param text
+ */
void gnt_keys_refine(char *text);
+
const char *gnt_key_translate(const char *name);
const char *gnt_key_lookup(const char *key);
+/**
+ *
+ * @param path
+ */
void gnt_keys_add_combination(const char *path);
+
+/**
+ *
+ * @param path
+ */
void gnt_keys_del_combination(const char *path);
-int gnt_keys_find_combination(const char *path);
+/**
+ *
+ * @param path
+ *
+ * @return
+ */
+int gnt_keys_find_combination(const char *path);
/* A lot of commonly used variable names are defined in <term.h>.
* #undef them to make life easier for everyone. */
diff --git a/finch/libgnt/gntlabel.c b/finch/libgnt/gntlabel.c
index a8a0a5474e..85e224dc65 100644
--- a/finch/libgnt/gntlabel.c
+++ b/finch/libgnt/gntlabel.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntlabel.h"
#include "gntutils.h"
diff --git a/finch/libgnt/gntlabel.h b/finch/libgnt/gntlabel.h
index 3b5c51cf98..226f7ba734 100644
--- a/finch/libgnt/gntlabel.h
+++ b/finch/libgnt/gntlabel.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_LABEL_H
#define GNT_LABEL_H
@@ -40,12 +62,35 @@ struct _GntLabelClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_label_get_gtype(void);
-GntWidget *gnt_label_new(const char *text);
-
-GntWidget *gnt_label_new_with_format(const char *text, GntTextFormatFlags flags);
-
+/**
+ *
+ * @param text
+ *
+ * @return
+ */
+GntWidget * gnt_label_new(const char *text);
+
+/**
+ *
+ * @param text
+ * @param flags
+ *
+ * @return
+ */
+GntWidget * gnt_label_new_with_format(const char *text, GntTextFormatFlags flags);
+
+/**
+ *
+ * @param label
+ * @param text
+ */
void gnt_label_set_text(GntLabel *label, const char *text);
G_END_DECLS
diff --git a/finch/libgnt/gntline.c b/finch/libgnt/gntline.c
index af5c461349..d2d079b043 100644
--- a/finch/libgnt/gntline.c
+++ b/finch/libgnt/gntline.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntline.h"
enum
diff --git a/finch/libgnt/gntline.h b/finch/libgnt/gntline.h
index 18dce54e5d..a2eafd28c7 100644
--- a/finch/libgnt/gntline.h
+++ b/finch/libgnt/gntline.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_LINE_H
#define GNT_LINE_H
@@ -40,12 +62,23 @@ struct _GntLineClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_line_get_gtype(void);
#define gnt_hline_new() gnt_line_new(FALSE)
#define gnt_vline_new() gnt_line_new(TRUE)
-GntWidget *gnt_line_new(gboolean vertical);
+/**
+ *
+ * @param vertical
+ *
+ * @return
+ */
+GntWidget * gnt_line_new(gboolean vertical);
G_END_DECLS
diff --git a/finch/libgnt/gntmain.c b/finch/libgnt/gntmain.c
index 9c3b13bc9e..bc49ecb9cd 100644
--- a/finch/libgnt/gntmain.c
+++ b/finch/libgnt/gntmain.c
@@ -1,5 +1,27 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#define _GNU_SOURCE
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__unix__)
#define _XOPEN_SOURCE_EXTENDED
#endif
@@ -51,7 +73,7 @@ static void setup_io(void);
static gboolean refresh_screen();
-GntWM *wm;
+static GntWM *wm;
static GntClipboard *clipboard;
#define HOLDING_ESCAPE (escape_stuff.timer != 0)
@@ -94,7 +116,7 @@ detect_mouse_action(const char *buffer)
GntWidget *widget = NULL;
PANEL *p = NULL;
- if (!wm->ordered || buffer[0] != 27)
+ if (!wm->cws->ordered || buffer[0] != 27)
return FALSE;
buffer++;
@@ -150,7 +172,7 @@ detect_mouse_action(const char *buffer)
if (event == GNT_LEFT_MOUSE_DOWN && widget && widget != wm->_list.window &&
!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) {
- if (widget != wm->ordered->data) {
+ if (widget != wm->cws->ordered->data) {
gnt_wm_raise_window(wm, widget);
}
if (y == widget->priv.y) {
@@ -161,7 +183,7 @@ detect_mouse_action(const char *buffer)
} else if (event == GNT_MOUSE_UP) {
if (button == MOUSE_NONE && y == getmaxy(stdscr) - 1) {
/* Clicked on the taskbar */
- int n = g_list_length(wm->list);
+ int n = g_list_length(wm->cws->list);
if (n) {
int width = getmaxx(stdscr) / n;
gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "switch-window-n", x/width, NULL);
@@ -359,8 +381,7 @@ sighandler(int sig)
switch (sig) {
#ifdef SIGWINCH
case SIGWINCH:
- werase(stdscr);
- wrefresh(stdscr);
+ erase();
g_idle_add(refresh_screen, NULL);
org_winch_handler(sig);
signal(SIGWINCH, sighandler);
@@ -463,6 +484,10 @@ void gnt_main()
* Stuff for 'window management' *
*********************************/
+void gnt_window_present(GntWidget *window) {
+ gnt_wm_raise_window(wm, window);
+}
+
void gnt_screen_occupy(GntWidget *widget)
{
gnt_wm_new_window(wm, widget);
@@ -494,7 +519,7 @@ gboolean gnt_widget_has_focus(GntWidget *widget)
if (widget == wm->_list.window)
return TRUE;
- if (wm->ordered && wm->ordered->data == widget) {
+ if (wm->cws->ordered && wm->cws->ordered->data == widget) {
if (GNT_IS_BOX(widget) &&
(GNT_BOX(widget)->active == w || widget == w))
return TRUE;
@@ -507,7 +532,7 @@ void gnt_widget_set_urgent(GntWidget *widget)
while (widget->parent)
widget = widget->parent;
- if (wm->ordered && wm->ordered->data == widget)
+ if (wm->cws->ordered && wm->cws->ordered->data == widget)
return;
GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_URGENT);
diff --git a/finch/libgnt/gntmenu.c b/finch/libgnt/gntmenu.c
index d418555b84..f8b5b5024e 100644
--- a/finch/libgnt/gntmenu.c
+++ b/finch/libgnt/gntmenu.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntmenu.h"
#include "gntmenuitemcheck.h"
@@ -220,7 +242,10 @@ gnt_menu_activate(GntWidget *widget)
static void
gnt_menu_hide(GntWidget *widget)
{
- GntMenu *menu = GNT_MENU(widget);
+ GntMenu *sub, *menu = GNT_MENU(widget);
+
+ while ((sub = menu->submenu))
+ gnt_widget_hide(GNT_WIDGET(sub));
if (menu->parentmenu)
menu->parentmenu->submenu = NULL;
}
diff --git a/finch/libgnt/gntmenu.h b/finch/libgnt/gntmenu.h
index 91fa9ab174..490a64e303 100644
--- a/finch/libgnt/gntmenu.h
+++ b/finch/libgnt/gntmenu.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_MENU_H
#define GNT_MENU_H
@@ -59,10 +81,26 @@ struct _GntMenuClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_menu_get_gtype(void);
-GntWidget *gnt_menu_new(GntMenuType type);
+/**
+ *
+ * @param type
+ *
+ * @return
+ */
+GntWidget * gnt_menu_new(GntMenuType type);
+/**
+ *
+ * @param menu
+ * @param item
+ */
void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item);
G_END_DECLS
diff --git a/finch/libgnt/gntmenuitem.c b/finch/libgnt/gntmenuitem.c
index a5cc2120a5..7e00c751ce 100644
--- a/finch/libgnt/gntmenuitem.c
+++ b/finch/libgnt/gntmenuitem.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntmenu.h"
#include "gntmenuitem.h"
diff --git a/finch/libgnt/gntmenuitem.h b/finch/libgnt/gntmenuitem.h
index f6820de370..397021bec5 100644
--- a/finch/libgnt/gntmenuitem.h
+++ b/finch/libgnt/gntmenuitem.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_MENUITEM_H
#define GNT_MENUITEM_H
@@ -58,12 +80,34 @@ struct _GntMenuItemClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_menuitem_get_gtype(void);
-GntMenuItem *gnt_menuitem_new(const char *text);
-
+/**
+ *
+ * @param text
+ *
+ * @return
+ */
+GntMenuItem * gnt_menuitem_new(const char *text);
+
+/**
+ *
+ * @param item
+ * @param callback
+ * @param data
+ */
void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data);
+/**
+ *
+ * @param item
+ * @param menu
+ */
void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu);
G_END_DECLS
diff --git a/finch/libgnt/gntmenuitemcheck.c b/finch/libgnt/gntmenuitemcheck.c
index 84e3154be7..9d026b3f13 100644
--- a/finch/libgnt/gntmenuitemcheck.c
+++ b/finch/libgnt/gntmenuitemcheck.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntmenuitemcheck.h"
static GntMenuItemClass *parent_class = NULL;
diff --git a/finch/libgnt/gntmenuitemcheck.h b/finch/libgnt/gntmenuitemcheck.h
index 021d92337a..4ef771d264 100644
--- a/finch/libgnt/gntmenuitemcheck.h
+++ b/finch/libgnt/gntmenuitemcheck.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_MENU_ITEM_CHECK_H
#define GNT_MENU_ITEM_CHECK_H
@@ -39,12 +61,34 @@ struct _GntMenuItemCheckClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_menuitem_check_get_gtype(void);
-GntMenuItem *gnt_menuitem_check_new(const char *text);
+/**
+ *
+ * @param text
+ *
+ * @return
+ */
+GntMenuItem * gnt_menuitem_check_new(const char *text);
+/**
+ *
+ * @param item
+ *
+ * @return
+ */
gboolean gnt_menuitem_check_get_checked(GntMenuItemCheck *item);
+/**
+ *
+ * @param item
+ * @param set
+ */
void gnt_menuitem_check_set_checked(GntMenuItemCheck *item, gboolean set);
G_END_DECLS
diff --git a/finch/libgnt/gntstyle.c b/finch/libgnt/gntstyle.c
index bbe5db52ae..c8555bb553 100644
--- a/finch/libgnt/gntstyle.c
+++ b/finch/libgnt/gntstyle.c
@@ -1,13 +1,42 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntstyle.h"
#include "gntcolors.h"
+#include "gntws.h"
+#include <glib.h>
#include <ctype.h>
+#include <glib/gprintf.h>
+#include <stdlib.h>
#include <string.h>
+#define MAX_WORKSPACES 99
+
#if GLIB_CHECK_VERSION(2,6,0)
static GKeyFile *gkfile;
#endif
+static GHashTable *unknowns;
static char * str_styles[GNT_STYLES];
static int int_styles[GNT_STYLES];
static int bool_styles[GNT_STYLES];
@@ -17,6 +46,11 @@ const char *gnt_style_get(GntStyle style)
return str_styles[style];
}
+const char *gnt_style_get_from_name(const char *name)
+{
+ return g_hash_table_lookup(unknowns, name);
+}
+
gboolean gnt_style_get_bool(GntStyle style, gboolean def)
{
int i;
@@ -87,6 +121,44 @@ parse_key(const char *key)
return (char *)gnt_key_translate(key);
}
+void gnt_style_read_workspaces(GntWM *wm)
+{
+#if GLIB_CHECK_VERSION(2,6,0)
+ int i;
+ gchar *name;
+ gsize c;
+
+ for (i = 1; i < MAX_WORKSPACES; ++i) {
+ int j;
+ GntWS *ws;
+ gchar **titles;
+ char *group = calloc(12, 1);
+ g_sprintf(group, "Workspace-%d", i);
+ name = g_key_file_get_value(gkfile, group, "name", NULL);
+ if (!name)
+ return;
+
+ ws = gnt_ws_new(name);
+ gnt_wm_add_workspace(wm, ws);
+ g_free(name);
+
+ titles = g_key_file_get_string_list(gkfile, group, "window-names", &c, NULL);
+ if (titles) {
+ for (j = 0; j < c; ++j)
+ g_hash_table_replace(wm->name_places, g_strdup(titles[j]), ws);
+ g_strfreev(titles);
+ }
+
+ titles = g_key_file_get_string_list(gkfile, group, "window-titles", &c, NULL);
+ if (titles) {
+ for (j = 0; j < c; ++j)
+ g_hash_table_replace(wm->title_places, g_strdup(titles[j]), ws);
+ g_strfreev(titles);
+ }
+ g_free(group);
+ }
+#endif
+}
void gnt_style_read_actions(GType type, GntBindableClass *klass)
{
#if GLIB_CHECK_VERSION(2,6,0)
@@ -221,6 +293,10 @@ read_general_style(GKeyFile *kfile)
str_styles[styles[i].en] =
g_key_file_get_string(kfile, "general", styles[i].style, NULL);
}
+
+ for (i = 0; i < nkeys; i++)
+ g_hash_table_replace(unknowns, g_strdup(keys[i]),
+ g_strdup(g_key_file_get_string(kfile, "general", keys[i], NULL)));
}
g_strfreev(keys);
}
@@ -231,6 +307,7 @@ void gnt_style_read_configure_file(const char *filename)
#if GLIB_CHECK_VERSION(2,6,0)
GError *error = NULL;
gkfile = g_key_file_new();
+ unknowns = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
if (!g_key_file_load_from_file(gkfile, filename, G_KEY_FILE_NONE, &error))
{
@@ -260,6 +337,7 @@ void gnt_uninit_styles()
for (i = 0; i < GNT_STYLES; i++)
g_free(str_styles[i]);
+ g_hash_table_destroy(unknowns);
#if GLIB_CHECK_VERSION(2,6,0)
g_key_file_free(gkfile);
#endif
diff --git a/finch/libgnt/gntstyle.h b/finch/libgnt/gntstyle.h
index 8550f34320..64b029fbee 100644
--- a/finch/libgnt/gntstyle.h
+++ b/finch/libgnt/gntstyle.h
@@ -1,4 +1,27 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gnt.h"
+#include "gntwm.h"
typedef enum
{
@@ -10,18 +33,49 @@ typedef enum
GNT_STYLES
} GntStyle;
+/**
+ *
+ * @param filename
+ */
void gnt_style_read_configure_file(const char *filename);
const char *gnt_style_get(GntStyle style);
+const char *gnt_style_get_from_name(const char *key);
+
+/**
+ *
+ * @param style
+ * @param def
+ *
+ * @return
+ */
gboolean gnt_style_get_bool(GntStyle style, gboolean def);
/* This should be called only once for the each type */
+/**
+ *
+ * @param type
+ * @param hash
+ */
void gnt_styles_get_keyremaps(GType type, GHashTable *hash);
+/**
+ *
+ * @param type
+ * @param klass
+ */
void gnt_style_read_actions(GType type, GntBindableClass *klass);
+void gnt_style_read_workspaces(GntWM *wm);
+
+/**
+ *
+ */
void gnt_init_styles(void);
+/**
+ *
+ */
void gnt_uninit_styles(void);
diff --git a/finch/libgnt/gnttextview.c b/finch/libgnt/gnttextview.c
index 7aa5acbcae..2874c33082 100644
--- a/finch/libgnt/gnttextview.c
+++ b/finch/libgnt/gnttextview.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gnttextview.h"
#include "gntutils.h"
diff --git a/finch/libgnt/gnttextview.h b/finch/libgnt/gnttextview.h
index d6c302b4c8..98cdbdb0ef 100644
--- a/finch/libgnt/gnttextview.h
+++ b/finch/libgnt/gnttextview.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_TEXT_VIEW_H
#define GNT_TEXT_VIEW_H
@@ -53,34 +75,102 @@ struct _GntTextViewClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_text_view_get_gtype(void);
/* XXX: For now, don't set a textview to have any border.
* If you want borders real bad, put it in a box. */
-GntWidget *gnt_text_view_new(void);
+/**
+ *
+ *
+ * @return
+ */
+GntWidget * gnt_text_view_new(void);
/* scroll > 0 means scroll up, < 0 means scroll down, == 0 means scroll to the end */
+/**
+ *
+ * @param view
+ * @param scroll
+ */
void gnt_text_view_scroll(GntTextView *view, int scroll);
+/**
+ *
+ * @param view
+ * @param text
+ * @param flags
+ */
void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags);
+/**
+ *
+ * @param view
+ * @param text
+ * @param flags
+ * @param tag
+ */
void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text, GntTextFormatFlags flags, const char *tag);
/* Move the cursor to the beginning of the next line and resets text-attributes.
* It first completes the current line with the current text-attributes. */
+/**
+ *
+ * @param view
+ */
void gnt_text_view_next_line(GntTextView *view);
+/**
+ *
+ * @param flags
+ *
+ * @return
+ */
chtype gnt_text_format_flag_to_chtype(GntTextFormatFlags flags);
+/**
+ *
+ * @param view
+ */
void gnt_text_view_clear(GntTextView *view);
+/**
+ *
+ * @param view
+ *
+ * @return
+ */
int gnt_text_view_get_lines_below(GntTextView *view);
+/**
+ *
+ * @param view
+ *
+ * @return
+ */
int gnt_text_view_get_lines_above(GntTextView *view);
/* If text is NULL, then the tag is removed. */
+/**
+ *
+ * @param view
+ * @param name
+ * @param text
+ * @param all
+ *
+ * @return
+ */
int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all);
+/**
+ *
+ * @param view
+ * @param widget
+ */
void gnt_text_view_attach_scroll_widget(GntTextView *view, GntWidget *widget);
G_END_DECLS
diff --git a/finch/libgnt/gnttree.c b/finch/libgnt/gnttree.c
index 3e8dfdefe1..064dadcc6f 100644
--- a/finch/libgnt/gnttree.c
+++ b/finch/libgnt/gnttree.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntmarshal.h"
#include "gntstyle.h"
#include "gnttree.h"
@@ -281,7 +303,7 @@ update_row_text(GntTree *tree, GntTreeRow *row)
notfirst = TRUE;
- if (len > width) {
+ if (len > width - 2) {
len = width - 1;
cut = TRUE;
}
@@ -731,15 +753,16 @@ gnt_tree_key_pressed(GntWidget *widget, const char *text)
g_signal_emit(tree, signals[SIG_TOGGLED], 0, row->key);
redraw_tree(tree);
}
+ } else {
+ return FALSE;
}
if (old != tree->current)
{
tree_selection_changed(tree, old, tree->current);
- return TRUE;
}
- return FALSE;
+ return TRUE;
}
static void
diff --git a/finch/libgnt/gnttree.h b/finch/libgnt/gnttree.h
index e7553216f0..2c25ff638e 100644
--- a/finch/libgnt/gnttree.h
+++ b/finch/libgnt/gnttree.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_TREE_H
#define GNT_TREE_H
@@ -74,75 +96,267 @@ struct _GntTreeClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_tree_get_gtype(void);
-GntWidget *gnt_tree_new(void); /* A tree with just one column */
-
-GntWidget *gnt_tree_new_with_columns(int columns);
-
+/**
+ *
+ *
+ * @return
+ */
+GntWidget * gnt_tree_new(void);
+
+ /* A tree with just one column */
+
+/**
+ *
+ * @param columns
+ *
+ * @return
+ */
+GntWidget * gnt_tree_new_with_columns(int columns);
+
+/**
+ *
+ * @param tree
+ * @param rows
+ */
void gnt_tree_set_visible_rows(GntTree *tree, int rows);
+/**
+ *
+ * @param tree
+ *
+ * @return
+ */
int gnt_tree_get_visible_rows(GntTree *tree);
+/**
+ *
+ * @param tree
+ * @param count
+ */
void gnt_tree_scroll(GntTree *tree, int count);
-GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro);
-
-GntTreeRow *gnt_tree_add_row_last(GntTree *tree, void *key, GntTreeRow *row, void *parent);
-
+/**
+ *
+ * @param tree
+ * @param key
+ * @param row
+ * @param parent
+ * @param bigbro
+ *
+ * @return
+ */
+GntTreeRow * gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro);
+
+/**
+ *
+ * @param tree
+ * @param key
+ * @param row
+ * @param parent
+ *
+ * @return
+ */
+GntTreeRow * gnt_tree_add_row_last(GntTree *tree, void *key, GntTreeRow *row, void *parent);
+
+/**
+ *
+ * @param tree
+ *
+ * @return
+ */
gpointer gnt_tree_get_selection_data(GntTree *tree);
/* Returned string needs to be freed */
-char *gnt_tree_get_selection_text(GntTree *tree);
-
-GList *gnt_tree_get_selection_text_list(GntTree *tree);
+/**
+ *
+ * @param tree
+ *
+ * @return
+ */
+char * gnt_tree_get_selection_text(GntTree *tree);
+
+/**
+ *
+ * @param tree
+ *
+ * @return
+ */
+GList * gnt_tree_get_selection_text_list(GntTree *tree);
const GList *gnt_tree_get_rows(GntTree *tree);
+/**
+ *
+ * @param tree
+ * @param key
+ */
void gnt_tree_remove(GntTree *tree, gpointer key);
+/**
+ *
+ * @param tree
+ */
void gnt_tree_remove_all(GntTree *tree);
/* Returns the visible line number of the selected row */
+/**
+ *
+ * @param tree
+ *
+ * @return
+ */
int gnt_tree_get_selection_visible_line(GntTree *tree);
+/**
+ *
+ * @param tree
+ * @param key
+ * @param colno
+ * @param text
+ */
void gnt_tree_change_text(GntTree *tree, gpointer key, int colno, const char *text);
-GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro);
-
+/**
+ *
+ * @param tree
+ * @param key
+ * @param row
+ * @param parent
+ * @param bigbro
+ *
+ * @return
+ */
+GntTreeRow * gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro);
+
+/**
+ *
+ * @param tree
+ * @param key
+ * @param set
+ */
void gnt_tree_set_choice(GntTree *tree, void *key, gboolean set);
+/**
+ *
+ * @param tree
+ * @param key
+ *
+ * @return
+ */
gboolean gnt_tree_get_choice(GntTree *tree, void *key);
+/**
+ *
+ * @param tree
+ * @param key
+ * @param flags
+ */
void gnt_tree_set_row_flags(GntTree *tree, void *key, GntTextFormatFlags flags);
+/**
+ *
+ * @param key
+ */
void gnt_tree_set_selected(GntTree *tree , void *key);
-GntTreeRow *gnt_tree_create_row(GntTree *tree, ...);
-
-GntTreeRow *gnt_tree_create_row_from_list(GntTree *tree, GList *list);
-
+/**
+ *
+ * @param tree
+ *
+ * @return
+ */
+GntTreeRow * gnt_tree_create_row(GntTree *tree, ...);
+
+/**
+ *
+ * @param tree
+ * @param list
+ *
+ * @return
+ */
+GntTreeRow * gnt_tree_create_row_from_list(GntTree *tree, GList *list);
+
+/**
+ *
+ * @param tree
+ * @param col
+ * @param width
+ */
void gnt_tree_set_col_width(GntTree *tree, int col, int width);
+/**
+ *
+ * @param tree
+ */
void gnt_tree_set_column_titles(GntTree *tree, ...);
+/**
+ *
+ * @param tree
+ * @param set
+ */
void gnt_tree_set_show_title(GntTree *tree, gboolean set);
+/**
+ *
+ * @param tree
+ * @param func
+ */
void gnt_tree_set_compare_func(GntTree *tree, GCompareFunc func);
+/**
+ *
+ * @param tree
+ * @param key
+ * @param expanded
+ */
void gnt_tree_set_expanded(GntTree *tree, void *key, gboolean expanded);
+/**
+ *
+ * @param tree
+ * @param set
+ */
void gnt_tree_set_show_separator(GntTree *tree, gboolean set);
+/**
+ *
+ * @param tree
+ * @param row
+ */
void gnt_tree_sort_row(GntTree *tree, void *row);
/* This will try to automatically adjust the width of the columns in the tree */
+/**
+ *
+ * @param tree
+ */
void gnt_tree_adjust_columns(GntTree *tree);
+/**
+ *
+ * @param tree
+ * @param hash
+ * @param eq
+ * @param kd
+ */
void gnt_tree_set_hash_fns(GntTree *tree, gpointer hash, gpointer eq, gpointer kd);
/* This can be useful when, for example, we want to store some data
* which we don't want/need to display. */
+/**
+ *
+ * @param tree
+ * @param col
+ * @param vis
+ */
void gnt_tree_set_column_visible(GntTree *tree, int col, gboolean vis);
G_END_DECLS
@@ -150,6 +364,11 @@ G_END_DECLS
/* The following functions should NOT be used by applications. */
/* This should be called by the subclasses of GntTree's in their _new function */
+/**
+ *
+ * @param tree
+ * @param col
+ */
void _gnt_tree_init_internals(GntTree *tree, int col);
#endif /* GNT_TREE_H */
diff --git a/finch/libgnt/gntutils.c b/finch/libgnt/gntutils.c
index fb7e00fe78..e6edb8aff3 100644
--- a/finch/libgnt/gntutils.c
+++ b/finch/libgnt/gntutils.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntbutton.h"
#include "gntcheckbox.h"
#include "gntcombobox.h"
diff --git a/finch/libgnt/gntutils.h b/finch/libgnt/gntutils.h
index f773c56846..c5c705ad31 100644
--- a/finch/libgnt/gntutils.h
+++ b/finch/libgnt/gntutils.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include <glib.h>
#include "gnt.h"
@@ -5,9 +27,22 @@
typedef gpointer (*GDupFunc)(gconstpointer data);
+/**
+ *
+ * @param text
+ * @param width
+ * @param height
+ */
void gnt_util_get_text_bound(const char *text, int *width, int *height);
/* excluding *end */
+/**
+ *
+ * @param start
+ * @param end
+ *
+ * @return
+ */
int gnt_util_onscreen_width(const char *start, const char *end);
const char *gnt_util_onscreen_width_to_pointer(const char *str, int len, int *w);
@@ -18,29 +53,62 @@ const char *gnt_util_onscreen_width_to_pointer(const char *str, int len, int *w)
*
* Returns a newly allocated string.
*/
-char *gnt_util_onscreen_fit_string(const char *string, int maxw);
-
-GHashTable *g_hash_table_duplicate(GHashTable *src, GHashFunc hash,
- GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d,
- GDupFunc key_dup, GDupFunc value_dup);
+/**
+ *
+ * @param string
+ * @param maxw
+ *
+ * @return
+ */
+char * gnt_util_onscreen_fit_string(const char *string, int maxw);
+/**
+ *
+ * @param src
+ * @param hash
+ * @param equal
+ * @param key_d
+ * @param value_d
+ * @param key_dup
+ * @param value_dup
+ *
+ * @return
+ */
+GHashTable * g_hash_table_duplicate(GHashTable *src, GHashFunc hash, GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d, GDupFunc key_dup, GDupFunc value_dup);
/**
* To be used with g_signal_new. Look in the key_pressed signal-definition in
* gntwidget.c for usage.
*/
-gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint,
- GValue *return_accu,
- const GValue *handler_return,
- gpointer dummy);
+/**
+ *
+ * @param ihint
+ * @param return_accu
+ * @param handler_return
+ * @param dummy
+ *
+ * @return
+ */
+gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer dummy);
/**
* Returns a GntTree populated with "key" -> "binding" for the widget.
*/
-GntWidget *gnt_widget_bindings_view(GntWidget *widget);
+/**
+ *
+ * @param widget
+ *
+ * @return
+ */
+GntWidget * gnt_widget_bindings_view(GntWidget *widget);
/**
* Parse widgets from 'string'.
*/
+/**
+ *
+ * @param string
+ * @param num
+ */
void gnt_util_parse_widgets(const char *string, int num, ...);
diff --git a/finch/libgnt/gntwidget.c b/finch/libgnt/gntwidget.c
index 2663c2d314..03db95aebc 100644
--- a/finch/libgnt/gntwidget.c
+++ b/finch/libgnt/gntwidget.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
/* Stuff brutally ripped from Gflib */
#include "gntwidget.h"
diff --git a/finch/libgnt/gntwidget.h b/finch/libgnt/gntwidget.h
index ff85f1b8e6..8f00e79dc0 100644
--- a/finch/libgnt/gntwidget.h
+++ b/finch/libgnt/gntwidget.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_WIDGET_H
#define GNT_WIDGET_H
@@ -112,39 +134,169 @@ struct _GntWidgetClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_widget_get_gtype(void);
+
+/**
+ *
+ * @param widget
+ */
void gnt_widget_destroy(GntWidget *widget);
+
+/**
+ *
+ * @param widget
+ */
void gnt_widget_show(GntWidget *widget);
+
+/**
+ *
+ * @param widget
+ */
void gnt_widget_draw(GntWidget *widget);
+
+/**
+ *
+ * @param widget
+ * @param x
+ * @param y
+ * @param width
+ * @param height
+ */
void gnt_widget_expose(GntWidget *widget, int x, int y, int width, int height);
+
+/**
+ *
+ * @param widget
+ */
void gnt_widget_hide(GntWidget *widget);
+/**
+ *
+ * @param widget
+ * @param x
+ * @param y
+ */
void gnt_widget_get_position(GntWidget *widget, int *x, int *y);
+
+/**
+ *
+ * @param widget
+ * @param x
+ * @param y
+ */
void gnt_widget_set_position(GntWidget *widget, int x, int y);
+
+/**
+ *
+ * @param widget
+ */
void gnt_widget_size_request(GntWidget *widget);
+
+/**
+ *
+ * @param widget
+ * @param width
+ * @param height
+ */
void gnt_widget_get_size(GntWidget *widget, int *width, int *height);
+
+/**
+ *
+ * @param widget
+ * @param width
+ * @param height
+ *
+ * @return
+ */
gboolean gnt_widget_set_size(GntWidget *widget, int width, int height);
+
+/**
+ *
+ * @param widget
+ * @param width
+ * @param height
+ *
+ * @return
+ */
gboolean gnt_widget_confirm_size(GntWidget *widget, int width, int height);
+/**
+ *
+ * @param widget
+ * @param keys
+ *
+ * @return
+ */
gboolean gnt_widget_key_pressed(GntWidget *widget, const char *keys);
+/**
+ *
+ * @param widget
+ * @param event
+ * @param x
+ * @param y
+ *
+ * @return
+ */
gboolean gnt_widget_clicked(GntWidget *widget, GntMouseEvent event, int x, int y);
+/**
+ *
+ * @param widget
+ * @param set
+ *
+ * @return
+ */
gboolean gnt_widget_set_focus(GntWidget *widget, gboolean set);
+
+/**
+ *
+ * @param widget
+ */
void gnt_widget_activate(GntWidget *widget);
+/**
+ *
+ * @param widget
+ * @param name
+ */
void gnt_widget_set_name(GntWidget *widget, const char *name);
const char *gnt_widget_get_name(GntWidget *widget);
/* Widget-subclasses should call this from the draw-callback.
* Applications should just call gnt_widget_draw instead of this. */
+/**
+ *
+ * @param widget
+ */
void gnt_widget_queue_update(GntWidget *widget);
+/**
+ *
+ * @param widget
+ * @param set
+ */
void gnt_widget_set_take_focus(GntWidget *widget, gboolean set);
+/**
+ *
+ * @param widget
+ * @param set
+ */
void gnt_widget_set_visible(GntWidget *widget, gboolean set);
+/**
+ *
+ * @param widget
+ *
+ * @return
+ */
gboolean gnt_widget_has_shadow(GntWidget *widget);
G_END_DECLS
diff --git a/finch/libgnt/gntwindow.c b/finch/libgnt/gntwindow.c
index e879b98373..6dcb54ba72 100644
--- a/finch/libgnt/gntwindow.c
+++ b/finch/libgnt/gntwindow.c
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#include "gntstyle.h"
#include "gntwindow.h"
@@ -5,9 +27,13 @@
enum
{
- SIGS = 1,
+ SIG_WORKSPACE_HIDE,
+ SIG_WORKSPACE_SHOW,
+ SIGS,
};
+static guint signals[SIGS] = { 0 };
+
static GntBoxClass *parent_class = NULL;
static void (*org_destroy)(GntWidget *widget);
@@ -42,6 +68,24 @@ gnt_window_class_init(GntWindowClass *klass)
org_destroy = wid_class->destroy;
wid_class->destroy = gnt_window_destroy;
+ signals[SIG_WORKSPACE_HIDE] =
+ g_signal_new("workspace-hidden",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[SIG_WORKSPACE_SHOW] =
+ g_signal_new("workspace-shown",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
gnt_bindable_class_register_action(bindable, "show-menu", show_menu,
GNT_KEY_CTRL_O, NULL);
gnt_bindable_register_binding(bindable, "show-menu", GNT_KEY_F10, NULL);
@@ -109,6 +153,20 @@ GntWidget *gnt_window_box_new(gboolean homo, gboolean vert)
return wid;
}
+void
+gnt_window_workspace_hiding(GntWindow *window)
+{
+ if (window->menu)
+ gnt_widget_hide(GNT_WIDGET(window->menu));
+ g_signal_emit(window, signals[SIG_WORKSPACE_HIDE], 0);
+}
+
+void
+gnt_window_workspace_showing(GntWindow *window)
+{
+ g_signal_emit(window, signals[SIG_WORKSPACE_SHOW], 0);
+}
+
void gnt_window_set_menu(GntWindow *window, GntMenu *menu)
{
/* If a menu already existed, then destroy that first. */
diff --git a/finch/libgnt/gntwindow.h b/finch/libgnt/gntwindow.h
index fe39bb3c69..c5db05fb46 100644
--- a/finch/libgnt/gntwindow.h
+++ b/finch/libgnt/gntwindow.h
@@ -1,3 +1,25 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#ifndef GNT_WINDOW_H
#define GNT_WINDOW_H
@@ -40,17 +62,42 @@ struct _GntWindowClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_window_get_gtype(void);
#define gnt_vwindow_new(homo) gnt_window_box_new(homo, TRUE)
#define gnt_hwindow_new(homo) gnt_window_box_new(homo, FALSE)
-GntWidget *gnt_window_new(void);
+/**
+ *
+ *
+ * @return
+ */
+GntWidget * gnt_window_new(void);
-GntWidget *gnt_window_box_new(gboolean homo, gboolean vert);
+/**
+ *
+ * @param homo
+ * @param vert
+ *
+ * @return
+ */
+GntWidget * gnt_window_box_new(gboolean homo, gboolean vert);
+/**
+ *
+ * @param window
+ * @param menu
+ */
void gnt_window_set_menu(GntWindow *window, GntMenu *menu);
+void gnt_window_workspace_hiding(GntWindow *);
+void gnt_window_workspace_showing(GntWindow *);
+
G_END_DECLS
#endif /* GNT_WINDOW_H */
diff --git a/finch/libgnt/gntwm.c b/finch/libgnt/gntwm.c
index f1b7c9c5ba..230e08b65b 100644
--- a/finch/libgnt/gntwm.c
+++ b/finch/libgnt/gntwm.c
@@ -1,11 +1,35 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
#define _GNU_SOURCE
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__unix__)
#define _XOPEN_SOURCE_EXTENDED
#endif
#include "config.h"
#include <ctype.h>
+#include <glib/gprintf.h>
+#include <gmodule.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -47,6 +71,8 @@ static void gnt_wm_win_moved(GntWM *wm, GntNode *node);
static void gnt_wm_give_focus(GntWM *wm, GntWidget *widget);
static void update_window_in_list(GntWM *wm, GntWidget *wid);
static void shift_window(GntWM *wm, GntWidget *widget, int dir);
+static gboolean workspace_next(GntBindable *wm, GList *n);
+static gboolean workspace_prev(GntBindable *wm, GList *n);
#ifndef NO_WIDECHAR
static int widestringwidth(wchar_t *wide);
@@ -56,6 +82,7 @@ static gboolean write_already(gpointer data);
static int write_timeout;
static time_t last_active_time;
static gboolean idle_update;
+static GList *act = NULL; /* list of WS with unseen activitiy */
static GList *
g_list_bring_to_front(GList *list, gpointer data)
@@ -74,61 +101,8 @@ free_node(gpointer data)
g_free(node);
}
-static void
-draw_taskbar(GntWM *wm, gboolean reposition)
-{
- static WINDOW *taskbar = NULL;
- GList *iter;
- int n, width = 0;
- int i;
-
- if (taskbar == NULL) {
- taskbar = newwin(1, getmaxx(stdscr), getmaxy(stdscr) - 1, 0);
- } else if (reposition) {
- int Y_MAX = getmaxy(stdscr) - 1;
- mvwin(taskbar, Y_MAX, 0);
- }
-
- wbkgdset(taskbar, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
- werase(taskbar);
-
- n = g_list_length(wm->list);
- if (n)
- width = getmaxx(stdscr) / n;
-
- for (i = 0, iter = wm->list; iter; iter = iter->next, i++)
- {
- GntWidget *w = iter->data;
- int color;
- const char *title;
-
- if (w == wm->ordered->data) {
- /* This is the current window in focus */
- color = GNT_COLOR_TITLE;
- } else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_URGENT)) {
- /* This is a window with the URGENT hint set */
- color = GNT_COLOR_URGENT;
- } else {
- color = GNT_COLOR_NORMAL;
- }
- wbkgdset(taskbar, '\0' | COLOR_PAIR(color));
- if (iter->next)
- mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), width);
- else
- mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), getmaxx(stdscr) - width * i);
- title = GNT_BOX(w)->title;
- mvwprintw(taskbar, 0, width * i, "%s", title ? title : "<gnt>");
- if (i)
- mvwaddch(taskbar, 0, width *i - 1, ACS_VLINE | A_STANDOUT | COLOR_PAIR(GNT_COLOR_NORMAL));
-
- update_window_in_list(wm, w);
- }
-
- wrefresh(taskbar);
-}
-
-static void
-copy_win(GntWidget *widget, GntNode *node)
+void
+gnt_wm_copy_win(GntWidget *widget, GntNode *node)
{
WINDOW *src, *dst;
int shadow;
@@ -199,6 +173,33 @@ right:
#endif
}
+static void
+update_act_msg()
+{
+ GntWidget *label;
+ GList *iter;
+ static GntWidget *message = NULL;
+ GString *text = g_string_new("act: ");
+ if (message)
+ gnt_widget_destroy(message);
+ if (g_list_length(act) == 0)
+ return;
+ for (iter = act; iter; iter = iter->next) {
+ GntWS *ws = iter->data;
+ g_string_append_printf(text, "%s, ", gnt_ws_get_name(ws));
+ }
+ g_string_erase(text, text->len - 2, 2);
+ message = gnt_vbox_new(FALSE);
+ label = gnt_label_new_with_format(text->str, GNT_TEXT_FLAG_BOLD | GNT_TEXT_FLAG_HIGHLIGHT);
+ GNT_WIDGET_UNSET_FLAGS(GNT_BOX(message), GNT_WIDGET_CAN_TAKE_FOCUS);
+ GNT_WIDGET_SET_FLAGS(GNT_BOX(message), GNT_WIDGET_TRANSIENT);
+ gnt_box_add_widget(GNT_BOX(message), label);
+ gnt_widget_set_name(message, "wm-message");
+ gnt_widget_set_position(message, 0, 0);
+ gnt_widget_draw(message);
+ g_string_free(text, TRUE);
+}
+
static gboolean
update_screen(GntWM *wm)
{
@@ -329,9 +330,18 @@ static void
gnt_wm_init(GTypeInstance *instance, gpointer class)
{
GntWM *wm = GNT_WM(instance);
- wm->list = NULL;
- wm->ordered = NULL;
+ wm->workspaces = NULL;
+ wm->name_places = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ wm->title_places = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ gnt_style_read_workspaces(wm);
+ if (wm->workspaces == NULL) {
+ wm->cws = gnt_ws_new("default");
+ gnt_wm_add_workspace(wm, wm->cws);
+ } else {
+ wm->cws = wm->workspaces->data;
+ }
wm->event_stack = FALSE;
+ wm->tagged = NULL;
wm->windows = NULL;
wm->actions = NULL;
wm->nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_node);
@@ -340,6 +350,7 @@ gnt_wm_init(GTypeInstance *instance, gpointer class)
read_window_positions(wm);
g_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idle, NULL);
time(&last_active_time);
+ gnt_wm_switch_workspace(wm, 0);
}
static void
@@ -351,23 +362,23 @@ switch_window(GntWM *wm, int direction)
if (wm->_list.window || wm->menu)
return;
- if (!wm->ordered || !wm->ordered->next)
+ if (!wm->cws->ordered || !wm->cws->ordered->next)
return;
- w = wm->ordered->data;
- pos = g_list_index(wm->list, w);
+ w = wm->cws->ordered->data;
+ pos = g_list_index(wm->cws->list, w);
pos += direction;
if (pos < 0)
- wid = g_list_last(wm->list)->data;
- else if (pos >= g_list_length(wm->list))
- wid = wm->list->data;
+ wid = g_list_last(wm->cws->list)->data;
+ else if (pos >= g_list_length(wm->cws->list))
+ wid = wm->cws->list->data;
else if (pos >= 0)
- wid = g_list_nth_data(wm->list, pos);
+ wid = g_list_nth_data(wm->cws->list, pos);
- wm->ordered = g_list_bring_to_front(wm->ordered, wid);
+ wm->cws->ordered = g_list_bring_to_front(wm->cws->ordered, wid);
- gnt_wm_raise_window(wm, wm->ordered->data);
+ gnt_wm_raise_window(wm, wm->cws->ordered->data);
if (w != wid) {
gnt_widget_set_focus(w, FALSE);
@@ -398,7 +409,7 @@ switch_window_n(GntBindable *bind, GList *list)
GList *l;
int n;
- if (!wm->ordered)
+ if (!wm->cws->ordered)
return TRUE;
if (list)
@@ -406,9 +417,9 @@ switch_window_n(GntBindable *bind, GList *list)
else
n = 0;
- w = wm->ordered->data;
+ w = wm->cws->ordered->data;
- if ((l = g_list_nth(wm->list, n)) != NULL)
+ if ((l = g_list_nth(wm->cws->list, n)) != NULL)
{
gnt_wm_raise_window(wm, l->data);
}
@@ -427,17 +438,17 @@ window_scroll_up(GntBindable *bindable, GList *null)
GntWidget *window;
GntNode *node;
- if (!wm->ordered)
+ if (!wm->cws->ordered)
return TRUE;
- window = wm->ordered->data;
+ window = wm->cws->ordered->data;
node = g_hash_table_lookup(wm->nodes, window);
if (!node)
return TRUE;
if (node->scroll) {
node->scroll--;
- copy_win(window, node);
+ gnt_wm_copy_win(window, node);
update_screen(wm);
}
return TRUE;
@@ -451,10 +462,10 @@ window_scroll_down(GntBindable *bindable, GList *null)
GntNode *node;
int w, h;
- if (!wm->ordered)
+ if (!wm->cws->ordered)
return TRUE;
- window = wm->ordered->data;
+ window = wm->cws->ordered->data;
node = g_hash_table_lookup(wm->nodes, window);
if (!node)
return TRUE;
@@ -462,7 +473,7 @@ window_scroll_down(GntBindable *bindable, GList *null)
gnt_widget_get_size(window, &w, &h);
if (h - node->scroll > getmaxy(node->window)) {
node->scroll++;
- copy_win(window, node);
+ gnt_wm_copy_win(window, node);
update_screen(wm);
}
return TRUE;
@@ -476,8 +487,8 @@ window_close(GntBindable *bindable, GList *null)
if (wm->_list.window)
return TRUE;
- if (wm->ordered) {
- gnt_widget_destroy(wm->ordered->data);
+ if (wm->cws->ordered) {
+ gnt_widget_destroy(wm->cws->ordered->data);
}
return TRUE;
@@ -490,10 +501,10 @@ help_for_widget(GntBindable *bindable, GList *null)
GntWidget *widget, *tree, *win, *active;
char *title;
- if (!wm->ordered)
+ if (!wm->cws->ordered)
return TRUE;
- widget = wm->ordered->data;
+ widget = wm->cws->ordered->data;
if (!GNT_IS_BOX(widget))
return TRUE;
active = GNT_BOX(widget)->active;
@@ -540,85 +551,123 @@ setup__list(GntWM *wm)
static void
window_list_activate(GntTree *tree, GntWM *wm)
{
- GntWidget *widget = gnt_tree_get_selection_data(GNT_TREE(tree));
+ GntBindable *sel = gnt_tree_get_selection_data(GNT_TREE(tree));
+
+ gnt_widget_destroy(wm->_list.window);
- if (!wm->ordered || !widget)
+ if (!sel)
return;
- gnt_widget_destroy(wm->_list.window);
- gnt_wm_raise_window(wm, widget);
+ if (GNT_IS_WS(sel)) {
+ gnt_wm_switch_workspace(wm, g_list_index(wm->workspaces, sel));
+ } else {
+ gnt_wm_raise_window(wm, GNT_WIDGET(sel));
+ }
}
static void
-populate_window_list(GntWM *wm)
+populate_window_list(GntWM *wm, gboolean workspace)
{
GList *iter;
GntTree *tree = GNT_TREE(wm->windows->tree);
- for (iter = wm->list; iter; iter = iter->next) {
- GntBox *box = GNT_BOX(iter->data);
+ if (!workspace) {
+ for (iter = wm->cws->list; iter; iter = iter->next) {
+ GntBox *box = GNT_BOX(iter->data);
- gnt_tree_add_row_last(tree, box,
- gnt_tree_create_row(tree, box->title), NULL);
- update_window_in_list(wm, GNT_WIDGET(box));
+ gnt_tree_add_row_last(tree, box,
+ gnt_tree_create_row(tree, box->title), NULL);
+ update_window_in_list(wm, GNT_WIDGET(box));
+ }
+ } else {
+ GList *ws = wm->workspaces;
+ for (; ws; ws = ws->next) {
+ gnt_tree_add_row_last(tree, ws->data,
+ gnt_tree_create_row(tree, gnt_ws_get_name(GNT_WS(ws->data))), NULL);
+ for (iter = GNT_WS(ws->data)->list; iter; iter = iter->next) {
+ GntBox *box = GNT_BOX(iter->data);
+
+ gnt_tree_add_row_last(tree, box,
+ gnt_tree_create_row(tree, box->title), ws->data);
+ update_window_in_list(wm, GNT_WIDGET(box));
+ }
+ }
}
}
static gboolean
window_list_key_pressed(GntWidget *widget, const char *text, GntWM *wm)
{
- if (text[1] == 0 && wm->ordered) {
- GntWidget *sel = gnt_tree_get_selection_data(GNT_TREE(widget));
+ if (text[1] == 0 && wm->cws->ordered) {
+ GntBindable *sel = gnt_tree_get_selection_data(GNT_TREE(widget));
switch (text[0]) {
case '-':
case ',':
- shift_window(wm, sel, -1);
+ if (GNT_IS_WS(sel)) {
+ /* reorder the workspace. */
+ } else
+ shift_window(wm, GNT_WIDGET(sel), -1);
break;
case '=':
case '.':
- shift_window(wm, sel, 1);
+ if (GNT_IS_WS(sel)) {
+ /* reorder the workspace. */
+ } else
+ shift_window(wm, GNT_WIDGET(sel), 1);
break;
default:
return FALSE;
}
gnt_tree_remove_all(GNT_TREE(widget));
- populate_window_list(wm);
+ populate_window_list(wm, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "workspace")));
gnt_tree_set_selected(GNT_TREE(widget), sel);
return TRUE;
}
return FALSE;
}
-static gboolean
-window_list(GntBindable *bindable, GList *null)
+static void
+list_of_windows(GntWM *wm, gboolean workspace)
{
- GntWM *wm = GNT_WM(bindable);
GntWidget *tree, *win;
-
- if (wm->_list.window || wm->menu)
- return TRUE;
-
- if (!wm->ordered)
- return TRUE;
-
setup__list(wm);
wm->windows = &wm->_list;
win = wm->windows->window;
tree = wm->windows->tree;
- gnt_box_set_title(GNT_BOX(win), "Window List");
+ gnt_box_set_title(GNT_BOX(win), workspace ? "Workspace List" : "Window List");
- populate_window_list(wm);
+ populate_window_list(wm, workspace);
+
+ if (wm->cws->ordered)
+ gnt_tree_set_selected(GNT_TREE(tree), wm->cws->ordered->data);
+ else if (workspace)
+ gnt_tree_set_selected(GNT_TREE(tree), wm->cws);
- gnt_tree_set_selected(GNT_TREE(tree), wm->ordered->data);
g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(window_list_activate), wm);
g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(window_list_key_pressed), wm);
+ g_object_set_data(G_OBJECT(tree), "workspace", GINT_TO_POINTER(workspace));
gnt_tree_set_col_width(GNT_TREE(tree), 0, getmaxx(stdscr) / 3);
gnt_widget_set_size(tree, 0, getmaxy(stdscr) / 2);
gnt_widget_set_position(win, getmaxx(stdscr) / 3, getmaxy(stdscr) / 4);
gnt_widget_show(win);
+}
+
+static gboolean
+window_list(GntBindable *bindable, GList *null)
+{
+ GntWM *wm = GNT_WM(bindable);
+
+ if (wm->_list.window || wm->menu)
+ return TRUE;
+
+ if (!wm->cws->ordered)
+ return TRUE;
+
+ list_of_windows(wm, FALSE);
+
return TRUE;
}
@@ -758,7 +807,7 @@ dump_screen(GntBindable *bindable, GList *null)
static void
shift_window(GntWM *wm, GntWidget *widget, int dir)
{
- GList *all = wm->list;
+ GList *all = wm->cws->list;
GList *list = g_list_find(all, widget);
int length, pos;
if (!list)
@@ -778,8 +827,8 @@ shift_window(GntWM *wm, GntWidget *widget, int dir)
all = g_list_insert(all, widget, pos);
all = g_list_delete_link(all, list);
- wm->list = all;
- draw_taskbar(wm, FALSE);
+ wm->cws->list = all;
+ gnt_ws_draw_taskbar(wm->cws, FALSE);
}
static gboolean
@@ -789,7 +838,7 @@ shift_left(GntBindable *bindable, GList *null)
if (wm->_list.window)
return TRUE;
- shift_window(wm, wm->ordered->data, -1);
+ shift_window(wm, wm->cws->ordered->data, -1);
return TRUE;
}
@@ -800,7 +849,7 @@ shift_right(GntBindable *bindable, GList *null)
if (wm->_list.window)
return TRUE;
- shift_window(wm, wm->ordered->data, 1);
+ shift_window(wm, wm->cws->ordered->data, 1);
return TRUE;
}
@@ -924,7 +973,7 @@ window_reverse(GntWidget *win, gboolean set, GntWM *wm)
for (i = 0; i < h; i += reverse_char(d, i, 0, set));
for (i = 0; i < h; i += reverse_char(d, i, w-1, set));
- copy_win(win, g_hash_table_lookup(wm->nodes, win));
+ gnt_wm_copy_win(win, g_hash_table_lookup(wm->nodes, win));
update_screen(wm);
}
@@ -934,11 +983,11 @@ start_move(GntBindable *bindable, GList *null)
GntWM *wm = GNT_WM(bindable);
if (wm->_list.window || wm->menu)
return TRUE;
- if (!wm->ordered)
+ if (!wm->cws->ordered)
return TRUE;
wm->mode = GNT_KP_MODE_MOVE;
- window_reverse(GNT_WIDGET(wm->ordered->data), TRUE, wm);
+ window_reverse(GNT_WIDGET(wm->cws->ordered->data), TRUE, wm);
return TRUE;
}
@@ -949,11 +998,11 @@ start_resize(GntBindable *bindable, GList *null)
GntWM *wm = GNT_WM(bindable);
if (wm->_list.window || wm->menu)
return TRUE;
- if (!wm->ordered)
+ if (!wm->cws->ordered)
return TRUE;
wm->mode = GNT_KP_MODE_RESIZE;
- window_reverse(GNT_WIDGET(wm->ordered->data), TRUE, wm);
+ window_reverse(GNT_WIDGET(wm->cws->ordered->data), TRUE, wm);
return TRUE;
}
@@ -980,12 +1029,11 @@ refresh_screen(GntBindable *bindable, GList *null)
GntWM *wm = GNT_WM(bindable);
endwin();
- refresh();
- curs_set(0); /* endwin resets the cursor to normal */
g_hash_table_foreach(wm->nodes, (GHFunc)refresh_node, NULL);
update_screen(wm);
- draw_taskbar(wm, TRUE);
+ gnt_ws_draw_taskbar(wm->cws, TRUE);
+ curs_set(0); /* endwin resets the cursor to normal */
return FALSE;
}
@@ -1016,6 +1064,78 @@ toggle_clipboard(GntBindable *bindable, GList *n)
return TRUE;
}
+static void remove_tag(gpointer wid, gpointer wim)
+{
+ GntWM *wm = GNT_WM(wim);
+ GntWidget *w = GNT_WIDGET(wid);
+ wm->tagged = g_list_remove(wm->tagged, w);
+ mvwhline(w->window, 0, 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), 3);
+ gnt_widget_draw(w);
+}
+
+static gboolean
+tag_widget(GntBindable *b, GList *params)
+{
+ GntWM *wm = GNT_WM(b);
+ GntWidget *widget;
+
+ if (!wm->cws->ordered)
+ return FALSE;
+ widget = wm->cws->ordered->data;
+
+ if (g_list_find(wm->tagged, widget)) {
+ remove_tag(widget, wm);
+ return TRUE;
+ }
+
+ wm->tagged = g_list_prepend(wm->tagged, widget);
+ wbkgdset(widget->window, ' ' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT));
+ mvwprintw(widget->window, 0, 1, "[T]");
+ gnt_widget_draw(widget);
+ return TRUE;
+}
+
+static void
+widget_move_ws(gpointer wid, gpointer w)
+{
+ GntWM *wm = GNT_WM(w);
+ gnt_wm_widget_move_workspace(wm, wm->cws, GNT_WIDGET(wid));
+}
+
+static gboolean
+place_tagged(GntBindable *b, GList *params)
+{
+ GntWM *wm = GNT_WM(b);
+ g_list_foreach(wm->tagged, widget_move_ws, wm);
+ g_list_foreach(wm->tagged, remove_tag, wm);
+ g_list_free(wm->tagged);
+ wm->tagged = NULL;
+ return TRUE;
+}
+
+static gboolean
+workspace_list(GntBindable *b, GList *params)
+{
+ GntWM *wm = GNT_WM(b);
+
+ if (wm->_list.window || wm->menu)
+ return TRUE;
+
+ list_of_windows(wm, TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+workspace_new(GntBindable *bindable, GList *null)
+{
+ GntWM *wm = GNT_WM(bindable);
+ GntWS *ws = gnt_ws_new(NULL);
+ gnt_wm_add_workspace(wm, ws);
+ gnt_wm_switch_workspace(wm, g_list_index(wm->workspaces, ws));
+ return TRUE;
+}
+
static void
gnt_wm_class_init(GntWMClass *klass)
{
@@ -1150,6 +1270,18 @@ gnt_wm_class_init(GntWMClass *klass)
"\033" GNT_KEY_CTRL_K, NULL);
gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "help-for-widget", help_for_widget,
"\033" "/", NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-new", workspace_new,
+ GNT_KEY_F9, NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-next", workspace_next,
+ "\033" ">", NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-prev", workspace_prev,
+ "\033" "<", NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-tag", tag_widget,
+ "\033" "t", NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "place-tagged", place_tagged,
+ "\033" "T", NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "workspace-list", workspace_list,
+ "\033" "s", NULL);
gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "toggle-clipboard",
toggle_clipboard, "\033" "C", NULL);
@@ -1194,6 +1326,119 @@ gnt_wm_get_gtype(void)
return type;
}
+
+void
+gnt_wm_add_workspace(GntWM *wm, GntWS *ws)
+{
+ wm->workspaces = g_list_append(wm->workspaces, ws);
+}
+
+gboolean
+gnt_wm_switch_workspace(GntWM *wm, gint n)
+{
+ GntWS *s = g_list_nth_data(wm->workspaces, n);
+ if (!s)
+ return FALSE;
+
+ if (wm->_list.window) {
+ gnt_widget_destroy(wm->_list.window);
+ }
+ gnt_ws_hide(wm->cws, wm->nodes);
+ wm->cws = s;
+ gnt_ws_show(wm->cws, wm->nodes);
+
+ gnt_ws_draw_taskbar(wm->cws, TRUE);
+ update_screen(wm);
+ if (wm->cws->ordered) {
+ gnt_widget_set_focus(wm->cws->ordered->data, TRUE);
+ gnt_wm_raise_window(wm, wm->cws->ordered->data);
+ }
+
+ if (act && g_list_find(act, wm->cws)) {
+ act = g_list_remove(act, wm->cws);
+ update_act_msg();
+ }
+ return TRUE;
+}
+
+gboolean
+gnt_wm_switch_workspace_prev(GntWM *wm)
+{
+ int n = g_list_index(wm->workspaces, wm->cws);
+ return gnt_wm_switch_workspace(wm, --n);
+}
+
+gboolean
+gnt_wm_switch_workspace_next(GntWM *wm)
+{
+ int n = g_list_index(wm->workspaces, wm->cws);
+ return gnt_wm_switch_workspace(wm, ++n);
+}
+
+static gboolean
+workspace_next(GntBindable *wm, GList *n)
+{
+ return gnt_wm_switch_workspace_next(GNT_WM(wm));
+}
+
+static gboolean
+workspace_prev(GntBindable *wm, GList *n)
+{
+ return gnt_wm_switch_workspace_prev(GNT_WM(wm));
+}
+
+void
+gnt_wm_widget_move_workspace(GntWM *wm, GntWS *neww, GntWidget *widget)
+{
+ GntWS *oldw = gnt_wm_widget_find_workspace(wm, widget);
+ GntNode *node;
+ if (!oldw || oldw == neww)
+ return;
+ node = g_hash_table_lookup(wm->nodes, widget);
+ if (node && node->ws == neww)
+ return;
+
+ if (node)
+ node->ws = neww;
+
+ gnt_ws_remove_widget(oldw, widget);
+ gnt_ws_add_widget(neww, widget);
+ if (neww == wm->cws) {
+ gnt_ws_widget_show(widget, wm->nodes);
+ } else {
+ gnt_ws_widget_hide(widget, wm->nodes);
+ }
+}
+
+static gint widget_in_workspace(gconstpointer workspace, gconstpointer wid)
+{
+ GntWS *s = (GntWS *)workspace;
+ if (s->list && g_list_find(s->list, wid))
+ return 0;
+ return 1;
+}
+
+GntWS *gnt_wm_widget_find_workspace(GntWM *wm, GntWidget *widget)
+{
+ GList *l = g_list_find_custom(wm->workspaces, widget, widget_in_workspace);
+ if (l)
+ return l->data;
+ return NULL;
+}
+
+static void free_workspaces(gpointer data, gpointer n)
+{
+ GntWS *s = data;
+ g_free(s->name);
+}
+
+void gnt_wm_set_workspaces(GntWM *wm, GList *workspaces)
+{
+ g_list_foreach(wm->workspaces, free_workspaces, NULL);
+ wm->workspaces = workspaces;
+ gnt_wm_switch_workspace(wm, 0);
+}
+
static void
update_window_in_list(GntWM *wm, GntWidget *wid)
{
@@ -1202,7 +1447,7 @@ update_window_in_list(GntWM *wm, GntWidget *wid)
if (wm->windows == NULL)
return;
- if (wid == wm->ordered->data)
+ if (wm->cws->ordered && wid == wm->cws->ordered->data)
flag |= GNT_TEXT_FLAG_DIM;
else if (GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_URGENT))
flag |= GNT_TEXT_FLAG_BOLD;
@@ -1210,6 +1455,29 @@ update_window_in_list(GntWM *wm, GntWidget *wid)
gnt_tree_set_row_flags(GNT_TREE(wm->windows->tree), wid, flag);
}
+static gboolean
+match_title(gpointer title, gpointer n, gpointer wid_title)
+{
+ /* maybe check for regex.h? */
+ if (g_strrstr((gchar *)wid_title, (gchar *)title))
+ return TRUE;
+ return FALSE;
+}
+
+static GntWS *
+new_widget_find_workspace(GntWM *wm, GntWidget *widget, gchar *wid_title)
+{
+ GntWS *ret;
+ const gchar *name;
+ ret = g_hash_table_find(wm->title_places, match_title, wid_title);
+ if (ret)
+ return ret;
+ name = gnt_widget_get_name(widget);
+ if (name)
+ ret = g_hash_table_lookup(wm->name_places, name);
+ return ret ? ret : wm->cws;
+}
+
static void
gnt_wm_new_window_real(GntWM *wm, GntWidget *widget)
{
@@ -1256,7 +1524,7 @@ gnt_wm_new_window_real(GntWM *wm, GntWidget *widget)
w = MIN(w, maxx);
h = MIN(h, maxy);
node->window = newwin(h + shadow, w + shadow, y, x);
- copy_win(widget, node);
+ gnt_wm_copy_win(widget, node);
}
#endif
@@ -1264,18 +1532,25 @@ gnt_wm_new_window_real(GntWM *wm, GntWidget *widget)
set_panel_userptr(node->panel, node);
if (!transient) {
+ GntWS *ws = wm->cws;
if (node->me != wm->_list.window) {
GntWidget *w = NULL;
- if (wm->ordered)
- w = wm->ordered->data;
+ if (GNT_IS_BOX(widget)) {
+ char *title = GNT_BOX(widget)->title;
+ ws = new_widget_find_workspace(wm, widget, title);
+ }
+
+ if (ws->ordered)
+ w = ws->ordered->data;
- wm->list = g_list_append(wm->list, widget);
+ node->ws = ws;
+ ws->list = g_list_append(ws->list, widget);
if (wm->event_stack)
- wm->ordered = g_list_prepend(wm->ordered, widget);
+ ws->ordered = g_list_prepend(ws->ordered, widget);
else
- wm->ordered = g_list_append(wm->ordered, widget);
+ ws->ordered = g_list_append(ws->ordered, widget);
gnt_widget_set_focus(widget, TRUE);
if (w)
@@ -1286,7 +1561,10 @@ gnt_wm_new_window_real(GntWM *wm, GntWidget *widget)
gnt_wm_raise_window(wm, node->me);
} else {
bottom_panel(node->panel); /* New windows should not grab focus */
+ gnt_widget_set_focus(node->me, FALSE);
gnt_widget_set_urgent(node->me);
+ if (wm->cws != ws)
+ gnt_ws_widget_hide(widget, wm->nodes);
}
}
}
@@ -1320,13 +1598,13 @@ void gnt_wm_new_window(GntWM *wm, GntWidget *widget)
&& GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)) {
gnt_tree_add_row_last(GNT_TREE(wm->windows->tree), widget,
gnt_tree_create_row(GNT_TREE(wm->windows->tree), GNT_BOX(widget)->title),
- NULL);
+ g_object_get_data(G_OBJECT(wm->windows->tree), "workspace") ? wm->cws : NULL);
update_window_in_list(wm, widget);
}
}
update_screen(wm);
- draw_taskbar(wm, FALSE);
+ gnt_ws_draw_taskbar(wm->cws, FALSE);
}
void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget)
@@ -1336,9 +1614,12 @@ void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget)
void gnt_wm_window_close(GntWM *wm, GntWidget *widget)
{
+ GntWS *s;
GntNode *node;
int pos;
+ s = gnt_wm_widget_find_workspace(wm, widget);
+
if ((node = g_hash_table_lookup(wm->nodes, widget)) == NULL)
return;
@@ -1349,18 +1630,20 @@ void gnt_wm_window_close(GntWM *wm, GntWidget *widget)
gnt_tree_remove(GNT_TREE(wm->windows->tree), widget);
}
- pos = g_list_index(wm->list, widget);
+ if (s) {
+ pos = g_list_index(s->list, widget);
- if (pos != -1) {
- wm->list = g_list_remove(wm->list, widget);
- wm->ordered = g_list_remove(wm->ordered, widget);
+ if (pos != -1) {
+ s->list = g_list_remove(s->list, widget);
+ s->ordered = g_list_remove(s->ordered, widget);
- if (wm->ordered)
- gnt_wm_raise_window(wm, wm->ordered->data);
+ if (s->ordered && wm->cws == s)
+ gnt_wm_raise_window(wm, s->ordered->data);
+ }
}
update_screen(wm);
- draw_taskbar(wm, FALSE);
+ gnt_ws_draw_taskbar(wm->cws, FALSE);
}
time_t gnt_wm_get_idle_time()
@@ -1381,10 +1664,10 @@ gboolean gnt_wm_process_input(GntWM *wm, const char *keys)
}
/* Do some manual checking */
- if (wm->ordered && wm->mode != GNT_KP_MODE_NORMAL) {
+ if (wm->cws->ordered && wm->mode != GNT_KP_MODE_NORMAL) {
int xmin = 0, ymin = 0, xmax = getmaxx(stdscr), ymax = getmaxy(stdscr) - 1;
int x, y, w, h;
- GntWidget *widget = GNT_WIDGET(wm->ordered->data);
+ GntWidget *widget = GNT_WIDGET(wm->cws->ordered->data);
int ox, oy, ow, oh;
gnt_widget_get_position(widget, &x, &y);
@@ -1460,8 +1743,8 @@ gboolean gnt_wm_process_input(GntWM *wm, const char *keys)
ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys);
else if (wm->_list.window)
ret = gnt_widget_key_pressed(wm->_list.window, keys);
- else if (wm->ordered)
- ret = gnt_widget_key_pressed(GNT_WIDGET(wm->ordered->data), keys);
+ else if (wm->cws->ordered)
+ ret = gnt_widget_key_pressed(GNT_WIDGET(wm->cws->ordered->data), keys);
return ret;
}
@@ -1595,9 +1878,9 @@ gnt_wm_give_focus(GntWM *wm, GntWidget *widget)
return;
if (widget != wm->_list.window && !GNT_IS_MENU(widget) &&
- wm->ordered->data != widget) {
- GntWidget *w = wm->ordered->data;
- wm->ordered = g_list_bring_to_front(wm->ordered, widget);
+ wm->cws->ordered->data != widget) {
+ GntWidget *w = wm->cws->ordered->data;
+ wm->cws->ordered = g_list_bring_to_front(wm->cws->ordered, widget);
gnt_widget_set_focus(w, FALSE);
}
@@ -1611,27 +1894,35 @@ gnt_wm_give_focus(GntWM *wm, GntWidget *widget)
top_panel(nd->panel);
}
update_screen(wm);
- draw_taskbar(wm, FALSE);
+ gnt_ws_draw_taskbar(wm->cws, FALSE);
}
void gnt_wm_update_window(GntWM *wm, GntWidget *widget)
{
- GntNode *node;
+ GntNode *node = NULL;
+ GntWS *ws;
while (widget->parent)
widget = widget->parent;
if (!GNT_IS_MENU(widget))
gnt_box_sync_children(GNT_BOX(widget));
+ ws = gnt_wm_widget_find_workspace(wm, widget);
node = g_hash_table_lookup(wm->nodes, widget);
if (node == NULL) {
gnt_wm_new_window(wm, widget);
} else
g_signal_emit(wm, signals[SIG_UPDATE_WIN], 0, node);
- copy_win(widget, node);
- update_screen(wm);
- draw_taskbar(wm, FALSE);
+ if (ws == wm->cws || GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) {
+ gnt_wm_copy_win(widget, node);
+ update_screen(wm);
+ gnt_ws_draw_taskbar(wm->cws, FALSE);
+ } else if (ws != wm->cws && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_URGENT)) {
+ if (!act || (act && !g_list_find(act, ws)))
+ act = g_list_prepend(act, ws);
+ update_act_msg();
+ }
}
gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget)
@@ -1644,6 +1935,9 @@ gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntW
void gnt_wm_raise_window(GntWM *wm, GntWidget *widget)
{
+ GntWS *ws = gnt_wm_widget_find_workspace(wm, widget);
+ if (wm->cws != ws)
+ gnt_wm_switch_workspace(wm, g_list_index(wm->workspaces, ws));
g_signal_emit(wm, signals[SIG_GIVE_FOCUS], 0, widget);
}
diff --git a/finch/libgnt/gntwm.h b/finch/libgnt/gntwm.h
index d1a9393635..825ec972e4 100644
--- a/finch/libgnt/gntwm.h
+++ b/finch/libgnt/gntwm.h
@@ -1,6 +1,31 @@
+/**
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT 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 library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GNTWM_H
+#define GNTWM_H
#include "gntwidget.h"
#include "gntmenu.h"
+#include "gntws.h"
#include <panel.h>
#include <time.h>
@@ -26,9 +51,10 @@ typedef struct
WINDOW *window;
int scroll;
PANEL *panel;
+ GntWS *ws;
} GntNode;
-typedef struct _GnttWM GntWM;
+typedef struct _GntWM GntWM;
typedef struct _GntPosition
{
@@ -45,14 +71,15 @@ typedef struct _GntAction
void (*callback)();
} GntAction;
-struct _GnttWM
+struct _GntWM
{
GntBindable inherit;
GMainLoop *loop;
- GList *list; /* List of windows ordered on their creation time */
- GList *ordered; /* List of windows ordered on their focus */
+ GList *workspaces;
+ GList *tagged; /* tagged windows */
+ GntWS *cws;
struct {
GntWidget *window;
@@ -62,6 +89,8 @@ struct _GnttWM
*actions; /* Action-list window */
GHashTable *nodes; /* GntWidget -> GntNode */
+ GHashTable *name_places; /* window name -> ws*/
+ GHashTable *title_places; /* window title -> ws */
GList *acts; /* List of actions */
@@ -144,28 +173,111 @@ struct _GntWMClass
G_BEGIN_DECLS
+/**
+ *
+ *
+ * @return
+ */
GType gnt_wm_get_gtype(void);
+void gnt_wm_add_workspace(GntWM *wm, GntWS *ws);
+
+gboolean gnt_wm_switch_workspace(GntWM *wm, gint n);
+gboolean gnt_wm_switch_workspace_prev(GntWM *wm);
+gboolean gnt_wm_switch_workspace_next(GntWM *wm);
+void gnt_wm_widget_move_workspace(GntWM *wm, GntWS *neww, GntWidget *widget);
+void gnt_wm_set_workspaces(GntWM *wm, GList *workspaces);
+GntWS *gnt_wm_widget_find_workspace(GntWM *wm, GntWidget *widget);
+
+/**
+ *
+ * @param wm
+ * @param widget
+ */
void gnt_wm_new_window(GntWM *wm, GntWidget *widget);
+/**
+ *
+ * @param wm
+ * @param widget
+ */
void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget);
+/**
+ *
+ * @param wm
+ * @param widget
+ */
void gnt_wm_window_close(GntWM *wm, GntWidget *widget);
+/**
+ *
+ * @param wm
+ * @param string
+ *
+ * @return
+ */
gboolean gnt_wm_process_input(GntWM *wm, const char *string);
+/**
+ *
+ * @param wm
+ * @param event
+ * @param x
+ * @param y
+ * @param widget
+ *
+ * @return
+ */
gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget);
+/**
+ *
+ * @param wm
+ * @param widget
+ * @param width
+ * @param height
+ */
void gnt_wm_resize_window(GntWM *wm, GntWidget *widget, int width, int height);
+/**
+ *
+ * @param wm
+ * @param widget
+ * @param x
+ * @param y
+ */
void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y);
+/**
+ *
+ * @param wm
+ * @param widget
+ */
void gnt_wm_update_window(GntWM *wm, GntWidget *widget);
+/**
+ *
+ * @param wm
+ * @param widget
+ */
void gnt_wm_raise_window(GntWM *wm, GntWidget *widget);
+/**
+ *
+ * @param wm
+ * @param set
+ */
void gnt_wm_set_event_stack(GntWM *wm, gboolean set);
+void gnt_wm_copy_win(GntWidget *widget, GntNode *node);
+
+/**
+ *
+ *
+ * @return
+ */
time_t gnt_wm_get_idle_time(void);
G_END_DECLS
+#endif
diff --git a/finch/libgnt/gntws.c b/finch/libgnt/gntws.c
new file mode 100644
index 0000000000..297a21d141
--- /dev/null
+++ b/finch/libgnt/gntws.c
@@ -0,0 +1,168 @@
+#include <gmodule.h>
+
+#include "gntbox.h"
+#include "gntwidget.h"
+#include "gntwindow.h"
+#include "gntwm.h"
+#include "gntws.h"
+
+static void
+widget_hide(gpointer data, gpointer nodes)
+{
+ GntWidget *widget = GNT_WIDGET(data);
+ GntNode *node = g_hash_table_lookup(nodes, widget);
+ if (GNT_IS_WINDOW(widget))
+ gnt_window_workspace_hiding(GNT_WINDOW(widget));
+ hide_panel(node->panel);
+}
+
+static void
+widget_show(gpointer data, gpointer nodes)
+{
+ GntNode *node = g_hash_table_lookup(nodes, data);
+ GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(data), GNT_WIDGET_INVISIBLE);
+ if (node) {
+ show_panel(node->panel);
+ gnt_wm_copy_win(GNT_WIDGET(data), node);
+ }
+}
+
+void
+gnt_ws_draw_taskbar(GntWS *ws, gboolean reposition)
+{
+ static WINDOW *taskbar = NULL;
+ GList *iter;
+ int n, width = 0;
+ int i;
+
+ if (taskbar == NULL) {
+ taskbar = newwin(1, getmaxx(stdscr), getmaxy(stdscr) - 1, 0);
+ } else if (reposition) {
+ int Y_MAX = getmaxy(stdscr) - 1;
+ mvwin(taskbar, Y_MAX, 0);
+ }
+
+ wbkgdset(taskbar, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
+ werase(taskbar);
+
+ n = g_list_length(ws->list);
+ if (n)
+ width = getmaxx(stdscr) / n;
+
+ for (i = 0, iter = ws->list; iter; iter = iter->next, i++) {
+ GntWidget *w = iter->data;
+ int color;
+ const char *title;
+
+ if (w == ws->ordered->data) {
+ /* This is the current window in focus */
+ color = GNT_COLOR_TITLE;
+ } else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_URGENT)) {
+ /* This is a window with the URGENT hint set */
+ color = GNT_COLOR_URGENT;
+ } else {
+ color = GNT_COLOR_NORMAL;
+ }
+ wbkgdset(taskbar, '\0' | COLOR_PAIR(color));
+ if (iter->next)
+ mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), width);
+ else
+ mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), getmaxx(stdscr) - width * i);
+ title = GNT_BOX(w)->title;
+ mvwprintw(taskbar, 0, width * i, "%s", title ? title : "<gnt>");
+ if (i)
+ mvwaddch(taskbar, 0, width *i - 1, ACS_VLINE | A_STANDOUT | COLOR_PAIR(GNT_COLOR_NORMAL));
+ }
+ wrefresh(taskbar);
+}
+
+static void
+gnt_ws_init(GTypeInstance *instance, gpointer class)
+{
+ GntWS *ws = GNT_WS(instance);
+ ws->list = NULL;
+ ws->ordered = NULL;
+ ws->name = NULL;
+}
+
+void gnt_ws_add_widget(GntWS *ws, GntWidget* wid)
+{
+ ws->list = g_list_append(ws->list, wid);
+ ws->ordered = g_list_prepend(ws->ordered, wid);
+}
+
+void gnt_ws_remove_widget(GntWS *ws, GntWidget* wid)
+{
+ ws->list = g_list_remove(ws->list, wid);
+ ws->ordered = g_list_remove(ws->ordered, wid);
+}
+
+void
+gnt_ws_set_name(GntWS *ws, const gchar *name)
+{
+ g_free(ws->name);
+ ws->name = g_strdup(name);
+}
+
+void
+gnt_ws_hide(GntWS *ws, GHashTable *nodes)
+{
+ g_list_foreach(ws->ordered, widget_hide, nodes);
+}
+
+void gnt_ws_widget_hide(GntWidget *widget, GHashTable *nodes) {
+ widget_hide(widget, nodes);
+}
+
+void gnt_ws_widget_show(GntWidget *widget, GHashTable *nodes) {
+ widget_show(widget, nodes);
+}
+
+void
+gnt_ws_show(GntWS *ws, GHashTable *nodes)
+{
+ GList *l;
+ for (l = g_list_last(ws->ordered); l; l = g_list_previous(l))
+ widget_show(l->data, nodes);
+}
+
+GType
+gnt_ws_get_gtype(void)
+{
+ static GType type = 0;
+
+ if(type == 0) {
+ static const GTypeInfo info = {
+ sizeof(GntWSClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ /*(GClassInitFunc)gnt_ws_class_init,*/
+ NULL,
+ NULL, /* class_data */
+ sizeof(GntWS),
+ 0, /* n_preallocs */
+ gnt_ws_init, /* instance_init */
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static(GNT_TYPE_BINDABLE,
+ "GntWS",
+ &info, 0);
+ }
+
+ return type;
+}
+
+GntWS *gnt_ws_new(const char *name)
+{
+ GntWS *ws = GNT_WS(g_object_new(GNT_TYPE_WS, NULL));
+ ws->name = g_strdup(name ? name : "(noname)");
+ return ws;
+}
+
+const char * gnt_ws_get_name(GntWS *ws)
+{
+ return ws->name;
+}
+
diff --git a/finch/libgnt/gntws.h b/finch/libgnt/gntws.h
new file mode 100644
index 0000000000..a68b6f841b
--- /dev/null
+++ b/finch/libgnt/gntws.h
@@ -0,0 +1,60 @@
+#ifndef GNTWS_H
+#define GNTWS_H
+
+#include "gntwidget.h"
+
+#include <panel.h>
+
+#define GNT_TYPE_WS (gnt_ws_get_gtype())
+#define GNT_WS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNT_TYPE_WS, GntWS))
+#define GNT_IS_WS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNT_TYPE_WS))
+#define GNT_IS_WS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WS))
+#define GNT_WS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WS, GntWSClass))
+
+typedef struct _GntWS GntWS;
+
+struct _GntWS
+{
+ GntBindable inherit;
+ gchar *name;
+ GList *list;
+ GList *ordered;
+ gpointer ui_data;
+
+ void *res1;
+ void *res2;
+ void *res3;
+ void *res4;
+};
+
+typedef struct _GntWSClass GntWSClass;
+
+struct _GntWSClass
+{
+ GntBindableClass parent;
+
+ void (*draw_taskbar)(GntWS *ws, gboolean );
+
+ void (*res1)(void);
+ void (*res2)(void);
+ void (*res3)(void);
+ void (*res4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType gnt_ws_get_gtype(void);
+
+GntWS *gnt_ws_new(const char *name);
+void gnt_ws_set_name(GntWS *, const gchar *);
+void gnt_ws_add_widget(GntWS *, GntWidget *);
+void gnt_ws_remove_widget(GntWS *, GntWidget *);
+void gnt_ws_widget_hide(GntWidget *, GHashTable *nodes);
+void gnt_ws_widget_show(GntWidget *, GHashTable *nodes);
+void gnt_ws_draw_taskbar(GntWS *, gboolean reposition);
+void gnt_ws_hide(GntWS *, GHashTable *);
+void gnt_ws_show(GntWS *, GHashTable *);
+
+const char * gnt_ws_get_name(GntWS *ws);
+
+#endif
diff --git a/finch/libgnt/wms/Makefile.am b/finch/libgnt/wms/Makefile.am
index 693551a94b..7bd28fa94e 100644
--- a/finch/libgnt/wms/Makefile.am
+++ b/finch/libgnt/wms/Makefile.am
@@ -1,9 +1,16 @@
s_la_LDFLAGS = -module -avoid-version
+irssi_la_LDFLAGS = -module -avoid-version
plugin_LTLIBRARIES = \
- s.la
+ s.la \
+ irssi.la
-plugindir = $(libdir)/finch
+plugindir = $(libdir)/gnt
+
+irssi_la_SOURCES = irssi.c
+irssi_la_LIBADD = \
+ $(GLIB_LIBS) \
+ $(top_builddir)/finch/libgnt/libgnt.la
s_la_SOURCES = s.c
s_la_LIBADD = \
diff --git a/finch/libgnt/wms/irssi.c b/finch/libgnt/wms/irssi.c
new file mode 100644
index 0000000000..4c6c03ce8c
--- /dev/null
+++ b/finch/libgnt/wms/irssi.c
@@ -0,0 +1,319 @@
+/**
+ * 1. Buddylist is aligned on the left.
+ * 2. The rest of the screen is split into MxN grid for conversation windows.
+ * - M = irssi-split-h in ~/.gntrc:[general]
+ * - N = irssi-split-v in ~/.gntrc:[general]
+ * - Press alt-shift-k/j/l/h to move the selected window to the frame
+ * above/below/left/right of the current frame.
+ * 3. All the other windows are always centered.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "gnt.h"
+#include "gntbox.h"
+#include "gntmenu.h"
+#include "gntstyle.h"
+#include "gntwm.h"
+#include "gntwindow.h"
+#include "gntlabel.h"
+
+#define TYPE_IRSSI (irssi_get_gtype())
+
+typedef struct _Irssi
+{
+ GntWM inherit;
+ int vert;
+ int horiz;
+
+ /* This is changed whenever the buddylist is opened/closed or resized. */
+ int buddylistwidth;
+} Irssi;
+
+typedef struct _IrssiClass
+{
+ GntWMClass inherit;
+} IrssiClass;
+
+GType irssi_get_gtype(void);
+void gntwm_init(GntWM **wm);
+
+static void (*org_new_window)(GntWM *wm, GntWidget *win);
+
+static void
+get_xywh_for_frame(Irssi *irssi, int hor, int vert, int *x, int *y, int *w, int *h)
+{
+ int width, height, rx, ry;
+
+ width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz;
+ height = (getmaxy(stdscr) - 1) / irssi->vert;
+
+ rx = irssi->buddylistwidth;
+ if (hor)
+ rx += hor * width;
+ rx++;
+
+ ry = 0;
+ if (vert)
+ ry += vert * height + 1;
+
+ if (x) *x = rx;
+ if (y) *y = ry;
+ if (w) {
+ *w = (hor == irssi->horiz - 1) ? (getmaxx(stdscr) - rx) : (width - 1);
+ }
+ if (h) {
+ *h = (vert == irssi->vert - 1) ? (getmaxy(stdscr) - 1 - ry) : (height - !!vert);
+ }
+}
+
+static void
+draw_line_separators(Irssi *irssi)
+{
+ int x, y;
+ int width, height;
+
+ wclear(stdscr);
+ /* Draw the separator for the buddylist */
+ if (irssi->buddylistwidth)
+ mvwvline(stdscr, 0, irssi->buddylistwidth,
+ ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1);
+
+ /* Now the separators for the conversation windows */
+ width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz;
+ height = (getmaxy(stdscr) - 1) / irssi->vert;
+ for (x = 1; x < irssi->horiz; x++) {
+ mvwvline(stdscr, 0, irssi->buddylistwidth + x * width,
+ ACS_VLINE | COLOR_PAIR(GNT_COLOR_NORMAL), getmaxy(stdscr) - 1);
+ }
+
+ for (y = 1; y < irssi->vert; y++) {
+ mvwhline(stdscr, y * height, irssi->buddylistwidth + 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL),
+ getmaxx(stdscr) - irssi->buddylistwidth);
+ for (x = 1; x < irssi->horiz; x++) {
+ mvwaddch(stdscr, y * height, x * width + irssi->buddylistwidth, ACS_PLUS | COLOR_PAIR(GNT_COLOR_NORMAL));
+ }
+ if (irssi->buddylistwidth)
+ mvwaddch(stdscr, y * height, irssi->buddylistwidth, ACS_LTEE | COLOR_PAIR(GNT_COLOR_NORMAL));
+ }
+}
+
+static gboolean
+is_budddylist(GntWidget *win)
+{
+ const char *name = gnt_widget_get_name(win);
+ if (name && strcmp(name, "buddylist") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+static void
+remove_border_set_position_size(GntWM *wm, GntWidget *win, int x, int y, int w, int h)
+{
+ gnt_box_set_toplevel(GNT_BOX(win), FALSE);
+ GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_CAN_TAKE_FOCUS);
+
+ gnt_widget_set_position(win, x, y);
+ mvwin(win->window, y, x);
+ gnt_widget_set_size(win, (w < 0) ? -1 : w + 2, h + 2);
+}
+
+static void
+irssi_new_window(GntWM *wm, GntWidget *win)
+{
+ const char *name;
+ int x, y, w, h;
+
+ name = gnt_widget_get_name(win);
+ if (!name || strcmp(name, "conversation-window")) {
+ if (!GNT_IS_MENU(win) && !GNT_WIDGET_IS_FLAG_SET(win, GNT_WIDGET_TRANSIENT)) {
+ if ((!name || strcmp(name, "buddylist"))) {
+ gnt_widget_get_size(win, &w, &h);
+ x = (getmaxx(stdscr) - w) / 2;
+ y = (getmaxy(stdscr) - h) / 2;
+ gnt_widget_set_position(win, x, y);
+ mvwin(win->window, y, x);
+ } else {
+ remove_border_set_position_size(wm, win, 0, 0, -1, getmaxy(stdscr) - 1);
+ gnt_widget_get_size(win, &((Irssi*)wm)->buddylistwidth, NULL);
+ draw_line_separators((Irssi*)wm);
+ }
+ }
+ org_new_window(wm, win);
+ return;
+ }
+
+ /* The window we have here is a conversation window. */
+
+ /* XXX: There should be some way to remember which frame a conversation window
+ * was in the last time. Perhaps save them in some ~/.gntpositionirssi or some
+ * such. */
+ get_xywh_for_frame((Irssi*)wm, 0, 0, &x, &y, &w, &h);
+ remove_border_set_position_size(wm, win, x, y, w, h);
+ org_new_window(wm, win);
+}
+
+static void
+irssi_window_resized(GntWM *wm, GntNode *node)
+{
+ if (!is_budddylist(node->me))
+ return;
+
+ gnt_widget_get_size(node->me, &((Irssi*)wm)->buddylistwidth, NULL);
+ draw_line_separators((Irssi*)wm);
+}
+
+static gboolean
+irssi_close_window(GntWM *wm, GntWidget *win)
+{
+ if (is_budddylist(win))
+ ((Irssi*)wm)->buddylistwidth = 0;
+ return FALSE;
+}
+
+static gboolean
+update_conv_window_title(GntNode *node)
+{
+ char title[256];
+ snprintf(title, sizeof(title), "%d: %s",
+ (int)g_object_get_data(G_OBJECT(node->me), "irssi-index") + 1, GNT_BOX(node->me)->title);
+ wbkgdset(node->window, '\0' | COLOR_PAIR(gnt_widget_has_focus(node->me) ? GNT_COLOR_TITLE : GNT_COLOR_TITLE_D));
+ mvwaddstr(node->window, 0, 0, title);
+ update_panels();
+ doupdate();
+ return FALSE;
+}
+
+static void
+irssi_update_window(GntWM *wm, GntNode *node)
+{
+ GntWidget *win = node->me;
+ const char *name = gnt_widget_get_name(win);
+ if (!name || !GNT_IS_BOX(win) || strcmp(name, "conversation-window"))
+ return;
+ g_object_set_data(G_OBJECT(win), "irssi-index", GINT_TO_POINTER(g_list_index(wm->cws->list, win)));
+ g_timeout_add(0, (GSourceFunc)update_conv_window_title, node);
+}
+
+static void
+find_window_position(Irssi *irssi, GntWidget *win, int *h, int *v)
+{
+ int x, y;
+ int width, height;
+
+ gnt_widget_get_position(win, &x, &y);
+ width = (getmaxx(stdscr) - irssi->buddylistwidth) / irssi->horiz;
+ height = (getmaxy(stdscr) - 1) / irssi->vert;
+
+ if (h)
+ *h = (x - irssi->buddylistwidth) / width;
+ if (v)
+ *v = y / height;
+}
+
+static gboolean
+move_direction(GntBindable *bindable, GList *list)
+{
+ GntWM *wm = GNT_WM(bindable);
+ Irssi *irssi = (Irssi*)wm;
+ int vert, hor;
+ int x, y, w, h;
+ GntWidget *win;
+
+ if (wm->cws->ordered == NULL || is_budddylist(win = GNT_WIDGET(wm->cws->ordered->data)))
+ return FALSE;
+
+ find_window_position(irssi, win, &hor, &vert);
+
+ switch ((int)list->data) {
+ case 'k':
+ vert = MAX(0, vert - 1);
+ break;
+ case 'j':
+ vert = MIN(vert + 1, irssi->vert - 1);
+ break;
+ case 'l':
+ hor = MIN(hor + 1, irssi->horiz - 1);
+ break;
+ case 'h':
+ hor = MAX(0, hor - 1);
+ break;
+ }
+ get_xywh_for_frame(irssi, hor, vert, &x, &y, &w, &h);
+ gnt_wm_move_window(wm, win, x, y);
+ gnt_wm_resize_window(wm, win, w, h);
+ return TRUE;
+}
+
+static void
+irssi_class_init(IrssiClass *klass)
+{
+ GntWMClass *pclass = GNT_WM_CLASS(klass);
+
+ org_new_window = pclass->new_window;
+
+ pclass->new_window = irssi_new_window;
+ pclass->window_resized = irssi_window_resized;
+ pclass->close_window = irssi_close_window;
+ pclass->window_update = irssi_update_window;
+
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-up", move_direction,
+ "\033" "K", GINT_TO_POINTER('k'), NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-down", move_direction,
+ "\033" "J", GINT_TO_POINTER('j'), NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-right", move_direction,
+ "\033" "L", GINT_TO_POINTER('l'), NULL);
+ gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "move-left", move_direction,
+ "\033" "H", GINT_TO_POINTER('h'), NULL);
+
+ gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
+ GNTDEBUG;
+}
+
+void gntwm_init(GntWM **wm)
+{
+ const char *style = NULL;
+ Irssi *irssi;
+
+ irssi = g_object_new(TYPE_IRSSI, NULL);
+ *wm = GNT_WM(irssi);
+
+ style = gnt_style_get_from_name("irssi-split-v");
+ irssi->vert = style ? atoi(style) : 1;
+
+ style = gnt_style_get_from_name("irssi-split-h");
+ irssi->horiz = style ? atoi(style) : 1;
+
+ irssi->vert = MAX(irssi->vert, 1);
+ irssi->horiz = MAX(irssi->horiz, 1);
+
+ irssi->buddylistwidth = 0;
+}
+
+GType irssi_get_gtype(void)
+{
+ static GType type = 0;
+
+ if(type == 0) {
+ static const GTypeInfo info = {
+ sizeof(IrssiClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc)irssi_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof(Irssi),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL
+ };
+
+ type = g_type_register_static(GNT_TYPE_WM,
+ "GntIrssi",
+ &info, 0);
+ }
+
+ return type;
+}
+
diff --git a/finch/libgnt/wms/s.c b/finch/libgnt/wms/s.c
index 490b595c4e..627d31413b 100644
--- a/finch/libgnt/wms/s.c
+++ b/finch/libgnt/wms/s.c
@@ -121,7 +121,7 @@ s_new_window(GntWM *wm, GntWidget *win)
static GntWidget *
find_widget(GntWM *wm, const char *wname)
{
- const GList *iter = wm->list;
+ const GList *iter = wm->cws->list;
for (; iter; iter = iter->next) {
GntWidget *widget = iter->data;
const char *name = gnt_widget_get_name(widget);
diff --git a/libpurple/Makefile.am b/libpurple/Makefile.am
index 7bc5c79b96..a5e1d79b42 100644
--- a/libpurple/Makefile.am
+++ b/libpurple/Makefile.am
@@ -151,7 +151,7 @@ dbus_sources = dbus-server.c dbus-useful.c
dbus_headers = dbus-bindings.h dbus-purple.h dbus-server.h dbus-useful.h dbus-define-api.h
dbus_exported = dbus-useful.h dbus-define-api.h account.h blist.h buddyicon.h \
- connection.h conversation.h core.h log.h notify.h prefs.h roomlist.h \
+ connection.h conversation.h core.h ft.h log.h notify.h prefs.h roomlist.h \
savedstatuses.h status.h server.h util.h xmlnode.h
purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders))
diff --git a/libpurple/account.c b/libpurple/account.c
index 5b2873eee9..57aad79925 100644
--- a/libpurple/account.c
+++ b/libpurple/account.c
@@ -371,7 +371,7 @@ static xmlnode *
accounts_to_xmlnode(void)
{
xmlnode *node, *child;
- GList *cur;
+ const GList *cur;
node = xmlnode_new("account");
xmlnode_set_attrib(node, "version", "1.0");
@@ -417,7 +417,7 @@ static void
schedule_accounts_save()
{
if (save_timer == 0)
- save_timer = purple_timeout_add(5000, save_cb, NULL);
+ save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
}
@@ -877,7 +877,7 @@ purple_account_new(const char *username, const char *protocol_id)
void
purple_account_destroy(PurpleAccount *account)
{
- GList *l;
+ const GList *l;
g_return_if_fail(account != NULL);
@@ -2272,7 +2272,7 @@ purple_accounts_reorder(PurpleAccount *account, gint new_index)
schedule_accounts_save();
}
-GList *
+const GList *
purple_accounts_get_all(void)
{
return accounts;
@@ -2282,7 +2282,7 @@ GList *
purple_accounts_get_all_active(void)
{
GList *list = NULL;
- GList *all = purple_accounts_get_all();
+ const GList *all = purple_accounts_get_all();
while (all != NULL) {
PurpleAccount *account = all->data;
@@ -2300,7 +2300,7 @@ PurpleAccount *
purple_accounts_find(const char *name, const char *protocol_id)
{
PurpleAccount *account = NULL;
- GList *l;
+ const GList *l;
char *who;
g_return_val_if_fail(name != NULL, NULL);
@@ -2327,7 +2327,7 @@ purple_accounts_find(const char *name, const char *protocol_id)
void
purple_accounts_restore_current_statuses()
{
- GList *l;
+ const GList *l;
PurpleAccount *account;
/* If we're not connected to the Internet right now, we bail on this */
diff --git a/libpurple/account.h b/libpurple/account.h
index ef07d72e2a..261c1ad676 100644
--- a/libpurple/account.h
+++ b/libpurple/account.h
@@ -886,7 +886,7 @@ void purple_accounts_reorder(PurpleAccount *account, gint new_index);
*
* @return A list of all accounts.
*/
-GList *purple_accounts_get_all(void);
+const GList *purple_accounts_get_all(void);
/**
* Returns a list of all enabled accounts
diff --git a/libpurple/accountopt.c b/libpurple/accountopt.c
index a2ccd9b6e5..e0556257cd 100644
--- a/libpurple/accountopt.c
+++ b/libpurple/accountopt.c
@@ -308,6 +308,7 @@ purple_account_user_split_new(const char *text, const char *default_value,
split->text = g_strdup(text);
split->field_sep = sep;
split->default_value = g_strdup(default_value);
+ split->reverse = TRUE;
return split;
}
@@ -345,3 +346,19 @@ purple_account_user_split_get_separator(const PurpleAccountUserSplit *split)
return split->field_sep;
}
+
+gboolean
+purple_account_user_split_get_reverse(const PurpleAccountUserSplit *split)
+{
+ g_return_val_if_fail(split != NULL, FALSE);
+
+ return split->reverse;
+}
+
+void
+purple_account_user_split_set_reverse(PurpleAccountUserSplit *split, gboolean reverse)
+{
+ g_return_if_fail(split != NULL);
+
+ split->reverse = reverse;
+}
diff --git a/libpurple/accountopt.h b/libpurple/accountopt.h
index 9ea58d5324..5b3da74932 100644
--- a/libpurple/accountopt.h
+++ b/libpurple/accountopt.h
@@ -64,6 +64,9 @@ typedef struct
char *text; /**< The text that will appear to the user. */
char *default_value; /**< The default value. */
char field_sep; /**< The field separator. */
+ gboolean reverse; /**< TRUE if the separator should be found
+ starting a the end of the string, FALSE
+ otherwise */
} PurpleAccountUserSplit;
@@ -353,6 +356,23 @@ const char *purple_account_user_split_get_default_value(
*/
char purple_account_user_split_get_separator(const PurpleAccountUserSplit *split);
+/**
+ * Returns the 'reverse' value for an account split.
+ *
+ * @param split The account username split.
+ *
+ * @return The 'reverse' value.
+ */
+gboolean purple_account_user_split_get_reverse(const PurpleAccountUserSplit *split);
+
+/**
+ * Sets the 'reverse' value for an account split.
+ *
+ * @param split The account username split.
+ * @param reverse The 'reverse' value
+ */
+void purple_account_user_split_set_reverse(PurpleAccountUserSplit *split, gboolean reverse);
+
/*@}*/
#ifdef __cplusplus
diff --git a/libpurple/blist.c b/libpurple/blist.c
index a8589d69e8..be32b66f66 100644
--- a/libpurple/blist.c
+++ b/libpurple/blist.c
@@ -304,7 +304,7 @@ blist_to_xmlnode()
{
xmlnode *node, *child, *grandchild;
PurpleBlistNode *gnode;
- GList *cur;
+ const GList *cur;
node = xmlnode_new("purple");
xmlnode_set_attrib(node, "version", "1.0");
@@ -365,7 +365,7 @@ void
purple_blist_schedule_save()
{
if (save_timer == 0)
- save_timer = purple_timeout_add(5000, save_cb, NULL);
+ save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
}
@@ -1895,7 +1895,7 @@ void purple_blist_remove_group(PurpleGroup *group)
{
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
PurpleBlistNode *node;
- GList *l;
+ const GList *l;
g_return_if_fail(group != NULL);
@@ -2500,6 +2500,13 @@ purple_blist_node_get_flags(PurpleBlistNode *node)
return node->flags;
}
+PurpleBlistNodeType
+purple_blist_node_get_type(PurpleBlistNode *node)
+{
+ g_return_val_if_fail(node != NULL, PURPLE_BLIST_OTHER_NODE);
+ return node->type;
+}
+
void
purple_blist_node_set_bool(PurpleBlistNode* node, const char *key, gboolean data)
{
diff --git a/libpurple/blist.h b/libpurple/blist.h
index 90b569e0ae..b196259c37 100644
--- a/libpurple/blist.h
+++ b/libpurple/blist.h
@@ -864,6 +864,15 @@ void purple_blist_node_set_flags(PurpleBlistNode *node, PurpleBlistNodeFlags fla
*/
PurpleBlistNodeFlags purple_blist_node_get_flags(PurpleBlistNode *node);
+/**
+ * Get the type of a given node.
+ *
+ * @param node The node.
+ *
+ * @return The type of the node.
+ */
+PurpleBlistNodeType purple_blist_node_get_type(PurpleBlistNode *node);
+
/*@}*/
/**
diff --git a/libpurple/buddyicon.c b/libpurple/buddyicon.c
index db27a0b02e..403a02d47b 100644
--- a/libpurple/buddyicon.c
+++ b/libpurple/buddyicon.c
@@ -24,7 +24,6 @@
*/
#include "internal.h"
#include "buddyicon.h"
-#include "cipher.h"
#include "conversation.h"
#include "dbus-maybe.h"
#include "debug.h"
@@ -93,33 +92,6 @@ unref_filename(const char *filename)
}
}
-static char *
-purple_buddy_icon_data_calculate_filename(guchar *icon_data, size_t icon_len)
-{
- PurpleCipherContext *context;
- gchar digest[41];
-
- context = purple_cipher_context_new_by_name("sha1", NULL);
- if (context == NULL)
- {
- purple_debug_error("buddyicon", "Could not find sha1 cipher\n");
- g_return_val_if_reached(NULL);
- }
-
- /* Hash the icon data */
- purple_cipher_context_append(context, icon_data, icon_len);
- if (!purple_cipher_context_digest_to_str(context, sizeof(digest), digest, NULL))
- {
- purple_debug_error("buddyicon", "Failed to get SHA-1 digest.\n");
- g_return_val_if_reached(NULL);
- }
- purple_cipher_context_destroy(context);
-
- /* Return the filename */
- return g_strdup_printf("%s.%s", digest,
- purple_util_get_image_extension(icon_data, icon_len));
-}
-
static void
purple_buddy_icon_data_cache(PurpleStoredImage *img)
{
@@ -238,7 +210,7 @@ purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len, const char *filen
if (filename == NULL)
{
- file = purple_buddy_icon_data_calculate_filename(icon_data, icon_len);
+ file = purple_util_get_image_filename(icon_data, icon_len);
if (file == NULL)
{
g_free(icon_data);
@@ -966,7 +938,7 @@ migrate_buddy_icon(PurpleBlistNode *node, const char *setting_name,
g_free(path);
- new_filename = purple_buddy_icon_data_calculate_filename(icon_data, icon_len);
+ new_filename = purple_util_get_image_filename(icon_data, icon_len);
if (new_filename == NULL)
{
purple_debug_error("buddyicon",
@@ -1049,7 +1021,7 @@ void
_purple_buddy_icons_account_loaded_cb()
{
const char *dirname = purple_buddy_icons_get_cache_dir();
- GList *cur;
+ const GList *cur;
for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
{
diff --git a/libpurple/buddyicon.h b/libpurple/buddyicon.h
index af8b6c7bc6..f5cabebc6b 100644
--- a/libpurple/buddyicon.h
+++ b/libpurple/buddyicon.h
@@ -31,6 +31,7 @@ typedef struct _PurpleBuddyIcon PurpleBuddyIcon;
#include "blist.h"
#include "imgstore.h"
#include "prpl.h"
+#include "util.h"
#ifdef __cplusplus
extern "C" {
diff --git a/libpurple/connection.c b/libpurple/connection.c
index a0dd9021b1..754c94fd00 100644
--- a/libpurple/connection.c
+++ b/libpurple/connection.c
@@ -72,7 +72,7 @@ update_keepalive(PurpleConnection *gc, gboolean on)
if (on && !gc->keepalive)
{
purple_debug_info("connection", "Activating keepalive.\n");
- gc->keepalive = purple_timeout_add(30000, send_keepalive, gc);
+ gc->keepalive = purple_timeout_add_seconds(30, send_keepalive, gc);
}
else if (!on && gc->keepalive > 0)
{
@@ -456,7 +456,7 @@ purple_connection_error(PurpleConnection *gc, const char *text)
void
purple_connections_disconnect_all(void)
{
- GList *l;
+ const GList *l;
PurpleConnection *gc;
while ((l = purple_connections_get_all()) != NULL) {
@@ -466,13 +466,13 @@ purple_connections_disconnect_all(void)
}
}
-GList *
+const GList *
purple_connections_get_all(void)
{
return connections;
}
-GList *
+const GList *
purple_connections_get_connecting(void)
{
return connections_connecting;
diff --git a/libpurple/connection.h b/libpurple/connection.h
index d2d73ccb23..1a87b4e56f 100644
--- a/libpurple/connection.h
+++ b/libpurple/connection.h
@@ -261,14 +261,14 @@ void purple_connections_disconnect_all(void);
*
* @return A list of all active connections.
*/
-GList *purple_connections_get_all(void);
+const GList *purple_connections_get_all(void);
/**
* Returns a list of all connections in the process of connecting.
*
* @return A list of connecting connections.
*/
-GList *purple_connections_get_connecting(void);
+const GList *purple_connections_get_connecting(void);
/**
* Checks if gc is still a valid pointer to a gc.
@@ -279,7 +279,7 @@ GList *purple_connections_get_connecting(void);
* TODO: Eventually this bad boy will be removed, because it is
* a gross fix for a crashy problem.
*/
-#define PURPLE_CONNECTION_IS_VALID(gc) (g_list_find(purple_connections_get_all(), (gc)) != NULL)
+#define PURPLE_CONNECTION_IS_VALID(gc) (g_list_find((GList *)purple_connections_get_all(), (gc)) != NULL)
/*@}*/
diff --git a/libpurple/conversation.c b/libpurple/conversation.c
index 3791cb6696..853911d53d 100644
--- a/libpurple/conversation.c
+++ b/libpurple/conversation.c
@@ -21,6 +21,7 @@
*/
#include "internal.h"
#include "blist.h"
+#include "cmds.h"
#include "conversation.h"
#include "dbus-maybe.h"
#include "debug.h"
@@ -108,8 +109,12 @@ common_send(PurpleConversation *conv, const char *message, PurpleMessageFlags ms
type = purple_conversation_get_type(conv);
- /* Always linkfy the text for display */
- displayed = purple_markup_linkify(message);
+ /* Always linkfy the text for display, unless we're
+ * explicitly asked to do otheriwse*/
+ if(msgflags & PURPLE_MESSAGE_NO_LINKIFY)
+ displayed = g_strdup(message);
+ else
+ displayed = purple_markup_linkify(message);
if ((conv->features & PURPLE_CONNECTION_HTML) &&
!(msgflags & PURPLE_MESSAGE_RAW))
@@ -626,7 +631,7 @@ void
purple_conversation_foreach(void (*func)(PurpleConversation *conv))
{
PurpleConversation *conv;
- GList *l;
+ const GList *l;
g_return_if_fail(func != NULL);
@@ -727,19 +732,19 @@ purple_conversation_get_data(PurpleConversation *conv, const char *key)
return g_hash_table_lookup(conv->data, key);
}
-GList *
+const GList *
purple_get_conversations(void)
{
return conversations;
}
-GList *
+const GList *
purple_get_ims(void)
{
return ims;
}
-GList *
+const GList *
purple_get_chats(void)
{
return chats;
@@ -754,7 +759,7 @@ purple_find_conversation_with_account(PurpleConversationType type,
PurpleConversation *c = NULL;
gchar *name1;
const gchar *name2;
- GList *cnv;
+ const GList *cnv;
g_return_val_if_fail(name != NULL, NULL);
@@ -814,7 +819,7 @@ purple_conversation_write(PurpleConversation *conv, const char *who,
return;
if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM &&
- !g_list_find(purple_get_conversations(), conv))
+ !g_list_find((GList *)purple_get_conversations(), conv))
return;
displayed = g_strdup(message);
@@ -1010,7 +1015,7 @@ purple_conv_im_start_typing_timeout(PurpleConvIm *im, int timeout)
conv = purple_conv_im_get_conversation(im);
name = purple_conversation_get_name(conv);
- im->typing_timeout = purple_timeout_add(timeout * 1000, reset_typing_cb, conv);
+ im->typing_timeout = purple_timeout_add_seconds(timeout, reset_typing_cb, conv);
}
void
@@ -1245,7 +1250,7 @@ purple_conv_chat_set_users(PurpleConvChat *chat, GList *users)
return users;
}
-GList *
+const GList *
purple_conv_chat_get_users(const PurpleConvChat *chat)
{
g_return_val_if_fail(chat != NULL, NULL);
@@ -1264,7 +1269,7 @@ purple_conv_chat_ignore(PurpleConvChat *chat, const char *name)
return;
purple_conv_chat_set_ignored(chat,
- g_list_append(purple_conv_chat_get_ignored(chat), g_strdup(name)));
+ g_list_append(chat->ignored, g_strdup(name)));
}
void
@@ -1279,11 +1284,11 @@ purple_conv_chat_unignore(PurpleConvChat *chat, const char *name)
if (!purple_conv_chat_is_user_ignored(chat, name))
return;
- item = g_list_find(purple_conv_chat_get_ignored(chat),
+ item = g_list_find((GList *)purple_conv_chat_get_ignored(chat),
purple_conv_chat_get_ignored_user(chat, name));
purple_conv_chat_set_ignored(chat,
- g_list_remove_link(purple_conv_chat_get_ignored(chat), item));
+ g_list_remove_link(chat->ignored, item));
g_free(item->data);
g_list_free_1(item);
@@ -1299,7 +1304,7 @@ purple_conv_chat_set_ignored(PurpleConvChat *chat, GList *ignored)
return ignored;
}
-GList *
+const GList *
purple_conv_chat_get_ignored(const PurpleConvChat *chat)
{
g_return_val_if_fail(chat != NULL, NULL);
@@ -1310,7 +1315,7 @@ purple_conv_chat_get_ignored(const PurpleConvChat *chat)
const char *
purple_conv_chat_get_ignored_user(const PurpleConvChat *chat, const char *user)
{
- GList *ignored;
+ const GList *ignored;
g_return_val_if_fail(chat != NULL, NULL);
g_return_val_if_fail(user != NULL, NULL);
@@ -1560,7 +1565,7 @@ purple_conv_chat_add_users(PurpleConvChat *chat, GList *users, GList *extra_msgs
cbuddy = purple_conv_chat_cb_new(user, alias, flag);
/* This seems dumb. Why should we set users thousands of times? */
purple_conv_chat_set_users(chat,
- g_list_prepend(purple_conv_chat_get_users(chat), cbuddy));
+ g_list_prepend(chat->in_room, cbuddy));
cbuddies = g_list_prepend(cbuddies, cbuddy);
@@ -1578,7 +1583,9 @@ purple_conv_chat_add_users(PurpleConvChat *chat, GList *users, GList *extra_msgs
}
g_free(escaped);
- purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
+ purple_conversation_write(conv, NULL, tmp,
+ PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
+ time(NULL));
g_free(tmp);
}
@@ -1627,7 +1634,7 @@ purple_conv_chat_rename_user(PurpleConvChat *chat, const char *old_user,
flags = purple_conv_chat_user_get_flags(chat, old_user);
cb = purple_conv_chat_cb_new(new_user, NULL, flags);
purple_conv_chat_set_users(chat,
- g_list_prepend(purple_conv_chat_get_users(chat), cb));
+ g_list_prepend(chat->in_room, cb));
if (!strcmp(chat->nick, purple_normalize(conv->account, old_user))) {
const char *alias;
@@ -1659,7 +1666,7 @@ purple_conv_chat_rename_user(PurpleConvChat *chat, const char *old_user,
if (cb) {
purple_conv_chat_set_users(chat,
- g_list_remove(purple_conv_chat_get_users(chat), cb));
+ g_list_remove(chat->in_room, cb));
purple_conv_chat_cb_destroy(cb);
}
@@ -1704,7 +1711,9 @@ purple_conv_chat_rename_user(PurpleConvChat *chat, const char *old_user,
g_free(escaped2);
}
- purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
+ purple_conversation_write(conv, NULL, tmp,
+ PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
+ time(NULL));
}
}
@@ -1751,7 +1760,7 @@ purple_conv_chat_remove_users(PurpleConvChat *chat, GList *users, const char *re
if (cb) {
purple_conv_chat_set_users(chat,
- g_list_remove(purple_conv_chat_get_users(chat), cb));
+ g_list_remove(chat->in_room, cb));
purple_conv_chat_cb_destroy(cb);
}
@@ -1781,7 +1790,9 @@ purple_conv_chat_remove_users(PurpleConvChat *chat, GList *users, const char *re
}
g_free(escaped);
- purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
+ purple_conversation_write(conv, NULL, tmp,
+ PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
+ time(NULL));
g_free(tmp);
}
@@ -1798,14 +1809,15 @@ purple_conv_chat_clear_users(PurpleConvChat *chat)
{
PurpleConversation *conv;
PurpleConversationUiOps *ops;
- GList *users, *names = NULL;
- GList *l;
+ GList *users;
+ const GList *l;
+ GList *names = NULL;
g_return_if_fail(chat != NULL);
conv = purple_conv_chat_get_conversation(chat);
ops = purple_conversation_get_ui_ops(conv);
- users = purple_conv_chat_get_users(chat);
+ users = chat->in_room;
if (ops != NULL && ops->chat_remove_users != NULL) {
for (l = users; l; l = l->next) {
@@ -1907,7 +1919,7 @@ const char *purple_conv_chat_get_nick(PurpleConvChat *chat) {
PurpleConversation *
purple_find_chat(const PurpleConnection *gc, int id)
{
- GList *l;
+ const GList *l;
PurpleConversation *conv;
for (l = purple_get_chats(); l != NULL; l = l->next) {
@@ -1956,7 +1968,7 @@ purple_conv_chat_cb_new(const char *name, const char *alias, PurpleConvChatBuddy
PurpleConvChatBuddy *
purple_conv_chat_cb_find(PurpleConvChat *chat, const char *name)
{
- GList *l;
+ const GList *l;
PurpleConvChatBuddy *cb = NULL;
g_return_val_if_fail(chat != NULL, NULL);
@@ -1993,6 +2005,29 @@ purple_conv_chat_cb_get_name(PurpleConvChatBuddy *cb)
return cb->name;
}
+GList *
+purple_conversation_get_extended_menu(PurpleConversation *conv)
+{
+ GList *menu = NULL;
+
+ g_return_val_if_fail(conv != NULL, NULL);
+
+ purple_signal_emit(purple_conversations_get_handle(),
+ "conversation-extended-menu", conv, &menu);
+ return menu;
+}
+
+gboolean
+purple_conversation_do_command(PurpleConversation *conv, const gchar *cmdline,
+ const gchar *markup, gchar **error)
+{
+ char *mark = (markup && *markup) ? NULL : g_markup_escape_text(cmdline, -1), *err = NULL;
+ PurpleCmdStatus status = purple_cmd_do_command(conv, cmdline, mark ? mark : markup, error ? error : &err);
+ g_free(mark);
+ g_free(err);
+ return (status == PURPLE_CMD_STATUS_OK);
+}
+
void *
purple_conversations_get_handle(void)
{
@@ -2256,6 +2291,12 @@ purple_conversations_init(void)
PURPLE_SUBTYPE_CONVERSATION),
purple_value_new(PURPLE_TYPE_STRING),
purple_value_new(PURPLE_TYPE_STRING));
+
+ purple_signal_register(handle, "conversation-extended-menu",
+ purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+ purple_value_new(PURPLE_TYPE_SUBTYPE,
+ PURPLE_SUBTYPE_CONVERSATION),
+ purple_value_new(PURPLE_TYPE_BOXED, "GList **"));
}
void
diff --git a/libpurple/conversation.h b/libpurple/conversation.h
index 69beaf4c9e..93b45f73e8 100644
--- a/libpurple/conversation.h
+++ b/libpurple/conversation.h
@@ -116,7 +116,9 @@ typedef enum
PURPLE_MESSAGE_RAW = 0x0800, /**< "Raw" message - don't
apply formatting */
PURPLE_MESSAGE_IMAGES = 0x1000, /**< Message contains images */
- PURPLE_MESSAGE_NOTIFY = 0x2000 /**< Message is a notification */
+ PURPLE_MESSAGE_NOTIFY = 0x2000, /**< Message is a notification */
+ PURPLE_MESSAGE_NO_LINKIFY = 0x4000 /**< Message should not be auto-
+ linkified */
} PurpleMessageFlags;
@@ -502,21 +504,21 @@ gpointer purple_conversation_get_data(PurpleConversation *conv, const char *key)
*
* @return A GList of all conversations.
*/
-GList *purple_get_conversations(void);
+const GList *purple_get_conversations(void);
/**
* Returns a list of all IMs.
*
* @return A GList of all IMs.
*/
-GList *purple_get_ims(void);
+const GList *purple_get_ims(void);
/**
* Returns a list of all chats.
*
* @return A GList of all chats.
*/
-GList *purple_get_chats(void);
+const GList *purple_get_chats(void);
/**
* Finds a conversation with the specified type, name, and Purple account.
@@ -875,7 +877,7 @@ GList *purple_conv_chat_set_users(PurpleConvChat *chat, GList *users);
*
* @return The list of users.
*/
-GList *purple_conv_chat_get_users(const PurpleConvChat *chat);
+const GList *purple_conv_chat_get_users(const PurpleConvChat *chat);
/**
* Ignores a user in a chat room.
@@ -910,7 +912,7 @@ GList *purple_conv_chat_set_ignored(PurpleConvChat *chat, GList *ignored);
*
* @return The list of ignored users.
*/
-GList *purple_conv_chat_get_ignored(const PurpleConvChat *chat);
+const GList *purple_conv_chat_get_ignored(const PurpleConvChat *chat);
/**
* Returns the actual name of the specified ignored user, if it exists in
@@ -1190,6 +1192,30 @@ const char *purple_conv_chat_cb_get_name(PurpleConvChatBuddy *cb);
*/
void purple_conv_chat_cb_destroy(PurpleConvChatBuddy *cb);
+/**
+ * Retrieves the extended menu items for the conversation.
+ *
+ * @param conv The conversation.
+ *
+ * @return A list of PurpleMenuAction items, harvested by the
+ * chat-extended-menu signal. The list and the menuaction
+ * items should be freed by the caller.
+ */
+GList * purple_conversation_get_extended_menu(PurpleConversation *conv);
+
+/**
+ * Perform a command in a conversation. Similar to @see purple_cmd_do_command
+ *
+ * @param conv The conversation.
+ * @param cmdline The entire command including the arguments.
+ * @param markup @c NULL, or the formatted command line.
+ * @param error If the command failed errormsg is filled in with the appropriate error
+ * message, if not @c NULL. It must be freed by the caller with g_free().
+ *
+ * @return @c TRUE if the command was executed successfully, @c FALSE otherwise.
+ */
+gboolean purple_conversation_do_command(PurpleConversation *conv, const gchar *cmdline, const gchar *markup, gchar **error);
+
/*@}*/
/**************************************************************************/
diff --git a/libpurple/core.c b/libpurple/core.c
index 54d7500fc0..cb95170e7b 100644
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -48,7 +48,11 @@
#include "util.h"
#ifdef HAVE_DBUS
+# define DBUS_API_SUBJECT_TO_CHANGE
+# include <dbus/dbus.h>
+# include "dbus-purple.h"
# include "dbus-server.h"
+# include "dbus-bindings.h"
#endif
struct PurpleCore
@@ -276,6 +280,91 @@ purple_core_get_ui_ops(void)
return _ops;
}
+#ifdef HAVE_DBUS
+static char *purple_dbus_owner_user_dir(void)
+{
+ DBusMessage *msg = NULL, *reply = NULL;
+ DBusConnection *dbus_connection = NULL;
+ DBusError dbus_error;
+ char *remote_user_dir = NULL;
+
+ if ((dbus_connection = purple_dbus_get_connection()) == NULL)
+ return NULL;
+
+ if ((msg = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "PurpleUserDir")) == NULL)
+ return NULL;
+
+ dbus_error_init(&dbus_error);
+ reply = dbus_connection_send_with_reply_and_block(dbus_connection, msg, 5000, &dbus_error);
+ dbus_message_unref(msg);
+ dbus_error_free(&dbus_error);
+
+ if (reply)
+ {
+ dbus_error_init(&dbus_error);
+ dbus_message_get_args(reply, &dbus_error, DBUS_TYPE_STRING, &remote_user_dir, DBUS_TYPE_INVALID);
+ remote_user_dir = g_strdup(remote_user_dir);
+ dbus_error_free(&dbus_error);
+ dbus_message_unref(reply);
+ }
+
+ return remote_user_dir;
+}
+
+static void purple_dbus_owner_show_buddy_list(void)
+{
+ DBusError dbus_error;
+ DBusMessage *msg = NULL, *reply = NULL;
+ DBusConnection *dbus_connection = NULL;
+
+ if ((dbus_connection = purple_dbus_get_connection()) == NULL)
+ return;
+
+ if ((msg = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "PurpleBlistShow")) == NULL)
+ return;
+
+ dbus_error_init(&dbus_error);
+ if ((reply = dbus_connection_send_with_reply_and_block(dbus_connection, msg, 5000, &dbus_error)) != NULL)
+ {
+ dbus_message_unref(msg);
+ }
+ dbus_error_free(&dbus_error);
+}
+#endif /* HAVE_DBUS */
+
+gboolean
+purple_core_ensure_single_instance()
+{
+ gboolean is_single_instance = TRUE;
+#ifdef HAVE_DBUS
+ /* in the future, other mechanisms might have already set this to FALSE */
+ if (is_single_instance)
+ {
+ if (!purple_dbus_is_owner())
+ {
+ const char *user_dir = purple_user_dir();
+ char *dbus_owner_user_dir = purple_dbus_owner_user_dir();
+
+ if (NULL == user_dir && NULL != dbus_owner_user_dir)
+ is_single_instance = TRUE;
+ else if (NULL != user_dir && NULL == dbus_owner_user_dir)
+ is_single_instance = TRUE;
+ else if (NULL == user_dir && NULL == dbus_owner_user_dir)
+ is_single_instance = FALSE;
+ else
+ is_single_instance = strcmp(dbus_owner_user_dir, user_dir);
+
+ if (!is_single_instance)
+ purple_dbus_owner_show_buddy_list();
+
+ g_free(dbus_owner_user_dir);
+ }
+ }
+#endif /* HAVE_DBUS */
+
+ return is_single_instance;
+}
+
static gboolean
move_and_symlink_dir(const char *path, const char *basename, const char *old_base, const char *new_base, const char *relative)
{
diff --git a/libpurple/core.h b/libpurple/core.h
index c529da73f0..b8c17122e7 100644
--- a/libpurple/core.h
+++ b/libpurple/core.h
@@ -121,6 +121,16 @@ PurpleCoreUiOps *purple_core_get_ui_ops(void);
*/
gboolean purple_core_migrate(void);
+/**
+ * Ensures that only one instance is running.
+ *
+ * @return A boolean such that @c TRUE indicates that this is the first instance,
+ * whereas @c FALSE indicates that there is another instance running.
+ *
+ * @since 2.1.0
+ */
+gboolean purple_core_ensure_single_instance(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/libpurple/dbus-analyze-functions.py b/libpurple/dbus-analyze-functions.py
index 7d9bab47ac..8058b7ca56 100644
--- a/libpurple/dbus-analyze-functions.py
+++ b/libpurple/dbus-analyze-functions.py
@@ -33,9 +33,13 @@ excluded = [\
]
# This is a list of functions that return a GList* whose elements are
-# string, not pointers to objects. Don't put any functions here, it
-# won't work.
-stringlists = []
+# string, not pointers to objects.
+stringlists = [
+ "purple_prefs_get_path_list",
+ "purple_prefs_get_string_list",
+ "purple_uri_list_extract_filenames",
+ "purple_uri_list_extract_uris",
+]
pointer = "#pointer#"
myexception = "My Exception"
@@ -148,7 +152,7 @@ class Binding:
return self.outputpurplestructure(type, name)
if type[0] in ["GList", "GSList"]:
- return self.outputlist(type, name)
+ return self.outputlist(type, name, const)
raise myexception
@@ -250,7 +254,7 @@ class ClientBinding (Binding):
self.returncode.append("return (%s*) GINT_TO_POINTER(%s);" % (type[0], name));
self.definepurplestructure(type)
- def outputlist(self, type, name):
+ def outputlist(self, type, name, const):
self.functiontype = "%s*" % type[0]
self.decls.append("GArray *%s;" % name)
self.outputparams.append(('dbus_g_type_get_collection("GArray", G_TYPE_INT)', name))
@@ -385,28 +389,40 @@ class ServerBinding (Binding):
self.addouttype("i", name)
# GList*, GSList*, assume that list is a list of objects
-
- # fixme: at the moment, we do NOT free the memory occupied by
- # the list, we should free it if the list has NOT been declared const
-
- # fixme: we assume that this is a list of objects, not a list
- # of strings
-
- def outputlist(self, type, name):
+ # unless the function is in stringlists
+ def outputlist(self, type, name, const):
self.cdecls.append("\tdbus_int32_t %s_LEN;" % name)
self.ccodeout.append("\tg_free(%s);" % name)
+ if const:
+ const_prefix = "const_"
+ else:
+ const_prefix = ""
+
+ if (const):
+ self.cdecls.append("\tconst %s *list;" % type[0]);
+ else:
+ self.cdecls.append("\t%s *list;" % type[0]);
+
if self.function.name in stringlists:
self.cdecls.append("\tchar **%s;" % name)
- self.ccode.append("\t%s = purple_%s_to_array(%s, FALSE, &%s_LEN);" % \
- (name, type[0], self.call, name))
+ self.ccode.append("\tlist = %s;" % self.call)
+ self.ccode.append("\t%s = (char **)purple_const_%s_to_array(list, &%s_LEN);" % \
+ (name, type[0], name))
self.cparamsout.append("\tDBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &%s, %s_LEN" \
% (name, name))
+ if (not const):
+ type_name = type[0].lower()[1:]
+ self.ccodeout.append("\tg_%s_foreach(list, (GFunc)g_free, NULL);" % type_name)
+ self.ccodeout.append("\tg_%s_free(list);" % type_name)
self.addouttype("as", name)
else:
self.cdecls.append("\tdbus_int32_t *%s;" % name)
- self.ccode.append("\t%s = purple_dbusify_%s(%s, FALSE, &%s_LEN);" % \
- (name, type[0], self.call, name))
+ self.ccode.append("\tlist = %s;" % self.call)
+ self.ccode.append("\t%s = purple_dbusify_const_%s(list, &%s_LEN);" % \
+ (name, type[0], name))
+ if (not const):
+ self.ccode.append("\tg_%s_free(list);" % type[0].lower()[1:])
self.cparamsout.append("\tDBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &%s, %s_LEN" \
% (name, name))
self.addouttype("ai", name)
diff --git a/libpurple/dbus-bindings.h b/libpurple/dbus-bindings.h
index b3bc88dd3f..824b37e4ae 100644
--- a/libpurple/dbus-bindings.h
+++ b/libpurple/dbus-bindings.h
@@ -83,14 +83,52 @@ purple_dbus_message_iter_get_args_valist (DBusMessageIter *iter,
int first_arg_type,
va_list var_args);
+/**
+ * @deprecated In 3.0.0, this method will have a signature and behavior
+ * like that of purple_dbusify_const_GList().
+ */
dbus_int32_t* purple_dbusify_GList(GList *list, gboolean free_memory,
dbus_int32_t *len);
+/**
+ * @deprecated In 3.0.0, this method will have a signature and behavior
+ * like that of purple_dbusify_const_GSList().
+ */
dbus_int32_t* purple_dbusify_GSList(GSList *list, gboolean free_memory,
dbus_int32_t *len);
+
+/**
+ * @since 2.1.0
+ */
+dbus_int32_t* purple_dbusify_const_GList(const GList *list, dbus_int32_t *len);
+
+/**
+ * @since 2.1.0
+ */
+dbus_int32_t* purple_dbusify_const_GSList(const GSList *list, dbus_int32_t *len);
+
+/**
+ * @deprecated In 3.0.0, this method will have a signature and behavior
+ * like that of purple_const_GList_to_array().
+ */
gpointer* purple_GList_to_array(GList *list, gboolean free_memory,
dbus_int32_t *len);
+/**
+ * @deprecated In 3.0.0, this method will have a signature and behavior
+ * like that of purple_const_GSList_to_array().
+ */
gpointer* purple_GSList_to_array(GSList *list, gboolean free_memory,
dbus_int32_t *len);
+
+/**
+ * @since 2.1.0
+ */
+gpointer* purple_const_GList_to_array(const GList *list, dbus_int32_t *len);
+
+/**
+ * @since 2.1.0
+ */
+gpointer* purple_const_GSList_to_array(const GSList *list, dbus_int32_t *len);
+
GHashTable *purple_dbus_iter_hash_table(DBusMessageIter *iter, DBusError *error);
const char* empty_to_null(const char *str);
diff --git a/libpurple/dbus-server.c b/libpurple/dbus-server.c
index e40a483844..bf4ea6eb15 100644
--- a/libpurple/dbus-server.c
+++ b/libpurple/dbus-server.c
@@ -65,6 +65,12 @@ static GHashTable *map_id_node;
static GHashTable *map_id_type;
static gchar *init_error;
+static int dbus_request_name_reply = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
+
+gboolean purple_dbus_is_owner(void)
+{
+ return(DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER == dbus_request_name_reply);
+}
/**
* This function initializes the pointer-id traslation system. It
@@ -284,74 +290,112 @@ null_to_empty(const char *s)
}
dbus_int32_t *
-purple_dbusify_GList(GList *list, gboolean free_memory, dbus_int32_t *len)
+purple_dbusify_const_GList(const GList *list, dbus_int32_t *len)
{
dbus_int32_t *array;
int i;
- GList *elem;
+ const GList *elem;
- *len = g_list_length(list);
- array = g_new0(dbus_int32_t, g_list_length(list));
+ /* g_list_length() should really take a const GList */
+ *len = g_list_length((GList *)list);
+ array = g_new0(dbus_int32_t, *len);
for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
array[i] = purple_dbus_pointer_to_id(elem->data);
- if (free_memory)
- g_list_free(list);
+ return array;
+}
+
+dbus_int32_t *
+purple_dbusify_GList(GList *list, gboolean free_memory, dbus_int32_t *len)
+{
+ dbus_int32_t *array = purple_dbusify_const_GList(list, len);
+
+ if (!free_memory)
+ return array;
+ g_list_free(list);
return array;
}
dbus_int32_t *
-purple_dbusify_GSList(GSList *list, gboolean free_memory, dbus_int32_t *len)
+purple_dbusify_const_GSList(const GSList *list, dbus_int32_t *len)
{
dbus_int32_t *array;
int i;
- GSList *elem;
+ const GSList *elem;
- *len = g_slist_length(list);
- array = g_new0(dbus_int32_t, g_slist_length(list));
+ /* g_slist_length should really take a const GSList */
+ *len = g_slist_length((GSList *)list);
+ array = g_new0(dbus_int32_t, *len);
for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
array[i] = purple_dbus_pointer_to_id(elem->data);
- if (free_memory)
- g_slist_free(list);
+ return array;
+}
+
+dbus_int32_t *
+purple_dbusify_GSList(GSList *list, gboolean free_memory, dbus_int32_t *len)
+{
+ dbus_int32_t *array = purple_dbusify_const_GSList(list, len);
+ if (!free_memory)
+ return array;
+
+ g_slist_free(list);
return array;
}
gpointer *
-purple_GList_to_array(GList *list, gboolean free_memory, dbus_int32_t *len)
+purple_const_GList_to_array(const GList *list, dbus_int32_t *len)
{
gpointer *array;
int i;
- GList *elem;
+ const GList *elem;
- *len = g_list_length(list);
- array = g_new0(gpointer, g_list_length(list));
+ *len = g_list_length((GList *)list);
+ array = g_new0(gpointer, *len);
for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
array[i] = elem->data;
- if (free_memory)
- g_list_free(list);
+ return array;
+}
+
+gpointer *
+purple_GList_to_array(GList *list, gboolean free_memory, dbus_int32_t *len)
+{
+ gpointer *array = purple_const_GList_to_array(list, len);
+
+ if (!free_memory)
+ return array;
+ g_list_free(list);
return array;
}
gpointer *
-purple_GSList_to_array(GSList *list, gboolean free_memory, dbus_int32_t *len)
+purple_const_GSList_to_array(const GSList *list, dbus_int32_t *len)
{
gpointer *array;
int i;
- GSList *elem;
+ const GSList *elem;
- *len = g_slist_length(list);
- array = g_new0(gpointer, g_slist_length(list));
+ *len = g_slist_length((GSList *)list);
+ array = g_new0(gpointer, *len);
for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
array[i] = elem->data;
- if (free_memory)
- g_slist_free(list);
+ return array;
+}
+
+gpointer *
+purple_GSList_to_array(GSList *list, gboolean free_memory, dbus_int32_t *len)
+{
+ gpointer *array = purple_const_GSList_to_array(list, len);
+
+ if (!free_memory)
+ return array;
+ g_slist_free(list);
return array;
}
@@ -592,6 +636,7 @@ purple_dbus_dispatch_init(void)
return;
}
+ dbus_request_name_reply =
result = dbus_bus_request_name(purple_dbus_connection,
DBUS_SERVICE_PURPLE, 0, &error);
diff --git a/libpurple/dbus-server.h b/libpurple/dbus-server.h
index 095285836c..bc181e48c2 100644
--- a/libpurple/dbus-server.h
+++ b/libpurple/dbus-server.h
@@ -169,6 +169,13 @@ const char *purple_dbus_get_init_error(void);
void *purple_dbus_get_handle(void);
/**
+ * Determines whether this instance owns the DBus service name
+ *
+ * @since 2.1.0
+ */
+gboolean purple_dbus_is_owner(void);
+
+/**
* Starts Purple's D-BUS server. It is responsible for handling DBUS
* requests from other applications.
*/
diff --git a/libpurple/dbus-useful.c b/libpurple/dbus-useful.c
index b288887b1f..a23c5a71dd 100644
--- a/libpurple/dbus-useful.c
+++ b/libpurple/dbus-useful.c
@@ -11,7 +11,7 @@ purple_accounts_find_ext(const char *name, const char *protocol_id,
gboolean (*account_test)(const PurpleAccount *account))
{
PurpleAccount *result = NULL;
- GList *l;
+ const GList *l;
char *who;
if (name)
diff --git a/libpurple/eventloop.c b/libpurple/eventloop.c
index 06a871093c..29c4f32aac 100644
--- a/libpurple/eventloop.c
+++ b/libpurple/eventloop.c
@@ -35,6 +35,17 @@ purple_timeout_add(guint interval, GSourceFunc function, gpointer data)
return ops->timeout_add(interval, function, data);
}
+guint
+purple_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data)
+{
+ PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
+
+ if (ops->timeout_add_seconds)
+ return ops->timeout_add_seconds(interval, function, data);
+ else
+ return ops->timeout_add(1000 * interval, function, data);
+}
+
gboolean
purple_timeout_remove(guint tag)
{
diff --git a/libpurple/eventloop.h b/libpurple/eventloop.h
index b0523f8876..bde4a0e55e 100644
--- a/libpurple/eventloop.h
+++ b/libpurple/eventloop.h
@@ -48,7 +48,7 @@ typedef struct _PurpleEventLoopUiOps PurpleEventLoopUiOps;
struct _PurpleEventLoopUiOps
{
/**
- * Creates a callback timer.
+ * Creates a callback timer with an interval measured in milliseconds.
* @see g_timeout_add, purple_timeout_add
**/
guint (*timeout_add)(guint interval, GSourceFunc function, gpointer data);
@@ -81,7 +81,20 @@ struct _PurpleEventLoopUiOps
*/
int (*input_get_error)(int fd, int *error);
- void (*_purple_reserved1)(void);
+ /**
+ * Creates a callback timer with an interval measured in seconds.
+ *
+ * This allows UIs to group timers for better power efficiency. For
+ * this reason, @a interval may be rounded by up to a second.
+ *
+ * Implementation of this UI op is optional. If it's not implemented,
+ * calls to purple_timeout_add_seconds() will be serviced by the
+ * timeout_add UI op.
+ *
+ * @see g_timeout_add_seconds, purple_timeout_add_seconds()
+ **/
+ guint (*timeout_add_seconds)(guint interval, GSourceFunc function, gpointer data);
+
void (*_purple_reserved2)(void);
void (*_purple_reserved3)(void);
void (*_purple_reserved4)(void);
@@ -93,10 +106,15 @@ struct _PurpleEventLoopUiOps
/*@{*/
/**
* Creates a callback timer.
+ *
* The timer will repeat until the function returns @c FALSE. The
* first call will be at the end of the first interval.
+ *
+ * If the timer is in a multiple of seconds, use purple_timeout_add_seconds()
+ * instead as it allows UIs to group timers for power efficiency.
+ *
* @param interval The time between calls of the function, in
- * milliseconds.
+ * milliseconds.
* @param function The function to call.
* @param data data to pass to @a function.
* @return A handle to the timer which can be passed to
@@ -105,6 +123,24 @@ struct _PurpleEventLoopUiOps
guint purple_timeout_add(guint interval, GSourceFunc function, gpointer data);
/**
+ * Creates a callback timer.
+ *
+ * The timer will repeat until the function returns @c FALSE. The
+ * first call will be at the end of the first interval.
+ *
+ * This function allows UIs to group timers for better power efficiency. For
+ * this reason, @a interval may be rounded by up to a second.
+ *
+ * @param interval The time between calls of the function, in
+ * seconds.
+ * @param function The function to call.
+ * @param data data to pass to @a function.
+ * @return A handle to the timer which can be passed to
+ * purple_timeout_remove to remove the timer.
+ */
+guint purple_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data);
+
+/**
* Removes a timeout handler.
*
* @param handle The handle, as returned by purple_timeout_add.
diff --git a/libpurple/example/nullclient.c b/libpurple/example/nullclient.c
index a7416eb60a..ae520d69e2 100644
--- a/libpurple/example/nullclient.c
+++ b/libpurple/example/nullclient.c
@@ -108,11 +108,15 @@ static PurpleEventLoopUiOps glib_eventloops =
glib_input_add,
g_source_remove,
NULL,
+#if GLIB_CHECK_VERSION(2,14,0)
+ g_timeout_add_seconds,
+#else
+ NULL,
+#endif
/* padding */
NULL,
NULL,
- NULL,
NULL
};
/*** End of the eventloop functions. ***/
diff --git a/libpurple/ft.c b/libpurple/ft.c
index b8924fca05..939a73b64e 100644
--- a/libpurple/ft.c
+++ b/libpurple/ft.c
@@ -23,6 +23,7 @@
*
*/
#include "internal.h"
+#include "dbus-maybe.h"
#include "ft.h"
#include "network.h"
#include "notify.h"
@@ -56,6 +57,7 @@ purple_xfer_new(PurpleAccount *account, PurpleXferType type, const char *who)
g_return_val_if_fail(who != NULL, NULL);
xfer = g_new0(PurpleXfer, 1);
+ PURPLE_DBUS_REGISTER_POINTER(xfer, PurpleXfer);
xfer->ref = 1;
xfer->type = type;
@@ -97,6 +99,7 @@ purple_xfer_destroy(PurpleXfer *xfer)
g_free(xfer->remote_ip);
g_free(xfer->local_filename);
+ PURPLE_DBUS_UNREGISTER_POINTER(xfer);
g_free(xfer);
xfers = g_list_remove(xfers, xfer);
}
@@ -551,6 +554,13 @@ purple_xfer_get_account(const PurpleXfer *xfer)
return xfer->account;
}
+const char *
+purple_xfer_get_remote_user(const PurpleXfer *xfer)
+{
+ g_return_val_if_fail(xfer != NULL, NULL);
+ return xfer->who;
+}
+
PurpleXferStatusType
purple_xfer_get_status(const PurpleXfer *xfer)
{
diff --git a/libpurple/ft.h b/libpurple/ft.h
index ecca0683f6..c70559392f 100644
--- a/libpurple/ft.h
+++ b/libpurple/ft.h
@@ -237,6 +237,15 @@ PurpleXferType purple_xfer_get_type(const PurpleXfer *xfer);
PurpleAccount *purple_xfer_get_account(const PurpleXfer *xfer);
/**
+ * Returns the name of the remote user.
+ *
+ * @param xfer The file transfer.
+ *
+ * @return The name of the remote user.
+ */
+const char *purple_xfer_get_remote_user(const PurpleXfer *xfer);
+
+/**
* Returns the status of the xfer.
*
* @param xfer The file transfer.
diff --git a/libpurple/idle.c b/libpurple/idle.c
index d89fff38ed..f6a7bca28e 100644
--- a/libpurple/idle.c
+++ b/libpurple/idle.c
@@ -199,7 +199,7 @@ check_idleness(void)
/* Idle reporting stuff */
if (report_idle && (time_idle >= IDLEMARK))
{
- GList *l;
+ const GList *l;
for (l = purple_connections_get_all(); l != NULL; l = l->next)
{
PurpleConnection *gc = l->data;
@@ -224,7 +224,11 @@ check_idleness_timer()
if (time_until_next_idle_event == 0)
idle_timer = 0;
else
- idle_timer = purple_timeout_add(1000 * (time_until_next_idle_event + 1), check_idleness_timer, NULL);
+ {
+ /* +1 for the boundary,
+ * +1 more for g_timeout_add_seconds rounding. */
+ idle_timer = purple_timeout_add_seconds(time_until_next_idle_event + 2, check_idleness_timer, NULL);
+ }
return FALSE;
}
@@ -311,8 +315,10 @@ static gboolean _do_purple_idle_touch_cb(gpointer data)
void
purple_idle_init()
{
- /* Add the timer to check if we're idle */
- idle_timer = purple_timeout_add(1000 * (IDLEMARK + 1), check_idleness_timer, NULL);
+ /* Add the timer to check if we're idle.
+ * IDLEMARK + 1 as the boundary,
+ * +1 more for g_timeout_add_seconds rounding. */
+ idle_timer = purple_timeout_add_seconds((IDLEMARK + 2), check_idleness_timer, NULL);
purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg",
purple_idle_get_handle(),
diff --git a/libpurple/imgstore.c b/libpurple/imgstore.c
index 5324175e20..39e82688e8 100644
--- a/libpurple/imgstore.c
+++ b/libpurple/imgstore.c
@@ -25,6 +25,7 @@
*/
#include <glib.h>
+#include "dbus-maybe.h"
#include "debug.h"
#include "imgstore.h"
#include "util.h"
@@ -56,6 +57,7 @@ purple_imgstore_add(gpointer data, size_t size, const char *filename)
g_return_val_if_fail(size > 0, 0);
img = g_new(PurpleStoredImage, 1);
+ PURPLE_DBUS_REGISTER_POINTER(img, PurpleStoredImage);
img->data = data;
img->size = size;
img->filename = g_strdup(filename);
@@ -159,6 +161,7 @@ purple_imgstore_unref(PurpleStoredImage *img)
g_free(img->data);
g_free(img->filename);
+ PURPLE_DBUS_UNREGISTER_POINTER(img);
g_free(img);
img = NULL;
}
diff --git a/libpurple/log.c b/libpurple/log.c
index e964ff9d40..6cca135419 100644
--- a/libpurple/log.c
+++ b/libpurple/log.c
@@ -32,6 +32,7 @@
#include "prefs.h"
#include "util.h"
#include "stringref.h"
+#include "imgstore.h"
static GSList *loggers = NULL;
@@ -405,6 +406,9 @@ void purple_log_logger_add (PurpleLogLogger *logger)
if (g_slist_find(loggers, logger))
return;
loggers = g_slist_append(loggers, logger);
+ if (strcmp(purple_prefs_get_string("/purple/logging/format"), logger->id) == 0) {
+ purple_prefs_trigger_callback("/purple/logging/format");
+ }
}
void purple_log_logger_remove (PurpleLogLogger *logger)
@@ -690,6 +694,107 @@ static char *log_get_timestamp(PurpleLog *log, time_t when)
return g_strdup(purple_time_format(&tm));
}
+/* NOTE: This can return msg (which you may or may not want to g_free())
+ * NOTE: or a newly allocated string which you MUST g_free(). */
+static char *
+convert_image_tags(const PurpleLog *log, const char *msg)
+{
+ const char *tmp;
+ const char *start;
+ const char *end;
+ GData *attributes;
+ GString *newmsg = NULL;
+
+ tmp = msg;
+
+ while (purple_markup_find_tag("img", tmp, &start, &end, &attributes)) {
+ int imgid = 0;
+ char *idstr = NULL;
+
+ if (newmsg == NULL)
+ newmsg = g_string_new("");
+
+ /* copy any text before the img tag */
+ if (tmp < start)
+ g_string_append_len(newmsg, tmp, start - tmp);
+
+ idstr = g_datalist_get_data(&attributes, "id");
+
+ imgid = atoi(idstr);
+ if (imgid != 0)
+ {
+ FILE *image_file;
+ char *dir;
+ PurpleStoredImage *image;
+ gconstpointer image_data;
+ char *new_filename = NULL;
+ char *path = NULL;
+ size_t image_byte_count;
+
+ image = purple_imgstore_find_by_id(imgid);
+ if (image == NULL)
+ {
+ /* This should never happen. */
+ g_string_free(newmsg, TRUE);
+ g_return_val_if_reached((char *)msg);
+ }
+
+ image_data = purple_imgstore_get_data(image);
+ image_byte_count = purple_imgstore_get_size(image);
+ dir = purple_log_get_log_dir(log->type, log->name, log->account);
+ new_filename = purple_util_get_image_filename(image_data, image_byte_count);
+
+ path = g_build_filename(dir, new_filename, NULL);
+
+ /* Only save unique files. */
+ if (!g_file_test(path, G_FILE_TEST_EXISTS))
+ {
+ if ((image_file = g_fopen(path, "wb")) != NULL)
+ {
+ if (!fwrite(image_data, image_byte_count, 1, image_file))
+ {
+ purple_debug_error("log", "Error writing %s: %s\n",
+ path, strerror(errno));
+ fclose(image_file);
+
+ /* Attempt to not leave half-written files around. */
+ unlink(path);
+ }
+ else
+ {
+ purple_debug_info("log", "Wrote image file: %s\n", path);
+ fclose(image_file);
+ }
+ }
+ else
+ {
+ purple_debug_error("log", "Unable to create file %s: %s\n",
+ path, strerror(errno));
+ }
+ }
+
+ /* Write the new image tag */
+ g_string_append_printf(newmsg, "<IMG SRC=\"%s\">", new_filename);
+ g_free(new_filename);
+ g_free(path);
+ }
+
+ /* Continue from the end of the tag */
+ tmp = end + 1;
+ }
+
+ if (newmsg == NULL)
+ {
+ /* No images were found to change. */
+ return (char *)msg;
+ }
+
+ /* Append any remaining message data */
+ g_string_append(newmsg, tmp);
+
+ return g_string_free(newmsg, FALSE);
+}
+
void purple_log_common_writer(PurpleLog *log, const char *ext)
{
PurpleLogCommonLoggerData *data = log->logger_data;
@@ -880,7 +985,7 @@ static void log_get_log_sets_common(GHashTable *sets)
GDir *protocol_dir;
const gchar *username;
gchar *protocol_unescaped;
- GList *account_iter;
+ const GList *account_iter;
GList *accounts = NULL;
if ((protocol_dir = g_dir_open(protocol_path, 0, NULL)) == NULL) {
@@ -1191,6 +1296,7 @@ static gsize html_logger_write(PurpleLog *log, PurpleMessageFlags type,
const char *from, time_t time, const char *message)
{
char *msg_fixed;
+ char *image_corrected_msg;
char *date;
char *header;
PurplePlugin *plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
@@ -1231,7 +1337,14 @@ static gsize html_logger_write(PurpleLog *log, PurpleMessageFlags type,
if(!data->file)
return 0;
- purple_markup_html_to_xhtml(message, &msg_fixed, NULL);
+ image_corrected_msg = convert_image_tags(log, message);
+ purple_markup_html_to_xhtml(image_corrected_msg, &msg_fixed, NULL);
+
+ /* Yes, this breaks encapsulation. But it's a static function and
+ * this saves a needless strdup(). */
+ if (image_corrected_msg != message)
+ g_free(image_corrected_msg);
+
date = log_get_timestamp(log, time);
if(log->type == PURPLE_LOG_SYSTEM){
diff --git a/libpurple/notify.c b/libpurple/notify.c
index cfb51d8376..4313ecd735 100644
--- a/libpurple/notify.c
+++ b/libpurple/notify.c
@@ -530,7 +530,7 @@ purple_notify_user_info_destroy(PurpleNotifyUserInfo *user_info)
g_free(user_info);
}
-GList *
+const GList *
purple_notify_user_info_get_entries(PurpleNotifyUserInfo *user_info)
{
g_return_val_if_fail(user_info != NULL, NULL);
diff --git a/libpurple/notify.h b/libpurple/notify.h
index 3130b26874..12723c53fe 100644
--- a/libpurple/notify.h
+++ b/libpurple/notify.h
@@ -458,7 +458,7 @@ void purple_notify_user_info_destroy(PurpleNotifyUserInfo *user_info);
*
* @result A GList of PurpleNotifyUserInfoEntry objects
*/
-GList *purple_notify_user_info_get_entries(PurpleNotifyUserInfo *user_info);
+const GList *purple_notify_user_info_get_entries(PurpleNotifyUserInfo *user_info);
/**
* Create a textual representation of a PurpleNotifyUserInfo, separating entries with newline
diff --git a/libpurple/plugins/joinpart.c b/libpurple/plugins/joinpart.c
index d6a6b9306c..394f085264 100644
--- a/libpurple/plugins/joinpart.c
+++ b/libpurple/plugins/joinpart.c
@@ -86,7 +86,7 @@ static gboolean should_hide_notice(PurpleConversation *conv, const char *name,
/* If the room is small, don't bother. */
chat = PURPLE_CONV_CHAT(conv);
threshold = purple_prefs_get_int(THRESHOLD_PREF);
- if (g_list_length(purple_conv_chat_get_users(chat)) < threshold)
+ if (g_list_length((GList *)purple_conv_chat_get_users(chat)) < threshold)
return FALSE;
/* We always care about our buddies! */
diff --git a/libpurple/plugins/perl/common/Account.xs b/libpurple/plugins/perl/common/Account.xs
index 2bff72e1d5..cfbc52c033 100644
--- a/libpurple/plugins/perl/common/Account.xs
+++ b/libpurple/plugins/perl/common/Account.xs
@@ -215,6 +215,7 @@ PPCODE:
t_GL = g_list_append(t_GL, SvPV(*av_fetch((AV *)SvRV(list), i, 0), t_sl));
}
purple_account_add_buddies(account, t_GL);
+ g_list_free(t_GL);
void
purple_account_add_buddy(account, buddy)
@@ -252,6 +253,8 @@ PPCODE:
t_GL2 = g_list_append(t_GL2, SvPV(*av_fetch((AV *)SvRV(B), i, 0), t_sl));
}
purple_account_remove_buddies(account, t_GL1, t_GL2);
+ g_list_free(t_GL1);
+ g_list_free(t_GL2);
void
purple_account_remove_buddy(account, buddy, group)
@@ -287,7 +290,7 @@ purple_accounts_reorder(account, new_index)
void
purple_accounts_get_all()
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Account")));
diff --git a/libpurple/plugins/perl/common/BuddyList.xs b/libpurple/plugins/perl/common/BuddyList.xs
index 4c37c043be..38d568c0cd 100644
--- a/libpurple/plugins/perl/common/BuddyList.xs
+++ b/libpurple/plugins/perl/common/BuddyList.xs
@@ -112,6 +112,10 @@ purple_group_on_account(group, account)
Purple::BuddyList::Group group
Purple::Account account
+const char *
+purple_group_get_name(group)
+ Purple::BuddyList::Group group
+
MODULE = Purple::BuddyList PACKAGE = Purple::BuddyList PREFIX = purple_blist_
PROTOTYPES: ENABLE
@@ -248,6 +252,9 @@ purple_blist_get_ui_ops()
Purple::Handle
purple_blist_get_handle()
+Purple::BuddyList::Node
+purple_blist_get_root()
+
void
purple_blist_init()
@@ -263,7 +270,7 @@ purple_blist_node_get_extended_menu(node)
PREINIT:
GList *l;
PPCODE:
- for (l = purple_blist_node_get_extended_menu(node); l != NULL; l = l->next) {
+ for (l = purple_blist_node_get_extended_menu(node); l != NULL; l = g_list_delete_link(l, l)) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Menu::Action")));
}
@@ -308,6 +315,15 @@ Purple::BuddyList::NodeFlags
purple_blist_node_get_flags(node)
Purple::BuddyList::Node node
+Purple::BuddyList::NodeType
+purple_blist_node_get_type(node)
+ Purple::BuddyList::Node node
+
+Purple::BuddyList::Node
+purple_blist_node_next(node, offline)
+ Purple::BuddyList::Node node
+ gboolean offline
+
MODULE = Purple::BuddyList PACKAGE = Purple::BuddyList::Chat PREFIX = purple_chat_
PROTOTYPES: ENABLE
diff --git a/libpurple/plugins/perl/common/Connection.xs b/libpurple/plugins/perl/common/Connection.xs
index 4a6bcc4c93..288902ff65 100644
--- a/libpurple/plugins/perl/common/Connection.xs
+++ b/libpurple/plugins/perl/common/Connection.xs
@@ -72,7 +72,7 @@ purple_connections_disconnect_all()
void
purple_connections_get_all()
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_connections_get_all(); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Connection")));
@@ -81,7 +81,7 @@ PPCODE:
void
purple_connections_get_connecting()
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_connections_get_connecting(); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Connection")));
diff --git a/libpurple/plugins/perl/common/Conversation.xs b/libpurple/plugins/perl/common/Conversation.xs
index 6521e913e3..1163c178f7 100644
--- a/libpurple/plugins/perl/common/Conversation.xs
+++ b/libpurple/plugins/perl/common/Conversation.xs
@@ -93,7 +93,7 @@ BOOT:
void
purple_get_ims()
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_get_ims(); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
@@ -102,7 +102,7 @@ PPCODE:
void
purple_get_conversations()
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_get_conversations(); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
@@ -111,7 +111,7 @@ PPCODE:
void
purple_get_chats()
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_get_chats(); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
@@ -218,6 +218,21 @@ purple_conversation_set_account(conv, account);
Purple::Conversation conv
Purple::Account account
+void
+purple_conversation_write(conv, who, message, flags, mtime)
+ Purple::Conversation conv
+ const char *who
+ const char *message
+ Purple::MessageFlags flags
+ time_t mtime
+
+gboolean
+purple_conversation_do_command(conv, cmdline, markup, error)
+ Purple::Conversation conv
+ const char *cmdline
+ const char *markup
+ char **error
+
MODULE = Purple::Conversation PACKAGE = Purple::Conversation::IM PREFIX = purple_conv_im_
PROTOTYPES: ENABLE
@@ -339,7 +354,7 @@ void
purple_conv_chat_get_users(chat)
Purple::Conversation::Chat chat
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_conv_chat_get_users(chat); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
@@ -379,7 +394,7 @@ void
purple_conv_chat_get_ignored(chat)
Purple::Conversation::Chat chat
PREINIT:
- GList *l;
+ const GList *l;
PPCODE:
for (l = purple_conv_chat_get_ignored(chat); l != NULL; l = l->next) {
XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
diff --git a/libpurple/plugins/perl/common/Prefs.xs b/libpurple/plugins/perl/common/Prefs.xs
index 855c3d49a0..d3f19bbe78 100644
--- a/libpurple/plugins/perl/common/Prefs.xs
+++ b/libpurple/plugins/perl/common/Prefs.xs
@@ -94,8 +94,9 @@ purple_prefs_get_string_list(name)
PREINIT:
GList *l;
PPCODE:
- for (l = purple_prefs_get_string_list(name); l != NULL; l = l->next) {
- XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::PrefValue")));
+ for (l = purple_prefs_get_string_list(name); l != NULL; l = g_list_delete_link(l, l)) {
+ XPUSHs(sv_2mortal(newSVpv(l->data, 0)));
+ g_free(l->data);
}
Purple::PrefType
diff --git a/libpurple/plugins/perl/common/module.h b/libpurple/plugins/perl/common/module.h
index f4d38d7ec3..aaa0dbc3a1 100644
--- a/libpurple/plugins/perl/common/module.h
+++ b/libpurple/plugins/perl/common/module.h
@@ -69,6 +69,7 @@ typedef PurpleAccountUserSplit * Purple__Account__UserSplit;
/* blist.h */
typedef PurpleBlistNode * Purple__BuddyList__Node;
typedef PurpleBlistNodeFlags Purple__BuddyList__NodeFlags;
+typedef PurpleBlistNodeType Purple__BuddyList__NodeType;
typedef PurpleBlistUiOps * Purple__BuddyList__UiOps;
typedef PurpleBuddyList * Purple__BuddyList;
typedef PurpleBuddy * Purple__BuddyList__Buddy;
diff --git a/libpurple/plugins/perl/common/typemap b/libpurple/plugins/perl/common/typemap
index 859cabc3a3..3c7269b317 100644
--- a/libpurple/plugins/perl/common/typemap
+++ b/libpurple/plugins/perl/common/typemap
@@ -52,6 +52,7 @@ Purple::BuddyList::Contact T_PurpleObj
Purple::BuddyList::Group T_PurpleObj
Purple::BuddyList::Node T_PurpleObj
Purple::BuddyList::NodeFlags T_IV
+Purple::BuddyList::NodeType T_IV
Purple::BuddyList::UiOps T_PurpleObj
Purple::Cipher T_PurpleObj
diff --git a/libpurple/plugins/perl/perl-handlers.c b/libpurple/plugins/perl/perl-handlers.c
index eb767297ef..614dbb1f85 100644
--- a/libpurple/plugins/perl/perl-handlers.c
+++ b/libpurple/plugins/perl/perl-handlers.c
@@ -214,6 +214,7 @@ static gboolean
perl_timeout_cb(gpointer data)
{
PurplePerlTimeoutHandler *handler = (PurplePerlTimeoutHandler *)data;
+ gboolean ret = FALSE;
dSP;
ENTER;
@@ -224,16 +225,16 @@ perl_timeout_cb(gpointer data)
call_sv(handler->callback, G_EVAL | G_SCALAR);
SPAGAIN;
+ ret = POPi;
+
PUTBACK;
FREETMPS;
LEAVE;
- /* We're returning FALSE, so no need to manually remove the source */
- handler->iotag = 0;
-
- destroy_timeout_handler(handler);
+ if (ret == FALSE)
+ destroy_timeout_handler(handler);
- return FALSE;
+ return ret;
}
typedef void *DATATYPE;
diff --git a/libpurple/plugins/tcl/tcl_cmds.c b/libpurple/plugins/tcl/tcl_cmds.c
index f269c88224..837b5e1772 100644
--- a/libpurple/plugins/tcl/tcl_cmds.c
+++ b/libpurple/plugins/tcl/tcl_cmds.c
@@ -43,7 +43,7 @@ static PurpleConnection *tcl_validate_gc(Tcl_Obj *obj, Tcl_Interp *interp);
static PurpleAccount *tcl_validate_account(Tcl_Obj *obj, Tcl_Interp *interp)
{
PurpleAccount *account;
- GList *cur;
+ const GList *cur;
account = purple_tcl_ref_get(interp, obj, PurpleTclRefAccount);
@@ -62,7 +62,7 @@ static PurpleAccount *tcl_validate_account(Tcl_Obj *obj, Tcl_Interp *interp)
static PurpleConversation *tcl_validate_conversation(Tcl_Obj *obj, Tcl_Interp *interp)
{
PurpleConversation *convo;
- GList *cur;
+ const GList *cur;
convo = purple_tcl_ref_get(interp, obj, PurpleTclRefConversation);
@@ -81,7 +81,7 @@ static PurpleConversation *tcl_validate_conversation(Tcl_Obj *obj, Tcl_Interp *i
static PurpleConnection *tcl_validate_gc(Tcl_Obj *obj, Tcl_Interp *interp)
{
PurpleConnection *gc;
- GList *cur;
+ const GList *cur;
gc = purple_tcl_ref_get(interp, obj, PurpleTclRefConnection);
@@ -612,7 +612,7 @@ int tcl_cmd_connection(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj
const char *cmds[] = { "account", "displayname", "handle", "list", NULL };
enum { CMD_CONN_ACCOUNT, CMD_CONN_DISPLAYNAME, CMD_CONN_HANDLE, CMD_CONN_LIST } cmd;
int error;
- GList *cur;
+ const GList *cur;
PurpleConnection *gc;
if (objc < 2) {
@@ -680,7 +680,7 @@ int tcl_cmd_conversation(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Ob
PurpleConversation *convo;
PurpleAccount *account;
PurpleConversationType type;
- GList *cur;
+ const GList *cur;
char *opt, *from, *what;
int error, argsused, flags = 0;
diff --git a/libpurple/pounce.c b/libpurple/pounce.c
index 0ea9046bd1..dbe8060458 100644
--- a/libpurple/pounce.c
+++ b/libpurple/pounce.c
@@ -273,7 +273,7 @@ static void
schedule_pounces_save(void)
{
if (save_timer == 0)
- save_timer = purple_timeout_add(5000, save_cb, NULL);
+ save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
}
diff --git a/libpurple/prefs.c b/libpurple/prefs.c
index 8ab9fbbfeb..b30269f1eb 100644
--- a/libpurple/prefs.c
+++ b/libpurple/prefs.c
@@ -226,7 +226,7 @@ static void
schedule_prefs_save(void)
{
if (save_timer == 0)
- save_timer = purple_timeout_add(5000, save_cb, NULL);
+ save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
}
diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c
index 956357cc0e..6bb060940f 100644
--- a/libpurple/protocols/irc/irc.c
+++ b/libpurple/protocols/irc/irc.c
@@ -592,7 +592,7 @@ static void irc_input_cb_ssl(gpointer data, PurpleSslConnection *gsc,
struct irc_conn *irc = gc->proto_data;
int len;
- if(!g_list_find(purple_connections_get_all(), gc)) {
+ if(!g_list_find((GList *)purple_connections_get_all(), gc)) {
purple_ssl_close(gsc);
return;
}
@@ -814,7 +814,8 @@ static void irc_keepalive(PurpleConnection *gc)
static PurplePluginProtocolInfo prpl_info =
{
- OPT_PROTO_CHAT_TOPIC | OPT_PROTO_PASSWORD_OPTIONAL,
+ OPT_PROTO_CHAT_TOPIC | OPT_PROTO_PASSWORD_OPTIONAL |
+ OPT_PROTO_SLASH_COMMANDS_NATIVE,
NULL, /* user_splits */
NULL, /* protocol_options */
NO_BUDDY_ICONS, /* icon_spec */
diff --git a/libpurple/protocols/jabber/jutil.c b/libpurple/protocols/jabber/jutil.c
index ec81df7bb2..6474dcea57 100644
--- a/libpurple/protocols/jabber/jutil.c
+++ b/libpurple/protocols/jabber/jutil.c
@@ -221,7 +221,7 @@ PurpleConversation *
jabber_find_unnormalized_conv(const char *name, PurpleAccount *account)
{
PurpleConversation *c = NULL;
- GList *cnv;
+ const GList *cnv;
g_return_val_if_fail(name != NULL, NULL);
diff --git a/libpurple/protocols/jabber/libxmpp.c b/libpurple/protocols/jabber/libxmpp.c
index 4210b6d445..264d0f581e 100644
--- a/libpurple/protocols/jabber/libxmpp.c
+++ b/libpurple/protocols/jabber/libxmpp.c
@@ -43,9 +43,11 @@ static PurplePluginProtocolInfo prpl_info =
{
#ifdef HAVE_CYRUS_SASL
OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
- OPT_PROTO_MAIL_CHECK | OPT_PROTO_PASSWORD_OPTIONAL,
+ OPT_PROTO_MAIL_CHECK | OPT_PROTO_PASSWORD_OPTIONAL |
+ OPT_PROTO_SLASH_COMMANDS_NATIVE,
#else
- OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK,
+ OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK |
+ OPT_PROTO_SLASH_COMMANDS_NATIVE,
#endif
NULL, /* user_splits */
NULL, /* protocol_options */
@@ -193,9 +195,11 @@ init_plugin(PurplePlugin *plugin)
/* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
split = purple_account_user_split_new(_("Domain"), NULL, '@');
+ 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"), "Home", '/');
+ purple_account_user_split_set_reverse(split, FALSE);
prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
option = purple_account_option_bool_new(_("Force old (port 5223) SSL"), "old_ssl", FALSE);
diff --git a/libpurple/protocols/msn/msn.c b/libpurple/protocols/msn/msn.c
index 11912fd4f4..459fd7e36c 100644
--- a/libpurple/protocols/msn/msn.c
+++ b/libpurple/protocols/msn/msn.c
@@ -1463,7 +1463,7 @@ msn_got_info(PurpleUtilFetchUrlData *url_data, gpointer data,
purple_debug_info("msn", "In msn_got_info\n");
/* Make sure the connection is still valid */
- if (g_list_find(purple_connections_get_all(), info_data->gc) == NULL)
+ if (g_list_find((GList *)purple_connections_get_all(), info_data->gc) == NULL)
{
purple_debug_warning("msn", "invalid connection. ignoring buddy info.\n");
g_free(info_data->name);
@@ -1883,7 +1883,7 @@ msn_got_photo(PurpleUtilFetchUrlData *url_data, gpointer user_data,
/* Make sure the connection is still valid if we got here by fetching a photo url */
if (url_text && (error_message != NULL ||
- g_list_find(purple_connections_get_all(), info_data->gc) == NULL))
+ g_list_find((GList *)purple_connections_get_all(), info_data->gc) == NULL))
{
purple_debug_warning("msn", "invalid connection. ignoring buddy photo info.\n");
g_free(stripped);
@@ -1982,7 +1982,7 @@ static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
if (acct && !purple_account_is_connected(acct))
acct = NULL;
} else { /* Otherwise find an active account for the protocol */
- GList *l = purple_accounts_get_all();
+ const GList *l = purple_accounts_get_all();
while (l) {
if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
&& purple_account_is_connected(l->data)) {
diff --git a/libpurple/protocols/msn/switchboard.c b/libpurple/protocols/msn/switchboard.c
index 09884c052c..debe4cc309 100644
--- a/libpurple/protocols/msn/switchboard.c
+++ b/libpurple/protocols/msn/switchboard.c
@@ -422,7 +422,7 @@ msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, MsnMsgErrorType error)
break;
case MSN_SB_ERROR_AUTHFAILED:
str_reason = _("Message could not be sent "
- "because we wer unable to establish a "
+ "because we were unable to establish a "
"session with the server. This is "
"likely a server problem, try again in "
"a few minutes:");
diff --git a/libpurple/protocols/oscar/oscar.c b/libpurple/protocols/oscar/oscar.c
index 0b66ebf225..5c19dd9b37 100644
--- a/libpurple/protocols/oscar/oscar.c
+++ b/libpurple/protocols/oscar/oscar.c
@@ -6558,7 +6558,7 @@ static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
if (acct && !purple_account_is_connected(acct))
acct = NULL;
} else { /* Otherwise find an active account for the protocol */
- GList *l = purple_accounts_get_all();
+ const GList *l = purple_accounts_get_all();
while (l) {
if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
&& purple_account_is_connected(l->data)) {
diff --git a/libpurple/protocols/silc/ft.c b/libpurple/protocols/silc/ft.c
index 05fa942305..32d0b72c63 100644
--- a/libpurple/protocols/silc/ft.c
+++ b/libpurple/protocols/silc/ft.c
@@ -111,7 +111,7 @@ silcpurple_ftp_monitor(SilcClient client,
} else if (error == SILC_CLIENT_FILE_TIMEOUT) {
purple_notify_error(gc, _("Secure File Transfer"),
_("Error during file transfer"),
- _("Connection timedout"));
+ _("Connection timed out"));
} else if (error == SILC_CLIENT_FILE_CONNECT_FAILED) {
purple_notify_error(gc, _("Secure File Transfer"),
_("Error during file transfer"),
diff --git a/libpurple/protocols/silc/silc.c b/libpurple/protocols/silc/silc.c
index 503ee735a0..70374d6714 100644
--- a/libpurple/protocols/silc/silc.c
+++ b/libpurple/protocols/silc/silc.c
@@ -1787,7 +1787,8 @@ static PurpleWhiteboardPrplOps silcpurple_wb_ops =
static PurplePluginProtocolInfo prpl_info =
{
OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
- OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE,
+ OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE |
+ OPT_PROTO_SLASH_COMMANDS_NATIVE,
NULL, /* user_splits */
NULL, /* protocol_options */
{"jpeg,gif,png,bmp", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
diff --git a/libpurple/protocols/silc10/silc.c b/libpurple/protocols/silc10/silc.c
index 45ca537114..7b455b2a77 100644
--- a/libpurple/protocols/silc10/silc.c
+++ b/libpurple/protocols/silc10/silc.c
@@ -1717,10 +1717,12 @@ static PurplePluginProtocolInfo prpl_info =
{
#ifdef HAVE_SILCMIME_H
OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
- OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE,
+ OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE |
+ OPT_PROTO_SLASH_COMMANDS_NATIVE,
#else
OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
- OPT_PROTO_PASSWORD_OPTIONAL,
+ OPT_PROTO_PASSWORD_OPTIONAL |
+ OPT_PROTO_SLASH_COMMANDS_NATIVE,
#endif
NULL, /* user_splits */
NULL, /* protocol_options */
diff --git a/libpurple/protocols/yahoo/yahoo.c b/libpurple/protocols/yahoo/yahoo.c
index 41b0057140..32c407e9e1 100644
--- a/libpurple/protocols/yahoo/yahoo.c
+++ b/libpurple/protocols/yahoo/yahoo.c
@@ -3861,7 +3861,7 @@ static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
if (acct && !purple_account_is_connected(acct))
acct = NULL;
} else { /* Otherwise find an active account for the protocol */
- GList *l = purple_accounts_get_all();
+ const GList *l = purple_accounts_get_all();
while (l) {
if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
&& purple_account_is_connected(l->data)) {
diff --git a/libpurple/protocols/yahoo/yahoochat.c b/libpurple/protocols/yahoo/yahoochat.c
index d5548ba21d..e21ccb16bc 100644
--- a/libpurple/protocols/yahoo/yahoochat.c
+++ b/libpurple/protocols/yahoo/yahoochat.c
@@ -633,10 +633,10 @@ void yahoo_process_chat_goto(PurpleConnection *gc, struct yahoo_packet *pkt)
* I think conference names are always ascii.
*/
-void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, GList *who)
+void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, const GList *who)
{
struct yahoo_packet *pkt;
- GList *w;
+ const GList *w;
purple_debug_misc("yahoo", "leaving conference %s\n", room);
@@ -653,11 +653,11 @@ void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, G
}
static int yahoo_conf_send(PurpleConnection *gc, const char *dn, const char *room,
- GList *members, const char *what)
+ const GList *members, const char *what)
{
struct yahoo_data *yd = gc->proto_data;
struct yahoo_packet *pkt;
- GList *who;
+ const GList *who;
char *msg, *msg2;
int utf8 = 1;
@@ -714,7 +714,7 @@ static void yahoo_conf_invite(PurpleConnection *gc, PurpleConversation *c,
{
struct yahoo_data *yd = gc->proto_data;
struct yahoo_packet *pkt;
- GList *members;
+ const GList *members;
char *msg2 = NULL;
if (msg)
diff --git a/libpurple/protocols/yahoo/yahoochat.h b/libpurple/protocols/yahoo/yahoochat.h
index 0dff4f5b21..0a9fe2d894 100644
--- a/libpurple/protocols/yahoo/yahoochat.h
+++ b/libpurple/protocols/yahoo/yahoochat.h
@@ -50,7 +50,7 @@ void yahoo_c_join(PurpleConnection *gc, GHashTable *data);
char *yahoo_get_chat_name(GHashTable *data);
void yahoo_c_invite(PurpleConnection *gc, int id, const char *msg, const char *name);
-void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, GList *who);
+void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, const GList *who);
void yahoo_chat_goto(PurpleConnection *gc, const char *name);
diff --git a/libpurple/prpl.c b/libpurple/prpl.c
index cffeab5c09..dde21d06cc 100644
--- a/libpurple/prpl.c
+++ b/libpurple/prpl.c
@@ -83,44 +83,50 @@ void
purple_prpl_got_user_idle(PurpleAccount *account, const char *name,
gboolean idle, time_t idle_time)
{
- PurpleBuddy *buddy;
PurplePresence *presence;
+ GSList *list;
g_return_if_fail(account != NULL);
g_return_if_fail(name != NULL);
g_return_if_fail(purple_account_is_connected(account));
- if ((buddy = purple_find_buddy(account, name)) == NULL)
+ if ((list = purple_find_buddies(account, name)) == NULL)
return;
- presence = purple_buddy_get_presence(buddy);
-
- purple_presence_set_idle(presence, idle, idle_time);
+ while (list) {
+ presence = purple_buddy_get_presence(list->data);
+ list = g_slist_delete_link(list, list);
+ purple_presence_set_idle(presence, idle, idle_time);
+ }
}
void
purple_prpl_got_user_login_time(PurpleAccount *account, const char *name,
time_t login_time)
{
- PurpleBuddy *buddy;
+ GSList *list;
PurplePresence *presence;
g_return_if_fail(account != NULL);
g_return_if_fail(name != NULL);
- if ((buddy = purple_find_buddy(account, name)) == NULL)
+ if ((list = purple_find_buddies(account, name)) == NULL)
return;
if (login_time == 0)
login_time = time(NULL);
- presence = purple_buddy_get_presence(buddy);
+ while (list) {
+ PurpleBuddy *buddy = list->data;
+ presence = purple_buddy_get_presence(buddy);
+ list = g_slist_delete_link(list, list);
- if (purple_presence_get_login_time(presence) != login_time)
- {
- purple_presence_set_login_time(presence, login_time);
+ if (purple_presence_get_login_time(presence) != login_time)
+ {
+ purple_presence_set_login_time(presence, login_time);
- purple_signal_emit(purple_blist_get_handle(), "buddy-got-login-time", buddy);
+ purple_signal_emit(purple_blist_get_handle(), "buddy-got-login-time", buddy);
+ }
}
}
diff --git a/libpurple/prpl.h b/libpurple/prpl.h
index eaf5d0f3b8..794a926c0c 100644
--- a/libpurple/prpl.h
+++ b/libpurple/prpl.h
@@ -158,6 +158,12 @@ typedef enum
*/
OPT_PROTO_REGISTER_NOSCREENNAME = 0x00000200,
+ /**
+ * Indicates that slash commands are native to this protocol.
+ * Used as a hint that unknown commands should not be sent as messages.
+ */
+ OPT_PROTO_SLASH_COMMANDS_NATIVE = 0x00000400,
+
} PurpleProtocolOptions;
/**
diff --git a/libpurple/purple-remote b/libpurple/purple-remote
index 96c235c224..eea3bba256 100755
--- a/libpurple/purple-remote
+++ b/libpurple/purple-remote
@@ -157,6 +157,12 @@ def execute(uri):
return None
+ elif command == "getstatus":
+ current = purple.PurpleSavedstatusGetCurrent()
+ status_type = purple.PurpleSavedstatusGetType(current)
+ status_id = purple.PurplePrimitiveGetIdFromType(status_type)
+ return status_id
+
elif command == "getinfo":
account = findaccount(accountname, protocol)
connection = cpurple.PurpleAccountGetConnection(account)
diff --git a/libpurple/savedstatuses.c b/libpurple/savedstatuses.c
index 5ef94d6343..f5d531b2a0 100644
--- a/libpurple/savedstatuses.c
+++ b/libpurple/savedstatuses.c
@@ -357,7 +357,7 @@ static void
schedule_save(void)
{
if (save_timer == 0)
- save_timer = purple_timeout_add(5000, save_cb, NULL);
+ save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
}
diff --git a/libpurple/server.c b/libpurple/server.c
index 70255a03d2..be62e81fc5 100644
--- a/libpurple/server.c
+++ b/libpurple/server.c
@@ -92,7 +92,7 @@ get_last_auto_response(PurpleConnection *gc, const char *name)
/* because we're modifying or creating a lar, schedule the
* function to expire them as the pref dictates */
- purple_timeout_add((SECS_BEFORE_RESENDING_AUTORESPONSE + 1) * 1000, expire_last_auto_responses, NULL);
+ purple_timeout_add_seconds((SECS_BEFORE_RESENDING_AUTORESPONSE + 1), expire_last_auto_responses, NULL);
tmp = last_auto_responses;
@@ -233,8 +233,9 @@ serv_got_alias(PurpleConnection *gc, const char *who, const char *alias)
char *tmp = g_strdup_printf(_("%s is now known as %s.\n"),
who, alias);
- purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM,
- time(NULL));
+ purple_conversation_write(conv, NULL, tmp,
+ PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
+ time(NULL));
g_free(tmp);
}
diff --git a/libpurple/util.c b/libpurple/util.c
index 102ceb38e7..828ae28840 100644
--- a/libpurple/util.c
+++ b/libpurple/util.c
@@ -22,6 +22,7 @@
*/
#include "internal.h"
+#include "cipher.h"
#include "conversation.h"
#include "core.h"
#include "debug.h"
@@ -156,6 +157,31 @@ purple_base16_decode(const char *str, gsize *ret_len)
return data;
}
+gchar *
+purple_base16_encode_chunked(const guchar *data, gsize len)
+{
+ int i;
+ gchar *ascii = NULL;
+
+ g_return_val_if_fail(data != NULL, NULL);
+ g_return_val_if_fail(len > 0, NULL);
+
+ /* For each byte of input, we need 2 bytes for the hex representation
+ * and 1 for the colon.
+ * The final colon will be replaced by a terminating NULL
+ */
+ ascii = g_malloc(len * 3 + 1);
+
+ for (i = 0; i < len; i++)
+ g_snprintf(&ascii[i * 3], 4, "%02hhx:", data[i]);
+
+ /* Replace the final colon with NULL */
+ ascii[len * 3 - 1] = 0;
+
+ return ascii;
+}
+
+
/**************************************************************************
* Base64 Functions
**************************************************************************/
@@ -987,7 +1013,6 @@ purple_markup_find_tag(const char *needle, const char *haystack,
g_return_val_if_fail( needle != NULL, FALSE);
g_return_val_if_fail( *needle != '\0', FALSE);
g_return_val_if_fail( haystack != NULL, FALSE);
- g_return_val_if_fail( *haystack != '\0', FALSE);
g_return_val_if_fail( start != NULL, FALSE);
g_return_val_if_fail( end != NULL, FALSE);
g_return_val_if_fail(attributes != NULL, FALSE);
@@ -1397,6 +1422,40 @@ purple_markup_html_to_xhtml(const char *html, char **xhtml_out,
plain = g_string_append_c(plain, '\n');
continue;
}
+ if(!g_ascii_strncasecmp(c, "<img", 4) && (*(c+4) == '>' || *(c+4) == ' ')) {
+ const char *p = c;
+ GString *src = NULL;
+ struct purple_parse_tag *pt;
+ while(*p && *p != '>') {
+ if(!g_ascii_strncasecmp(p, "src=", strlen("src="))) {
+ const char *q = p + strlen("src=");
+ src = g_string_new("");
+ if(*q == '\'' || *q == '\"')
+ q++;
+ while(*q && *q != '\"' && *q != '\'' && *q != ' ') {
+ src = g_string_append_c(src, *q);
+ q++;
+ }
+ p = q;
+ }
+ p++;
+ }
+ if ((c = strchr(c, '>')) != NULL)
+ c++;
+ else
+ c = p;
+ pt = g_new0(struct purple_parse_tag, 1);
+ pt->src_tag = "img";
+ pt->dest_tag = "img";
+ tags = g_list_prepend(tags, pt);
+ if(xhtml && src && src->len)
+ g_string_append_printf(xhtml, "<img src='%s' alt=''>", g_strstrip(src->str));
+ else
+ pt->ignore = TRUE;
+ if (src)
+ g_string_free(src, TRUE);
+ continue;
+ }
if(!g_ascii_strncasecmp(c, "<b>", 3) || !g_ascii_strncasecmp(c, "<bold>", strlen("<bold>"))) {
struct purple_parse_tag *pt = g_new0(struct purple_parse_tag, 1);
pt->src_tag = *(c+2) == '>' ? "b" : "bold";
@@ -1538,10 +1597,7 @@ purple_markup_html_to_xhtml(const char *html, char **xhtml_out,
pt->dest_tag = "span";
tags = g_list_prepend(tags, pt);
if(style->len)
- {
- if(xhtml)
- g_string_append_printf(xhtml, "<span style='%s'>", g_strstrip(style->str));
- }
+ g_string_append_printf(xhtml, "<span style='%s'>", g_strstrip(style->str));
else
pt->ignore = TRUE;
g_string_free(style, TRUE);
@@ -2670,6 +2726,33 @@ purple_util_get_image_extension(gconstpointer data, size_t len)
return "icon";
}
+char *
+purple_util_get_image_filename(gconstpointer image_data, size_t image_len)
+{
+ PurpleCipherContext *context;
+ gchar digest[41];
+
+ context = purple_cipher_context_new_by_name("sha1", NULL);
+ if (context == NULL)
+ {
+ purple_debug_error("util", "Could not find sha1 cipher\n");
+ g_return_val_if_reached(NULL);
+ }
+
+ /* Hash the image data */
+ purple_cipher_context_append(context, image_data, image_len);
+ if (!purple_cipher_context_digest_to_str(context, sizeof(digest), digest, NULL))
+ {
+ purple_debug_error("util", "Failed to get SHA-1 digest.\n");
+ g_return_val_if_reached(NULL);
+ }
+ purple_cipher_context_destroy(context);
+
+ /* Return the filename */
+ return g_strdup_printf("%s.%s", digest,
+ purple_util_get_image_extension(image_data, image_len));
+}
+
gboolean
purple_program_is_valid(const char *program)
{
diff --git a/libpurple/util.h b/libpurple/util.h
index 3c138fe0f0..8f0c1b4bc8 100644
--- a/libpurple/util.h
+++ b/libpurple/util.h
@@ -32,6 +32,7 @@
#include "account.h"
#include "xmlnode.h"
+#include "notify.h"
#ifdef __cplusplus
extern "C" {
@@ -118,6 +119,21 @@ gchar *purple_base16_encode(const guchar *data, gsize len);
*/
guchar *purple_base16_decode(const char *str, gsize *ret_len);
+/**
+ * Converts a chunk of binary data to a chunked base-16 representation
+ * (handy for key fingerprints)
+ *
+ * Example output: 01:23:45:67:89:AB:CD:EF
+ *
+ * @param data The data to convert.
+ * @param len The length of the data.
+ *
+ * @return The base-16 string in the ASCII chunked encoding. Must be
+ * g_free'd when no longer needed.
+ */
+gchar *purple_base16_encode_chunked(const guchar *data, gsize len);
+
+
/*@}*/
/**************************************************************************/
@@ -608,6 +624,12 @@ FILE *purple_mkstemp(char **path, gboolean binary);
const char *
purple_util_get_image_extension(gconstpointer data, size_t len);
+/**
+ * Returns a SHA-1 hash string of the data passed in with the correct file
+ * extention appended.
+ */
+char *purple_util_get_image_filename(gconstpointer image_data, size_t image_len);
+
/*@}*/
diff --git a/libpurple/xmlnode.c b/libpurple/xmlnode.c
index c804532de5..942d480234 100644
--- a/libpurple/xmlnode.c
+++ b/libpurple/xmlnode.c
@@ -333,8 +333,9 @@ xmlnode_get_data(xmlnode *node)
for(c = node->child; c; c = c->next) {
if(c->type == XMLNODE_TYPE_DATA) {
if(!str)
- str = g_string_new("");
- str = g_string_append_len(str, c->data, c->data_sz);
+ str = g_string_new_len(c->data, c->data_sz);
+ else
+ str = g_string_append_len(str, c->data, c->data_sz);
}
}
@@ -344,6 +345,18 @@ xmlnode_get_data(xmlnode *node)
return g_string_free(str, FALSE);
}
+char *
+xmlnode_get_data_unescaped(xmlnode *node)
+{
+ char *escaped = xmlnode_get_data(node);
+
+ char *unescaped = escaped ? purple_unescape_html(escaped) : NULL;
+
+ g_free(escaped);
+
+ return unescaped;
+}
+
static char *
xmlnode_to_str_helper(xmlnode *node, int *len, gboolean formatting, int depth)
{
diff --git a/libpurple/xmlnode.h b/libpurple/xmlnode.h
index f9a94fb908..ab337a3008 100644
--- a/libpurple/xmlnode.h
+++ b/libpurple/xmlnode.h
@@ -124,16 +124,26 @@ xmlnode *xmlnode_get_next_twin(xmlnode *node);
void xmlnode_insert_data(xmlnode *node, const char *data, gssize size);
/**
- * Gets data from a node.
+ * Gets (escaped) data from a node.
*
* @param node The node to get data from.
*
- * @return The data from the node. You must g_free
- * this string when finished using it.
+ * @return The data from the node. This data is in raw escaped format.
+ * You must g_free this string when finished using it.
*/
char *xmlnode_get_data(xmlnode *node);
/**
+ * Gets unescaped data from a node.
+ *
+ * @param node The node to get data from.
+ *
+ * @return The data from the node, in unescaped form. You must g_free
+ * this string when finished using it.
+ */
+char *xmlnode_get_data_unescaped(xmlnode *node);
+
+/**
* Sets an attribute for a node.
*
* @param node The node to set an attribute for.
diff --git a/pidgin/Makefile.am b/pidgin/Makefile.am
index 2f29d82a67..58544bedfd 100644
--- a/pidgin/Makefile.am
+++ b/pidgin/Makefile.am
@@ -109,6 +109,8 @@ pidgin_SOURCES = \
gtksession.c \
gtksound.c \
gtksourceiter.c \
+ gtksourceundomanager.c \
+ gtksourceview-marshal.c \
gtkstatusbox.c \
gtkthemes.c \
gtkutils.c \
@@ -156,6 +158,8 @@ pidgin_headers = \
gtksession.h \
gtksound.h \
gtksourceiter.h \
+ gtksourceundomanager.h \
+ gtksourceview-marshal.h \
gtkstatusbox.h \
pidginstock.h \
gtkthemes.h \
diff --git a/pidgin/Makefile.mingw b/pidgin/Makefile.mingw
index 9967b8f223..1008d377ed 100644
--- a/pidgin/Makefile.mingw
+++ b/pidgin/Makefile.mingw
@@ -85,6 +85,7 @@ PIDGIN_C_SRC = \
gtkscrollbook.c \
gtksound.c \
gtksourceiter.c \
+ gtksourceundomanager.c \
gtkstatusbox.c \
gtkthemes.c \
gtkutils.c \
diff --git a/pidgin/gtkaccount.c b/pidgin/gtkaccount.c
index cdbcde0bdd..6bfbcfcd87 100644
--- a/pidgin/gtkaccount.c
+++ b/pidgin/gtkaccount.c
@@ -480,11 +480,15 @@ add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent)
GtkWidget *entry = l->data;
PurpleAccountUserSplit *split = l2->data;
- const char *value = NULL, *protocol = NULL;
+ const char *value = NULL;
char *c;
if (dialog->account != NULL) {
- c = strrchr(username,
+ if(purple_account_user_split_get_reverse(split))
+ c = strrchr(username,
+ purple_account_user_split_get_separator(split));
+ else
+ c = strchr(username,
purple_account_user_split_get_separator(split));
if (c != NULL) {
@@ -500,9 +504,8 @@ add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent)
/* 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));
- protocol = g_object_get_data(G_OBJECT(item), "protocol");
- if (value == NULL && protocol != NULL && !strcmp(protocol, "prpl-fake") &&
- !strcmp(purple_account_user_split_get_text(split), _("Domain")))
+ if (value == NULL && g_object_get_data(G_OBJECT(item), "fake") &&
+ !strcmp(purple_account_user_split_get_text(split), _("Domain")))
value = "gmail.com";
if (value != NULL)
@@ -703,7 +706,7 @@ add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent)
GList *l;
char buf[1024];
char *title, *tmp;
- const char *str_value, *protocol;
+ const char *str_value;
gboolean bool_value;
if (dialog->protocol_frame != NULL) {
@@ -830,8 +833,7 @@ add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent)
/* 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));
- protocol = g_object_get_data(G_OBJECT(item), "protocol");
- if (str_value == NULL && protocol != NULL && !strcmp(protocol, "prpl-fake") &&
+ if (str_value == NULL && g_object_get_data(G_OBJECT(item), "fake") &&
!strcmp(_("Connect server"), purple_account_option_get_text(option)))
str_value = "talk.google.com";
@@ -1468,18 +1470,8 @@ pidgin_account_dialog_show(PidginAccountDialogType type,
if ((dialog->plugin = purple_find_prpl(dialog->protocol_id)) != NULL)
dialog->prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(dialog->plugin);
-
- dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(win), "account");
-
- if (type == PIDGIN_ADD_ACCOUNT_DIALOG)
- gtk_window_set_title(GTK_WINDOW(win), _("Add Account"));
- else
- gtk_window_set_title(GTK_WINDOW(win), _("Modify Account"));
-
- gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
-
- gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER);
+ dialog->window = win = pidgin_create_window((type == PIDGIN_ADD_ACCOUNT_DIALOG) ? _("Add Account") : _("Modify Account"),
+ PIDGIN_HIG_BORDER, "account", FALSE);
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(account_win_destroy_cb), dialog);
@@ -1594,7 +1586,7 @@ signed_on_off_cb(PurpleConnection *gc, gpointer user_data)
account = purple_connection_get_account(gc);
model = GTK_TREE_MODEL(accounts_window->model);
- index = g_list_index(purple_accounts_get_all(), account);
+ index = g_list_index((GList *)purple_accounts_get_all(), account);
if (gtk_tree_model_iter_nth_child(model, &iter, NULL, index))
{
@@ -1797,13 +1789,13 @@ drag_data_received_cb(GtkWidget *widget, GdkDragContext *ctx,
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
move_account_after(dialog->model, &dialog->drag_iter,
&iter);
- dest_index = g_list_index(purple_accounts_get_all(),
+ dest_index = g_list_index((GList *)purple_accounts_get_all(),
account) + 1;
break;
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
- dest_index = g_list_index(purple_accounts_get_all(),
+ dest_index = g_list_index((GList *)purple_accounts_get_all(),
account);
move_account_before(dialog->model, &dialog->drag_iter,
@@ -2102,7 +2094,7 @@ add_account_to_liststore(PurpleAccount *account, gpointer user_data)
static gboolean
populate_accounts_list(AccountsWindow *dialog)
{
- GList *l;
+ const GList *l;
gboolean ret = FALSE;
GdkPixbuf *global_buddyicon = NULL;
const char *path;
@@ -2306,7 +2298,7 @@ static void
global_buddyicon_changed(const char *name, PurplePrefType type,
gconstpointer value, gpointer window)
{
- GList *list;
+ const GList *list;
for (list = purple_accounts_get_all(); list; list = list->next) {
account_modified_cb(list->data, window);
}
@@ -2323,7 +2315,6 @@ pidgin_accounts_window_show(void)
GtkWidget *button;
int width, height;
-
if (accounts_window != NULL) {
gtk_window_present(GTK_WINDOW(accounts_window->window));
return;
@@ -2334,11 +2325,8 @@ pidgin_accounts_window_show(void)
width = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/accounts/dialog/width");
height = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/accounts/dialog/height");
- dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ dialog->window = win = pidgin_create_window(_("Accounts"), PIDGIN_HIG_BORDER, "accounts", TRUE);
gtk_window_set_default_size(GTK_WINDOW(win), width, height);
- gtk_window_set_role(GTK_WINDOW(win), "accounts");
- gtk_window_set_title(GTK_WINDOW(win), _("Accounts"));
- gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER);
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(accedit_win_destroy_cb), accounts_window);
@@ -2441,7 +2429,7 @@ add_user_cb(PidginAccountAddUserData *data)
{
PurpleConnection *gc = purple_account_get_connection(data->account);
- if (g_list_find(purple_connections_get_all(), gc))
+ if (g_list_find((GList *)purple_connections_get_all(), gc))
{
purple_blist_request_add_buddy(data->account, data->username,
NULL, data->alias);
diff --git a/pidgin/gtkblist.c b/pidgin/gtkblist.c
index 9ebcec4ff0..e1322c5174 100644
--- a/pidgin/gtkblist.c
+++ b/pidgin/gtkblist.c
@@ -273,12 +273,7 @@ static gboolean gtk_blist_configure_cb(GtkWidget *w, GdkEventConfigure *event, g
static void gtk_blist_menu_info_cb(GtkWidget *w, PurpleBuddy *b)
{
- PurpleNotifyUserInfo *info = purple_notify_user_info_new();
- purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving..."));
- purple_notify_userinfo(b->account->gc, purple_buddy_get_name(b), info, NULL, NULL);
- purple_notify_user_info_destroy(info);
-
- serv_get_info(b->account->gc, b->name);
+ pidgin_retrieve_user_info(b->account->gc, purple_buddy_get_name(b));
}
static void gtk_blist_menu_im_cb(GtkWidget *w, PurpleBuddy *b)
@@ -701,7 +696,7 @@ chat_account_filter_func(PurpleAccount *account)
gboolean
pidgin_blist_joinchat_is_showable()
{
- GList *c;
+ const GList *c;
PurpleConnection *gc;
for (c = purple_connections_get_all(); c != NULL; c = c->next) {
@@ -1155,7 +1150,8 @@ pidgin_blist_make_buddy_menu(GtkWidget *menu, PurpleBuddy *buddy, gboolean sub)
}
static gboolean
-gtk_blist_key_press_cb(GtkWidget *tv, GdkEventKey *event, gpointer data) {
+gtk_blist_key_press_cb(GtkWidget *tv, GdkEventKey *event, gpointer data)
+{
PurpleBlistNode *node;
GValue val;
GtkTreeIter iter;
@@ -1182,7 +1178,7 @@ gtk_blist_key_press_cb(GtkWidget *tv, GdkEventKey *event, gpointer data) {
return FALSE;
}
if(buddy)
- gtk_blist_menu_info_cb(NULL, buddy);
+ pidgin_retrieve_user_info(buddy->account->gc, buddy->name);
} else if (event->keyval == GDK_F2) {
gtk_blist_menu_alias_cb(tv, node);
}
@@ -1436,7 +1432,7 @@ static gboolean gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event,
prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
if (prpl && prpl_info->get_info)
- gtk_blist_menu_info_cb(NULL, b);
+ pidgin_retrieve_user_info(b->account->gc, b->name);
handled = TRUE;
}
@@ -1555,7 +1551,7 @@ static void
add_buddies_from_vcard(const char *prpl_id, PurpleGroup *group, GList *list,
const char *alias)
{
- GList *l;
+ const GList *l;
PurpleAccount *account = NULL;
PurpleConnection *gc;
@@ -2864,6 +2860,7 @@ static GtkItemFactoryEntry blist_menu[] =
{ 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/_About Pidgin"), NULL, pidgin_dialogs_about, 0, "<Item>", NULL },
{ N_("/Buddies/_Quit"), "<CTL>Q", purple_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT },
/* Accounts menu */
@@ -2880,9 +2877,9 @@ static GtkItemFactoryEntry blist_menu[] =
{ N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<Item>", NULL },
{ N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL },
{ N_("/Tools/System _Log"), NULL, gtk_blist_show_systemlog_cb, 0, "<Item>", NULL },
+ { N_("/Tools/_Debug Window"), NULL, toggle_debug, 0, "<Item>", NULL },
{ "/Tools/sep3", NULL, NULL, 0, "<Separator>", NULL },
{ N_("/Tools/Mute _Sounds"), "<CTL>S", pidgin_blist_mute_sounds_cb, 0, "<CheckItem>", NULL },
-
/* Help */
{ N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL },
{ N_("/Help/Online _Help"), "F1", gtk_blist_show_onlinehelp_cb, 0, "<StockItem>", GTK_STOCK_HELP },
@@ -2912,7 +2909,7 @@ static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full)
prpl = purple_find_prpl(purple_account_get_protocol_id(chat->account));
prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
- if (g_list_length(purple_connections_get_all()) > 1)
+ if (g_list_length((GList *)purple_connections_get_all()) > 1)
{
tmp = g_markup_escape_text(chat->account->username, -1);
g_string_append_printf(str, _("\n<b>Account:</b> %s"), tmp);
@@ -2977,7 +2974,7 @@ static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full)
user_info = purple_notify_user_info_new();
/* Account */
- if (full && g_list_length(purple_connections_get_all()) > 1)
+ if (full && g_list_length((GList *)purple_connections_get_all()) > 1)
{
tmp = g_markup_escape_text(purple_account_get_username(
purple_buddy_get_account(b)), -1);
@@ -3864,15 +3861,17 @@ account_status_changed(PurpleAccount *account, PurpleStatus *old,
static gboolean
gtk_blist_window_key_press_cb(GtkWidget *w, GdkEventKey *event, PidginBuddyList *gtkblist)
{
- GtkWidget *imhtml;
+ GtkWidget *widget;
if (!gtkblist)
return FALSE;
- imhtml = gtk_window_get_focus(GTK_WINDOW(gtkblist->window));
+ widget = gtk_window_get_focus(GTK_WINDOW(gtkblist->window));
- if (GTK_IS_IMHTML(imhtml) && gtk_bindings_activate(GTK_OBJECT(imhtml), event->keyval, event->state))
- return TRUE;
+ if (GTK_IS_IMHTML(widget) || GTK_IS_ENTRY(widget)) {
+ if (gtk_bindings_activate(GTK_OBJECT(widget), event->keyval, event->state))
+ return TRUE;
+ }
return FALSE;
}
@@ -4235,7 +4234,7 @@ static void pidgin_blist_show(PurpleBuddyList *list)
{"application/x-im-contact", 0, DRAG_BUDDY},
{"text/x-vcard", 0, DRAG_VCARD }};
if (gtkblist && gtkblist->window) {
- purple_blist_set_visible(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_visible"));
+ purple_blist_set_visible(TRUE);
return;
}
@@ -4244,9 +4243,7 @@ static void pidgin_blist_show(PurpleBuddyList *list)
gtkblist->empty_avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
gdk_pixbuf_fill(gtkblist->empty_avatar, 0x00000000);
- gtkblist->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(gtkblist->window), "buddy_list");
- gtk_window_set_title(GTK_WINDOW(gtkblist->window), _("Buddy List"));
+ gtkblist->window = pidgin_create_window(_("Buddy List"), 0, "buddy_list", TRUE);
g_signal_connect(G_OBJECT(gtkblist->window), "focus-in-event",
G_CALLBACK(blist_focus_cb), gtkblist);
GTK_WINDOW(gtkblist->window)->allow_shrink = TRUE;
@@ -4902,7 +4899,7 @@ static void pidgin_blist_update_group(PurpleBuddyList *list, PurpleBlistNode *no
GROUP_EXPANDER_VISIBLE_COLUMN, TRUE,
CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE,
BUDDY_ICON_VISIBLE_COLUMN, FALSE,
- IDLE_VISIBLE_COLUMN, FALSE,
+ IDLE_VISIBLE_COLUMN, FALSE,
EMBLEM_VISIBLE_COLUMN, FALSE,
-1);
g_free(title);
@@ -5000,6 +4997,7 @@ static void buddy_node(PurpleBuddy *buddy, GtkTreeIter *iter, PurpleBlistNode *n
idle = i2;
}
}
+
gtk_tree_store_set(gtkblist->treemodel, iter,
STATUS_ICON_COLUMN, status,
STATUS_ICON_VISIBLE_COLUMN, TRUE,
@@ -5014,7 +5012,7 @@ static void buddy_node(PurpleBuddy *buddy, GtkTreeIter *iter, PurpleBlistNode *n
CONTACT_EXPANDER_COLUMN, NULL,
CONTACT_EXPANDER_VISIBLE_COLUMN, expanded,
GROUP_EXPANDER_VISIBLE_COLUMN, FALSE,
- -1);
+ -1);
g_free(mark);
g_free(idle);
@@ -5032,7 +5030,6 @@ static void pidgin_blist_update_contact(PurpleBuddyList *list, PurpleBlistNode *
PurpleContact *contact;
PurpleBuddy *buddy;
struct _pidgin_blist_node *gtknode;
-
if (editing_blist)
return;
@@ -5131,7 +5128,6 @@ static void pidgin_blist_update_chat(PurpleBuddyList *list, PurpleBlistNode *nod
PurpleChat *chat;
g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
-
if (editing_blist)
return;
@@ -5735,7 +5731,7 @@ pidgin_blist_request_add_chat(PurpleAccount *account, PurpleGroup *group,
{
PidginAddChatData *data;
PidginBuddyList *gtkblist;
- GList *l;
+ const GList *l;
PurpleConnection *gc;
GtkWidget *label;
GtkWidget *rowbox;
@@ -6502,7 +6498,8 @@ pidgin_blist_update_accounts_menu(void)
{
GtkWidget *menuitem = NULL, *submenu = NULL;
GtkAccelGroup *accel_group = NULL;
- GList *l = NULL, *accounts = NULL;
+ GList *l = NULL;
+ const GList *accounts;
gboolean disabled_accounts = FALSE;
if (accountmenu == NULL)
diff --git a/pidgin/gtkconv.c b/pidgin/gtkconv.c
index c912d26e71..7ad691c2d7 100644
--- a/pidgin/gtkconv.c
+++ b/pidgin/gtkconv.c
@@ -272,65 +272,7 @@ static void
default_formatize(PidginConversation *c)
{
PurpleConversation *conv = c->active_conv;
-
- if (conv->features & PURPLE_CONNECTION_HTML)
- {
- char color[8];
- GdkColor fg_color, bg_color;
-
- if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold") != GTK_IMHTML(c->entry)->edit.bold)
- gtk_imhtml_toggle_bold(GTK_IMHTML(c->entry));
-
- if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic") != GTK_IMHTML(c->entry)->edit.italic)
- gtk_imhtml_toggle_italic(GTK_IMHTML(c->entry));
-
- if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline") != GTK_IMHTML(c->entry)->edit.underline)
- gtk_imhtml_toggle_underline(GTK_IMHTML(c->entry));
-
- gtk_imhtml_toggle_fontface(GTK_IMHTML(c->entry),
- purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/font_face"));
-
- if (!(conv->features & PURPLE_CONNECTION_NO_FONTSIZE))
- {
- int size = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/font_size");
-
- /* 3 is the default. */
- if (size != 3)
- gtk_imhtml_font_set_size(GTK_IMHTML(c->entry), size);
- }
-
- if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor"), "") != 0)
- {
- 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);
- } else
- strcpy(color, "");
-
- gtk_imhtml_toggle_forecolor(GTK_IMHTML(c->entry), color);
-
- if(!(conv->features & 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);
- } else
- strcpy(color, "");
-
- gtk_imhtml_toggle_background(GTK_IMHTML(c->entry), color);
-
- if (conv->features & PURPLE_CONNECTION_FORMATTING_WBFO)
- gtk_imhtml_set_whole_buffer_formatting_only(GTK_IMHTML(c->entry), TRUE);
- else
- gtk_imhtml_set_whole_buffer_formatting_only(GTK_IMHTML(c->entry), FALSE);
- }
+ gtk_imhtml_setup_entry(GTK_IMHTML(c->entry), conv->features);
}
static void
@@ -478,6 +420,7 @@ check_for_and_do_command(PurpleConversation *conv)
char *cmd;
const char *prefix;
GtkTextIter start;
+ gboolean retval = FALSE;
gtkconv = PIDGIN_CONVERSATION(conv);
prefix = pidgin_get_cmd_prefix();
@@ -501,24 +444,50 @@ check_for_and_do_command(PurpleConversation *conv)
gtk_text_buffer_get_end_iter(GTK_IMHTML(gtkconv->entry)->text_buffer, &end);
markup = gtk_imhtml_get_markup_range(GTK_IMHTML(gtkconv->entry), &start, &end);
status = purple_cmd_do_command(conv, cmdline, markup, &error);
- g_free(cmd);
g_free(markup);
switch (status) {
case PURPLE_CMD_STATUS_OK:
- return TRUE;
+ retval = TRUE;
+ break;
case PURPLE_CMD_STATUS_NOT_FOUND:
- return FALSE;
+ {
+ PurplePluginProtocolInfo *prpl_info = NULL;
+ PurpleConnection *gc;
+
+ if ((gc = purple_conversation_get_gc(conv)))
+ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+
+ if ((prpl_info != NULL) && (prpl_info->options & OPT_PROTO_SLASH_COMMANDS_NATIVE)) {
+ char *firstspace;
+ char *slash;
+
+ firstspace = strchr(cmdline, ' ');
+ if (firstspace != NULL) {
+ slash = strrchr(firstspace, '/');
+ } else {
+ slash = strchr(cmdline, '/');
+ }
+
+ if (slash == NULL) {
+ purple_conversation_write(conv, "", _("Unknown command."), PURPLE_MESSAGE_NO_LOG, time(NULL));
+ retval = TRUE;
+ }
+ }
+ break;
+ }
case PURPLE_CMD_STATUS_WRONG_ARGS:
purple_conversation_write(conv, "", _("Syntax Error: You typed the wrong number of arguments "
"to that command."),
PURPLE_MESSAGE_NO_LOG, time(NULL));
- return TRUE;
+ retval = TRUE;
+ break;
case PURPLE_CMD_STATUS_FAILED:
purple_conversation_write(conv, "", error ? error : _("Your command failed for an unknown reason."),
PURPLE_MESSAGE_NO_LOG, time(NULL));
g_free(error);
- return TRUE;
+ retval = TRUE;
+ break;
case PURPLE_CMD_STATUS_WRONG_TYPE:
if(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
purple_conversation_write(conv, "", _("That command only works in chats, not IMs."),
@@ -526,16 +495,18 @@ check_for_and_do_command(PurpleConversation *conv)
else
purple_conversation_write(conv, "", _("That command only works in IMs, not chats."),
PURPLE_MESSAGE_NO_LOG, time(NULL));
- return TRUE;
+ retval = TRUE;
+ break;
case PURPLE_CMD_STATUS_WRONG_PRPL:
purple_conversation_write(conv, "", _("That command doesn't work on this protocol."),
PURPLE_MESSAGE_NO_LOG, time(NULL));
- return TRUE;
+ retval = TRUE;
+ break;
}
}
g_free(cmd);
- return FALSE;
+ return retval;
}
static void
@@ -667,7 +638,7 @@ static void chat_do_info(PidginConversation *gtkconv, const char *who)
purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who);
}
else
- prpl_info->get_info(gc, who);
+ pidgin_retrieve_user_info(gc, who);
}
}
@@ -678,14 +649,8 @@ info_cb(GtkWidget *widget, PidginConversation *gtkconv)
PurpleConversation *conv = gtkconv->active_conv;
if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
- PurpleNotifyUserInfo *info = purple_notify_user_info_new();
- purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving..."));
- purple_notify_userinfo(conv->account->gc, purple_conversation_get_name(conv), info, NULL, NULL);
- purple_notify_user_info_destroy(info);
-
- serv_get_info(purple_conversation_get_gc(conv),
+ pidgin_retrieve_user_info(purple_conversation_get_gc(conv),
purple_conversation_get_name(conv));
-
gtk_widget_grab_focus(gtkconv->entry);
} else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
/* Get info of the person currently selected in the GtkTreeView */
@@ -2273,34 +2238,18 @@ delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos,
static GList *get_prpl_icon_list(PurpleAccount *account)
{
GList *l = NULL;
- GdkPixbuf *pixbuf;
- PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account)));
- const char *prpl = prpl_info->list_icon(account, NULL);
- char *filename, *path;
- l = g_hash_table_lookup(prpl_lists, prpl);
+ PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account));
+ PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+ const char *prplname = prpl_info->list_icon(account, NULL);
+ l = g_hash_table_lookup(prpl_lists, prplname);
if (l)
return l;
- filename = g_strdup_printf("%s.png", prpl);
- path = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "16", filename, NULL);
- pixbuf = gdk_pixbuf_new_from_file(path, NULL);
- if (pixbuf)
- l = g_list_append(l, pixbuf);
- g_free(path);
-
- path = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "22", filename, NULL);
- pixbuf = gdk_pixbuf_new_from_file(path, NULL);
- if (pixbuf)
- l = g_list_append(l, pixbuf);
- g_free(path);
-
- path = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "48", filename, NULL);
- pixbuf = gdk_pixbuf_new_from_file(path, NULL);
- if (pixbuf)
- l = g_list_append(l, pixbuf);
- g_free(path);
-
- g_hash_table_insert(prpl_lists, g_strdup(prpl), l);
+ l = g_list_prepend(l, pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_LARGE));
+ l = g_list_prepend(l, pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM));
+ l = g_list_prepend(l, pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL));
+
+ g_hash_table_insert(prpl_lists, g_strdup(prplname), l);
return l;
}
@@ -2741,7 +2690,7 @@ pidgin_conversations_find_unseen_list(PurpleConversationType type,
gboolean hidden_only,
guint max_count)
{
- GList *l;
+ const GList *l;
GList *r = NULL;
guint c = 0;
@@ -3029,10 +2978,65 @@ regenerate_options_items(PidginWindow *win)
gtk_widget_show_all(menu);
}
+static void
+remove_from_list(GtkWidget *widget, PidginWindow *win)
+{
+ GList *list = g_object_get_data(G_OBJECT(win->window), "plugin-actions");
+ list = g_list_remove(list, widget);
+ g_object_set_data(G_OBJECT(win->window), "plugin-actions", list);
+}
+
+static void
+regenerate_plugins_items(PidginWindow *win)
+{
+ GList *action_items;
+ GtkWidget *menu;
+ GList *list;
+ PidginConversation *gtkconv;
+ PurpleConversation *conv;
+ GtkWidget *item;
+
+ if (win->window == NULL || win == hidden_convwin)
+ return;
+
+ gtkconv = pidgin_conv_window_get_active_gtkconv(win);
+ if (gtkconv == NULL)
+ return;
+
+ conv = gtkconv->active_conv;
+ action_items = g_object_get_data(G_OBJECT(win->window), "plugin-actions");
+
+ /* Remove the old menuitems */
+ while (action_items) {
+ g_signal_handlers_disconnect_by_func(G_OBJECT(action_items->data),
+ G_CALLBACK(remove_from_list), win);
+ gtk_widget_destroy(action_items->data);
+ action_items = g_list_delete_link(action_items, action_items);
+ }
+
+ menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Options"));
+
+ list = purple_conversation_get_extended_menu(conv);
+ if (list) {
+ action_items = g_list_prepend(NULL, (item = pidgin_separator(menu)));
+ g_signal_connect(G_OBJECT(item), "destroy", G_CALLBACK(remove_from_list), win);
+ }
+
+ for(; list; list = g_list_delete_link(list, list)) {
+ PurpleMenuAction *act = (PurpleMenuAction *) list->data;
+ item = pidgin_append_menu_action(menu, act, conv);
+ action_items = g_list_prepend(action_items, item);
+ gtk_widget_show_all(item);
+ g_signal_connect(G_OBJECT(item), "destroy", G_CALLBACK(remove_from_list), win);
+ }
+ g_object_set_data(G_OBJECT(win->window), "plugin-actions", action_items);
+}
+
static void menubar_activated(GtkWidget *item, gpointer data)
{
PidginWindow *win = data;
regenerate_options_items(win);
+ regenerate_plugins_items(win);
/* The following are to make sure the 'More' submenu is not regenerated every time
* the focus shifts from 'Conversations' to some other menu and back. */
@@ -3846,7 +3850,7 @@ tab_complete(PurpleConversation *conv)
g_list_free(list);
} else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
- GList *l = purple_conv_chat_get_users(chat);
+ const GList *l = purple_conv_chat_get_users(chat);
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(PIDGIN_CONVERSATION(conv)->u.chat->list));
GtkTreeIter iter;
int f;
@@ -4244,45 +4248,17 @@ static void resize_imhtml_cb(PidginConversation *gtkconv)
}
}
-static GtkWidget *
-setup_chat_pane(PidginConversation *gtkconv)
+static void
+setup_chat_topic(PidginConversation *gtkconv, GtkWidget *vbox)
{
- PurplePluginProtocolInfo *prpl_info;
PurpleConversation *conv = gtkconv->active_conv;
- PidginChatPane *gtkchat;
- PurpleConnection *gc;
- GtkWidget *vpaned, *hpaned;
- GtkWidget *vbox, *hbox, *frame;
- GtkWidget *imhtml_sw;
- GtkPolicyType imhtml_sw_hscroll;
- GtkWidget *lbox;
- GtkWidget *label;
- GtkWidget *list;
- GtkWidget *sw;
- GtkListStore *ls;
- GtkCellRenderer *rend;
- GtkTreeViewColumn *col;
- void *blist_handle = purple_blist_get_handle();
- GList *focus_chain = NULL;
- int ul_width;
-
- gtkchat = gtkconv->u.chat;
- gc = purple_conversation_get_gc(conv);
- g_return_val_if_fail(gc != NULL, NULL);
- g_return_val_if_fail(gc->prpl != NULL, NULL);
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
-
- /* Setup the outer pane. */
- vpaned = gtk_vpaned_new();
- gtk_widget_show(vpaned);
-
- /* Setup the top part of the pane. */
- vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
- gtk_paned_pack1(GTK_PANED(vpaned), vbox, TRUE, TRUE);
- gtk_widget_show(vbox);
-
+ PurpleConnection *gc = purple_conversation_get_gc(conv);
+ PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
if (prpl_info->options & OPT_PROTO_CHAT_TOPIC)
{
+ GtkWidget *hbox, *label;
+ PidginChatPane *gtkchat = gtkconv->u.chat;
+
hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
@@ -4305,35 +4281,19 @@ setup_chat_pane(PidginConversation *gtkconv)
g_signal_connect(G_OBJECT(gtkchat->topic_text), "key_press_event",
G_CALLBACK(entry_key_press_cb), gtkconv);
}
+}
- /* Setup the horizontal pane. */
- hpaned = gtk_hpaned_new();
- gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
- gtk_widget_show(hpaned);
-
- /* Setup gtkihmtml. */
- frame = pidgin_create_imhtml(FALSE, &gtkconv->imhtml, NULL, &imhtml_sw);
- gtk_widget_set_name(gtkconv->imhtml, "pidgin_conv_imhtml");
- gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), TRUE);
- gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE);
- gtk_widget_show(frame);
- gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
- &imhtml_sw_hscroll, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
- imhtml_sw_hscroll, GTK_POLICY_ALWAYS);
-
- gtk_widget_set_size_request(gtkconv->imhtml,
- purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_width"),
- purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_height"));
- g_signal_connect(G_OBJECT(gtkconv->imhtml), "size-allocate",
- G_CALLBACK(size_allocate_cb), gtkconv);
-
- g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event",
- G_CALLBACK(entry_stop_rclick_cb), NULL);
- g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_press_event",
- G_CALLBACK(refocus_entry_cb), gtkconv);
- g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event",
- G_CALLBACK(refocus_entry_cb), gtkconv);
+static void
+setup_chat_userlist(PidginConversation *gtkconv, GtkWidget *hpaned)
+{
+ PidginChatPane *gtkchat = gtkconv->u.chat;
+ GtkWidget *lbox, *sw, *list;
+ GtkListStore *ls;
+ GtkCellRenderer *rend;
+ GtkTreeViewColumn *col;
+ int ul_width;
+ void *blist_handle = purple_blist_get_handle();
+ PurpleConversation *conv = gtkconv->active_conv;
/* Build the right pane. */
lbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
@@ -4381,9 +4341,7 @@ setup_chat_pane(PidginConversation *gtkconv)
G_CALLBACK(gtkconv_chat_popup_menu_cb), gtkconv);
g_signal_connect(G_OBJECT(lbox), "size-allocate", G_CALLBACK(lbox_size_allocate_cb), gtkconv);
-
rend = gtk_cell_renderer_text_new();
-
g_object_set(rend,
"foreground-set", TRUE,
"weight-set", TRUE,
@@ -4414,74 +4372,16 @@ setup_chat_pane(PidginConversation *gtkconv)
gtkchat->list = list;
gtk_container_add(GTK_CONTAINER(sw), list);
-
- /* Setup the bottom half of the conversation window */
- vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
- gtk_paned_pack2(GTK_PANED(vpaned), vbox, FALSE, TRUE);
- gtk_widget_show(vbox);
-
- gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
- gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, TRUE, TRUE, 0);
- gtk_widget_show(gtkconv->lower_hbox);
-
- vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
- gtk_box_pack_end(GTK_BOX(gtkconv->lower_hbox), vbox, TRUE, TRUE, 0);
- gtk_widget_show(vbox);
-
- /* Setup the toolbar, entry widget and all signals */
- frame = pidgin_create_imhtml(TRUE, &gtkconv->entry, &gtkconv->toolbar, NULL);
- gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
- gtk_widget_show(frame);
-
- g_signal_connect(G_OBJECT(gtkconv->entry), "populate-popup",
- G_CALLBACK(entry_popup_menu_cb), gtkconv);
-
- gtk_widget_set_name(gtkconv->entry, "pidgin_conv_entry");
- gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->entry),
- purple_account_get_protocol_name(conv->account));
- gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
- purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/entry_height"));
- gtkconv->entry_buffer =
- gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
- g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", gtkconv);
- g_signal_connect_swapped(G_OBJECT(gtkconv->entry_buffer), "changed",
- G_CALLBACK(resize_imhtml_cb), gtkconv);
-
- g_signal_connect(G_OBJECT(gtkconv->entry), "key_press_event",
- G_CALLBACK(entry_key_press_cb), gtkconv);
- g_signal_connect_after(G_OBJECT(gtkconv->entry), "message_send",
- G_CALLBACK(send_cb), gtkconv);
- g_signal_connect_after(G_OBJECT(gtkconv->entry), "button_press_event",
- G_CALLBACK(entry_stop_rclick_cb), NULL);
- g_signal_connect(G_OBJECT(gtkconv->lower_hbox), "size-allocate",
- G_CALLBACK(size_allocate_cb), gtkconv);
-
- default_formatize(gtkconv);
-
- /*
- * Focus for chat windows should be as follows:
- * Tab title -> chat topic -> conversation scrollback -> user list ->
- * user list buttons -> entry -> buttons at bottom
- */
- focus_chain = g_list_prepend(focus_chain, gtkconv->entry);
- gtk_container_set_focus_chain(GTK_CONTAINER(vbox), focus_chain);
-
- return vpaned;
}
static GtkWidget *
-setup_im_pane(PidginConversation *gtkconv)
+setup_common_pane(PidginConversation *gtkconv)
{
+ GtkWidget *paned, *vbox, *frame, *imhtml_sw;
PurpleConversation *conv = gtkconv->active_conv;
- GtkWidget *frame;
- GtkWidget *imhtml_sw;
+ gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT);
GtkPolicyType imhtml_sw_hscroll;
- GtkWidget *paned;
- GtkWidget *vbox;
- GtkWidget *vbox2;
- GList *focus_chain = NULL;
- /* Setup the outer pane */
paned = gtk_vpaned_new();
gtk_widget_show(paned);
@@ -4492,18 +4392,39 @@ setup_im_pane(PidginConversation *gtkconv)
/* Setup the gtkimhtml widget */
frame = pidgin_create_imhtml(FALSE, &gtkconv->imhtml, NULL, &imhtml_sw);
+ if (chat) {
+ GtkWidget *hpaned;
+
+ /* Add the topic */
+ setup_chat_topic(gtkconv, vbox);
+
+ /* Add the gtkimhtml frame */
+ hpaned = gtk_hpaned_new();
+ gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
+ gtk_widget_show(hpaned);
+ gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE);
+
+ /* Now add the userlist */
+ setup_chat_userlist(gtkconv, hpaned);
+ } else {
+ gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
+ }
+ gtk_widget_show(frame);
+
gtk_widget_set_name(gtkconv->imhtml, "pidgin_conv_imhtml");
gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),TRUE);
- gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
- gtk_widget_show(frame);
+
gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
&imhtml_sw_hscroll, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
imhtml_sw_hscroll, GTK_POLICY_ALWAYS);
gtk_widget_set_size_request(gtkconv->imhtml,
+ chat ? purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_width") :
purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/default_width"),
+ chat ? purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_height") :
purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/default_height"));
+
g_signal_connect(G_OBJECT(gtkconv->imhtml), "size-allocate",
G_CALLBACK(size_allocate_cb), gtkconv);
@@ -4515,35 +4436,32 @@ setup_im_pane(PidginConversation *gtkconv)
G_CALLBACK(refocus_entry_cb), gtkconv);
/* Setup the bottom half of the conversation window */
- vbox2 = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
- gtk_paned_pack2(GTK_PANED(paned), vbox2, FALSE, TRUE);
- gtk_widget_show(vbox2);
+ vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+ gtk_paned_pack2(GTK_PANED(paned), vbox, FALSE, TRUE);
+ gtk_widget_show(vbox);
gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
- gtk_box_pack_start(GTK_BOX(vbox2), gtkconv->lower_hbox, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, TRUE, TRUE, 0);
gtk_widget_show(gtkconv->lower_hbox);
- vbox2 = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
- gtk_box_pack_end(GTK_BOX(gtkconv->lower_hbox), vbox2, TRUE, TRUE, 0);
- gtk_widget_show(vbox2);
+ vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+ gtk_box_pack_end(GTK_BOX(gtkconv->lower_hbox), vbox, TRUE, TRUE, 0);
+ gtk_widget_show(vbox);
/* Setup the toolbar, entry widget and all signals */
frame = pidgin_create_imhtml(TRUE, &gtkconv->entry, &gtkconv->toolbar, NULL);
- gtk_box_pack_start(GTK_BOX(vbox2), frame, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
gtk_widget_show(frame);
- g_signal_connect(G_OBJECT(gtkconv->entry), "populate-popup",
- G_CALLBACK(entry_popup_menu_cb), gtkconv);
-
gtk_widget_set_name(gtkconv->entry, "pidgin_conv_entry");
gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->entry),
- purple_account_get_protocol_name(conv->account));
+ purple_account_get_protocol_name(conv->account));
gtk_widget_set_size_request(gtkconv->lower_hbox, -1,
+ chat ? purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/entry_height") :
purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height"));
- gtkconv->entry_buffer =
- gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
- g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", gtkconv);
+ g_signal_connect(G_OBJECT(gtkconv->entry), "populate-popup",
+ G_CALLBACK(entry_popup_menu_cb), gtkconv);
g_signal_connect(G_OBJECT(gtkconv->entry), "key_press_event",
G_CALLBACK(entry_key_press_cb), gtkconv);
g_signal_connect_after(G_OBJECT(gtkconv->entry), "message_send",
@@ -4553,32 +4471,28 @@ setup_im_pane(PidginConversation *gtkconv)
g_signal_connect(G_OBJECT(gtkconv->lower_hbox), "size-allocate",
G_CALLBACK(size_allocate_cb), gtkconv);
- g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "insert_text",
- G_CALLBACK(insert_text_cb), gtkconv);
- g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "delete_range",
- G_CALLBACK(delete_text_cb), gtkconv);
+ gtkconv->entry_buffer =
+ gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
+ g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", gtkconv);
+
+ if (!chat) {
+ /* For sending typing notifications for IMs */
+ g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "insert_text",
+ G_CALLBACK(insert_text_cb), gtkconv);
+ g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "delete_range",
+ G_CALLBACK(delete_text_cb), gtkconv);
+ gtkconv->u.im->typing_timer = 0;
+ gtkconv->u.im->animate = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/animate_buddy_icons");
+ gtkconv->u.im->show_icon = TRUE;
+ }
+
g_signal_connect_swapped(G_OBJECT(gtkconv->entry_buffer), "changed",
G_CALLBACK(resize_imhtml_cb), gtkconv);
- /* had to move this after the imtoolbar is attached so that the
- * signals get fired to toggle the buttons on the toolbar as well.
- */
default_formatize(gtkconv);
-
g_signal_connect_after(G_OBJECT(gtkconv->entry), "format_function_clear",
- G_CALLBACK(clear_formatting_cb), gtkconv);
+ G_CALLBACK(clear_formatting_cb), gtkconv);
- gtkconv->u.im->animate = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/animate_buddy_icons");
- gtkconv->u.im->show_icon = TRUE;
-
- /*
- * Focus for IM windows should be as follows:
- * Tab title -> conversation scrollback -> entry
- */
- focus_chain = g_list_prepend(focus_chain, gtkconv->entry);
- gtk_container_set_focus_chain(GTK_CONTAINER(vbox2), focus_chain);
-
- gtkconv->u.im->typing_timer = 0;
return paned;
}
@@ -4774,12 +4688,10 @@ private_gtkconv_new(PurpleConversation *conv, gboolean hidden)
if (conv_type == PURPLE_CONV_TYPE_IM) {
gtkconv->u.im = g_malloc0(sizeof(PidginImPane));
-
- pane = setup_im_pane(gtkconv);
} else if (conv_type == PURPLE_CONV_TYPE_CHAT) {
gtkconv->u.chat = g_malloc0(sizeof(PidginChatPane));
- pane = setup_chat_pane(gtkconv);
}
+ pane = setup_common_pane(gtkconv);
gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->imhtml),
gtk_imhtml_get_format_functions(GTK_IMHTML(gtkconv->imhtml)) | GTK_IMHTML_IMAGE);
@@ -5177,7 +5089,11 @@ pidgin_conv_write_conv(PurpleConversation *conv, const char *name, const char *a
g_return_if_fail(gc != NULL);
/* Make sure URLs are clickable */
- displaying = purple_markup_linkify(message);
+ if(flags & PURPLE_MESSAGE_NO_LINKIFY)
+ displaying = g_strdup(message);
+ else
+ displaying = purple_markup_linkify(message);
+
plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
pidgin_conversations_get_handle(), (type == PURPLE_CONV_TYPE_IM ?
"displaying-im-msg" : "displaying-chat-msg"),
@@ -5530,7 +5446,7 @@ pidgin_conv_chat_add_users(PurpleConversation *conv, GList *cbuddies, gboolean n
gtkconv = PIDGIN_CONVERSATION(conv);
gtkchat = gtkconv->u.chat;
- num_users = g_list_length(purple_conv_chat_get_users(chat));
+ num_users = g_list_length((GList *)purple_conv_chat_get_users(chat));
g_snprintf(tmp, sizeof(tmp),
ngettext("%d person in room", "%d people in room",
@@ -5624,7 +5540,7 @@ pidgin_conv_chat_remove_users(PurpleConversation *conv, GList *users)
gtkconv = PIDGIN_CONVERSATION(conv);
gtkchat = gtkconv->u.chat;
- num_users = g_list_length(purple_conv_chat_get_users(chat));
+ num_users = g_list_length((GList *)purple_conv_chat_get_users(chat));
for (l = users; l != NULL; l = l->next) {
model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list));
@@ -6621,7 +6537,7 @@ static void
close_on_tabs_pref_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
- GList *l;
+ const GList *l;
PurpleConversation *conv;
PidginConversation *gtkconv;
@@ -6645,7 +6561,7 @@ spellcheck_pref_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
#ifdef USE_GTKSPELL
- GList *cl;
+ const GList *cl;
PurpleConversation *conv;
PidginConversation *gtkconv;
GtkSpell *spell;
@@ -6692,7 +6608,7 @@ static void
show_timestamps_pref_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
- GList *l;
+ const GList *l;
PurpleConversation *conv;
PidginConversation *gtkconv;
PidginWindow *win;
@@ -6720,7 +6636,7 @@ static void
show_formatting_toolbar_pref_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
- GList *l;
+ const GList *l;
PurpleConversation *conv;
PidginConversation *gtkconv;
PidginWindow *win;
@@ -6750,7 +6666,7 @@ static void
animate_buddy_icons_pref_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
- GList *l;
+ const GList *l;
PurpleConversation *conv;
PidginConversation *gtkconv;
PidginWindow *win;
@@ -6777,7 +6693,7 @@ static void
show_buddy_icons_pref_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
- GList *l;
+ const GList *l;
for (l = purple_get_conversations(); l != NULL; l = l->next) {
PurpleConversation *conv = l->data;
@@ -6903,7 +6819,7 @@ get_gtkconv_with_contact(PurpleContact *contact)
static void
account_signed_off_cb(PurpleConnection *gc, gpointer event)
{
- GList *iter;
+ const GList *iter;
for (iter = purple_get_conversations(); iter; iter = iter->next)
{
@@ -8092,6 +8008,7 @@ switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
generate_send_to_items(win);
regenerate_options_items(win);
+ regenerate_plugins_items(win);
pidgin_conv_switch_active_conversation(conv);
@@ -8162,6 +8079,12 @@ create_icon_lists(GtkWidget *w)
prpl_lists = g_hash_table_new(g_str_hash, g_str_equal);
}
+static void
+plugin_changed_cb(PurplePlugin *p, gpointer data)
+{
+ regenerate_plugins_items(data);
+}
+
PidginWindow *
pidgin_conv_window_new()
{
@@ -8175,10 +8098,7 @@ pidgin_conv_window_new()
window_list = g_list_append(window_list, win);
/* Create the window. */
- win->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(win->window), "conversation");
- gtk_window_set_resizable(GTK_WINDOW(win->window), TRUE);
- gtk_container_set_border_width(GTK_CONTAINER(win->window), 0);
+ win->window = pidgin_create_window(NULL, 0, "conversation", TRUE);
GTK_WINDOW(win->window)->allow_shrink = TRUE;
if (available_list == NULL) {
@@ -8236,6 +8156,13 @@ pidgin_conv_window_new()
gtk_widget_show(testidea);
+ /* Update the plugin actions when plugins are (un)loaded */
+ purple_signal_connect(purple_plugins_get_handle(), "plugin-load",
+ win, PURPLE_CALLBACK(plugin_changed_cb), win);
+ purple_signal_connect(purple_plugins_get_handle(), "plugin-unload",
+ win, PURPLE_CALLBACK(plugin_changed_cb), win);
+
+
#ifdef _WIN32
g_signal_connect(G_OBJECT(win->window), "show",
G_CALLBACK(winpidgin_ensure_onscreen), win->window);
@@ -8275,6 +8202,7 @@ pidgin_conv_window_destroy(PidginWindow *win)
g_object_unref(G_OBJECT(win->menu.item_factory));
purple_notify_close_with_handle(win);
+ purple_signals_disconnect_by_handle(win);
g_free(win);
}
diff --git a/pidgin/gtkdialogs.c b/pidgin/gtkdialogs.c
index 7f64d205b4..b52838bb9a 100644
--- a/pidgin/gtkdialogs.c
+++ b/pidgin/gtkdialogs.c
@@ -822,17 +822,8 @@ pidgin_dialogs_info_cb(gpointer data, PurpleRequestFields *fields)
if (username != NULL && purple_str_has_suffix(username, "rocksmyworld"))
found = pidgin_dialogs_ee(username);
- if (!found && username != NULL && *username != '\0' && account != NULL) {
-
- PurpleConnection *gc = purple_account_get_connection(account);
-
- PurpleNotifyUserInfo *info = purple_notify_user_info_new();
- purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving..."));
- purple_notify_userinfo(gc, username, info, NULL, NULL);
- purple_notify_user_info_destroy(info);
-
- serv_get_info(gc, username);
- }
+ if (!found && username != NULL && *username != '\0' && account != NULL)
+ pidgin_retrieve_user_info(purple_account_get_connection(account), username);
g_free(username);
}
@@ -1241,3 +1232,4 @@ pidgin_dialogs_remove_chat(PurpleChat *chat)
g_free(text);
}
+}
diff --git a/pidgin/gtkdocklet.c b/pidgin/gtkdocklet.c
index 5b4e09d5fc..4fa0c262f4 100644
--- a/pidgin/gtkdocklet.c
+++ b/pidgin/gtkdocklet.c
@@ -109,7 +109,8 @@ get_pending_list(guint max)
static gboolean
docklet_update_status()
{
- GList *convs, *l;
+ GList *convs;
+ const GList *l;
int count;
PurpleSavedStatus *saved_status;
PurpleStatusPrimitive newstatus = PURPLE_STATUS_OFFLINE;
@@ -213,8 +214,7 @@ docklet_update_status()
static gboolean
online_account_supports_chat()
{
- GList *c = NULL;
- c = purple_connections_get_all();
+ const GList *c = purple_connections_get_all();
while(c != NULL) {
PurpleConnection *gc = c->data;
diff --git a/pidgin/gtkeventloop.c b/pidgin/gtkeventloop.c
index d8b0623bcc..fcc2c31c3f 100644
--- a/pidgin/gtkeventloop.c
+++ b/pidgin/gtkeventloop.c
@@ -120,7 +120,11 @@ static PurpleEventLoopUiOps eventloop_ops =
pidgin_input_add,
g_source_remove,
NULL, /* input_get_error */
+#if GLIB_CHECK_VERSION(2,14,0)
+ g_timeout_add_seconds,
+#else
NULL,
+#endif
NULL,
NULL,
NULL
diff --git a/pidgin/gtkft.c b/pidgin/gtkft.c
index e18fe0876d..eb3b74a5aa 100644
--- a/pidgin/gtkft.c
+++ b/pidgin/gtkft.c
@@ -758,10 +758,7 @@ pidgin_xfer_dialog_new(void)
purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/filetransfer/clear_finished");
/* Create the window. */
- dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(window), "file transfer");
- gtk_window_set_title(GTK_WINDOW(window), _("File Transfers"));
- gtk_container_set_border_width(GTK_CONTAINER(window), PIDGIN_HIG_BORDER);
+ dialog->window = window = pidgin_create_window(_("File Transfers"), PIDGIN_HIG_BORDER, "file transfer", TRUE);
g_signal_connect(G_OBJECT(window), "delete_event",
G_CALLBACK(delete_win_cb), dialog);
diff --git a/pidgin/gtkimhtml.c b/pidgin/gtkimhtml.c
index 895475763a..b67b032e8c 100644
--- a/pidgin/gtkimhtml.c
+++ b/pidgin/gtkimhtml.c
@@ -27,10 +27,15 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#include "pidgin.h"
+
#include "debug.h"
#include "util.h"
#include "gtkimhtml.h"
#include "gtksourceiter.h"
+#include "gtksourceundomanager.h"
+#include "gtksourceview-marshal.h"
#include <gtk/gtk.h>
#include <glib/gerror.h>
#include <gdk/gdkkeysyms.h>
@@ -136,6 +141,8 @@ enum {
CLEAR_FORMAT,
UPDATE_FORMAT,
MESSAGE_SEND,
+ UNDO,
+ REDO,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0 };
@@ -1150,6 +1157,23 @@ static gboolean gtk_imhtml_button_press_event(GtkIMHtml *imhtml, GdkEventButton
return FALSE;
}
+static void
+gtk_imhtml_undo(GtkIMHtml *imhtml) {
+ g_return_if_fail(GTK_IS_IMHTML(imhtml));
+ g_return_if_fail(imhtml->editable);
+
+ gtk_source_undo_manager_undo(imhtml->undo_manager);
+}
+
+static void
+gtk_imhtml_redo(GtkIMHtml *imhtml) {
+ g_return_if_fail(GTK_IS_IMHTML(imhtml));
+ g_return_if_fail(imhtml->editable);
+
+ gtk_source_undo_manager_redo(imhtml->undo_manager);
+
+}
+
static gboolean imhtml_message_send(GtkIMHtml *imhtml)
{
return FALSE;
@@ -1228,6 +1252,7 @@ gtk_imhtml_finalize (GObject *object)
g_queue_free(imhtml->animations);
g_free(imhtml->protocol_name);
g_free(imhtml->search_string);
+ g_object_unref(imhtml->undo_manager);
G_OBJECT_CLASS(parent_class)->finalize (object);
if (clipboard_selection)
gtk_clipboard_set_with_owner(clipboard_selection,
@@ -1297,10 +1322,32 @@ static void gtk_imhtml_class_init (GtkIMHtmlClass *klass)
NULL,
0, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+ signals [UNDO] = g_signal_new ("undo",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkIMHtmlClass, undo),
+ NULL,
+ NULL,
+ gtksourceview_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ signals [REDO] = g_signal_new ("redo",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkIMHtmlClass, redo),
+ NULL,
+ NULL,
+ gtksourceview_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+
klass->toggle_format = imhtml_toggle_format;
klass->message_send = imhtml_message_send;
klass->clear_format = imhtml_clear_formatting;
+ klass->undo = gtk_imhtml_undo;
+ klass->redo = gtk_imhtml_redo;
gobject_class->finalize = gtk_imhtml_finalize;
widget_class->drag_motion = gtk_text_view_drag_motion;
@@ -1325,12 +1372,17 @@ static void gtk_imhtml_class_init (GtkIMHtmlClass *klass)
gtk_binding_entry_add_signal (binding_set, GDK_r, GDK_CONTROL_MASK, "format_function_clear", 0);
gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "message_send", 0);
gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "message_send", 0);
+ gtk_binding_entry_add_signal (binding_set, GDK_z, GDK_CONTROL_MASK, "undo", 0);
+ gtk_binding_entry_add_signal (binding_set, GDK_z, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "redo", 0);
+ gtk_binding_entry_add_signal (binding_set, GDK_F14, 0, "undo", 0);
+
}
static void gtk_imhtml_init (GtkIMHtml *imhtml)
{
GtkTextIter iter;
imhtml->text_buffer = gtk_text_buffer_new(NULL);
+ imhtml->undo_manager = gtk_source_undo_manager_new(imhtml->text_buffer);
gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter);
gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR);
@@ -3113,14 +3165,13 @@ void gtk_imhtml_page_down (GtkIMHtml *imhtml)
GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id)
{
GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage));
- GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img));
GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale;
GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to;
GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free;
im_image->pixbuf = img;
- im_image->image = image;
+ im_image->image = GTK_IMAGE(gtk_image_new_from_pixbuf(im_image->pixbuf));
im_image->width = gdk_pixbuf_get_width(img);
im_image->height = gdk_pixbuf_get_height(img);
im_image->mark = NULL;
@@ -3132,6 +3183,76 @@ GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, i
return GTK_IMHTML_SCALABLE(im_image);
}
+static gboolean
+animate_image_cb(gpointer data)
+{
+ GtkIMHtmlImage *im_image;
+ int width, height;
+ int delay;
+
+ im_image = data;
+
+ /* Update the pointer to this GdkPixbuf frame of the animation */
+ g_object_unref(G_OBJECT(im_image->pixbuf));
+ gdk_pixbuf_animation_iter_advance(GTK_IMHTML_ANIMATION(im_image)->iter, NULL);
+ im_image->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(GTK_IMHTML_ANIMATION(im_image)->iter);
+ g_object_ref(G_OBJECT(im_image->pixbuf));
+
+ /* Update the displayed GtkImage */
+ width = gdk_pixbuf_get_width(gtk_image_get_pixbuf(im_image->image));
+ height = gdk_pixbuf_get_height(gtk_image_get_pixbuf(im_image->image));
+ if (width > 0 && height > 0)
+ {
+ /* Need to scale the new frame to the same size as the old frame */
+ GdkPixbuf *tmp;
+ tmp = gdk_pixbuf_scale_simple(im_image->pixbuf, width, height, GDK_INTERP_BILINEAR);
+ gtk_image_set_from_pixbuf(im_image->image, tmp);
+ g_object_unref(G_OBJECT(tmp));
+ } else {
+ /* Display at full-size */
+ gtk_image_set_from_pixbuf(im_image->image, im_image->pixbuf);
+ }
+
+ delay = MIN(gdk_pixbuf_animation_iter_get_delay_time(GTK_IMHTML_ANIMATION(im_image)->iter), 100);
+ GTK_IMHTML_ANIMATION(im_image)->timer = g_timeout_add(delay, animate_image_cb, im_image);
+
+ return FALSE;
+}
+
+GtkIMHtmlScalable *gtk_imhtml_animation_new(GdkPixbufAnimation *anim, const gchar *filename, int id)
+{
+ GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlAnimation));
+
+ GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale;
+ GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to;
+ GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_animation_free;
+
+ GTK_IMHTML_ANIMATION(im_image)->anim = anim;
+ if (gdk_pixbuf_animation_is_static_image(anim)) {
+ GTK_IMHTML_ANIMATION(im_image)->iter = NULL;
+ im_image->pixbuf = gdk_pixbuf_animation_get_static_image(anim);
+ GTK_IMHTML_ANIMATION(im_image)->timer = 0;
+ } else {
+ int delay;
+ GTK_IMHTML_ANIMATION(im_image)->iter = gdk_pixbuf_animation_get_iter(anim, NULL);
+ im_image->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(GTK_IMHTML_ANIMATION(im_image)->iter);
+ delay = MIN(gdk_pixbuf_animation_iter_get_delay_time(GTK_IMHTML_ANIMATION(im_image)->iter), 100);
+ GTK_IMHTML_ANIMATION(im_image)->timer = g_timeout_add(delay, animate_image_cb, im_image);
+ }
+ im_image->image = GTK_IMAGE(gtk_image_new_from_pixbuf(im_image->pixbuf));
+ im_image->width = gdk_pixbuf_animation_get_width(anim);
+ im_image->height = gdk_pixbuf_animation_get_height(anim);
+ im_image->mark = NULL;
+ im_image->filename = g_strdup(filename);
+ im_image->id = id;
+ im_image->filesel = NULL;
+
+ g_object_ref(anim);
+ g_object_ref(im_image->pixbuf);
+
+ return GTK_IMHTML_SCALABLE(im_image);
+}
+
void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height)
{
GtkIMHtmlImage *im_image = (GtkIMHtmlImage *)scale;
@@ -3406,7 +3527,6 @@ static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtm
static gboolean gtk_imhtml_smiley_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlSmiley *smiley)
{
GdkPixbufAnimation *anim = NULL;
- GdkPixbuf *pix = NULL;
GtkIMHtmlScalable *image = NULL;
gboolean ret;
@@ -3417,11 +3537,9 @@ static gboolean gtk_imhtml_smiley_clicked(GtkWidget *w, GdkEvent *event, GtkIMHt
if (!anim)
return FALSE;
- pix = gdk_pixbuf_animation_get_static_image(anim);
- image = gtk_imhtml_image_new(pix, smiley->smile, 0);
+ image = gtk_imhtml_animation_new(anim, smiley->smile, 0);
ret = gtk_imhtml_image_clicked(w, event, (GtkIMHtmlImage*)image);
g_object_set_data_full(G_OBJECT(w), "image-data", image, (GDestroyNotify)gtk_imhtml_image_free);
- g_object_unref(G_OBJECT(pix));
return ret;
}
@@ -3436,6 +3554,19 @@ void gtk_imhtml_image_free(GtkIMHtmlScalable *scale)
g_free(scale);
}
+void gtk_imhtml_animation_free(GtkIMHtmlScalable *scale)
+{
+ GtkIMHtmlAnimation *animation = (GtkIMHtmlAnimation *)scale;
+
+ if (animation->timer > 0)
+ g_source_remove(animation->timer);
+ if (animation->iter != NULL)
+ g_object_unref(animation->iter);
+ g_object_unref(animation->anim);
+
+ gtk_imhtml_image_free(scale);
+}
+
void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter)
{
GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale;
@@ -4516,7 +4647,7 @@ void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *
void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *iter)
{
- GdkPixbuf *pixbuf = NULL;
+ GdkPixbufAnimation *anim = NULL;
const char *filename = NULL;
gpointer image;
GdkRectangle rect;
@@ -4543,28 +4674,33 @@ void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *ite
GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
gdk_pixbuf_loader_write(loader, data, len, NULL);
gdk_pixbuf_loader_close(loader, NULL);
- pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
- if (pixbuf)
- g_object_ref(G_OBJECT(pixbuf));
+ anim = gdk_pixbuf_loader_get_animation(loader);
+ if (anim)
+ g_object_ref(G_OBJECT(anim));
g_object_unref(G_OBJECT(loader));
}
}
- if (pixbuf) {
+ if (anim) {
struct im_image_data *t = g_new(struct im_image_data, 1);
filename = imhtml->funcs->image_get_filename(image);
imhtml->funcs->image_ref(id);
t->id = id;
t->mark = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, iter, TRUE);
imhtml->im_images = g_slist_prepend(imhtml->im_images, t);
+ scalable = gtk_imhtml_animation_new(anim, filename, id);
+ g_object_unref(G_OBJECT(anim));
} else {
+ GdkPixbuf *pixbuf;
pixbuf = gtk_widget_render_icon(GTK_WIDGET(imhtml), GTK_STOCK_MISSING_IMAGE,
GTK_ICON_SIZE_BUTTON, "gtkimhtml-missing-image");
+ scalable = gtk_imhtml_image_new(pixbuf, filename, id);
+ g_object_unref(G_OBJECT(pixbuf));
}
sd = g_new(struct scalable_data, 1);
- sd->scalable = scalable = gtk_imhtml_image_new(pixbuf, filename, id);
+ sd->scalable = scalable;
sd->mark = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, iter, TRUE);
gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
scalable->add_to(scalable, imhtml, iter);
@@ -4572,8 +4708,6 @@ void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *ite
gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml));
scalable->scale(scalable, rect.width - minus, rect.height);
imhtml->scalables = g_list_append(imhtml->scalables, sd);
-
- g_object_unref(G_OBJECT(pixbuf));
}
static const gchar *tag_to_html_start(GtkTextTag *tag)
@@ -4899,3 +5033,70 @@ void gtk_imhtml_set_funcs(GtkIMHtml *imhtml, GtkIMHtmlFuncs *f)
g_return_if_fail(imhtml != NULL);
imhtml->funcs = f;
}
+
+void gtk_imhtml_setup_entry(GtkIMHtml *imhtml, PurpleConnectionFlags flags)
+{
+ if (flags & PURPLE_CONNECTION_HTML) {
+ char color[8];
+ GdkColor fg_color, bg_color;
+
+ gtk_imhtml_set_format_functions(imhtml, GTK_IMHTML_ALL);
+ if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold") != imhtml->edit.bold)
+ gtk_imhtml_toggle_bold(imhtml);
+
+ if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic") != imhtml->edit.italic)
+ gtk_imhtml_toggle_italic(imhtml);
+
+ if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline") != imhtml->edit.underline)
+ gtk_imhtml_toggle_underline(imhtml);
+
+ gtk_imhtml_toggle_fontface(imhtml,
+ purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/font_face"));
+
+ if (!(flags & PURPLE_CONNECTION_NO_FONTSIZE))
+ {
+ int size = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/font_size");
+
+ /* 3 is the default. */
+ if (size != 3)
+ gtk_imhtml_font_set_size(imhtml, size);
+ }
+
+ if(strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor"), "") != 0)
+ {
+ 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);
+ } else
+ strcpy(color, "");
+
+ gtk_imhtml_toggle_forecolor(imhtml, color);
+
+ 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);
+ } else
+ strcpy(color, "");
+
+ gtk_imhtml_toggle_background(imhtml, color);
+
+ if (flags & PURPLE_CONNECTION_FORMATTING_WBFO)
+ gtk_imhtml_set_whole_buffer_formatting_only(imhtml, TRUE);
+ else
+ gtk_imhtml_set_whole_buffer_formatting_only(imhtml, FALSE);
+ } else {
+ imhtml_clear_formatting(imhtml);
+ gtk_imhtml_set_format_functions(imhtml, 0);
+ }
+}
+
+
diff --git a/pidgin/gtkimhtml.h b/pidgin/gtkimhtml.h
index f559b16bb3..e665557b71 100644
--- a/pidgin/gtkimhtml.h
+++ b/pidgin/gtkimhtml.h
@@ -27,6 +27,9 @@
#include <gtk/gtktextview.h>
#include <gtk/gtktooltips.h>
#include <gtk/gtkimage.h>
+#include "gtksourceundomanager.h"
+
+#include "connection.h"
#ifdef __cplusplus
extern "C" {
@@ -43,6 +46,7 @@ extern "C" {
#define GTK_IS_IMHTML(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_IMHTML))
#define GTK_IS_IMHTML_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_IMHTML))
#define GTK_IMHTML_SCALABLE(obj) ((GtkIMHtmlScalable *)obj)
+#define GTK_IMHTML_ANIMATION(obj) ((GtkIMHtmlAnimation *)obj)
typedef struct _GtkIMHtml GtkIMHtml;
typedef struct _GtkIMHtmlClass GtkIMHtmlClass;
@@ -51,6 +55,7 @@ typedef struct _GtkSmileyTree GtkSmileyTree;
typedef struct _GtkIMHtmlSmiley GtkIMHtmlSmiley;
typedef struct _GtkIMHtmlScalable GtkIMHtmlScalable;
typedef struct _GtkIMHtmlImage GtkIMHtmlImage;
+typedef struct _GtkIMHtmlAnimation GtkIMHtmlAnimation;
typedef struct _GtkIMHtmlHr GtkIMHtmlHr;
typedef struct _GtkIMHtmlFuncs GtkIMHtmlFuncs;
@@ -126,6 +131,7 @@ struct _GtkIMHtml {
GSList *im_images;
GtkIMHtmlFuncs *funcs;
+ GtkSourceUndoManager *undo_manager;
};
struct _GtkIMHtmlClass {
@@ -137,6 +143,8 @@ struct _GtkIMHtmlClass {
void (*clear_format)(GtkIMHtml *);
void (*update_format)(GtkIMHtml *);
gboolean (*message_send)(GtkIMHtml *);
+ void (*undo)(GtkIMHtml *);
+ void (*redo)(GtkIMHtml *);
};
struct _GtkIMHtmlFontDetail {
@@ -175,8 +183,8 @@ struct _GtkIMHtmlScalable {
struct _GtkIMHtmlImage {
GtkIMHtmlScalable scalable;
- GtkImage *image;
- GdkPixbuf *pixbuf;
+ GtkImage *image; /**< Contains the scaled version of this pixbuf. */
+ GdkPixbuf *pixbuf; /**< The original pixbuf, before any scaling. */
GtkTextMark *mark;
gchar *filename;
int width;
@@ -185,6 +193,13 @@ struct _GtkIMHtmlImage {
GtkWidget *filesel;
};
+struct _GtkIMHtmlAnimation {
+ GtkIMHtmlImage imhtmlimage;
+ GdkPixbufAnimation *anim; /**< The original animation, before any scaling. */
+ GdkPixbufAnimationIter *iter;
+ guint timer;
+};
+
struct _GtkIMHtmlHr {
GtkIMHtmlScalable scalable;
GtkWidget *sep;
@@ -405,7 +420,7 @@ void gtk_imhtml_page_down(GtkIMHtml *imhtml);
GtkIMHtmlScalable *gtk_imhtml_scalable_new(void);
/**
- * Creates and returns an new GTK+ IM/HTML scalable object with an image.
+ * Creates and returns a new GTK+ IM/HTML scalable object with an image.
*
* @param img A GdkPixbuf of the image to add.
* @param filename The filename to associate with the image.
@@ -416,19 +431,47 @@ GtkIMHtmlScalable *gtk_imhtml_scalable_new(void);
GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id);
/**
+ * Creates and returns a new GTK+ IM/HTML scalable object with an
+ * animated image.
+ *
+ * @param img A GdkPixbufAnimation of the image to add.
+ * @param filename The filename to associate with the image.
+ * @param id The id to associate with the image.
+ *
+ * @return A new IM/HTML Scalable object with an image.
+ */
+/*
+ * TODO: All this animation code could be combined much better with
+ * the image code. It couldn't be done when it was written
+ * because it requires breaking backward compatibility. It
+ * would be good to do it for 3.0.0.
+ */
+GtkIMHtmlScalable *gtk_imhtml_animation_new(GdkPixbufAnimation *img, const gchar *filename, int id);
+
+/**
* Destroys and frees a GTK+ IM/HTML scalable image.
*
* @param scale The GTK+ IM/HTML scalable.
*/
+/* TODO: Is there any reason this isn't private? */
void gtk_imhtml_image_free(GtkIMHtmlScalable *scale);
/**
+ * Destroys and frees a GTK+ IM/HTML scalable animation.
+ *
+ * @param scale The GTK+ IM/HTML scalable.
+ */
+/* TODO: Is there any reason this isn't private? */
+void gtk_imhtml_animation_free(GtkIMHtmlScalable *scale);
+
+/**
* Rescales a GTK+ IM/HTML scalable image to a given size.
*
* @param scale The GTK+ IM/HTML scalable.
* @param width The new width.
* @param height The new height.
*/
+/* TODO: Is there any reason this isn't private? */
void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height);
/**
@@ -438,6 +481,7 @@ void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height);
* @param imhtml The GTK+ IM/HTML.
* @param iter The GtkTextIter at which to add the scalable.
*/
+/* TODO: Is there any reason this isn't private? */
void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter);
/**
@@ -786,6 +830,14 @@ char **gtk_imhtml_get_markup_lines(GtkIMHtml *imhtml);
*/
char *gtk_imhtml_get_text(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *stop);
+/**
+ * Setup formatting for an imhtml depending on the flags specified.
+ *
+ * @param imhtml The GTK+ IM/HTML.
+ * @param flags The connection flag which describes the allowed types of formatting.
+ */
+void gtk_imhtml_setup_entry(GtkIMHtml *imhtml, PurpleConnectionFlags flags);
+
/*@}*/
#ifdef __cplusplus
diff --git a/pidgin/gtkimhtmltoolbar.c b/pidgin/gtkimhtmltoolbar.c
index fbee83b650..ac07c47044 100644
--- a/pidgin/gtkimhtmltoolbar.c
+++ b/pidgin/gtkimhtmltoolbar.c
@@ -792,7 +792,8 @@ static void toggle_button_set_active_block(GtkToggleButton *button,
g_object_unref(object);
}
-static void update_buttons(GtkIMHtmlToolbar *toolbar) {
+static void update_buttons(GtkIMHtmlToolbar *toolbar)
+{
gboolean bold, italic, underline;
char *tmp;
char *tmp2;
@@ -852,6 +853,66 @@ static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *location,
update_buttons(toolbar);
}
+
+/* This comes from gtkmenutoolbutton.c from gtk+
+ * Copyright (C) 2003 Ricardo Fernandez Pascual
+ * Copyright (C) 2004 Paolo Borelli
+ */
+static void
+menu_position_func (GtkMenu *menu,
+ int *x,
+ int *y,
+ gboolean *push_in,
+ gpointer data)
+{
+ GtkRequisition menu_req;
+ GtkTextDirection direction;
+ GdkRectangle monitor;
+ gint monitor_num;
+ GdkScreen *screen;
+ GtkWidget *widget = GTK_WIDGET(data);
+
+ gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
+
+ direction = gtk_widget_get_direction (widget);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (menu));
+ monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
+ if (monitor_num < 0)
+ monitor_num = 0;
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ gdk_window_get_origin (widget->window, x, y);
+ *x += widget->allocation.x;
+ *y += widget->allocation.y;
+
+ if (direction == GTK_TEXT_DIR_LTR)
+ *x += MAX (widget->allocation.width - menu_req.width, 0);
+ else if (menu_req.width > widget->allocation.width)
+ *x -= menu_req.width - widget->allocation.width;
+
+ if ((*y + widget->allocation.height + menu_req.height) <= monitor.y + monitor.height)
+ *y += widget->allocation.height;
+ else if ((*y - menu_req.height) >= monitor.y)
+ *y -= menu_req.height;
+ else if (monitor.y + monitor.height - (*y + widget->allocation.height) > *y)
+ *y += widget->allocation.height;
+ else
+ *y -= menu_req.height;
+ *push_in = FALSE;
+}
+
+static void pidgin_menu_clicked(GtkWidget *button, GtkMenu *menu)
+{
+ gtk_widget_show_all(GTK_WIDGET(menu));
+ gtk_menu_popup(menu, NULL, NULL, menu_position_func, button, 0, gtk_get_current_event_time());
+}
+
+static void pidgin_menu_deactivate(GtkWidget *menu, GtkToggleButton *button)
+{
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
+}
+
enum {
LAST_SIGNAL
};
@@ -899,182 +960,221 @@ static void gtk_imhtmltoolbar_class_init (GtkIMHtmlToolbarClass *class)
gobject_class->finalize = gtk_imhtmltoolbar_finalize;
}
-static void gtk_imhtmltoolbar_init (GtkIMHtmlToolbar *toolbar)
+static void gtk_imhtmltoolbar_create_old_buttons(GtkIMHtmlToolbar *toolbar)
{
- GtkWidget *hbox = GTK_WIDGET(toolbar);
GtkWidget *button;
- GtkWidget *sep;
- GtkSizeGroup *sg;
-
- toolbar->imhtml = NULL;
- toolbar->font_dialog = NULL;
- toolbar->fgcolor_dialog = NULL;
- toolbar->bgcolor_dialog = NULL;
- toolbar->link_dialog = NULL;
- toolbar->smiley_dialog = NULL;
- toolbar->image_dialog = NULL;
-
- toolbar->tooltips = gtk_tooltips_new();
-
- gtk_box_set_spacing(GTK_BOX(toolbar), 3);
- sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
-
/* Bold */
button = pidgin_pixbuf_toolbar_button_from_stock(GTK_STOCK_BOLD);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button, _("Bold"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(do_bold), toolbar);
-
toolbar->bold = button;
+
/* Italic */
button = pidgin_pixbuf_toolbar_button_from_stock(GTK_STOCK_ITALIC);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button, _("Italic"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(do_italic), toolbar);
-
toolbar->italic = button;
/* Underline */
button = pidgin_pixbuf_toolbar_button_from_stock(GTK_STOCK_UNDERLINE);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button, _("Underline"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(do_underline), toolbar);
-
toolbar->underline = button;
- /* Sep */
- sep = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
-
/* Increase font size */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_TEXT_LARGER);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button,
- _("Larger font size"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(do_big), toolbar);
-
toolbar->larger_size = button;
/* Decrease font size */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_TEXT_SMALLER);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button,
- _("Smaller font size"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(do_small), toolbar);
-
toolbar->smaller_size = button;
- /* Sep */
- sep = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
-
/* Font Face */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_FONT_FACE);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button,
- _("Font face"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(toggle_font), toolbar);
-
toolbar->font = button;
/* Foreground Color */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_FGCOLOR);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button,
- _("Foreground font color"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(toggle_fg_color), toolbar);
-
toolbar->fgcolor = button;
/* Background Color */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_BGCOLOR);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button,
- _("Background color"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(toggle_bg_color), toolbar);
-
toolbar->bgcolor = button;
- /* Sep */
- sep = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
-
- /* Reset Formatting */
- button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_CLEAR);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button,
- _("Reset formatting"), NULL);
-
- g_signal_connect(G_OBJECT(button), "clicked",
- G_CALLBACK(clear_formatting_cb), toolbar);
-
- toolbar->clear = button;
-
- /* Sep */
- sep = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
-
- /* Insert Link */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT_LINK);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button, _("Insert link"), NULL);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(insert_link_cb), toolbar);
-
toolbar->link = button;
/* Insert IM Image */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button, _("Insert image"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(insert_image_cb), toolbar);
-
toolbar->image = button;
/* Insert Smiley */
button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY);
- gtk_size_group_add_widget(sg, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_tooltips_set_tip(toolbar->tooltips, button, _("Insert smiley"), NULL);
-
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(insert_smiley_cb), toolbar);
-
toolbar->smiley = button;
+}
+
+static void
+button_sensitiveness_changed(GtkWidget *button, gpointer dontcare, GtkWidget *item)
+{
+ gtk_widget_set_sensitive(item, GTK_WIDGET_IS_SENSITIVE(button));
+}
+
+static void
+update_menuitem(GtkToggleButton *button, GtkCheckMenuItem *item)
+{
+ g_signal_handlers_block_by_func(G_OBJECT(item), G_CALLBACK(gtk_button_clicked), button);
+ gtk_check_menu_item_set_active(item, gtk_toggle_button_get_active(button));
+ g_signal_handlers_unblock_by_func(G_OBJECT(item), G_CALLBACK(gtk_button_clicked), button);
+}
+
+static void gtk_imhtmltoolbar_init (GtkIMHtmlToolbar *toolbar)
+{
+ GtkWidget *hbox = GTK_WIDGET(toolbar);
+ GtkWidget *bbox;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *insert_button;
+ GtkWidget *font_button;
+ GtkWidget *font_menu;
+ GtkWidget *insert_menu;
+ GtkWidget *button;
+ GtkWidget *sep;
+ int i;
+ struct {
+ const char *label;
+ GtkWidget **button;
+ } buttons[] = {
+ {_("_Bold"), &toolbar->bold},
+ {_("_Italic"), &toolbar->italic},
+ {_("_Underline"), &toolbar->underline},
+ {_("_Larger"), &toolbar->larger_size},
+#if 0
+ {_("_Normal"), &toolbar->normal_size},
+#endif
+ {_("_Smaller"), &toolbar->smaller_size},
+ {_("_Font face"), &toolbar->font},
+ {_("_Foreground color"), &toolbar->fgcolor},
+ {_("_Background color"), &toolbar->bgcolor},
+ {NULL, NULL}
+ };
+
+
+ toolbar->imhtml = NULL;
+ toolbar->font_dialog = NULL;
+ toolbar->fgcolor_dialog = NULL;
+ toolbar->bgcolor_dialog = NULL;
+ toolbar->link_dialog = NULL;
+ toolbar->smiley_dialog = NULL;
+ toolbar->image_dialog = NULL;
+
+ toolbar->tooltips = gtk_tooltips_new();
+
+ gtk_box_set_spacing(GTK_BOX(toolbar), 3);
+ gtk_imhtmltoolbar_create_old_buttons(toolbar);
+
+ /* Fonts */
+ font_button = gtk_toggle_button_new();
+ gtk_button_set_relief(GTK_BUTTON(font_button), GTK_RELIEF_NONE);
+ bbox = gtk_hbox_new(FALSE, 3);
+ gtk_container_add(GTK_CONTAINER(font_button), bbox);
+ image = gtk_image_new_from_stock(GTK_STOCK_BOLD, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+ gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0);
+ label = gtk_label_new_with_mnemonic(_("_Font"));
+ gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), font_button, FALSE, FALSE, 0);
+ gtk_widget_show_all(font_button);
+
+ font_menu = gtk_menu_new();
+
+
+ for (i = 0; buttons[i].label; i++) {
+ GtkWidget *old = *buttons[i].button;
+ GtkWidget *menuitem = gtk_check_menu_item_new_with_mnemonic(buttons[i].label);
+ g_signal_connect_swapped(G_OBJECT(menuitem), "activate",
+ G_CALLBACK(gtk_button_clicked), old);
+ g_signal_connect_after(G_OBJECT(old), "toggled",
+ G_CALLBACK(update_menuitem), menuitem);
+ gtk_menu_shell_append(GTK_MENU_SHELL(font_menu), menuitem);
+ g_signal_connect(G_OBJECT(old), "notify::sensitive",
+ G_CALLBACK(button_sensitiveness_changed), menuitem);
+ }
+
+ g_signal_connect(G_OBJECT(font_button), "clicked", G_CALLBACK(pidgin_menu_clicked), font_menu);
+ g_signal_connect(G_OBJECT(font_menu), "deactivate", G_CALLBACK(pidgin_menu_deactivate), font_button);
+
+ /* Sep */
+ sep = gtk_vseparator_new();
+ gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
+ gtk_widget_show_all(sep);
+
+ /* Reset Formatting */
+ button = gtk_toggle_button_new();
+ gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+ bbox = gtk_hbox_new(FALSE, 3);
+ gtk_container_add(GTK_CONTAINER(button), bbox);
+ image = gtk_image_new_from_stock(PIDGIN_STOCK_CLEAR, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+ gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0);
+ label = gtk_label_new_with_mnemonic(_("_Reset font"));
+ gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show_all(button);
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(clear_formatting_cb), toolbar);
+ toolbar->clear = button;
+
+ /* Sep */
+ sep = gtk_vseparator_new();
+ gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0);
+ gtk_widget_show_all(sep);
+
+ /* Insert */
+ insert_button = gtk_toggle_button_new();
+ gtk_button_set_relief(GTK_BUTTON(insert_button), GTK_RELIEF_NONE);
+ bbox = gtk_hbox_new(FALSE, 3);
+ gtk_container_add(GTK_CONTAINER(insert_button), bbox);
+ image = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+ gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0);
+ label = gtk_label_new_with_mnemonic(_("_Insert"));
+ gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), insert_button, FALSE, FALSE, 0);
+ gtk_widget_show_all(insert_button);
+
+ insert_menu = gtk_menu_new();
+
+ button = gtk_menu_item_new_with_mnemonic(_("_Smiley"));
+ g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gtk_button_clicked), toolbar->smiley);
+ gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), button);
+
+ button = gtk_menu_item_new_with_mnemonic(_("_Image"));
+ g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gtk_button_clicked), toolbar->image);
+ gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), button);
+
+ button = gtk_menu_item_new_with_mnemonic(_("_Link"));
+ g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gtk_button_clicked), toolbar->link);
+ gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), button);
+
+ g_signal_connect(G_OBJECT(insert_button), "clicked", G_CALLBACK(pidgin_menu_clicked), insert_menu);
+ g_signal_connect(G_OBJECT(insert_menu), "deactivate", G_CALLBACK(pidgin_menu_deactivate), insert_button);
toolbar->sml = NULL;
- gtk_widget_show_all(hbox);
}
GtkWidget *gtk_imhtmltoolbar_new()
diff --git a/pidgin/gtklog.c b/pidgin/gtklog.c
index a7d489c0a8..d54bdcfa50 100644
--- a/pidgin/gtklog.c
+++ b/pidgin/gtklog.c
@@ -757,7 +757,7 @@ void pidgin_log_show_contact(PurpleContact *contact) {
void pidgin_syslog_show()
{
- GList *accounts = NULL;
+ const GList *accounts;
GList *logs = NULL;
if (syslog_viewer != NULL) {
diff --git a/pidgin/gtkmain.c b/pidgin/gtkmain.c
index abc6fcdf37..08f4a368d6 100644
--- a/pidgin/gtkmain.c
+++ b/pidgin/gtkmain.c
@@ -125,7 +125,7 @@ dologin_named(const char *name)
}
g_strfreev(names);
} else { /* no name given, use the first account */
- GList *accounts;
+ const GList *accounts;
accounts = purple_accounts_get_all();
if (accounts != NULL)
@@ -435,7 +435,7 @@ int main(int argc, char *argv[])
char *opt_login_arg = NULL;
char *opt_session_arg = NULL;
char *search_path;
- GList *accounts;
+ const GList *accounts;
#ifdef HAVE_SIGNAL_H
int sig_indx; /* for setting up signal catching */
sigset_t sigset;
@@ -450,6 +450,7 @@ int main(int argc, char *argv[])
gboolean gui_check;
gboolean debug_enabled;
gboolean migration_failed = FALSE;
+ GList *active_accounts;
struct option long_options[] = {
{"config", required_argument, NULL, 'c'},
@@ -727,6 +728,15 @@ int main(int argc, char *argv[])
abort();
}
+ if (!purple_core_ensure_single_instance()) {
+ purple_core_quit();
+#ifdef HAVE_SIGNAL_H
+ g_free(segfault_message);
+#endif
+ return 0;
+ }
+
+
/* TODO: Move blist loading into purple_blist_init() */
purple_set_blist(purple_blist_new());
purple_blist_load();
@@ -822,13 +832,13 @@ int main(int argc, char *argv[])
purple_accounts_restore_current_statuses();
}
- if ((accounts = purple_accounts_get_all_active()) == NULL)
+ if ((active_accounts = purple_accounts_get_all_active()) == NULL)
{
pidgin_accounts_window_show();
}
else
{
- g_list_free(accounts);
+ g_list_free(active_accounts);
}
#ifdef HAVE_STARTUP_NOTIFICATION
diff --git a/pidgin/gtknotify.c b/pidgin/gtknotify.c
index 95f581b136..d489697183 100644
--- a/pidgin/gtknotify.c
+++ b/pidgin/gtknotify.c
@@ -583,10 +583,8 @@ pidgin_notify_formatted(const char *title, const char *primary,
char label_text[2048];
char *linked_text, *primary_esc, *secondary_esc;
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(window), title);
+ window = pidgin_create_window(title, PIDGIN_HIG_BORDER, NULL, TRUE);
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
- gtk_container_set_border_width(GTK_CONTAINER(window), PIDGIN_HIG_BORDER);
g_signal_connect(G_OBJECT(window), "delete_event",
G_CALLBACK(formatted_close_cb), NULL);
@@ -718,10 +716,8 @@ pidgin_notify_searchresults(PurpleConnection *gc, const char *title,
data->results = results;
/* Create the window */
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(window), (title ? title :_("Search Results")));
+ window = pidgin_create_window(title ? title :_("Search Results"), PIDGIN_HIG_BORDER, NULL, TRUE);
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
- gtk_container_set_border_width(GTK_CONTAINER(window), PIDGIN_HIG_BORDER);
g_signal_connect_swapped(G_OBJECT(window), "delete_event",
G_CALLBACK(searchresults_close_cb), data);
diff --git a/pidgin/gtkpounce.c b/pidgin/gtkpounce.c
index 47aa1176cd..42b9ad3cb2 100644
--- a/pidgin/gtkpounce.c
+++ b/pidgin/gtkpounce.c
@@ -38,6 +38,7 @@
#include "gtkblist.h"
#include "gtkdialogs.h"
+#include "gtkimhtml.h"
#include "gtkpounce.h"
#include "pidginstock.h"
#include "gtkutils.h"
@@ -241,7 +242,8 @@ static void
save_pounce_cb(GtkWidget *w, PidginPounceDialog *dialog)
{
const char *name;
- const char *message, *command, *sound, *reason;
+ const char *command, *sound, *reason;
+ char *message;
PurplePounceEvent events = PURPLE_POUNCE_NONE;
PurplePounceOption options = PURPLE_POUNCE_OPTION_NONE;
@@ -290,13 +292,16 @@ save_pounce_cb(GtkWidget *w, PidginPounceDialog *dialog)
events |= PURPLE_POUNCE_MESSAGE_RECEIVED;
/* Data fields */
- message = gtk_entry_get_text(GTK_ENTRY(dialog->send_msg_entry));
+ message = gtk_imhtml_get_markup(GTK_IMHTML(dialog->send_msg_entry));
command = gtk_entry_get_text(GTK_ENTRY(dialog->exec_cmd_entry));
sound = gtk_entry_get_text(GTK_ENTRY(dialog->play_sound_entry));
reason = gtk_entry_get_text(GTK_ENTRY(dialog->popup_entry));
if (*reason == '\0') reason = NULL;
- if (*message == '\0') message = NULL;
+ if (*message == '\0') {
+ g_free(message);
+ message = NULL;
+ }
if (*command == '\0') command = NULL;
if (*sound == '\0') sound = NULL;
@@ -349,6 +354,7 @@ save_pounce_cb(GtkWidget *w, PidginPounceDialog *dialog)
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->save_pounce)));
update_pounces();
+ g_free(message);
delete_win_cb(NULL, NULL, dialog);
}
@@ -446,6 +452,14 @@ static const GtkTargetEntry dnd_targets[] =
{"application/x-im-contact", 0, 1}
};
+static void
+reset_send_msg_entry(PidginPounceDialog *dialog, GtkWidget *dontcare)
+{
+ PurpleAccount *account = pidgin_account_option_menu_get_selected(dialog->account_menu);
+ gtk_imhtml_setup_entry(GTK_IMHTML(dialog->send_msg_entry),
+ (account && account->gc) ? account->gc->flags : PURPLE_CONNECTION_HTML);
+}
+
void
pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
PurplePounce *cur_pounce)
@@ -462,6 +476,7 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
GtkSizeGroup *sg;
GPtrArray *sound_widgets;
GPtrArray *exec_widgets;
+ GtkWidget *send_msg_imhtml;
g_return_if_fail((cur_pounce != NULL) ||
(account != NULL) ||
@@ -481,7 +496,7 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
}
else
{
- GList *connections = purple_connections_get_all();
+ const GList *connections = purple_connections_get_all();
PurpleConnection *gc;
if (connections != NULL)
@@ -498,15 +513,9 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
/* Create the window. */
- dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ dialog->window = window = pidgin_create_window((cur_pounce == NULL ? _("New Buddy Pounce") : _("Edit Buddy Pounce")),
+ PIDGIN_HIG_BORDER, "buddy_pounce", FALSE) ;
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
- gtk_window_set_role(GTK_WINDOW(window), "buddy_pounce");
- gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
- gtk_window_set_title(GTK_WINDOW(window),
- (cur_pounce == NULL
- ? _("New Buddy Pounce") : _("Edit Buddy Pounce")));
-
- gtk_container_set_border_width(GTK_CONTAINER(window), PIDGIN_HIG_BORDER);
g_signal_connect(G_OBJECT(window), "delete_event",
G_CALLBACK(delete_win_cb), dialog);
@@ -653,7 +662,8 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
dialog->play_sound
= gtk_check_button_new_with_mnemonic(_("P_lay a sound"));
- dialog->send_msg_entry = gtk_entry_new();
+ send_msg_imhtml = pidgin_create_imhtml(TRUE, &dialog->send_msg_entry, NULL, NULL);
+ reset_send_msg_entry(dialog, NULL);
dialog->exec_cmd_entry = gtk_entry_new();
dialog->popup_entry = gtk_entry_new();
dialog->exec_cmd_browse = gtk_button_new_with_mnemonic(_("Brows_e..."));
@@ -661,7 +671,7 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
dialog->play_sound_browse = gtk_button_new_with_mnemonic(_("Br_owse..."));
dialog->play_sound_test = gtk_button_new_with_mnemonic(_("Pre_view"));
- gtk_widget_set_sensitive(dialog->send_msg_entry, FALSE);
+ gtk_widget_set_sensitive(send_msg_imhtml, FALSE);
gtk_widget_set_sensitive(dialog->exec_cmd_entry, FALSE);
gtk_widget_set_sensitive(dialog->popup_entry, FALSE);
gtk_widget_set_sensitive(dialog->exec_cmd_browse, FALSE);
@@ -673,8 +683,6 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
gtk_size_group_add_widget(sg, dialog->open_win);
gtk_size_group_add_widget(sg, dialog->popup);
gtk_size_group_add_widget(sg, dialog->popup_entry);
- gtk_size_group_add_widget(sg, dialog->send_msg);
- gtk_size_group_add_widget(sg, dialog->send_msg_entry);
gtk_size_group_add_widget(sg, dialog->exec_cmd);
gtk_size_group_add_widget(sg, dialog->exec_cmd_entry);
gtk_size_group_add_widget(sg, dialog->exec_cmd_browse);
@@ -689,23 +697,23 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->popup_entry, 1, 4, 1, 2,
GTK_FILL, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->send_msg, 0, 1, 2, 3,
+ gtk_table_attach(GTK_TABLE(table), dialog->send_msg, 0, 4, 2, 3,
GTK_FILL, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->send_msg_entry, 1, 4, 2, 3,
+ gtk_table_attach(GTK_TABLE(table), send_msg_imhtml, 0, 4, 3, 4,
GTK_FILL, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd, 0, 1, 3, 4,
+ gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd, 0, 1, 4, 5,
GTK_FILL, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_entry, 1, 2, 3, 4,
+ gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_entry, 1, 2, 4, 5,
GTK_FILL, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_browse, 2, 3, 3, 4,
+ gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_browse, 2, 3, 4, 5,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->play_sound, 0, 1, 4, 5,
+ gtk_table_attach(GTK_TABLE(table), dialog->play_sound, 0, 1, 5, 6,
GTK_FILL, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->play_sound_entry, 1, 2, 4, 5,
+ gtk_table_attach(GTK_TABLE(table), dialog->play_sound_entry, 1, 2, 5, 6,
GTK_FILL, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->play_sound_browse, 2, 3, 4, 5,
+ gtk_table_attach(GTK_TABLE(table), dialog->play_sound_browse,2, 3, 5, 6,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
- gtk_table_attach(GTK_TABLE(table), dialog->play_sound_test, 3, 4, 4, 5,
+ gtk_table_attach(GTK_TABLE(table), dialog->play_sound_test, 3, 4, 5, 6,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
gtk_table_set_row_spacings(GTK_TABLE(table), PIDGIN_HIG_BOX_SPACE / 2);
@@ -714,7 +722,7 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
gtk_widget_show(dialog->popup);
gtk_widget_show(dialog->popup_entry);
gtk_widget_show(dialog->send_msg);
- gtk_widget_show(dialog->send_msg_entry);
+ gtk_widget_show(send_msg_imhtml);
gtk_widget_show(dialog->exec_cmd);
gtk_widget_show(dialog->exec_cmd_entry);
gtk_widget_show(dialog->exec_cmd_browse);
@@ -729,7 +737,7 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
g_signal_connect(G_OBJECT(dialog->send_msg), "clicked",
G_CALLBACK(pidgin_toggle_sensitive),
- dialog->send_msg_entry);
+ send_msg_imhtml);
g_signal_connect(G_OBJECT(dialog->popup), "clicked",
G_CALLBACK(pidgin_toggle_sensitive),
@@ -765,7 +773,12 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
g_object_set_data_full(G_OBJECT(dialog->window), "sound-widgets",
sound_widgets, (GDestroyNotify)g_ptr_array_free);
- g_signal_connect(G_OBJECT(dialog->send_msg_entry), "activate",
+ g_signal_connect_swapped(G_OBJECT(dialog->send_msg_entry), "format_function_clear",
+ G_CALLBACK(reset_send_msg_entry), dialog);
+ g_signal_connect_swapped(G_OBJECT(dialog->account_menu), "changed",
+ G_CALLBACK(reset_send_msg_entry), dialog);
+
+ g_signal_connect(G_OBJECT(dialog->send_msg_entry), "message_send",
G_CALLBACK(save_pounce_cb), dialog);
g_signal_connect(G_OBJECT(dialog->popup_entry), "activate",
G_CALLBACK(save_pounce_cb), dialog);
@@ -892,7 +905,7 @@ pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
"send-message",
"message")) != NULL)
{
- gtk_entry_set_text(GTK_ENTRY(dialog->send_msg_entry), value);
+ gtk_imhtml_append_text(GTK_IMHTML(dialog->send_msg_entry), value, 0);
}
if ((value = purple_pounce_action_get_attribute(cur_pounce,
@@ -1323,11 +1336,8 @@ pidgin_pounces_manager_show(void)
width = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/pounces/dialog/width");
height = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/pounces/dialog/height");
- dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ dialog->window = win = pidgin_create_window(_("Buddy Pounces"), PIDGIN_HIG_BORDER, "pounces", TRUE);
gtk_window_set_default_size(GTK_WINDOW(win), width, height);
- gtk_window_set_role(GTK_WINDOW(win), "pounces");
- gtk_window_set_title(GTK_WINDOW(win), _("Buddy Pounces"));
- gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER);
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(pounces_manager_destroy_cb), dialog);
diff --git a/pidgin/gtkprefs.c b/pidgin/gtkprefs.c
index 96fc0377c7..d9881867c1 100644
--- a/pidgin/gtkprefs.c
+++ b/pidgin/gtkprefs.c
@@ -949,7 +949,7 @@ conv_page()
label = gtk_label_new_with_mnemonic(_("Conversation _font:"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font");
- font_button = gtk_font_button_new_with_font(purple_prefs_get_string(font_name ? font_name : NULL));
+ font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL);
gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE);
gtk_box_pack_start(GTK_BOX(hbox), font_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
@@ -977,19 +977,9 @@ conv_page()
gtk_imhtml_append_text(GTK_IMHTML(imhtml), _("This is how your outgoing message text will appear when you use protocols that support formatting. :)"), 0);
- gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
- if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_bold"))
- gtk_imhtml_toggle_bold(GTK_IMHTML(imhtml));
- if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_italic"))
- gtk_imhtml_toggle_italic(GTK_IMHTML(imhtml));
- if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/send_underline"))
- gtk_imhtml_toggle_underline(GTK_IMHTML(imhtml));
-
- gtk_imhtml_font_set_size(GTK_IMHTML(imhtml), purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/font_size"));
- gtk_imhtml_toggle_forecolor(GTK_IMHTML(imhtml), purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/fgcolor"));
- gtk_imhtml_toggle_background(GTK_IMHTML(imhtml), purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/bgcolor"));
- gtk_imhtml_toggle_fontface(GTK_IMHTML(imhtml), purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/font_face"));
+ gtk_imhtml_setup_entry(GTK_IMHTML(imhtml), PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_FORMATTING_WBFO);
g_signal_connect_after(G_OBJECT(imhtml), "format_function_toggle",
G_CALLBACK(formatting_toggle_cb), toolbar);
@@ -1987,11 +1977,7 @@ void pidgin_prefs_show(void)
/* Back to instant-apply! I win! BU-HAHAHA! */
/* Create the window */
- prefs = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(prefs), "preferences");
- gtk_window_set_title(GTK_WINDOW(prefs), _("Preferences"));
- gtk_window_set_resizable (GTK_WINDOW(prefs), FALSE);
- gtk_container_set_border_width(GTK_CONTAINER(prefs), PIDGIN_HIG_BORDER);
+ prefs = pidgin_create_window(_("Preferences"), PIDGIN_HIG_BORDER, "preferences", FALSE);
g_signal_connect(G_OBJECT(prefs), "destroy",
G_CALLBACK(delete_prefs), NULL);
diff --git a/pidgin/gtkprivacy.c b/pidgin/gtkprivacy.c
index 67d4500bcb..eed0ccb40b 100644
--- a/pidgin/gtkprivacy.c
+++ b/pidgin/gtkprivacy.c
@@ -366,11 +366,7 @@ privacy_dialog_new(void)
dialog = g_new0(PidginPrivacyDialog, 1);
- dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_resizable(GTK_WINDOW(dialog->win), FALSE);
- gtk_window_set_role(GTK_WINDOW(dialog->win), "privacy");
- gtk_window_set_title(GTK_WINDOW(dialog->win), _("Privacy"));
- gtk_container_set_border_width(GTK_CONTAINER(dialog->win), PIDGIN_HIG_BORDER);
+ dialog->win = pidgin_create_window(_("Privacy"), PIDGIN_HIG_BORDER, "privacy", FALSE);
g_signal_connect(G_OBJECT(dialog->win), "delete_event",
G_CALLBACK(destroy_cb), dialog);
diff --git a/pidgin/gtkrequest.c b/pidgin/gtkrequest.c
index 017061ec02..634302d0f7 100644
--- a/pidgin/gtkrequest.c
+++ b/pidgin/gtkrequest.c
@@ -1070,16 +1070,12 @@ pidgin_request_fields(const char *title, const char *primary,
data->cbs[0] = ok_cb;
data->cbs[1] = cancel_cb;
- data->dialog = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- if (title != NULL)
- gtk_window_set_title(GTK_WINDOW(win), title);
+
#ifdef _WIN32
- gtk_window_set_title(GTK_WINDOW(win), PIDGIN_ALERT_TITLE);
-#endif
-
- gtk_window_set_role(GTK_WINDOW(win), "multifield");
- gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER);
+ data->dialog = win = pidgin_create_window(PIDGIN_ALERT_TITLE, PIDGIN_HIG_BORDER, "multifield", TRUE) ;
+#else /* !_WIN32 */
+ data->dialog = win = pidgin_create_window(title, PIDGIN_HIG_BORDER, "multifield", TRUE) ;
+#endif /* _WIN32 */
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(destroy_multifield_cb), data);
diff --git a/pidgin/gtkroomlist.c b/pidgin/gtkroomlist.c
index a22a162a19..15023064eb 100644
--- a/pidgin/gtkroomlist.c
+++ b/pidgin/gtkroomlist.c
@@ -343,7 +343,7 @@ static gboolean account_filter_func(PurpleAccount *account)
gboolean
pidgin_roomlist_is_showable()
{
- GList *c;
+ const GList *c;
PurpleConnection *gc;
for (c = purple_connections_get_all(); c != NULL; c = c->next) {
@@ -371,11 +371,7 @@ pidgin_roomlist_dialog_new_with_account(PurpleAccount *account)
dialog->account = account;
/* Create the window. */
- dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(window), "room list");
- gtk_window_set_title(GTK_WINDOW(window), _("Room List"));
-
- gtk_container_set_border_width(GTK_CONTAINER(window), PIDGIN_HIG_BORDER);
+ dialog->window = window = pidgin_create_window(_("Room List"), PIDGIN_HIG_BORDER, "room list", TRUE);
g_signal_connect(G_OBJECT(window), "delete_event",
G_CALLBACK(delete_win_cb), dialog);
diff --git a/pidgin/gtksavedstatuses.c b/pidgin/gtksavedstatuses.c
index 52eef02a4d..69c221f81a 100644
--- a/pidgin/gtksavedstatuses.c
+++ b/pidgin/gtksavedstatuses.c
@@ -551,11 +551,8 @@ pidgin_status_window_show(void)
width = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/status/dialog/width");
height = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/status/dialog/height");
- dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ dialog->window = win = pidgin_create_window(_("Saved Statuses"), PIDGIN_HIG_BORDER, "statuses", TRUE);
gtk_window_set_default_size(GTK_WINDOW(win), width, height);
- gtk_window_set_role(GTK_WINDOW(win), "statuses");
- gtk_window_set_title(GTK_WINDOW(win), _("Saved Statuses"));
- gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER);
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(status_window_destroy_cb), dialog);
@@ -1015,7 +1012,7 @@ status_editor_add_account(StatusEditor *dialog, PurpleAccount *account,
static void
status_editor_populate_list(StatusEditor *dialog, PurpleSavedStatus *saved_status)
{
- GList *iter;
+ const GList *iter;
PurpleSavedStatusSub *substatus;
gtk_list_store_clear(dialog->model);
@@ -1085,10 +1082,7 @@ pidgin_status_editor_show(gboolean edit, PurpleSavedStatus *saved_status)
if (edit)
dialog->original_title = g_strdup(purple_savedstatus_get_title(saved_status));
- dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(win), "status");
- gtk_window_set_title(GTK_WINDOW(win), _("Status"));
- gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER);
+ dialog->window = win = pidgin_create_window (_("Status"), PIDGIN_HIG_BORDER, "status", FALSE) ;
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(status_editor_destroy_cb), dialog);
@@ -1422,13 +1416,9 @@ edit_substatus(StatusEditor *status_editor, PurpleAccount *account)
dialog->status_editor = status_editor;
dialog->account = account;
- dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(win), "substatus");
tmp = g_strdup_printf(_("Status for %s"), purple_account_get_username(account));
- gtk_window_set_title(GTK_WINDOW(win), tmp);
+ dialog->window = win = pidgin_create_window(tmp, PIDGIN_HIG_BORDER, "substatus", FALSE) ;
g_free(tmp);
- gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
- gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER);
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(substatus_editor_destroy_cb), dialog);
diff --git a/pidgin/gtksourceundomanager.c b/pidgin/gtksourceundomanager.c
new file mode 100644
index 0000000000..14528f3595
--- /dev/null
+++ b/pidgin/gtksourceundomanager.c
@@ -0,0 +1,1123 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gtksourceundomanager.c
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gtksourceundomanager.h"
+#include "gtksourceview-marshal.h"
+
+
+#define DEFAULT_MAX_UNDO_LEVELS 25
+
+
+typedef struct _GtkSourceUndoAction GtkSourceUndoAction;
+typedef struct _GtkSourceUndoInsertAction GtkSourceUndoInsertAction;
+typedef struct _GtkSourceUndoDeleteAction GtkSourceUndoDeleteAction;
+
+typedef enum {
+ GTK_SOURCE_UNDO_ACTION_INSERT,
+ GTK_SOURCE_UNDO_ACTION_DELETE
+} GtkSourceUndoActionType;
+
+/*
+ * We use offsets instead of GtkTextIters because the last ones
+ * require to much memory in this context without giving us any advantage.
+ */
+
+struct _GtkSourceUndoInsertAction
+{
+ gint pos;
+ gchar *text;
+ gint length;
+ gint chars;
+};
+
+struct _GtkSourceUndoDeleteAction
+{
+ gint start;
+ gint end;
+ gchar *text;
+ gboolean forward;
+};
+
+struct _GtkSourceUndoAction
+{
+ GtkSourceUndoActionType action_type;
+
+ union {
+ GtkSourceUndoInsertAction insert;
+ GtkSourceUndoDeleteAction delete;
+ } action;
+
+ gint order_in_group;
+
+ /* It is TRUE whether the action can be merged with the following action. */
+ guint mergeable : 1;
+
+ /* It is TRUE whether the action is marked as "modified".
+ * An action is marked as "modified" if it changed the
+ * state of the buffer from "not modified" to "modified". Only the first
+ * action of a group can be marked as modified.
+ * There can be a single action marked as "modified" in the actions list.
+ */
+ guint modified : 1;
+};
+
+/* INVALID is a pointer to an invalid action */
+#define INVALID ((void *) "IA")
+
+struct _GtkSourceUndoManagerPrivate
+{
+ GtkTextBuffer *document;
+
+ GList* actions;
+ gint next_redo;
+
+ gint actions_in_current_group;
+
+ gint running_not_undoable_actions;
+
+ gint num_of_groups;
+
+ gint max_undo_levels;
+
+ guint can_undo : 1;
+ guint can_redo : 1;
+
+ /* It is TRUE whether, while undoing an action of the current group (with order_in_group > 1),
+ * the state of the buffer changed from "not modified" to "modified".
+ */
+ guint modified_undoing_group : 1;
+
+ /* Pointer to the action (in the action list) marked as "modified".
+ * It is NULL when no action is marked as "modified".
+ * It is INVALID when the action marked as "modified" has been removed
+ * from the action list (freeing the list or resizing it) */
+ GtkSourceUndoAction *modified_action;
+};
+
+enum {
+ CAN_UNDO,
+ CAN_REDO,
+ LAST_SIGNAL
+};
+
+static void gtk_source_undo_manager_class_init (GtkSourceUndoManagerClass *klass);
+static void gtk_source_undo_manager_init (GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_finalize (GObject *object);
+
+static void gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer,
+ GtkTextIter *pos,
+ const gchar *text,
+ gint length,
+ GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer,
+ GtkTextIter *start,
+ GtkTextIter *end,
+ GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_begin_user_action_handler (GtkTextBuffer *buffer,
+ GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_modified_changed_handler (GtkTextBuffer *buffer,
+ GtkSourceUndoManager *um);
+
+static void gtk_source_undo_manager_free_action_list (GtkSourceUndoManager *um);
+
+static void gtk_source_undo_manager_add_action (GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action);
+static void gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager *um,
+ gint n);
+static void gtk_source_undo_manager_check_list_size (GtkSourceUndoManager *um);
+
+static gboolean gtk_source_undo_manager_merge_action (GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action);
+
+static GObjectClass *parent_class = NULL;
+static guint undo_manager_signals [LAST_SIGNAL] = { 0 };
+
+GType
+gtk_source_undo_manager_get_type (void)
+{
+ static GType undo_manager_type = 0;
+
+ if (undo_manager_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof (GtkSourceUndoManagerClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gtk_source_undo_manager_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GtkSourceUndoManager),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gtk_source_undo_manager_init,
+ NULL /* value_table */
+ };
+
+ undo_manager_type = g_type_register_static (G_TYPE_OBJECT,
+ "GtkSourceUndoManager",
+ &our_info,
+ 0);
+ }
+
+ return undo_manager_type;
+}
+
+static void
+gtk_source_undo_manager_class_init (GtkSourceUndoManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gtk_source_undo_manager_finalize;
+
+ klass->can_undo = NULL;
+ klass->can_redo = NULL;
+
+ undo_manager_signals[CAN_UNDO] =
+ g_signal_new ("can_undo",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkSourceUndoManagerClass, can_undo),
+ NULL, NULL,
+ gtksourceview_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+ undo_manager_signals[CAN_REDO] =
+ g_signal_new ("can_redo",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkSourceUndoManagerClass, can_redo),
+ NULL, NULL,
+ gtksourceview_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+}
+
+static void
+gtk_source_undo_manager_init (GtkSourceUndoManager *um)
+{
+ um->priv = g_new0 (GtkSourceUndoManagerPrivate, 1);
+
+ um->priv->actions = NULL;
+ um->priv->next_redo = 0;
+
+ um->priv->can_undo = FALSE;
+ um->priv->can_redo = FALSE;
+
+ um->priv->running_not_undoable_actions = 0;
+
+ um->priv->num_of_groups = 0;
+
+ um->priv->max_undo_levels = DEFAULT_MAX_UNDO_LEVELS;
+
+ um->priv->modified_action = NULL;
+
+ um->priv->modified_undoing_group = FALSE;
+}
+
+static void
+gtk_source_undo_manager_finalize (GObject *object)
+{
+ GtkSourceUndoManager *um;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (object));
+
+ um = GTK_SOURCE_UNDO_MANAGER (object);
+
+ g_return_if_fail (um->priv != NULL);
+
+ if (um->priv->actions != NULL)
+ {
+ gtk_source_undo_manager_free_action_list (um);
+ }
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
+ G_CALLBACK (gtk_source_undo_manager_delete_range_handler),
+ um);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
+ G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
+ um);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
+ G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler),
+ um);
+
+ g_free (um->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+GtkSourceUndoManager*
+gtk_source_undo_manager_new (GtkTextBuffer* buffer)
+{
+ GtkSourceUndoManager *um;
+
+ um = GTK_SOURCE_UNDO_MANAGER (g_object_new (GTK_SOURCE_TYPE_UNDO_MANAGER, NULL));
+
+ g_return_val_if_fail (um->priv != NULL, NULL);
+ um->priv->document = buffer;
+
+ g_signal_connect (G_OBJECT (buffer), "insert_text",
+ G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
+ um);
+
+ g_signal_connect (G_OBJECT (buffer), "delete_range",
+ G_CALLBACK (gtk_source_undo_manager_delete_range_handler),
+ um);
+
+ g_signal_connect (G_OBJECT (buffer), "begin_user_action",
+ G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler),
+ um);
+
+ g_signal_connect (G_OBJECT (buffer), "modified_changed",
+ G_CALLBACK (gtk_source_undo_manager_modified_changed_handler),
+ um);
+ return um;
+}
+
+void
+gtk_source_undo_manager_begin_not_undoable_action (GtkSourceUndoManager *um)
+{
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+
+ ++um->priv->running_not_undoable_actions;
+}
+
+static void
+gtk_source_undo_manager_end_not_undoable_action_internal (GtkSourceUndoManager *um)
+{
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+
+ g_return_if_fail (um->priv->running_not_undoable_actions > 0);
+
+ --um->priv->running_not_undoable_actions;
+}
+
+void
+gtk_source_undo_manager_end_not_undoable_action (GtkSourceUndoManager *um)
+{
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+
+ gtk_source_undo_manager_end_not_undoable_action_internal (um);
+
+ if (um->priv->running_not_undoable_actions == 0)
+ {
+ gtk_source_undo_manager_free_action_list (um);
+
+ um->priv->next_redo = -1;
+
+ if (um->priv->can_undo)
+ {
+ um->priv->can_undo = FALSE;
+ g_signal_emit (G_OBJECT (um),
+ undo_manager_signals [CAN_UNDO],
+ 0,
+ FALSE);
+ }
+
+ if (um->priv->can_redo)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit (G_OBJECT (um),
+ undo_manager_signals [CAN_REDO],
+ 0,
+ FALSE);
+ }
+ }
+}
+
+gboolean
+gtk_source_undo_manager_can_undo (const GtkSourceUndoManager *um)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE);
+ g_return_val_if_fail (um->priv != NULL, FALSE);
+
+ return um->priv->can_undo;
+}
+
+gboolean
+gtk_source_undo_manager_can_redo (const GtkSourceUndoManager *um)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE);
+ g_return_val_if_fail (um->priv != NULL, FALSE);
+
+ return um->priv->can_redo;
+}
+
+static void
+set_cursor (GtkTextBuffer *buffer, gint cursor)
+{
+ GtkTextIter iter;
+
+ /* Place the cursor at the requested position */
+ gtk_text_buffer_get_iter_at_offset (buffer, &iter, cursor);
+ gtk_text_buffer_place_cursor (buffer, &iter);
+}
+
+static void
+insert_text (GtkTextBuffer *buffer, gint pos, const gchar *text, gint len)
+{
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
+ gtk_text_buffer_insert (buffer, &iter, text, len);
+}
+
+static void
+delete_text (GtkTextBuffer *buffer, gint start, gint end)
+{
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+
+ gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+
+ if (end < 0)
+ gtk_text_buffer_get_end_iter (buffer, &end_iter);
+ else
+ gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+
+ gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+}
+
+static gchar*
+get_chars (GtkTextBuffer *buffer, gint start, gint end)
+{
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+
+ gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+
+ if (end < 0)
+ gtk_text_buffer_get_end_iter (buffer, &end_iter);
+ else
+ gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+
+ return gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, TRUE);
+}
+
+void
+gtk_source_undo_manager_undo (GtkSourceUndoManager *um)
+{
+ GtkSourceUndoAction *undo_action;
+ gboolean modified = FALSE;
+
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+ g_return_if_fail (um->priv->can_undo);
+
+ um->priv->modified_undoing_group = FALSE;
+
+ gtk_source_undo_manager_begin_not_undoable_action (um);
+
+ do
+ {
+ undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo + 1);
+ g_return_if_fail (undo_action != NULL);
+
+ /* undo_action->modified can be TRUE only if undo_action->order_in_group <= 1 */
+ g_return_if_fail ((undo_action->order_in_group <= 1) ||
+ ((undo_action->order_in_group > 1) && !undo_action->modified));
+
+ if (undo_action->order_in_group <= 1)
+ {
+ /* Set modified to TRUE only if the buffer did not change its state from
+ * "not modified" to "modified" undoing an action (with order_in_group > 1)
+ * in current group. */
+ modified = (undo_action->modified && !um->priv->modified_undoing_group);
+ }
+
+ switch (undo_action->action_type)
+ {
+ case GTK_SOURCE_UNDO_ACTION_DELETE:
+ insert_text (
+ um->priv->document,
+ undo_action->action.delete.start,
+ undo_action->action.delete.text,
+ strlen (undo_action->action.delete.text));
+
+ if (undo_action->action.delete.forward)
+ set_cursor (
+ um->priv->document,
+ undo_action->action.delete.start);
+ else
+ set_cursor (
+ um->priv->document,
+ undo_action->action.delete.end);
+
+ break;
+
+ case GTK_SOURCE_UNDO_ACTION_INSERT:
+ delete_text (
+ um->priv->document,
+ undo_action->action.insert.pos,
+ undo_action->action.insert.pos +
+ undo_action->action.insert.chars);
+
+ set_cursor (
+ um->priv->document,
+ undo_action->action.insert.pos);
+ break;
+
+ default:
+ /* Unknown action type. */
+ g_return_if_reached ();
+ }
+
+ ++um->priv->next_redo;
+
+ } while (undo_action->order_in_group > 1);
+
+ if (modified)
+ {
+ --um->priv->next_redo;
+ gtk_text_buffer_set_modified (um->priv->document, FALSE);
+ ++um->priv->next_redo;
+ }
+
+ gtk_source_undo_manager_end_not_undoable_action_internal (um);
+
+ um->priv->modified_undoing_group = FALSE;
+
+ if (!um->priv->can_redo)
+ {
+ um->priv->can_redo = TRUE;
+ g_signal_emit (G_OBJECT (um),
+ undo_manager_signals [CAN_REDO],
+ 0,
+ TRUE);
+ }
+
+ if (um->priv->next_redo >= (gint)(g_list_length (um->priv->actions) - 1))
+ {
+ um->priv->can_undo = FALSE;
+ g_signal_emit (G_OBJECT (um),
+ undo_manager_signals [CAN_UNDO],
+ 0,
+ FALSE);
+ }
+}
+
+void
+gtk_source_undo_manager_redo (GtkSourceUndoManager *um)
+{
+ GtkSourceUndoAction *undo_action;
+ gboolean modified = FALSE;
+
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+ g_return_if_fail (um->priv->can_redo);
+
+ undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo);
+ g_return_if_fail (undo_action != NULL);
+
+ gtk_source_undo_manager_begin_not_undoable_action (um);
+
+ do
+ {
+ if (undo_action->modified)
+ {
+ g_return_if_fail (undo_action->order_in_group <= 1);
+ modified = TRUE;
+ }
+
+ --um->priv->next_redo;
+
+ switch (undo_action->action_type)
+ {
+ case GTK_SOURCE_UNDO_ACTION_DELETE:
+ delete_text (
+ um->priv->document,
+ undo_action->action.delete.start,
+ undo_action->action.delete.end);
+
+ set_cursor (
+ um->priv->document,
+ undo_action->action.delete.start);
+
+ break;
+
+ case GTK_SOURCE_UNDO_ACTION_INSERT:
+ set_cursor (
+ um->priv->document,
+ undo_action->action.insert.pos);
+
+ insert_text (
+ um->priv->document,
+ undo_action->action.insert.pos,
+ undo_action->action.insert.text,
+ undo_action->action.insert.length);
+
+ break;
+
+ default:
+ /* Unknown action type */
+ ++um->priv->next_redo;
+ g_return_if_reached ();
+ }
+
+ if (um->priv->next_redo < 0)
+ undo_action = NULL;
+ else
+ undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo);
+
+ } while ((undo_action != NULL) && (undo_action->order_in_group > 1));
+
+ if (modified)
+ {
+ ++um->priv->next_redo;
+ gtk_text_buffer_set_modified (um->priv->document, FALSE);
+ --um->priv->next_redo;
+ }
+
+ gtk_source_undo_manager_end_not_undoable_action_internal (um);
+
+ if (um->priv->next_redo < 0)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_REDO], 0, FALSE);
+ }
+
+ if (!um->priv->can_undo)
+ {
+ um->priv->can_undo = TRUE;
+ g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_UNDO], 0, TRUE);
+ }
+}
+
+static void
+gtk_source_undo_action_free (GtkSourceUndoAction *action)
+{
+ if (action == NULL)
+ return;
+
+ if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
+ g_free (action->action.insert.text);
+ else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
+ g_free (action->action.delete.text);
+ else
+ g_return_if_reached ();
+
+ g_free (action);
+}
+
+static void
+gtk_source_undo_manager_free_action_list (GtkSourceUndoManager *um)
+{
+ GList *l;
+
+ l = um->priv->actions;
+
+ while (l != NULL)
+ {
+ GtkSourceUndoAction *action = l->data;
+
+ if (action->order_in_group == 1)
+ --um->priv->num_of_groups;
+
+ if (action->modified)
+ um->priv->modified_action = INVALID;
+
+ gtk_source_undo_action_free (action);
+
+ l = g_list_next (l);
+ }
+
+ g_list_free (um->priv->actions);
+ um->priv->actions = NULL;
+}
+
+static void
+gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer,
+ GtkTextIter *pos,
+ const gchar *text,
+ gint length,
+ GtkSourceUndoManager *um)
+{
+ GtkSourceUndoAction undo_action;
+
+ if (um->priv->running_not_undoable_actions > 0)
+ return;
+
+ g_return_if_fail (strlen (text) >= (guint)length);
+
+ undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT;
+
+ undo_action.action.insert.pos = gtk_text_iter_get_offset (pos);
+ undo_action.action.insert.text = (gchar*) text;
+ undo_action.action.insert.length = length;
+ undo_action.action.insert.chars = g_utf8_strlen (text, length);
+
+ if ((undo_action.action.insert.chars > 1) || (g_utf8_get_char (text) == '\n'))
+
+ undo_action.mergeable = FALSE;
+ else
+ undo_action.mergeable = TRUE;
+
+ undo_action.modified = FALSE;
+
+ gtk_source_undo_manager_add_action (um, &undo_action);
+}
+
+static void
+gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer,
+ GtkTextIter *start,
+ GtkTextIter *end,
+ GtkSourceUndoManager *um)
+{
+ GtkSourceUndoAction undo_action;
+ GtkTextIter insert_iter;
+
+ if (um->priv->running_not_undoable_actions > 0)
+ return;
+
+ undo_action.action_type = GTK_SOURCE_UNDO_ACTION_DELETE;
+
+ gtk_text_iter_order (start, end);
+
+ undo_action.action.delete.start = gtk_text_iter_get_offset (start);
+ undo_action.action.delete.end = gtk_text_iter_get_offset (end);
+
+ undo_action.action.delete.text = get_chars (
+ buffer,
+ undo_action.action.delete.start,
+ undo_action.action.delete.end);
+
+ /* figure out if the user used the Delete or the Backspace key */
+ gtk_text_buffer_get_iter_at_mark (buffer, &insert_iter,
+ gtk_text_buffer_get_insert (buffer));
+ if (gtk_text_iter_get_offset (&insert_iter) <= undo_action.action.delete.start)
+ undo_action.action.delete.forward = TRUE;
+ else
+ undo_action.action.delete.forward = FALSE;
+
+ if (((undo_action.action.delete.end - undo_action.action.delete.start) > 1) ||
+ (g_utf8_get_char (undo_action.action.delete.text ) == '\n'))
+ undo_action.mergeable = FALSE;
+ else
+ undo_action.mergeable = TRUE;
+
+ undo_action.modified = FALSE;
+
+ gtk_source_undo_manager_add_action (um, &undo_action);
+
+ g_free (undo_action.action.delete.text);
+
+}
+
+static void
+gtk_source_undo_manager_begin_user_action_handler (GtkTextBuffer *buffer, GtkSourceUndoManager *um)
+{
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+
+ if (um->priv->running_not_undoable_actions > 0)
+ return;
+
+ um->priv->actions_in_current_group = 0;
+}
+
+static void
+gtk_source_undo_manager_add_action (GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action)
+{
+ GtkSourceUndoAction* action;
+
+ if (um->priv->next_redo >= 0)
+ {
+ gtk_source_undo_manager_free_first_n_actions (um, um->priv->next_redo + 1);
+ }
+
+ um->priv->next_redo = -1;
+
+ if (!gtk_source_undo_manager_merge_action (um, undo_action))
+ {
+ action = g_new (GtkSourceUndoAction, 1);
+ *action = *undo_action;
+
+ if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
+ action->action.insert.text = g_strdup (undo_action->action.insert.text);
+ else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
+ action->action.delete.text = g_strdup (undo_action->action.delete.text);
+ else
+ {
+ g_free (action);
+ g_return_if_reached ();
+ }
+
+ ++um->priv->actions_in_current_group;
+ action->order_in_group = um->priv->actions_in_current_group;
+
+ if (action->order_in_group == 1)
+ ++um->priv->num_of_groups;
+
+ um->priv->actions = g_list_prepend (um->priv->actions, action);
+ }
+
+ gtk_source_undo_manager_check_list_size (um);
+
+ if (!um->priv->can_undo)
+ {
+ um->priv->can_undo = TRUE;
+ g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_UNDO], 0, TRUE);
+ }
+
+ if (um->priv->can_redo)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_REDO], 0, FALSE);
+ }
+}
+
+static void
+gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager *um,
+ gint n)
+{
+ gint i;
+
+ if (um->priv->actions == NULL)
+ return;
+
+ for (i = 0; i < n; i++)
+ {
+ GtkSourceUndoAction *action = g_list_first (um->priv->actions)->data;
+
+ if (action->order_in_group == 1)
+ --um->priv->num_of_groups;
+
+ if (action->modified)
+ um->priv->modified_action = INVALID;
+
+ gtk_source_undo_action_free (action);
+
+ um->priv->actions = g_list_delete_link (um->priv->actions,
+ um->priv->actions);
+
+ if (um->priv->actions == NULL)
+ return;
+ }
+}
+
+static void
+gtk_source_undo_manager_check_list_size (GtkSourceUndoManager *um)
+{
+ gint undo_levels;
+
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+
+ undo_levels = gtk_source_undo_manager_get_max_undo_levels (um);
+
+ if (undo_levels < 1)
+ return;
+
+ if (um->priv->num_of_groups > undo_levels)
+ {
+ GtkSourceUndoAction *undo_action;
+ GList *last;
+
+ last = g_list_last (um->priv->actions);
+ undo_action = (GtkSourceUndoAction*) last->data;
+
+ do
+ {
+ GList *tmp;
+
+ if (undo_action->order_in_group == 1)
+ --um->priv->num_of_groups;
+
+ if (undo_action->modified)
+ um->priv->modified_action = INVALID;
+
+ gtk_source_undo_action_free (undo_action);
+
+ tmp = g_list_previous (last);
+ um->priv->actions = g_list_delete_link (um->priv->actions, last);
+ last = tmp;
+ g_return_if_fail (last != NULL);
+
+ undo_action = (GtkSourceUndoAction*) last->data;
+
+ } while ((undo_action->order_in_group > 1) ||
+ (um->priv->num_of_groups > undo_levels));
+ }
+}
+
+/**
+ * gtk_source_undo_manager_merge_action:
+ * @um: a #GtkSourceUndoManager.
+ * @undo_action: a #GtkSourceUndoAction.
+ *
+ * This function tries to merge the undo action at the top of
+ * the stack with a new undo action. So when we undo for example
+ * typing, we can undo the whole word and not each letter by itself.
+ *
+ * Return Value: %TRUE is merge was sucessful, %FALSE otherwise.²
+ **/
+static gboolean
+gtk_source_undo_manager_merge_action (GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action)
+{
+ GtkSourceUndoAction *last_action;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE);
+ g_return_val_if_fail (um->priv != NULL, FALSE);
+
+ if (um->priv->actions == NULL)
+ return FALSE;
+
+ last_action = (GtkSourceUndoAction*) g_list_nth_data (um->priv->actions, 0);
+
+ if (!last_action->mergeable)
+ return FALSE;
+
+ if ((!undo_action->mergeable) ||
+ (undo_action->action_type != last_action->action_type))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
+ {
+ if ((last_action->action.delete.forward != undo_action->action.delete.forward) ||
+ ((last_action->action.delete.start != undo_action->action.delete.start) &&
+ (last_action->action.delete.start != undo_action->action.delete.end)))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ if (last_action->action.delete.start == undo_action->action.delete.start)
+ {
+ gchar *str;
+
+#define L (last_action->action.delete.end - last_action->action.delete.start - 1)
+#define g_utf8_get_char_at(p,i) g_utf8_get_char(g_utf8_offset_to_pointer((p),(i)))
+
+ /* Deleted with the delete key */
+ if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
+ (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
+ ((g_utf8_get_char_at (last_action->action.delete.text, L) == ' ') ||
+ (g_utf8_get_char_at (last_action->action.delete.text, L) == '\t')))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ str = g_strdup_printf ("%s%s", last_action->action.delete.text,
+ undo_action->action.delete.text);
+
+ g_free (last_action->action.delete.text);
+ last_action->action.delete.end += (undo_action->action.delete.end -
+ undo_action->action.delete.start);
+ last_action->action.delete.text = str;
+ }
+ else
+ {
+ gchar *str;
+
+ /* Deleted with the backspace key */
+ if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
+ (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
+ ((g_utf8_get_char (last_action->action.delete.text) == ' ') ||
+ (g_utf8_get_char (last_action->action.delete.text) == '\t')))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ str = g_strdup_printf ("%s%s", undo_action->action.delete.text,
+ last_action->action.delete.text);
+
+ g_free (last_action->action.delete.text);
+ last_action->action.delete.start = undo_action->action.delete.start;
+ last_action->action.delete.text = str;
+ }
+ }
+ else if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
+ {
+ gchar* str;
+
+#define I (last_action->action.insert.chars - 1)
+
+ if ((undo_action->action.insert.pos !=
+ (last_action->action.insert.pos + last_action->action.insert.chars)) ||
+ ((g_utf8_get_char (undo_action->action.insert.text) != ' ') &&
+ (g_utf8_get_char (undo_action->action.insert.text) != '\t') &&
+ ((g_utf8_get_char_at (last_action->action.insert.text, I) == ' ') ||
+ (g_utf8_get_char_at (last_action->action.insert.text, I) == '\t')))
+ )
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ str = g_strdup_printf ("%s%s", last_action->action.insert.text,
+ undo_action->action.insert.text);
+
+ g_free (last_action->action.insert.text);
+ last_action->action.insert.length += undo_action->action.insert.length;
+ last_action->action.insert.text = str;
+ last_action->action.insert.chars += undo_action->action.insert.chars;
+
+ }
+ else
+ /* Unknown action inside undo merge encountered */
+ g_return_val_if_reached (TRUE);
+
+ return TRUE;
+}
+
+gint
+gtk_source_undo_manager_get_max_undo_levels (GtkSourceUndoManager *um)
+{
+ g_return_val_if_fail (um != NULL, 0);
+ g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), 0);
+
+ return um->priv->max_undo_levels;
+}
+
+void
+gtk_source_undo_manager_set_max_undo_levels (GtkSourceUndoManager *um,
+ gint max_undo_levels)
+{
+ gint old_levels;
+
+ g_return_if_fail (um != NULL);
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+
+ old_levels = um->priv->max_undo_levels;
+ um->priv->max_undo_levels = max_undo_levels;
+
+ if (max_undo_levels < 1)
+ return;
+
+ if (old_levels > max_undo_levels)
+ {
+ /* strip redo actions first */
+ while (um->priv->next_redo >= 0 && (um->priv->num_of_groups > max_undo_levels))
+ {
+ gtk_source_undo_manager_free_first_n_actions (um, 1);
+ um->priv->next_redo--;
+ }
+
+ /* now remove undo actions if necessary */
+ gtk_source_undo_manager_check_list_size (um);
+
+ /* emit "can_undo" and/or "can_redo" if appropiate */
+ if (um->priv->next_redo < 0 && um->priv->can_redo)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_REDO], 0, FALSE);
+ }
+
+ if (um->priv->can_undo &&
+ um->priv->next_redo >= (gint)(g_list_length (um->priv->actions) - 1))
+ {
+ um->priv->can_undo = FALSE;
+ g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_UNDO], 0, FALSE);
+ }
+ }
+}
+
+static void
+gtk_source_undo_manager_modified_changed_handler (GtkTextBuffer *buffer,
+ GtkSourceUndoManager *um)
+{
+ GtkSourceUndoAction *action;
+ GList *list;
+
+ g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
+ g_return_if_fail (um->priv != NULL);
+
+ if (um->priv->actions == NULL)
+ return;
+
+ list = g_list_nth (um->priv->actions, um->priv->next_redo + 1);
+
+ if (list != NULL)
+ action = (GtkSourceUndoAction*) list->data;
+ else
+ action = NULL;
+
+ if (gtk_text_buffer_get_modified (buffer) == FALSE)
+ {
+ if (action != NULL)
+ action->mergeable = FALSE;
+
+ if (um->priv->modified_action != NULL)
+ {
+ if (um->priv->modified_action != INVALID)
+ um->priv->modified_action->modified = FALSE;
+
+ um->priv->modified_action = NULL;
+ }
+
+ return;
+ }
+
+ if (action == NULL)
+ {
+ g_return_if_fail (um->priv->running_not_undoable_actions > 0);
+
+ return;
+ }
+
+ /* gtk_text_buffer_get_modified (buffer) == TRUE */
+
+ g_return_if_fail (um->priv->modified_action == NULL);
+
+ if (action->order_in_group > 1)
+ um->priv->modified_undoing_group = TRUE;
+
+ while (action->order_in_group > 1)
+ {
+ list = g_list_next (list);
+ g_return_if_fail (list != NULL);
+
+ action = (GtkSourceUndoAction*) list->data;
+ g_return_if_fail (action != NULL);
+ }
+
+ action->modified = TRUE;
+ um->priv->modified_action = action;
+}
diff --git a/pidgin/gtksourceundomanager.h b/pidgin/gtksourceundomanager.h
new file mode 100644
index 0000000000..ffe5da5cf8
--- /dev/null
+++ b/pidgin/gtksourceundomanager.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gtksourceundomanager.h
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002, 2003 Paolo Maggi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA. * *
+ */
+
+#ifndef __GTK_SOURCE_UNDO_MANAGER_H__
+#define __GTK_SOURCE_UNDO_MANAGER_H__
+
+#include <gtk/gtktextbuffer.h>
+
+#define GTK_SOURCE_TYPE_UNDO_MANAGER (gtk_source_undo_manager_get_type ())
+#define GTK_SOURCE_UNDO_MANAGER(obj) (GTK_CHECK_CAST ((obj), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManager))
+#define GTK_SOURCE_UNDO_MANAGER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManagerClass))
+#define GTK_SOURCE_IS_UNDO_MANAGER(obj) (GTK_CHECK_TYPE ((obj), GTK_SOURCE_TYPE_UNDO_MANAGER))
+#define GTK_SOURCE_IS_UNDO_MANAGER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_SOURCE_TYPE_UNDO_MANAGER))
+#define GTK_SOURCE_UNDO_MANAGER_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManagerClass))
+
+
+typedef struct _GtkSourceUndoManager GtkSourceUndoManager;
+typedef struct _GtkSourceUndoManagerClass GtkSourceUndoManagerClass;
+
+typedef struct _GtkSourceUndoManagerPrivate GtkSourceUndoManagerPrivate;
+
+struct _GtkSourceUndoManager
+{
+ GObject base;
+
+ GtkSourceUndoManagerPrivate *priv;
+};
+
+struct _GtkSourceUndoManagerClass
+{
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*can_undo) (GtkSourceUndoManager *um, gboolean can_undo);
+ void (*can_redo) (GtkSourceUndoManager *um, gboolean can_redo);
+};
+
+GType gtk_source_undo_manager_get_type (void) G_GNUC_CONST;
+
+GtkSourceUndoManager* gtk_source_undo_manager_new (GtkTextBuffer *buffer);
+
+gboolean gtk_source_undo_manager_can_undo (const GtkSourceUndoManager *um);
+gboolean gtk_source_undo_manager_can_redo (const GtkSourceUndoManager *um);
+
+void gtk_source_undo_manager_undo (GtkSourceUndoManager *um);
+void gtk_source_undo_manager_redo (GtkSourceUndoManager *um);
+
+void gtk_source_undo_manager_begin_not_undoable_action
+ (GtkSourceUndoManager *um);
+void gtk_source_undo_manager_end_not_undoable_action
+ (GtkSourceUndoManager *um);
+
+gint gtk_source_undo_manager_get_max_undo_levels
+ (GtkSourceUndoManager *um);
+void gtk_source_undo_manager_set_max_undo_levels
+ (GtkSourceUndoManager *um,
+ gint undo_levels);
+
+#endif /* __GTK_SOURCE_UNDO_MANAGER_H__ */
+
+
diff --git a/pidgin/gtksourceview-marshal.c b/pidgin/gtksourceview-marshal.c
new file mode 100644
index 0000000000..a006eb35a7
--- /dev/null
+++ b/pidgin/gtksourceview-marshal.c
@@ -0,0 +1,95 @@
+#include "gtksourceview-marshal.h"
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:VOID (gtksourceview-marshal.list:1) */
+
+/* VOID:BOOLEAN (gtksourceview-marshal.list:2) */
+
+/* VOID:BOXED (gtksourceview-marshal.list:3) */
+
+/* VOID:BOXED,BOXED (gtksourceview-marshal.list:4) */
+void
+gtksourceview_marshal_VOID__BOXED_BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__BOXED_BOXED) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__BOXED_BOXED callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__BOXED_BOXED) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ g_marshal_value_peek_boxed (param_values + 2),
+ data2);
+}
+
+/* VOID:STRING (gtksourceview-marshal.list:5) */
+
diff --git a/pidgin/gtksourceview-marshal.h b/pidgin/gtksourceview-marshal.h
new file mode 100644
index 0000000000..8da30a9e96
--- /dev/null
+++ b/pidgin/gtksourceview-marshal.h
@@ -0,0 +1,32 @@
+
+#ifndef __gtksourceview_marshal_MARSHAL_H__
+#define __gtksourceview_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:VOID (gtksourceview-marshal.list:1) */
+#define gtksourceview_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
+
+/* VOID:BOOLEAN (gtksourceview-marshal.list:2) */
+#define gtksourceview_marshal_VOID__BOOLEAN g_cclosure_marshal_VOID__BOOLEAN
+
+/* VOID:BOXED (gtksourceview-marshal.list:3) */
+#define gtksourceview_marshal_VOID__BOXED g_cclosure_marshal_VOID__BOXED
+
+/* VOID:BOXED,BOXED (gtksourceview-marshal.list:4) */
+extern void gtksourceview_marshal_VOID__BOXED_BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:STRING (gtksourceview-marshal.list:5) */
+#define gtksourceview_marshal_VOID__STRING g_cclosure_marshal_VOID__STRING
+
+G_END_DECLS
+
+#endif /* __gtksourceview_marshal_MARSHAL_H__ */
+
diff --git a/pidgin/gtkstatusbox.c b/pidgin/gtkstatusbox.c
index bd545b412a..9c49666310 100644
--- a/pidgin/gtkstatusbox.c
+++ b/pidgin/gtkstatusbox.c
@@ -1434,7 +1434,7 @@ buddy_icon_set_cb(const char *filename, PidginStatusBox *box)
}
}
} else {
- GList *accounts;
+ const GList *accounts;
for (accounts = purple_accounts_get_all(); accounts != NULL; accounts = accounts->next) {
PurpleAccount *account = accounts->data;
PurplePlugin *plug = purple_find_prpl(purple_account_get_protocol_id(account));
diff --git a/pidgin/gtkthemes.c b/pidgin/gtkthemes.c
index 0d18147520..f1a242ab20 100644
--- a/pidgin/gtkthemes.c
+++ b/pidgin/gtkthemes.c
@@ -237,7 +237,7 @@ void pidgin_themes_load_smiley_theme(const char *file, gboolean load)
}
if (load) {
- GList *cnv;
+ const GList *cnv;
if (current_smiley_theme)
pidgin_themes_destroy_smiley_theme(current_smiley_theme);
diff --git a/pidgin/gtkutils.c b/pidgin/gtkutils.c
index 1040c6135b..eb97096acb 100644
--- a/pidgin/gtkutils.c
+++ b/pidgin/gtkutils.c
@@ -130,6 +130,22 @@ pidgin_setup_imhtml(GtkWidget *imhtml)
}
GtkWidget *
+pidgin_create_window(const char *title, guint border_width, const char *role, gboolean resizable)
+{
+ GtkWindow *wnd = NULL;
+
+ wnd = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+ if (title)
+ gtk_window_set_title(wnd, title);
+ gtk_container_set_border_width(GTK_CONTAINER(wnd), border_width);
+ if (role)
+ gtk_window_set_role(wnd, role);
+ gtk_window_set_resizable(wnd, resizable);
+
+ return GTK_WIDGET(wnd);
+}
+
+GtkWidget *
pidgin_create_imhtml(gboolean editable, GtkWidget **imhtml_ret, GtkWidget **toolbar_ret, GtkWidget **sw_ret)
{
GtkWidget *frame;
@@ -245,13 +261,14 @@ pidgin_toggle_showhide(GtkWidget *widget, GtkWidget *to_toggle)
gtk_widget_show(to_toggle);
}
-void pidgin_separator(GtkWidget *menu)
+GtkWidget *pidgin_separator(GtkWidget *menu)
{
GtkWidget *menuitem;
menuitem = gtk_separator_menu_item_new();
gtk_widget_show(menuitem);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ return menuitem;
}
GtkWidget *pidgin_new_item(GtkWidget *menu, const char *str)
@@ -462,7 +479,7 @@ aop_menu_cb(GtkWidget *optmenu, GCallback cb)
}
static GtkWidget *
-aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer per_item_data)
+aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer per_item_data, const char *data)
{
GtkWidget *item;
GtkWidget *hbox;
@@ -495,6 +512,7 @@ aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer
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);
@@ -502,6 +520,39 @@ aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer
return item;
}
+static GdkPixbuf *
+pidgin_create_prpl_icon_from_prpl(PurplePlugin *prpl, PidginPrplIconSize size, PurpleAccount *account)
+{
+ PurplePluginProtocolInfo *prpl_info;
+ const char *protoname = NULL;
+ char buf[MAXPATHLEN];
+ char *filename = NULL;
+ GdkPixbuf *pixbuf;
+
+ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+ if (prpl_info->list_icon == NULL)
+ return NULL;
+
+ protoname = prpl_info->list_icon(account, NULL);
+ if (protoname == NULL)
+ return NULL;
+
+ /*
+ * Status icons will be themeable too, and then it will look up
+ * protoname from the theme
+ */
+ g_snprintf(buf, sizeof(buf), "%s.png", protoname);
+
+ filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
+ size == PIDGIN_PRPL_ICON_SMALL ? "16" :
+ size == PIDGIN_PRPL_ICON_MEDIUM ? "22" : "48",
+ buf, NULL);
+ pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+ g_free(filename);
+
+ return pixbuf;
+}
+
static GtkWidget *
aop_option_menu_new(AopMenu *aop_menu, GCallback cb, gpointer user_data)
{
@@ -552,25 +603,6 @@ aop_option_menu_select_by_data(GtkWidget *optmenu, gpointer data)
}
}
-static GdkPixbuf *
-get_prpl_pixbuf(PurplePluginProtocolInfo *prpl_info)
-{
- const char *proto_name;
- GdkPixbuf *pixbuf = NULL;
- char *filename;
- char buf[256];
-
- proto_name = prpl_info->list_icon(NULL, NULL);
- g_return_val_if_fail(proto_name != NULL, NULL);
-
- g_snprintf(buf, sizeof(buf), "%s.png", proto_name);
- filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "16", buf, NULL);
- pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
- g_free(filename);
-
- return pixbuf;
-}
-
static AopMenu *
create_protocols_menu(const char *default_proto_id)
{
@@ -602,11 +634,14 @@ create_protocols_menu(const char *default_proto_id)
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 = gdk_pixbuf_new_from_file(filename, NULL);
g_free(filename);
gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
- aop_menu_item_new(sg, pixbuf, gtalk_name, "prpl-jabber"));
+ item = aop_menu_item_new(sg, pixbuf, gtalk_name, "prpl-jabber", "protocol"));
+ g_object_set_data(G_OBJECT(item), "fake", GINT_TO_POINTER(1));
if (pixbuf)
g_object_unref(pixbuf);
@@ -615,10 +650,10 @@ create_protocols_menu(const char *default_proto_id)
i++;
}
- pixbuf = get_prpl_pixbuf(prpl_info);
+ 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));
+ aop_menu_item_new(sg, pixbuf, plugin->info->name, plugin->info->id, "protocol"));
if (pixbuf)
g_object_unref(pixbuf);
@@ -652,8 +687,8 @@ create_account_menu(PurpleAccount *default_account,
AopMenu *aop_menu = NULL;
PurpleAccount *account;
GdkPixbuf *pixbuf = NULL;
- GList *list;
- GList *p;
+ const GList *list;
+ const GList *p;
GtkSizeGroup *sg;
int i;
char buf[256];
@@ -670,7 +705,6 @@ create_account_menu(PurpleAccount *default_account,
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
for (p = list, i = 0; p != NULL; p = p->next, i++) {
- PurplePluginProtocolInfo *prpl_info = NULL;
PurplePlugin *plugin;
if (show_all)
@@ -688,18 +722,12 @@ create_account_menu(PurpleAccount *default_account,
plugin = purple_find_prpl(purple_account_get_protocol_id(account));
- if (plugin)
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
-
- /* Load the image. */
- if (prpl_info) {
- pixbuf = get_prpl_pixbuf(prpl_info);
+ pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
- if (pixbuf) {
- if (purple_account_is_disconnected(account) && show_all &&
- purple_connections_get_all())
- gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
- }
+ if (pixbuf) {
+ if (purple_account_is_disconnected(account) && show_all &&
+ purple_connections_get_all())
+ gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
}
if (purple_account_get_alias(account)) {
@@ -714,7 +742,7 @@ create_account_menu(PurpleAccount *default_account,
}
gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
- aop_menu_item_new(sg, pixbuf, buf, account));
+ aop_menu_item_new(sg, pixbuf, buf, account, "account"));
if (pixbuf)
g_object_unref(pixbuf);
@@ -883,6 +911,15 @@ pidgin_load_accels()
g_free(filename);
}
+void pidgin_retrieve_user_info(PurpleConnection *conn, const char *name)
+{
+ PurpleNotifyUserInfo *info = purple_notify_user_info_new();
+ purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving..."));
+ purple_notify_userinfo(conn, name, info, NULL, NULL);
+ purple_notify_user_info_destroy(info);
+ serv_get_info(conn, name);
+}
+
gboolean
pidgin_parse_x_im_contact(const char *msg, gboolean all_accounts,
PurpleAccount **ret_account, char **ret_protocol,
@@ -958,9 +995,9 @@ pidgin_parse_x_im_contact(const char *msg, gboolean all_accounts,
/* Check for a compatible account. */
if (ret_account != NULL)
{
- GList *list;
+ const GList *list;
PurpleAccount *account = NULL;
- GList *l;
+ const GList *l;
const char *protoname;
if (all_accounts)
@@ -1583,40 +1620,13 @@ GdkPixbuf *
pidgin_create_prpl_icon(PurpleAccount *account, PidginPrplIconSize size)
{
PurplePlugin *prpl;
- PurplePluginProtocolInfo *prpl_info;
- const char *protoname = NULL;
- char buf[256]; /* TODO: We should use a define for max file length */
- char *filename = NULL;
- GdkPixbuf *pixbuf;
g_return_val_if_fail(account != NULL, NULL);
prpl = purple_find_prpl(purple_account_get_protocol_id(account));
if (prpl == NULL)
return NULL;
-
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
- if (prpl_info->list_icon == NULL)
- return NULL;
-
- protoname = prpl_info->list_icon(account, NULL);
- if (protoname == NULL)
- return NULL;
-
- /*
- * Status icons will be themeable too, and then it will look up
- * protoname from the theme
- */
- g_snprintf(buf, sizeof(buf), "%s.png", protoname);
-
- filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
- size == PIDGIN_PRPL_ICON_SMALL ? "16" :
- size == PIDGIN_PRPL_ICON_MEDIUM ? "22" : "48",
- buf, NULL);
- pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
- g_free(filename);
-
- return pixbuf;
+ return pidgin_create_prpl_icon_from_prpl(prpl, size, account);
}
static void
@@ -1632,62 +1642,63 @@ menu_action_cb(GtkMenuItem *item, gpointer object)
callback(object, data);
}
-void
+GtkWidget *
pidgin_append_menu_action(GtkWidget *menu, PurpleMenuAction *act,
gpointer object)
{
+ GtkWidget *menuitem;
+
if (act == NULL) {
- pidgin_separator(menu);
+ return pidgin_separator(menu);
+ }
+
+ if (act->children == NULL) {
+ menuitem = gtk_menu_item_new_with_mnemonic(act->label);
+
+ if (act->callback != NULL) {
+ g_object_set_data(G_OBJECT(menuitem),
+ "purplecallback",
+ act->callback);
+ g_object_set_data(G_OBJECT(menuitem),
+ "purplecallbackdata",
+ act->data);
+ g_signal_connect(G_OBJECT(menuitem), "activate",
+ G_CALLBACK(menu_action_cb),
+ object);
+ } else {
+ gtk_widget_set_sensitive(menuitem, FALSE);
+ }
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
} else {
- GtkWidget *menuitem;
-
- if (act->children == NULL) {
- menuitem = gtk_menu_item_new_with_mnemonic(act->label);
-
- if (act->callback != NULL) {
- g_object_set_data(G_OBJECT(menuitem),
- "purplecallback",
- act->callback);
- g_object_set_data(G_OBJECT(menuitem),
- "purplecallbackdata",
- act->data);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(menu_action_cb),
- object);
- } else {
- gtk_widget_set_sensitive(menuitem, FALSE);
- }
+ GList *l = NULL;
+ GtkWidget *submenu = NULL;
+ GtkAccelGroup *group;
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
- } else {
- GList *l = NULL;
- GtkWidget *submenu = NULL;
- GtkAccelGroup *group;
-
- menuitem = gtk_menu_item_new_with_mnemonic(act->label);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
- submenu = gtk_menu_new();
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
-
- group = gtk_menu_get_accel_group(GTK_MENU(menu));
- if (group) {
- char *path = g_strdup_printf("%s/%s", GTK_MENU_ITEM(menuitem)->accel_path, act->label);
- gtk_menu_set_accel_path(GTK_MENU(submenu), path);
- g_free(path);
- gtk_menu_set_accel_group(GTK_MENU(submenu), group);
- }
+ menuitem = gtk_menu_item_new_with_mnemonic(act->label);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
- for (l = act->children; l; l = l->next) {
- PurpleMenuAction *act = (PurpleMenuAction *)l->data;
+ submenu = gtk_menu_new();
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
- pidgin_append_menu_action(submenu, act, object);
- }
- g_list_free(act->children);
- act->children = NULL;
+ group = gtk_menu_get_accel_group(GTK_MENU(menu));
+ if (group) {
+ char *path = g_strdup_printf("%s/%s", GTK_MENU_ITEM(menuitem)->accel_path, act->label);
+ gtk_menu_set_accel_path(GTK_MENU(submenu), path);
+ g_free(path);
+ gtk_menu_set_accel_group(GTK_MENU(submenu), group);
+ }
+
+ for (l = act->children; l; l = l->next) {
+ PurpleMenuAction *act = (PurpleMenuAction *)l->data;
+
+ pidgin_append_menu_action(submenu, act, object);
}
- purple_menu_action_free(act);
+ g_list_free(act->children);
+ act->children = NULL;
}
+ purple_menu_action_free(act);
+ return menuitem;
}
#if GTK_CHECK_VERSION(2,3,0)
diff --git a/pidgin/gtkutils.h b/pidgin/gtkutils.h
index 704e8423f8..bc1b5236f3 100644
--- a/pidgin/gtkutils.h
+++ b/pidgin/gtkutils.h
@@ -93,6 +93,18 @@ void pidgin_setup_imhtml(GtkWidget *imhtml);
GtkWidget *pidgin_create_imhtml(gboolean editable, GtkWidget **imhtml_ret, GtkWidget **toolbar_ret, GtkWidget **sw_ret);
/**
+ * Creates a new window
+ *
+ * @param title The window title, or @c NULL
+ * @param border_width The window's desired border width
+ * @param role A string indicating what the window is responsible for doing, or @c NULL
+ * @param resizable Whether the window should be resizable (@c TRUE) or not (@c FALSE)
+ *
+ * @since 2.1.0
+ */
+GtkWidget *pidgin_create_window(const char *title, guint border_width, const char *role, gboolean resizable);
+
+/**
* Toggles the sensitivity of a widget.
*
* @param widget @c NULL. Used for signal handlers.
@@ -130,8 +142,10 @@ void pidgin_toggle_showhide(GtkWidget *widget, GtkWidget *to_toggle);
* Adds a separator to a menu.
*
* @param menu The menu to add a separator to.
+ *
+ * @return The separator.
*/
-void pidgin_separator(GtkWidget *menu);
+GtkWidget *pidgin_separator(GtkWidget *menu);
/**
* Creates a menu item.
@@ -307,6 +321,14 @@ gboolean pidgin_save_accels(gpointer data);
void pidgin_load_accels(void);
/**
+ * Get information about a user. Show immediate feedback.
+ *
+ * @param conn The connection to get information from.
+ * @param name The user to get information about.
+ */
+void pidgin_retrieve_user_info(PurpleConnection *conn, const char *name);
+
+/**
* Parses an application/x-im-contact MIME message and returns the
* data inside.
*
@@ -404,8 +426,10 @@ GdkPixbuf * pidgin_create_status_icon(PurpleStatusPrimitive primitive, GtkWidget
* @param menu The menu to append to.
* @param act The PurpleMenuAction to append.
* @param gobject The object to be passed to the action callback.
+ *
+ * @return The menuitem added.
*/
-void pidgin_append_menu_action(GtkWidget *menu, PurpleMenuAction *act,
+GtkWidget *pidgin_append_menu_action(GtkWidget *menu, PurpleMenuAction *act,
gpointer gobject);
/**
diff --git a/pidgin/gtkwhiteboard.c b/pidgin/gtkwhiteboard.c
index d38caf0752..69b710c1b8 100644
--- a/pidgin/gtkwhiteboard.c
+++ b/pidgin/gtkwhiteboard.c
@@ -28,6 +28,7 @@
#include "debug.h"
#include "gtkwhiteboard.h"
+#include "gtkutils.h"
/******************************************************************************
* Prototypes
@@ -143,21 +144,14 @@ static void pidgin_whiteboard_create(PurpleWhiteboard *wb)
gtkwb->brush_color = 0xff0000;
}
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtkwb->window = window;
- gtk_widget_set_name(window, wb->who);
-
/* Try and set window title as the name of the buddy, else just use their
* username
*/
buddy = purple_find_buddy(wb->account, wb->who);
- if (buddy != NULL)
- gtk_window_set_title((GtkWindow*)(window), purple_buddy_get_contact_alias(buddy));
- else
- gtk_window_set_title((GtkWindow*)(window), wb->who);
-
- gtk_window_set_resizable((GtkWindow*)(window), FALSE);
+ window = pidgin_create_window(buddy != NULL ? purple_buddy_get_contact_alias(buddy) : wb->who, 0, NULL, FALSE);
+ gtkwb->window = window;
+ gtk_widget_set_name(window, wb->who);
g_signal_connect(G_OBJECT(window), "delete_event",
G_CALLBACK(whiteboard_close_cb), gtkwb);
diff --git a/pidgin/pidginstock.c b/pidgin/pidginstock.c
index dd92048dc8..0bdd7af25a 100644
--- a/pidgin/pidginstock.c
+++ b/pidgin/pidginstock.c
@@ -151,6 +151,7 @@ static struct SizedStockIcon {
{ PIDGIN_STOCK_TOOLBAR_FONT_FACE, "toolbar", "font-face.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
{ PIDGIN_STOCK_TOOLBAR_TEXT_SMALLER, "toolbar", "font-size-down.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
{ PIDGIN_STOCK_TOOLBAR_TEXT_LARGER, "toolbar", "font-size-up.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
+ { PIDGIN_STOCK_TOOLBAR_INSERT, "toolbar", "insert.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
{ PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE, "toolbar", "insert-image.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
{ PIDGIN_STOCK_TOOLBAR_INSERT_LINK, "toolbar", "insert-link.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
{ PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, "toolbar", "message-new.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
diff --git a/pidgin/pidginstock.h b/pidgin/pidginstock.h
index 0e366d30ea..89dd11e3ec 100644
--- a/pidgin/pidginstock.h
+++ b/pidgin/pidginstock.h
@@ -116,6 +116,7 @@
#define PIDGIN_STOCK_TOOLBAR_FONT_FACE "pidgin-font-face"
#define PIDGIN_STOCK_TOOLBAR_TEXT_SMALLER "pidgin-text-smaller"
#define PIDGIN_STOCK_TOOLBAR_TEXT_LARGER "pidgin-text-larger"
+#define PIDGIN_STOCK_TOOLBAR_INSERT "pidgin-insert"
#define PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE "pidgin-insert-image"
#define PIDGIN_STOCK_TOOLBAR_INSERT_LINK "pidgin-insert-link"
#define PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW "pidgin-message-new"
diff --git a/pidgin/pixmaps/toolbar/16/Makefile.am b/pidgin/pixmaps/toolbar/16/Makefile.am
index e478efcb71..cf7269c30d 100644
--- a/pidgin/pixmaps/toolbar/16/Makefile.am
+++ b/pidgin/pixmaps/toolbar/16/Makefile.am
@@ -6,6 +6,7 @@ EXTRA_DIST = change-bgcolor.png \
font-face.png \
font-size-down.png \
font-size-up.png \
+ insert.png \
insert-image.png \
insert-link.png \
message-new.png \
diff --git a/pidgin/plugins/cap/cap.c b/pidgin/plugins/cap/cap.c
index 0037132d70..69211cac8f 100644
--- a/pidgin/plugins/cap/cap.c
+++ b/pidgin/plugins/cap/cap.c
@@ -918,7 +918,8 @@ static void numeric_spinner_prefs_cb(GtkSpinButton *spinbutton, gpointer user_da
static PidginPluginUiInfo ui_info = {
get_config_frame,
- 0 /* page_num (reserved) */
+ 0 /* page_num (reserved) */,
+ NULL,NULL,NULL,NULL
};
static PurplePluginInfo info = {
@@ -944,7 +945,8 @@ static PurplePluginInfo info = {
&ui_info, /**< ui_info */
NULL, /**< extra_info */
NULL, /**< prefs_info */
- NULL
+ NULL,
+ NULL,NULL,NULL,NULL
};
static GtkWidget * get_config_frame(PurplePlugin *plugin) {
diff --git a/pidgin/plugins/gestures/gestures.c b/pidgin/plugins/gestures/gestures.c
index 425fd5c695..e7835257f6 100644
--- a/pidgin/plugins/gestures/gestures.c
+++ b/pidgin/plugins/gestures/gestures.c
@@ -176,7 +176,7 @@ static gboolean
plugin_load(PurplePlugin *plugin)
{
PurpleConversation *conv;
- GList *l;
+ const GList *l;
for (l = purple_get_conversations(); l != NULL; l = l->next) {
conv = (PurpleConversation *)l->data;
@@ -199,7 +199,7 @@ plugin_unload(PurplePlugin *plugin)
{
PurpleConversation *conv;
PidginConversation *gtkconv;
- GList *l;
+ const GList *l;
for (l = purple_get_conversations(); l != NULL; l = l->next) {
conv = (PurpleConversation *)l->data;
diff --git a/pidgin/plugins/gevolution/add_buddy_dialog.c b/pidgin/plugins/gevolution/add_buddy_dialog.c
index 197587bd68..ec54e31ba9 100644
--- a/pidgin/plugins/gevolution/add_buddy_dialog.c
+++ b/pidgin/plugins/gevolution/add_buddy_dialog.c
@@ -162,7 +162,7 @@ add_ims(GevoAddBuddyDialog *dialog, EContact *contact, const char *name,
GList *list, const char *id)
{
PurpleAccount *account = NULL;
- GList *l;
+ const GList *l;
GtkTreeIter iter;
GdkPixbuf *pixbuf;
@@ -442,10 +442,7 @@ gevo_add_buddy_dialog_show(PurpleAccount *account, const char *username,
if (username != NULL)
dialog->username = g_strdup(username);
- dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(dialog->win), "add_buddy");
- gtk_window_set_title(GTK_WINDOW(dialog->win), _("Add Buddy"));
- gtk_container_set_border_width(GTK_CONTAINER(dialog->win), 12);
+ dialog->win = pidgin_create_window(_("Add Buddy"), PIDGIN_HIG_BORDER, "add_buddy", TRUE);
gtk_widget_set_size_request(dialog->win, -1, 400);
g_signal_connect(G_OBJECT(dialog->win), "delete_event",
diff --git a/pidgin/plugins/gevolution/assoc-buddy.c b/pidgin/plugins/gevolution/assoc-buddy.c
index 5aa28dccc2..fd87a960cb 100644
--- a/pidgin/plugins/gevolution/assoc-buddy.c
+++ b/pidgin/plugins/gevolution/assoc-buddy.c
@@ -329,9 +329,7 @@ gevo_associate_buddy_dialog_new(PurpleBuddy *buddy)
dialog->buddy = buddy;
- dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(dialog->win), "assoc_buddy");
- gtk_container_set_border_width(GTK_CONTAINER(dialog->win), 12);
+ dialog->win = pidgin_create_window(NULL, PIDGIN_HIG_BORDER, "assoc_buddy", TRUE);
g_signal_connect(G_OBJECT(dialog->win), "delete_event",
G_CALLBACK(delete_win_cb), dialog);
diff --git a/pidgin/plugins/gevolution/gevolution.c b/pidgin/plugins/gevolution/gevolution.c
index a895524d3f..46e7aa55b4 100644
--- a/pidgin/plugins/gevolution/gevolution.c
+++ b/pidgin/plugins/gevolution/gevolution.c
@@ -69,7 +69,8 @@ update_ims_from_contact(EContact *contact, const char *name,
const char *prpl_id, EContactField field)
{
GList *ims = e_contact_get(contact, field);
- GList *l, *l2;
+ const GList *l;
+ const GList *l2;
if (ims == NULL)
return;
@@ -400,7 +401,7 @@ get_config_frame(PurplePlugin *plugin)
GtkCellRenderer *renderer;
GdkPixbuf *pixbuf;
GtkListStore *model;
- GList *l;
+ const GList *l;
/* Outside container */
ret = gtk_vbox_new(FALSE, 18);
diff --git a/pidgin/plugins/gevolution/new_person_dialog.c b/pidgin/plugins/gevolution/new_person_dialog.c
index 95a2365eec..578623d943 100644
--- a/pidgin/plugins/gevolution/new_person_dialog.c
+++ b/pidgin/plugins/gevolution/new_person_dialog.c
@@ -246,11 +246,7 @@ gevo_new_person_dialog_show(EBook *book, EContact *contact,
dialog->book = book;
g_object_ref(book);
- dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(dialog->win), "new_person");
- gtk_window_set_title(GTK_WINDOW(dialog->win), _("New Person"));
- gtk_window_set_resizable(GTK_WINDOW(dialog->win), FALSE);
- gtk_container_set_border_width(GTK_CONTAINER(dialog->win), 12);
+ dialog->win = pidgin_create_window(_("New Person"), PIDGIN_HIG_BORDER, "new_person", FALSE);
g_signal_connect(G_OBJECT(dialog->win), "delete_event",
G_CALLBACK(delete_win_cb), dialog);
diff --git a/pidgin/plugins/notify.c b/pidgin/plugins/notify.c
index 921bfe9050..8157bbb967 100644
--- a/pidgin/plugins/notify.c
+++ b/pidgin/plugins/notify.c
@@ -624,7 +624,7 @@ options_entry_cb(GtkWidget *widget, GdkEventFocus *evt, gpointer data)
static void
apply_method()
{
- GList *convs;
+ const GList *convs;
PidginWindow *purplewin = NULL;
for (convs = purple_get_conversations(); convs != NULL;
@@ -644,7 +644,7 @@ apply_method()
static void
apply_notify()
{
- GList *convs = purple_get_conversations();
+ const GList *convs = purple_get_conversations();
while (convs) {
PurpleConversation *conv = (PurpleConversation *)convs->data;
@@ -818,7 +818,7 @@ get_config_frame(PurplePlugin *plugin)
static gboolean
plugin_load(PurplePlugin *plugin)
{
- GList *convs = purple_get_conversations();
+ const GList *convs = purple_get_conversations();
void *conv_handle = purple_conversations_get_handle();
void *gtk_conv_handle = pidgin_conversations_get_handle();
@@ -860,7 +860,7 @@ plugin_load(PurplePlugin *plugin)
static gboolean
plugin_unload(PurplePlugin *plugin)
{
- GList *convs = purple_get_conversations();
+ const GList *convs = purple_get_conversations();
while (convs) {
PurpleConversation *conv = (PurpleConversation *)convs->data;
diff --git a/pidgin/plugins/relnot.c b/pidgin/plugins/relnot.c
index b8011a7f0b..1ded39109e 100644
--- a/pidgin/plugins/relnot.c
+++ b/pidgin/plugins/relnot.c
@@ -70,8 +70,9 @@ version_fetch_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
message = g_string_new("");
g_string_append_printf(message, _("You are using %s version %s. The "
"current version is %s. You can get it from "
- "<a href=\"" PURPLE_WEBSITE "\">" PURPLE_WEBSITE "</a><hr>"),
- PIDGIN_NAME, purple_core_get_version(), cur_ver);
+ "<a href=\"%s\">%s</a><hr>"),
+ PIDGIN_NAME, purple_core_get_version(), cur_ver,
+ PURPLE_WEBSITE, PURPLE_WEBSITE);
if(*changelog) {
formatted = purple_strdup_withhtml(changelog);
diff --git a/pidgin/plugins/spellchk.c b/pidgin/plugins/spellchk.c
index f9916ea0dd..3b13400f22 100644
--- a/pidgin/plugins/spellchk.c
+++ b/pidgin/plugins/spellchk.c
@@ -2118,7 +2118,7 @@ static gboolean
plugin_load(PurplePlugin *plugin)
{
void *conv_handle = purple_conversations_get_handle();
- GList *convs;
+ const GList *convs;
load_conf();
@@ -2137,7 +2137,7 @@ plugin_load(PurplePlugin *plugin)
static gboolean
plugin_unload(PurplePlugin *plugin)
{
- GList *convs;
+ const GList *convs;
/* Detach from existing conversations */
for (convs = purple_get_conversations(); convs != NULL; convs = convs->next)
diff --git a/pidgin/plugins/ticker/ticker.c b/pidgin/plugins/ticker/ticker.c
index b30184aa96..f1fce9638e 100644
--- a/pidgin/plugins/ticker/ticker.c
+++ b/pidgin/plugins/ticker/ticker.c
@@ -36,6 +36,7 @@
#include "gtkblist.h"
#include "gtkplugin.h"
+#include "gtkutils.h"
#include "gtkticker.h"
@@ -70,12 +71,10 @@ static void buddy_ticker_create_window() {
return;
}
- tickerwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ tickerwindow = pidgin_create_window(_("Buddy Ticker"), 0, "ticker", TRUE);
gtk_window_set_default_size(GTK_WINDOW(tickerwindow), 500, -1);
g_signal_connect(G_OBJECT(tickerwindow), "delete_event",
G_CALLBACK (buddy_ticker_destroy_window), NULL);
- gtk_window_set_title (GTK_WINDOW(tickerwindow), _("Buddy Ticker"));
- gtk_window_set_role (GTK_WINDOW(tickerwindow), "ticker");
ticker = gtk_ticker_new();
gtk_ticker_set_spacing(GTK_TICKER(ticker), 20);
diff --git a/pidgin/plugins/timestamp.c b/pidgin/plugins/timestamp.c
index 55590498d1..55e066ef7d 100644
--- a/pidgin/plugins/timestamp.c
+++ b/pidgin/plugins/timestamp.c
@@ -77,7 +77,7 @@ timestamp_displaying_conv_msg(PurpleAccount *account, const char *who,
time_t now = time(NULL) / interval * interval;
time_t then;
- if (!g_list_find(purple_get_conversations(), conv))
+ if (!g_list_find((GList *)purple_get_conversations(), conv))
return FALSE;
then = GPOINTER_TO_INT(purple_conversation_get_data(
@@ -98,7 +98,7 @@ timestamp_new_convo(PurpleConversation *conv)
PidginConversation *gtk_conv = PIDGIN_CONVERSATION(conv);
GtkTextBuffer *buffer;
- if (!g_list_find(purple_get_conversations(), conv))
+ if (!g_list_find((GList *)purple_get_conversations(), conv))
return;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_conv->imhtml));
diff --git a/pidgin/plugins/xmppconsole.c b/pidgin/plugins/xmppconsole.c
index fb3684d7bf..03133ac1f3 100644
--- a/pidgin/plugins/xmppconsole.c
+++ b/pidgin/plugins/xmppconsole.c
@@ -29,6 +29,7 @@
#if !GTK_CHECK_VERSION(2,4,0)
#include "pidgincombobox.h"
#endif
+#include "gtkutils.h"
typedef struct {
PurpleConnection *gc;
@@ -730,7 +731,7 @@ create_console()
GtkWidget *label;
GtkTextBuffer *buffer;
GtkWidget *toolbar;
- GList *connections;
+ const GList *connections;
#if GTK_CHECK_VERSION(2,4,0)
GtkToolItem *button;
#endif
@@ -742,10 +743,8 @@ create_console()
console = g_new0(XmppConsole, 1);
- console->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(console->window), _("XMPP Console"));
+ console->window = pidgin_create_window(_("XMPP Console"), PIDGIN_HIG_BORDER, NULL, TRUE);
g_signal_connect(G_OBJECT(console->window), "destroy", G_CALLBACK(console_destroy), NULL);
- gtk_container_set_border_width(GTK_CONTAINER(console->window), 12);
gtk_window_set_default_size(GTK_WINDOW(console->window), 580, 400);
gtk_container_add(GTK_CONTAINER(console->window), vbox);