pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Update yahoo for the GResolver migration
use-gresolver
2015-12-18, Gary Kramlich
13c3a5bb74d8
Update yahoo for the GResolver migration
/*
* PidginConvThemeLoader for Pidgin
*
* Pidgin 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 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
"pidgin.h"
#include
"gtkconv-theme-loader.h"
#include
"gtkconv-theme.h"
#include
"xmlnode.h"
#include
"debug.h"
#include
"prefs.h"
/*****************************************************************************
* Conversation Theme Builder
*****************************************************************************/
static
GHashTable
*
read_info_plist
(
PurpleXmlNode
*
plist
)
{
GHashTable
*
info
;
PurpleXmlNode
*
key
,
*
value
;
gboolean
fail
=
FALSE
;
info
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
g_free
);
for
(
key
=
purple_xmlnode_get_child
(
plist
,
"dict/key"
);
key
;
key
=
purple_xmlnode_get_next_twin
(
key
))
{
char
*
keyname
;
GValue
*
val
;
;
for
(
value
=
key
->
next
;
value
&&
value
->
type
!=
PURPLE_XMLNODE_TYPE_TAG
;
value
=
value
->
next
)
;
if
(
!
value
)
{
fail
=
TRUE
;
break
;
}
val
=
g_new0
(
GValue
,
1
);
if
(
g_str_equal
(
value
->
name
,
"string"
))
{
g_value_init
(
val
,
G_TYPE_STRING
);
g_value_take_string
(
val
,
purple_xmlnode_get_data_unescaped
(
value
));
}
else
if
(
g_str_equal
(
value
->
name
,
"true"
))
{
g_value_init
(
val
,
G_TYPE_BOOLEAN
);
g_value_set_boolean
(
val
,
TRUE
);
}
else
if
(
g_str_equal
(
value
->
name
,
"false"
))
{
g_value_init
(
val
,
G_TYPE_BOOLEAN
);
g_value_set_boolean
(
val
,
FALSE
);
}
else
if
(
g_str_equal
(
value
->
name
,
"real"
))
{
char
*
temp
=
purple_xmlnode_get_data_unescaped
(
value
);
g_value_init
(
val
,
G_TYPE_FLOAT
);
g_value_set_float
(
val
,
atof
(
temp
));
g_free
(
temp
);
}
else
if
(
g_str_equal
(
value
->
name
,
"integer"
))
{
char
*
temp
=
purple_xmlnode_get_data_unescaped
(
value
);
g_value_init
(
val
,
G_TYPE_INT
);
g_value_set_int
(
val
,
atoi
(
temp
));
g_free
(
temp
);
}
else
{
/* NOTE: We don't support array, data, date, or dict as values,
since they don't seem to be needed for styles. */
g_free
(
val
);
fail
=
TRUE
;
break
;
}
keyname
=
purple_xmlnode_get_data_unescaped
(
key
);
g_hash_table_insert
(
info
,
keyname
,
val
);
}
if
(
fail
)
{
g_hash_table_destroy
(
info
);
info
=
NULL
;
}
return
info
;
}
static
gboolean
pidgin_conv_loader_probe
(
const
gchar
*
dir
)
{
gboolean
result
;
gchar
*
plist_file
;
plist_file
=
g_build_filename
(
dir
,
"Contents"
,
"Info.plist"
,
NULL
);
result
=
g_file_test
(
plist_file
,
G_FILE_TEST_IS_REGULAR
);
g_free
(
plist_file
);
return
result
;
}
static
PurpleTheme
*
pidgin_conv_loader_build
(
const
gchar
*
dir
)
{
PidginConvTheme
*
theme
=
NULL
;
char
*
contents
;
PurpleXmlNode
*
plist
;
GHashTable
*
info
;
GValue
*
val
;
int
MessageViewVersion
;
const
char
*
CFBundleName
;
const
char
*
CFBundleIdentifier
;
GDir
*
variants
;
char
*
variant_dir
;
g_return_val_if_fail
(
dir
!=
NULL
,
NULL
);
/* Load Info.plist for theme information */
contents
=
g_build_filename
(
dir
,
"Contents"
,
NULL
);
plist
=
purple_xmlnode_from_file
(
contents
,
"Info.plist"
,
"Info.plist"
,
"gtkconv-theme-loader"
);
g_free
(
contents
);
if
(
plist
==
NULL
)
{
purple_debug_error
(
"gtkconv-theme-loader"
,
"Failed to load Contents/Info.plist in %s
\n
"
,
dir
);
return
NULL
;
}
info
=
read_info_plist
(
plist
);
purple_xmlnode_free
(
plist
);
if
(
info
==
NULL
)
{
purple_debug_error
(
"gtkconv-theme-loader"
,
"Failed to load Contents/Info.plist in %s
\n
"
,
dir
);
return
NULL
;
}
/* Check for required keys: CFBundleName */
val
=
g_hash_table_lookup
(
info
,
"CFBundleName"
);
if
(
!
val
||
!
G_VALUE_HOLDS_STRING
(
val
))
{
purple_debug_error
(
"gtkconv-theme-loader"
,
"%s/Contents/Info.plist missing required string key CFBundleName.
\n
"
,
dir
);
g_hash_table_destroy
(
info
);
return
NULL
;
}
CFBundleName
=
g_value_get_string
(
val
);
/* Check for required keys: CFBundleIdentifier */
val
=
g_hash_table_lookup
(
info
,
"CFBundleIdentifier"
);
if
(
!
val
||
!
G_VALUE_HOLDS_STRING
(
val
))
{
purple_debug_error
(
"gtkconv-theme-loader"
,
"%s/Contents/Info.plist missing required string key CFBundleIdentifier.
\n
"
,
dir
);
g_hash_table_destroy
(
info
);
return
NULL
;
}
CFBundleIdentifier
=
g_value_get_string
(
val
);
/* Check for required keys: MessageViewVersion */
val
=
g_hash_table_lookup
(
info
,
"MessageViewVersion"
);
if
(
!
val
||
!
G_VALUE_HOLDS_INT
(
val
))
{
purple_debug_error
(
"gtkconv-theme-loader"
,
"%s/Contents/Info.plist missing required integer key MessageViewVersion.
\n
"
,
dir
);
g_hash_table_destroy
(
info
);
return
NULL
;
}
MessageViewVersion
=
g_value_get_int
(
val
);
if
(
MessageViewVersion
<
3
)
{
purple_debug_error
(
"gtkconv-theme-loader"
,
"%s is a legacy style (version %d) and will not be loaded.
\n
"
,
CFBundleName
,
MessageViewVersion
);
g_hash_table_destroy
(
info
);
return
NULL
;
}
theme
=
g_object_new
(
PIDGIN_TYPE_CONV_THEME
,
"type"
,
"conversation"
,
"name"
,
CFBundleName
,
"directory"
,
dir
,
"info"
,
info
,
NULL
);
/* Read list of variants */
variant_dir
=
g_build_filename
(
dir
,
"Contents"
,
"Resources"
,
"Variants"
,
NULL
);
variants
=
g_dir_open
(
variant_dir
,
0
,
NULL
);
g_free
(
variant_dir
);
if
(
variants
)
{
char
*
prefname
;
const
char
*
default_variant
=
NULL
;
const
char
*
file
;
/* Make sure prefs exist */
prefname
=
g_strdup_printf
(
PIDGIN_PREFS_ROOT
"/conversations/themes/%s"
,
CFBundleIdentifier
);
purple_prefs_add_none
(
prefname
);
g_free
(
prefname
);
/* Try user-set variant */
prefname
=
g_strdup_printf
(
PIDGIN_PREFS_ROOT
"/conversations/themes/%s/variant"
,
CFBundleIdentifier
);
if
(
purple_prefs_exists
(
prefname
))
default_variant
=
purple_prefs_get_string
(
prefname
);
g_free
(
prefname
);
if
(
default_variant
&&
*
default_variant
)
{
pidgin_conversation_theme_set_variant
(
theme
,
default_variant
);
}
else
{
/* Try theme default */
val
=
g_hash_table_lookup
(
info
,
"DefaultVariant"
);
if
(
val
&&
G_VALUE_HOLDS_STRING
(
val
))
{
default_variant
=
g_value_get_string
(
val
);
if
(
default_variant
&&
*
default_variant
)
pidgin_conversation_theme_set_variant
(
theme
,
default_variant
);
else
default_variant
=
NULL
;
}
else
default_variant
=
NULL
;
}
while
((
file
=
g_dir_read_name
(
variants
))
!=
NULL
)
{
const
char
*
end
=
g_strrstr
(
file
,
".css"
);
char
*
name
;
if
((
end
==
NULL
)
||
(
*
(
end
+
4
)
!=
'\0'
))
continue
;
name
=
g_strndup
(
file
,
end
-
file
);
pidgin_conversation_theme_add_variant
(
theme
,
name
);
/* Set variant with first found */
if
(
!
default_variant
)
{
pidgin_conversation_theme_set_variant
(
theme
,
name
);
default_variant
=
name
;
}
}
g_dir_close
(
variants
);
}
return
PURPLE_THEME
(
theme
);
}
/******************************************************************************
* GObject Stuff
*****************************************************************************/
static
void
pidgin_conv_theme_loader_class_init
(
PidginConvThemeLoaderClass
*
klass
)
{
PurpleThemeLoaderClass
*
loader_klass
=
PURPLE_THEME_LOADER_CLASS
(
klass
);
loader_klass
->
purple_theme_loader_build
=
pidgin_conv_loader_build
;
loader_klass
->
probe_directory
=
pidgin_conv_loader_probe
;
}
GType
pidgin_conversation_theme_loader_get_type
(
void
)
{
static
GType
type
=
0
;
if
(
type
==
0
)
{
static
const
GTypeInfo
info
=
{
sizeof
(
PidginConvThemeLoaderClass
),
NULL
,
/* base_init */
NULL
,
/* base_finalize */
(
GClassInitFunc
)
pidgin_conv_theme_loader_class_init
,
/* class_init */
NULL
,
/* class_finalize */
NULL
,
/* class_data */
sizeof
(
PidginConvThemeLoader
),
0
,
/* n_preallocs */
NULL
,
/* instance_init */
NULL
,
/* value table */
};
type
=
g_type_register_static
(
PURPLE_TYPE_THEME_LOADER
,
"PidginConvThemeLoader"
,
&
info
,
0
);
}
return
type
;
}