grim/guifications2
Clone
Summary
Browse
Changes
Graph
well we compile somewhat successfully, but we don't load against 3.0.0-devel
2011-12-04, Gary Kramlich
3a8f4f41e93b
well we compile somewhat successfully, but we don't load against 3.0.0-devel
/*
* Guifications - The end all, be all, toaster popup plugin
* Copyright (C) 2003-2008 Gary Kramlich
*
* 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.
*/
#include
<glib.h>
#include
<gdk/gdk.h>
#include
<sys/stat.h>
#include
<sys/types.h>
#include
<string.h>
#include
<stdlib.h>
#ifdef HAVE_CONFIG_H
#
include
"../gf_config.h"
#endif
#include
"gf_internal.h"
#include
<debug.h>
#include
<util.h>
#include
<xmlnode.h>
#include
"gf_item.h"
#include
"gf_preferences.h"
#include
"gf_theme_info.h"
#include
"gf_theme_ops.h"
#include
"gf_utils.h"
struct
_GfTheme
{
gint
api_version
;
gchar
*
file
;
gchar
*
path
;
GfThemeInfo
*
info
;
GfThemeOptions
*
ops
;
GList
*
notifications
;
GfNotification
*
master
;
};
#include
"gf_theme.h"
static
GList
*
probed_themes
=
NULL
;
static
GList
*
loaded_themes
=
NULL
;
/***********************************************************************
* Loading, Unloading, Probing, and Finding ...
**********************************************************************/
GfTheme
*
gf_theme_new
()
{
GfTheme
*
theme
;
theme
=
g_new0
(
GfTheme
,
1
);
return
theme
;
}
GfTheme
*
gf_theme_new_from_file
(
const
gchar
*
filename
)
{
GfTheme
*
theme
;
gchar
*
contents
;
gint
api_version
;
gsize
length
;
xmlnode
*
root
,
*
parent
,
*
child
;
g_return_val_if_fail
(
filename
,
NULL
);
if
(
!
g_file_get_contents
(
filename
,
&
contents
,
&
length
,
NULL
))
{
purple_debug_info
(
"Guifications"
,
"** Error: failed to get file contents
\n
"
);
return
NULL
;
}
if
(
!
(
root
=
xmlnode_from_str
(
contents
,
length
)))
{
purple_debug_info
(
"Guifications"
,
"** Error: Could not parse file
\n
"
);
g_free
(
contents
);
return
NULL
;
}
g_free
(
contents
);
if
(
!
(
parent
=
xmlnode_get_child
(
root
,
"theme"
)))
{
purple_debug_info
(
"Guifications"
,
"** Error: No theme element found
\n
"
);
xmlnode_free
(
root
);
return
NULL
;
}
api_version
=
atoi
(
xmlnode_get_attrib
(
parent
,
"api"
));
if
(
api_version
!=
GF_THEME_API_VERSION
)
{
purple_debug_info
(
"Guifications"
,
"** Error: Theme API version mismatch
\n
"
);
xmlnode_free
(
root
);
return
NULL
;
}
/* allocate the theme */
theme
=
gf_theme_new
();
/* info to know */
theme
->
api_version
=
api_version
;
theme
->
file
=
g_strdup
(
filename
);
theme
->
path
=
g_path_get_dirname
(
filename
);
/* get the themes info */
if
(
!
(
child
=
xmlnode_get_child
(
parent
,
"info"
)))
{
purple_debug_info
(
"Guifications"
,
"** Error: No info element found
\n
"
);
gf_theme_unload
(
theme
);
xmlnode_free
(
root
);
return
NULL
;
}
if
(
!
(
theme
->
info
=
gf_theme_info_new_from_xmlnode
(
child
)))
{
purple_debug_info
(
"Guifications"
,
"** Error: could not load theme info
\n
"
);
gf_theme_unload
(
theme
);
xmlnode_free
(
root
);
return
NULL
;
}
/* get the themes options */
if
(
!
(
child
=
xmlnode_get_child
(
parent
,
"options"
)))
{
gf_theme_unload
(
theme
);
xmlnode_free
(
root
);
return
NULL
;
}
theme
->
ops
=
gf_theme_options_new_from_xmlnode
(
child
);
/* get all the notifications */
child
=
xmlnode_get_child
(
parent
,
"notification"
);
while
(
child
)
{
GfNotification
*
notification
;
notification
=
gf_notification_new_from_xmlnode
(
theme
,
child
);
if
(
notification
)
theme
->
notifications
=
g_list_append
(
theme
->
notifications
,
notification
);
child
=
xmlnode_get_next_twin
(
child
);
}
/* loading was successful free the xmlnode */
xmlnode_free
(
root
);
return
theme
;
}
GfTheme
*
gf_theme_find_theme_by_name
(
const
gchar
*
name
)
{
GfTheme
*
theme
;
GList
*
l
;
g_return_val_if_fail
(
name
,
NULL
);
for
(
l
=
loaded_themes
;
l
;
l
=
l
->
next
)
{
theme
=
GF_THEME
(
l
->
data
);
if
(
!
g_utf8_collate
(
gf_theme_info_get_name
(
theme
->
info
),
name
))
return
theme
;
}
return
NULL
;
}
GfTheme
*
gf_theme_find_theme_by_filename
(
const
gchar
*
filename
)
{
GfTheme
*
theme
;
GList
*
l
;
g_return_val_if_fail
(
filename
,
NULL
);
for
(
l
=
loaded_themes
;
l
;
l
=
l
->
next
)
{
theme
=
GF_THEME
(
l
->
data
);
if
(
!
g_ascii_strcasecmp
(
gf_theme_get_filename
(
theme
),
filename
))
return
theme
;
}
return
NULL
;
}
gchar
*
gf_theme_strip_name
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
NULL
);
return
gf_theme_info_strip_name
(
theme
->
info
);
}
gboolean
gf_theme_is_loaded
(
const
gchar
*
filename
)
{
GfTheme
*
theme
;
GList
*
l
;
g_return_val_if_fail
(
filename
,
FALSE
);
for
(
l
=
loaded_themes
;
l
;
l
=
l
->
next
)
{
theme
=
GF_THEME
(
l
->
data
);
if
(
!
g_ascii_strcasecmp
(
filename
,
theme
->
file
))
return
TRUE
;
}
return
FALSE
;
}
gboolean
gf_theme_is_probed
(
const
gchar
*
filename
)
{
g_return_val_if_fail
(
filename
,
FALSE
);
if
(
g_list_find_custom
(
probed_themes
,
filename
,
gf_utils_compare_strings
))
return
TRUE
;
else
return
FALSE
;
}
gboolean
gf_theme_save_to_file
(
GfTheme
*
theme
,
const
gchar
*
filename
)
{
GList
*
l
;
gchar
*
api
,
*
data
;
FILE
*
fp
=
NULL
;
xmlnode
*
root
,
*
parent
,
*
child
;
g_return_val_if_fail
(
theme
,
FALSE
);
g_return_val_if_fail
(
filename
,
FALSE
);
root
=
xmlnode_new
(
"guifications"
);
parent
=
xmlnode_new_child
(
root
,
"theme"
);
api
=
g_strdup_printf
(
"%d"
,
GF_THEME_API_VERSION
);
xmlnode_set_attrib
(
parent
,
"api"
,
api
);
g_free
(
api
);
if
((
child
=
gf_theme_info_to_xmlnode
(
theme
->
info
)))
xmlnode_insert_child
(
parent
,
child
);
if
((
child
=
gf_theme_options_to_xmlnode
(
theme
->
ops
)))
xmlnode_insert_child
(
parent
,
child
);
for
(
l
=
theme
->
notifications
;
l
;
l
=
l
->
next
)
{
if
((
child
=
gf_notification_to_xmlnode
(
GF_NOTIFICATION
(
l
->
data
))))
xmlnode_insert_child
(
parent
,
child
);
}
data
=
xmlnode_to_formatted_str
(
root
,
NULL
);
fp
=
g_fopen
(
filename
,
"wb"
);
if
(
!
fp
)
{
purple_debug_info
(
"guifications"
,
"Error trying to save theme %s
\n
"
,
filename
);
}
else
{
if
(
data
)
fprintf
(
fp
,
"%s"
,
data
);
fclose
(
fp
);
}
g_free
(
data
);
xmlnode_free
(
root
);
return
TRUE
;
}
void
gf_theme_destory
(
GfTheme
*
theme
)
{
GList
*
l
;
g_return_if_fail
(
theme
);
theme
->
api_version
=
0
;
if
(
theme
->
file
)
g_free
(
theme
->
file
);
if
(
theme
->
path
)
g_free
(
theme
->
path
);
if
(
theme
->
info
)
gf_theme_info_destroy
(
theme
->
info
);
if
(
theme
->
ops
)
gf_theme_options_destroy
(
theme
->
ops
);
for
(
l
=
theme
->
notifications
;
l
;
l
=
l
->
next
)
gf_notification_destroy
(
GF_NOTIFICATION
(
l
->
data
));
g_list_free
(
theme
->
notifications
);
theme
->
notifications
=
NULL
;
g_free
(
theme
);
theme
=
NULL
;
}
void
gf_theme_load
(
const
gchar
*
filename
)
{
GfTheme
*
theme
=
NULL
;
if
((
theme
=
gf_theme_new_from_file
(
filename
)))
loaded_themes
=
g_list_append
(
loaded_themes
,
theme
);
}
void
gf_theme_unload
(
GfTheme
*
theme
)
{
g_return_if_fail
(
theme
);
loaded_themes
=
g_list_remove
(
loaded_themes
,
theme
);
gf_theme_destory
(
theme
);
}
void
gf_theme_probe
(
const
gchar
*
filename
)
{
GfTheme
*
theme
;
gboolean
loaded
;
g_return_if_fail
(
filename
);
loaded
=
gf_theme_is_loaded
(
filename
);
if
(
gf_theme_is_probed
(
filename
))
gf_theme_unprobe
(
filename
);
if
(
loaded
)
gf_theme_unload
(
gf_theme_find_theme_by_filename
(
filename
));
theme
=
gf_theme_new_from_file
(
filename
);
if
(
theme
)
{
probed_themes
=
g_list_append
(
probed_themes
,
g_strdup
(
filename
));
if
(
loaded
)
loaded_themes
=
g_list_append
(
loaded_themes
,
theme
);
else
gf_theme_destory
(
theme
);
}
}
void
gf_themes_probe
()
{
GDir
*
dir
;
gchar
*
path
=
NULL
,
*
probe_dirs
[
3
];
const
gchar
*
file
;
gint
i
;
probe_dirs
[
0
]
=
g_build_filename
(
DATADIR
,
"pixmaps"
,
"pidgin"
,
"guifications"
,
"themes"
,
NULL
);
probe_dirs
[
1
]
=
g_build_filename
(
purple_user_dir
(),
"guifications"
,
"themes"
,
NULL
);
probe_dirs
[
2
]
=
NULL
;
for
(
i
=
0
;
probe_dirs
[
i
];
i
++
)
{
dir
=
g_dir_open
(
probe_dirs
[
i
],
0
,
NULL
);
if
(
dir
)
{
while
((
file
=
g_dir_read_name
(
dir
)))
{
/* disallow themes in hidden dirs */
if
(
file
[
0
]
==
'.'
)
continue
;
path
=
g_build_filename
(
probe_dirs
[
i
],
file
,
"theme.xml"
,
NULL
);
if
(
path
)
{
if
(
g_file_test
(
path
,
G_FILE_TEST_EXISTS
))
{
purple_debug_info
(
"Guifications"
,
"Probing %s
\n
"
,
path
);
gf_theme_probe
(
path
);
}
g_free
(
path
);
}
}
g_dir_close
(
dir
);
}
else
if
(
i
==
1
)
{
/* if the user theme dir doesn't exist, create it */
purple_build_dir
(
probe_dirs
[
i
],
S_IRUSR
|
S_IWUSR
|
S_IXUSR
);
}
g_free
(
probe_dirs
[
i
]);
}
}
void
gf_theme_unprobe
(
const
gchar
*
filename
)
{
GList
*
l
,
*
ll
;
gchar
*
file
;
g_return_if_fail
(
filename
);
for
(
l
=
probed_themes
;
l
;
l
=
ll
)
{
ll
=
l
->
next
;
file
=
(
gchar
*
)
l
->
data
;
if
(
!
g_ascii_strcasecmp
(
file
,
filename
))
{
probed_themes
=
g_list_remove
(
probed_themes
,
file
);
g_free
(
file
);
}
}
}
void
gf_themes_unprobe
()
{
GList
*
l
;
gchar
*
file
;
for
(
l
=
probed_themes
;
l
;
l
=
l
->
next
)
{
if
((
file
=
(
gchar
*
)
l
->
data
))
{
purple_debug_info
(
"Guifications"
,
"unprobing %s
\n
"
,
file
);
g_free
(
file
);
}
}
if
(
probed_themes
)
g_list_free
(
probed_themes
);
probed_themes
=
NULL
;
}
/*******************************************************************************
* Theme API
******************************************************************************/
gint
gf_theme_get_api_version
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
-1
);
return
theme
->
api_version
;
}
const
gchar
*
gf_theme_get_filename
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
NULL
);
return
theme
->
file
;
}
const
gchar
*
gf_theme_get_path
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
NULL
);
return
theme
->
path
;
}
GfNotification
*
gf_theme_get_master
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
NULL
);
return
theme
->
master
;
}
void
gf_theme_set_master
(
GfTheme
*
theme
,
GfNotification
*
notification
)
{
g_return_if_fail
(
theme
);
g_return_if_fail
(
notification
);
theme
->
master
=
notification
;
}
static
void
gf_theme_get_supported_func
(
gpointer
key
,
gpointer
val
,
gpointer
data
)
{
GString
*
str
=
data
;
gchar
*
type
=
key
;
gint
value
=
GPOINTER_TO_INT
(
val
);
if
(
strlen
(
str
->
str
)
!=
0
)
str
=
g_string_append
(
str
,
", "
);
str
=
g_string_append
(
str
,
type
);
if
(
value
>
1
)
g_string_append_printf
(
str
,
" (%d)"
,
value
);
}
gchar
*
gf_theme_get_supported_notifications
(
GfTheme
*
theme
)
{
GfNotification
*
notification
;
GHashTable
*
table
;
GList
*
l
;
GString
*
str
;
const
gchar
*
type
;
gchar
*
ret
;
gint
value
;
gpointer
pvalue
;
g_return_val_if_fail
(
theme
,
NULL
);
table
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
for
(
l
=
theme
->
notifications
;
l
;
l
=
l
->
next
)
{
notification
=
GF_NOTIFICATION
(
l
->
data
);
type
=
gf_notification_get_type
(
notification
);
if
(
type
&&
type
[
0
]
==
'!'
)
continue
;
pvalue
=
g_hash_table_lookup
(
table
,
type
);
if
(
pvalue
)
value
=
GPOINTER_TO_INT
(
pvalue
)
+
1
;
else
value
=
1
;
g_hash_table_replace
(
table
,
(
gpointer
)
type
,
GINT_TO_POINTER
(
value
));
}
str
=
g_string_new
(
""
);
g_hash_table_foreach
(
table
,
gf_theme_get_supported_func
,
str
);
g_hash_table_destroy
(
table
);
ret
=
str
->
str
;
g_string_free
(
str
,
FALSE
);
return
ret
;
}
void
gf_theme_set_theme_info
(
GfTheme
*
theme
,
GfThemeInfo
*
info
)
{
g_return_if_fail
(
theme
);
g_return_if_fail
(
info
);
if
(
theme
->
info
)
gf_theme_info_destroy
(
theme
->
info
);
theme
->
info
=
info
;
}
GfThemeInfo
*
gf_theme_get_theme_info
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
NULL
);
return
theme
->
info
;
}
void
gf_theme_set_theme_options
(
GfTheme
*
theme
,
GfThemeOptions
*
ops
)
{
g_return_if_fail
(
theme
);
g_return_if_fail
(
ops
);
if
(
theme
->
ops
)
gf_theme_options_destroy
(
theme
->
ops
);
theme
->
ops
=
ops
;
}
GfThemeOptions
*
gf_theme_get_theme_options
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
NULL
);
return
theme
->
ops
;
}
void
gf_theme_add_notification
(
GfTheme
*
theme
,
GfNotification
*
notification
)
{
const
gchar
*
type
=
NULL
;
g_return_if_fail
(
theme
);
g_return_if_fail
(
notification
);
type
=
gf_notification_get_type
(
notification
);
if
(
!
g_utf8_collate
(
GF_NOTIFICATION_MASTER
,
type
))
{
if
(
theme
->
master
)
{
const
gchar
*
name
=
NULL
;
name
=
gf_theme_info_get_name
(
theme
->
info
);
purple_debug_info
(
"Guifications"
,
"Theme %s already has a master notification
\n
"
,
name
?
name
:
"(NULL)"
);
return
;
}
else
{
theme
->
master
=
notification
;
}
}
theme
->
notifications
=
g_list_append
(
theme
->
notifications
,
notification
);
}
void
gf_theme_remove_notification
(
GfTheme
*
theme
,
GfNotification
*
notification
)
{
const
gchar
*
type
=
NULL
;
g_return_if_fail
(
theme
);
g_return_if_fail
(
notification
);
type
=
gf_notification_get_type
(
notification
);
if
(
!
g_utf8_collate
(
GF_NOTIFICATION_MASTER
,
type
))
{
purple_debug_info
(
"Guifications"
,
"Master notifications can not be removed
\n
"
);
return
;
}
theme
->
notifications
=
g_list_remove
(
theme
->
notifications
,
notification
);
}
GList
*
gf_theme_get_notifications
(
GfTheme
*
theme
)
{
g_return_val_if_fail
(
theme
,
NULL
);
return
theme
->
notifications
;
}
GList
*
gf_themes_get_all
()
{
return
probed_themes
;
}
GList
*
gf_themes_get_loaded
()
{
return
loaded_themes
;
}
void
gf_themes_unload
()
{
GfTheme
*
theme
;
GList
*
l
=
NULL
,
*
ll
=
NULL
;
for
(
l
=
loaded_themes
;
l
;
l
=
ll
)
{
ll
=
l
->
next
;
theme
=
GF_THEME
(
l
->
data
);
if
(
theme
)
{
gf_theme_unload
(
theme
);
theme
=
NULL
;
}
}
g_list_free
(
loaded_themes
);
loaded_themes
=
NULL
;
}
void
gf_themes_save_loaded
()
{
GfTheme
*
theme
;
GList
*
l
=
NULL
,
*
s
=
NULL
;
for
(
l
=
loaded_themes
;
l
;
l
=
l
->
next
)
{
theme
=
GF_THEME
(
l
->
data
);
if
(
theme
)
s
=
g_list_append
(
s
,
theme
->
file
);
}
purple_prefs_set_string_list
(
GF_PREF_LOADED_THEMES
,
s
);
g_list_free
(
s
);
}
void
gf_themes_load_saved
(){
GList
*
s
,
*
l
;
gchar
*
filename
=
NULL
;
for
(
l
=
s
=
purple_prefs_get_string_list
(
GF_PREF_LOADED_THEMES
);
s
;
s
=
s
->
next
)
{
filename
=
(
gchar
*
)
s
->
data
;
if
(
gf_theme_is_probed
(
filename
))
gf_theme_load
(
filename
);
g_free
(
filename
);
}
g_list_free
(
l
);
}