pidgin/purple-plugin-pack
Clone
Summary
Browse
Changes
Graph
fixed warnings in splitter
2013-04-07, Gary Kramlich
cca84690a1cb
fixed warnings in splitter
/*
* Stocker - Adds a stock ticker to the buddy list
* Copyright (C) 2005-2008 Gary Kramlich <grim@reaperworld.com>
*
* 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
<gdk/gdk.h>
#include
<gtk/gtk.h>
#include
<gtkplugin.h>
#include
<gtkprefs.h>
#include
<gtkblist.h>
#include
<gtkutils.h>
#include
<prefs.h>
#include
"gtkticker.h"
#include
"stocker_prefs.h"
#define URL_REQUEST "http:
//quotewebvip-m01.blue.aol.com/?action=aim&syms=%s&fields=nspg"
#define CHANGE_INCREASE "<span color=\"green3\">%+0.04g</span>"
#define CHANGE_DECREASE "<span color=\"red\">%+0.04g</span>"
#define CHANGE_NONE "%0.04g"
/******************************************************************************
* structs
*****************************************************************************/
#define STOCKER_QUOTE(obj) ((StockerQuote *)(obj))
typedef
struct
{
gchar
*
symbol
;
GtkWidget
*
label
;
guint
ref
;
}
StockerQuote
;
/******************************************************************************
* globals
*****************************************************************************/
static
GtkWidget
*
ticker
=
NULL
;
static
GHashTable
*
quotes
=
NULL
;
static
guint
quotes_id
=
0
,
interval_id
=
0
,
interval_timer
=
0
;
/******************************************************************************
* Quote stuff
*****************************************************************************/
static
StockerQuote
*
stocker_quote_new
(
const
gchar
*
symbol
)
{
StockerQuote
*
ret
=
g_new0
(
StockerQuote
,
1
);
gchar
*
label
=
NULL
;
ret
->
symbol
=
g_strdup
(
symbol
);
label
=
g_strdup_printf
(
"%s (refreshing)"
,
symbol
);
ret
->
label
=
gtk_label_new
(
label
);
g_free
(
label
);
gtk_ticker_add
(
GTK_TICKER
(
ticker
),
ret
->
label
);
gtk_widget_show
(
ret
->
label
);
ret
->
ref
=
1
;
return
ret
;
}
static
void
stocker_quote_ref
(
StockerQuote
*
quote
)
{
quote
->
ref
++
;
}
static
void
stocker_quote_unref
(
StockerQuote
*
quote
)
{
quote
->
ref
--
;
if
(
quote
->
ref
!=
0
)
return
;
g_free
(
quote
->
symbol
);
gtk_widget_destroy
(
quote
->
label
);
g_free
(
quote
);
quote
=
NULL
;
}
static
void
stocker_quote_update
(
StockerQuote
*
quote
,
const
gchar
*
name
,
gdouble
current
,
gdouble
change
)
{
GString
*
str
=
g_string_sized_new
(
512
);
g_string_append_printf
(
str
,
"<span weight=
\"
bold
\"
>%s</span> "
"<span size=
\"
small
\"
>(%s)</span> $%g "
,
name
,
quote
->
symbol
,
current
);
if
(
change
<
0.0
)
g_string_append_printf
(
str
,
CHANGE_DECREASE
,
change
);
else
if
(
change
>
0.0
)
g_string_append_printf
(
str
,
CHANGE_INCREASE
,
change
);
else
g_string_append_printf
(
str
,
CHANGE_NONE
,
change
);
gtk_label_set_markup
(
GTK_LABEL
(
quote
->
label
),
str
->
str
);
g_string_free
(
str
,
TRUE
);
}
/******************************************************************************
* main stuff
*****************************************************************************/
static
void
stocker_refresh_url_cb
(
PurpleUtilFetchUrlData
*
url_data
,
gpointer
data
,
const
gchar
*
text
,
gsize
len
,
const
gchar
*
errmsg
)
{
const
gchar
*
p
=
text
;
gchar
*
t
;
while
((
p
=
g_strstr_len
(
p
,
strlen
(
p
),
"DATA="
)))
{
const
gchar
*
name
=
NULL
,
*
symbol
=
NULL
;
gdouble
current
=
0.0
,
change
=
0.0
;
/* move paste the data text */
p
+=
5
;
/* find the name */
t
=
strchr
(
p
,
';'
);
*
t
=
'\0'
;
name
=
p
;
/* find the symbol */
p
=
t
+
1
;
t
=
strchr
(
p
,
';'
);
*
t
=
'\0'
;
symbol
=
p
;
/* find the current price */
p
=
t
+
1
;
t
=
strchr
(
p
,
';'
);
*
t
=
'\0'
;
current
=
atof
(
p
);
/* find the change */
p
=
t
+
1
;
t
=
strchr
(
p
,
'\r'
);
*
t
=
'\0'
;
change
=
atof
(
p
);
/* now move p to the EOL */
p
=
t
+
1
;
if
(
symbol
)
{
StockerQuote
*
quote
=
g_hash_table_lookup
(
quotes
,
symbol
);
if
(
quote
)
{
stocker_quote_update
(
quote
,
name
,
current
,
change
);
}
}
}
}
static
void
stocker_refresh_helper
(
gpointer
k
,
gpointer
v
,
gpointer
d
)
{
GString
*
str
=
(
GString
*
)
d
;
gchar
*
symbol
=
(
gchar
*
)
k
;
g_string_append_printf
(
str
,
"%s%s"
,
(
str
->
len
>
0
)
?
","
:
""
,
symbol
);
}
static
void
stocker_refresh
(
void
)
{
GString
*
syms
=
g_string_sized_new
(
64
);
gchar
*
url
=
NULL
;
g_hash_table_foreach
(
quotes
,
stocker_refresh_helper
,
syms
);
url
=
g_strdup_printf
(
URL_REQUEST
,
syms
->
str
);
g_string_free
(
syms
,
TRUE
);
purple_util_fetch_url
(
url
,
TRUE
,
"purple"
,
TRUE
,
stocker_refresh_url_cb
,
NULL
);
g_free
(
url
);
}
static
gboolean
stocker_create
()
{
PurpleBuddyList
*
blist
;
PidginBuddyList
*
gtkblist
;
if
(
GTK_IS_WIDGET
(
ticker
))
gtk_widget_destroy
(
ticker
);
blist
=
purple_get_blist
();
if
(
!
blist
)
return
FALSE
;
gtkblist
=
PIDGIN_BLIST
(
blist
);
ticker
=
gtk_ticker_new
();
gtk_box_pack_start
(
GTK_BOX
(
gtkblist
->
vbox
),
ticker
,
FALSE
,
FALSE
,
0
);
gtk_ticker_set_spacing
(
GTK_TICKER
(
ticker
),
16
);
gtk_ticker_start_scroll
(
GTK_TICKER
(
ticker
));
gtk_widget_show_all
(
ticker
);
return
TRUE
;
}
static
void
stocker_blist_created
(
PurpleBuddyList
*
blist
,
gpointer
data
)
{
stocker_create
();
}
static
void
stocker_quotes_refresh
(
GList
*
symbols
)
{
StockerQuote
*
quote
=
NULL
;
GHashTable
*
new_quotes
=
NULL
,
*
temp
=
NULL
;
GList
*
l
=
NULL
;
/* this is a bit more complicated than I'd like, but we need a way to be
* able to remove quotes that we don't know by name. So we create a new
* hashtable, copy all the existing quotes over to it, add the new ones,
* then delete the old table and use the new one.
*/
new_quotes
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
stocker_quote_unref
);
for
(
l
=
symbols
;
l
;
l
=
l
->
next
)
{
gchar
*
symbol
=
l
->
data
;
/* sanity check to make sure we have a symbol */
if
(
!
symbol
)
continue
;
/* look for a quote */
quote
=
g_hash_table_lookup
(
quotes
,
symbol
);
if
(
quote
)
{
/* ref the quote so it stays alive */
stocker_quote_ref
(
quote
);
}
else
{
/* this is a new symbol, create a quote for it */
quote
=
stocker_quote_new
(
symbol
);
}
/* insert the quote into the new hashtable */
g_hash_table_insert
(
new_quotes
,
g_strdup
(
symbol
),
quote
);
}
/* hold onto the old pointer */
temp
=
quotes
;
/* update the pointer to the updated list */
quotes
=
new_quotes
;
/* kill the old table */
g_hash_table_destroy
(
temp
);
/* refresh everything */
stocker_refresh
();
}
static
void
stocker_quotes_changed_cb
(
const
gchar
*
name
,
PurplePrefType
type
,
gconstpointer
value
,
gpointer
data
)
{
stocker_quotes_refresh
((
GList
*
)
value
);
}
static
gboolean
stocker_refresh_cb
(
gpointer
data
)
{
stocker_refresh
();
return
TRUE
;
}
static
void
stocker_interval_changed_cb
(
const
gchar
*
name
,
PurplePrefType
type
,
gconstpointer
value
,
gpointer
data
)
{
gint
new_time
=
GPOINTER_TO_INT
(
value
);
/* remove the old timer */
purple_timeout_remove
(
interval_timer
);
/* add the new one */
interval_timer
=
purple_timeout_add_seconds
(
new_time
*
60
,
stocker_refresh_cb
,
NULL
);
}
/******************************************************************************
* plugin crap
*****************************************************************************/
static
gboolean
stocker_load
(
PurplePlugin
*
plugin
)
{
void
*
prefs_handle
=
purple_prefs_get_handle
();
gint
interval
;
stocker_create
();
quotes
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
stocker_quote_unref
);
purple_signal_connect
(
pidgin_blist_get_handle
(),
"gtkblist-created"
,
plugin
,
PURPLE_CALLBACK
(
stocker_blist_created
),
NULL
);
quotes_id
=
purple_prefs_connect_callback
(
prefs_handle
,
PREF_SYMBOLS
,
stocker_quotes_changed_cb
,
NULL
);
interval_id
=
purple_prefs_connect_callback
(
prefs_handle
,
PREF_INTERVAL
,
stocker_interval_changed_cb
,
NULL
);
interval
=
60
*
purple_prefs_get_int
(
PREF_INTERVAL
);
interval_timer
=
purple_timeout_add_seconds
(
interval
,
stocker_refresh_cb
,
NULL
);
stocker_quotes_refresh
(
purple_prefs_get_string_list
(
PREF_SYMBOLS
));
stocker_refresh
();
return
TRUE
;
}
static
gboolean
stocker_unload
(
PurplePlugin
*
plugin
)
{
return
FALSE
;
}
static
void
stocker_destroy
(
PurplePlugin
*
plugin
)
{
purple_timeout_remove
(
interval_timer
);
if
(
GTK_IS_WIDGET
(
ticker
))
gtk_widget_destroy
(
ticker
);
ticker
=
NULL
;
}
static
PidginPluginUiInfo
stocker_ui_info
=
{
stocker_prefs_get_frame
};
static
PurplePluginInfo
stocker_info
=
{
PURPLE_PLUGIN_MAGIC
,
PURPLE_MAJOR_VERSION
,
PURPLE_MINOR_VERSION
,
PURPLE_PLUGIN_STANDARD
,
PIDGIN_PLUGIN_TYPE
,
0
,
NULL
,
PURPLE_PRIORITY_DEFAULT
,
"gtk-plugin_pack-stocker"
,
NULL
,
PP_VERSION
,
NULL
,
NULL
,
"Gary Kramlich <grim@reaperworld.com>"
,
PP_WEBSITE
,
stocker_load
,
stocker_unload
,
stocker_destroy
,
&
stocker_ui_info
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
};
static
void
stocker_init
(
PurplePlugin
*
plugin
)
{
#ifdef ENABLE_NLS
bindtextdomain
(
GETTEXT_PACKAGE
,
PP_LOCALEDIR
);
bind_textdomain_codeset
(
GETTEXT_PACKAGE
,
"UTF-8"
);
#endif
/* ENABLE_NLS */
stocker_info
.
name
=
_
(
"Stocker"
);
stocker_info
.
summary
=
_
(
"A stock ticker"
);
stocker_info
.
description
=
_
(
"Adds a stock ticker similar to the one in the Windows AIM client to"
" the bottom of the buddy list."
);
stocker_prefs_init
();
}
PURPLE_INIT_PLUGIN
(
stocker
,
stocker_init
,
stocker_info
)