pidgin/purple-plugin-pack

Add the turtles target to keep the foot clan at bay
default tip
13 months ago, Gary Kramlich
63ad7e4f10b4
Add the turtles target to keep the foot clan at bay

Testing Done:
Ran `ninja turtles` and verified it worked correctly.

Reviewed at https://reviews.imfreedom.org/r/2409/
/*
* irssi - Implements several irssi features for Purple
* Copyright (C) 2005-2008 Gary Kramlich <grim@reaperworld.com>
* Copyright (C) 2006-2008 John Bailey <rekkanoryo@rekkanoryo.org>
* Copyright (C) 2006-2008 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02111-1301, USA.
*/
/* If you can't figure out what this line is for, DON'T TOUCH IT. */
#include "../common/pp_internal.h"
#include <blist.h>
#include <cmds.h>
#include <plugin.h>
#include <gtkblist.h>
#include <gtkconv.h>
#include "layout.h"
#define IRSSI_LAYOUT_SETTING "irssi::layout"
#define SETTING_TO_INTS(s, i1, i2) { \
(i1) = (s) & 0x3ff; \
(i2) = (s) >> 10; \
}
#define SETTING_FROM_INTS(i1, i2) (((i1) << 10 ) + (i2))
/******************************************************************************
* Globals
*****************************************************************************/
static PurpleCmdId irssi_layout_cmd_id = 0;
/******************************************************************************
* Helpers
*****************************************************************************/
static PurpleBlistNode *
irssi_layout_get_node_from_conv(PurpleConversation *conv) {
PurpleAccount *account = NULL;
PurpleBlistNode *node = NULL;
PurpleConversationType type = purple_conversation_get_type(conv);
const char *name = NULL;
account = purple_conversation_get_account(conv);
name = purple_conversation_get_name(conv);
/* this is overkill for now, but who knows, we _may_ need it later */
if(type == PURPLE_CONV_TYPE_CHAT)
node = (PurpleBlistNode *)purple_blist_find_chat(account, name);
else if(type == PURPLE_CONV_TYPE_IM)
node = (PurpleBlistNode *)purple_find_buddy(account, name);
return node;
}
static PurpleConversation *
irssi_layout_get_conv_from_node(PurpleBlistNode *node, gboolean create) {
PurpleAccount *account = NULL;
PurpleConversation *conv = NULL;
PurpleConversationType ctype = PURPLE_CONV_TYPE_UNKNOWN;
const gchar *name = NULL;
switch(node->type) {
case PURPLE_BLIST_CHAT_NODE: {
PurpleChat *chat = (PurpleChat *)node;
ctype = PURPLE_CONV_TYPE_CHAT;
name = purple_chat_get_name(chat);
account = chat->account;
break;
}
case PURPLE_BLIST_BUDDY_NODE: {
PurpleBuddy *buddy = (PurpleBuddy *)node;
ctype = PURPLE_CONV_TYPE_IM;
name = buddy->name;
account = buddy->account;
break;
}
default:
return NULL;
break;
}
conv = purple_find_conversation_with_account(ctype, name, account);
if(!conv && create) {
conv = purple_conversation_new(ctype, account, name);
/* dirty hack alert! */
if(ctype == (PurpleConversationType)PURPLE_BLIST_CHAT_NODE) {
PurpleChat *chat = (PurpleChat *)node;
purple_conv_chat_left(PURPLE_CONV_CHAT(conv));
serv_join_chat(account->gc, chat->components);
}
}
return conv;
}
static gint
irssi_layout_get_setting(PidginConversation *gtkconv) {
PurpleConversation *conv = gtkconv->active_conv;
PurpleBlistNode *node = NULL;
gint ret = 0;
node = irssi_layout_get_node_from_conv(conv);
if(node)
ret = purple_blist_node_get_int(node, IRSSI_LAYOUT_SETTING);
return ret;
}
static void
irssi_layout_reset(void) {
PurpleBlistNode *node = purple_blist_get_root();
for(; node; node = purple_blist_node_next(node, TRUE))
purple_blist_node_remove_setting(node, IRSSI_LAYOUT_SETTING);
}
static void
irssi_layout_save(void) {
PurpleBlistNode *node = NULL;
GList *wins = NULL;
gint i, j;
/* reset the previous layouts if any exist */
irssi_layout_reset();
/* now save the layout... */
wins = pidgin_conv_windows_get_list();
for(i = 1; wins; wins = wins->next, i++) {
PidginWindow *win = wins->data;
GList *convs = pidgin_conv_window_get_gtkconvs(win);
for(j = 1; convs; convs = convs->next, j++) {
PidginConversation *gtkconv = convs->data;
PurpleConversation *conv = gtkconv->active_conv;
node = irssi_layout_get_node_from_conv(conv);
if(node)
purple_blist_node_set_int(node, IRSSI_LAYOUT_SETTING,
SETTING_FROM_INTS(i, j));
}
}
}
static void
irssi_layout_load(void) {
PurpleConversation *conv = NULL;
PurpleBlistNode *node;
PidginConversation *gtkconv = NULL;
PidginWindow *window = NULL;
GList *convs = NULL, *settings = NULL, *wins = NULL;
gint current = 1;
node = purple_blist_get_root();
/* build our GList's with the conversation and the setting */
for(; node; node = purple_blist_node_next(node, FALSE)) {
gint setting = purple_blist_node_get_int(node, IRSSI_LAYOUT_SETTING);
if(setting == 0)
continue;
conv = irssi_layout_get_conv_from_node(node, FALSE);
if(conv) {
convs = g_list_prepend(convs, conv);
settings = g_list_prepend(settings, GINT_TO_POINTER(setting));
}
}
/* now restore the layout */
/* we start by looping until all of our settings are handled */
while(convs) {
GList *l1 = NULL, *l2 = NULL;
/* now go through the list and make sure we put the conversations in
* the correct windows.
*/
for(l1 = convs, l2 = settings; l1; ) {
GList *s = NULL;
gint win, pos, setting;
/* this is a junk var needed for the horrible macro below */
(void)pos;
setting = GPOINTER_TO_INT(l2->data);
SETTING_TO_INTS(setting, pos, win);
if(win != current)
continue;
conv = l1->data;
gtkconv = PIDGIN_CONVERSATION(conv);
/* pop of the nodes we just handled but hold our places and update
* the head pointers.
*/
/* convs */
s = l1;
l1 = l1->next;
convs = g_list_delete_link(convs, s);
/* settings */
s = l2;
l2 = l2->next;
settings = g_list_delete_link(settings, s);
/* now find the actual window this should go into */
wins = pidgin_conv_windows_get_list();
window = g_list_nth_data(wins, win - 1);
if(!window) {
/* make dat der dun winda */
window = pidgin_conv_window_new();
}
/* add the conversation to the window */
if(gtkconv->win != window) {
pidgin_conv_window_remove_gtkconv(gtkconv->win, gtkconv);
pidgin_conv_window_add_gtkconv(window, gtkconv);
}
}
current++;
}
/* All the conversations are in the correct windows. Now we make sure
* they're in their right positions.
*/
for(wins = pidgin_conv_windows_get_list(); wins; wins = wins->next) {
gint count, i, pos, position;
gint w; /* junk var */
(void)w;
window = wins->data;
count = pidgin_conv_window_get_gtkconv_count(window);
if(count <= 1)
continue;
for(position = 1; position < count; position++) {
gtkconv = pidgin_conv_window_get_gtkconv_at_index(window, position);
pos = irssi_layout_get_setting(gtkconv);
SETTING_TO_INTS(pos, pos, w);
if(pos <= 0)
continue;
/* this could probably use tweaking, but it _should_ work */
for(i = pos; i < position; i++) {
PidginConversation *gtkconv2 = NULL;
gint p;
gtkconv2 =
pidgin_conv_window_get_gtkconv_at_index(window, i);
p = irssi_layout_get_setting(gtkconv2);
if(p <= 0 || p <= pos)
continue;
gtk_notebook_reorder_child(GTK_NOTEBOOK(window->notebook),
gtkconv->tab_cont, i);
}
}
}
}
static PurpleCmdRet
irssi_layout_cmd_cb(PurpleConversation *conv, const gchar *cmd, gchar **args,
gchar **error, void *data)
{
const gchar *sub_cmd = args[0];
if(!g_ascii_strcasecmp(sub_cmd, "load")) {
irssi_layout_load();
} else if(!g_ascii_strcasecmp(sub_cmd, "save")) {
irssi_layout_save();
} else if(!g_ascii_strcasecmp(sub_cmd, "reset")) {
irssi_layout_reset();
}
return PURPLE_CMD_RET_OK;
}
/******************************************************************************
* "API"
*****************************************************************************/
void
irssi_layout_init(PurplePlugin *plugin) {
const gchar *help;
if(irssi_layout_cmd_id != 0)
return;
/*
* XXX: Translators: DO NOT TRANSLATE the first "layout" or the "\nsave"
* or "reset" at the beginning of the last line below, or the HTML tags.
*/
help = _("<pre>layout &lt;save|reset&gt;: Remember the layout of the "
"current conversations to reopen them when Purple is restarted.\n"
"save - saves the current layout\n"
"reset - clears the current saved layout\n"
"</pre>");
irssi_layout_cmd_id =
purple_cmd_register("layout", "w", PURPLE_CMD_P_PLUGIN,
PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT, NULL,
PURPLE_CMD_FUNC(irssi_layout_cmd_cb), help, NULL);
}
void
irssi_layout_uninit(PurplePlugin *plugin) {
if(irssi_layout_cmd_id == 0)
return;
purple_cmd_unregister(irssi_layout_cmd_id);
}