grim/guifications2
Clone
Summary
Browse
Changes
Graph
Changelog recent changes.
org.guifications.gf2
2007-12-15, John Bailey
805b2801bf8a
Changelog recent changes.
/*
* Guifications - The end all, be all, toaster popup plugin
* Copyright (C) 2003-2005 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
<stdlib.h>
#include
<glib.h>
#include
<gdk/gdk.h>
#include
<debug.h>
#include
<xmlnode.h>
#include
"gf_event_info.h"
#include
"gf_gtk_utils.h"
#include
"gf_item.h"
#include
"gf_notification.h"
#include
"gf_preferences.h"
#include
"gf_theme.h"
#include
"gf_theme_ops.h"
#include
"gf_utils.h"
struct
_GfNotification
{
GfTheme
*
theme
;
gchar
*
n_type
;
gchar
*
alias
;
gboolean
use_gtk
;
gchar
*
background
;
gint
width
;
gint
height
;
GList
*
items
;
};
/*******************************************************************************
* API
******************************************************************************/
GfNotification
*
gf_notification_new
(
GfTheme
*
theme
)
{
GfNotification
*
notification
;
g_return_val_if_fail
(
theme
,
NULL
);
notification
=
g_new0
(
GfNotification
,
1
);
notification
->
theme
=
theme
;
notification
->
use_gtk
=
TRUE
;
notification
->
height
=
140
;
notification
->
width
=
120
;
return
notification
;
}
GfNotification
*
gf_notification_new_from_xmlnode
(
GfTheme
*
theme
,
xmlnode
*
node
)
{
GfNotification
*
notification
;
GfItem
*
item
;
xmlnode
*
child
;
const
gchar
*
data
;
g_return_val_if_fail
(
theme
,
NULL
);
g_return_val_if_fail
(
node
,
NULL
);
notification
=
gf_notification_new
(
theme
);
notification
->
n_type
=
g_strdup
(
xmlnode_get_attrib
(
node
,
"type"
));
if
(
!
notification
->
n_type
)
{
purple_debug_info
(
"Guifications"
,
"** Error: Notification type unknown
\n
"
);
gf_notification_destroy
(
notification
);
return
NULL
;
}
if
(
!
g_utf8_collate
(
notification
->
n_type
,
GF_NOTIFICATION_MASTER
))
gf_theme_set_master
(
theme
,
notification
);
data
=
xmlnode_get_attrib
(
node
,
"use_gtk"
);
if
(
data
)
notification
->
use_gtk
=
atoi
(
data
);
data
=
xmlnode_get_attrib
(
node
,
"background"
);
if
(
data
)
notification
->
background
=
g_strdup
(
data
);
data
=
xmlnode_get_attrib
(
node
,
"width"
);
if
(
data
)
notification
->
width
=
atoi
(
data
);
data
=
xmlnode_get_attrib
(
node
,
"height"
);
if
(
data
)
notification
->
height
=
atoi
(
data
);
data
=
xmlnode_get_attrib
(
node
,
"alias"
);
if
(
data
)
notification
->
alias
=
g_strdup
(
data
);
if
(
notification
->
use_gtk
)
{
if
(
notification
->
width
<
GF_NOTIFICATION_MIN
||
notification
->
height
<
GF_NOTIFICATION_MIN
)
{
purple_debug_info
(
"Guifications"
,
"** Error: notification '%s' is using the "
"gtk background but %dx%d is less than the %dx%d minimum
\n
"
,
notification
->
n_type
,
notification
->
width
,
notification
->
height
,
GF_NOTIFICATION_MIN
,
GF_NOTIFICATION_MIN
);
gf_notification_destroy
(
notification
);
return
NULL
;
}
}
else
if
(
!
notification
->
background
)
{
purple_debug_info
(
"Guifications"
,
"** Error: notification '%s' is not using the "
"gtk background and does not have a background image
\n
"
,
notification
->
n_type
);
gf_notification_destroy
(
notification
);
return
NULL
;
}
child
=
xmlnode_get_child
(
node
,
"item"
);
while
(
child
)
{
item
=
gf_item_new_from_xmlnode
(
notification
,
child
);
if
(
item
)
gf_notification_add_item
(
notification
,
item
);
child
=
xmlnode_get_next_twin
(
child
);
}
return
notification
;
}
GfNotification
*
gf_notification_copy
(
GfNotification
*
notification
)
{
GfNotification
*
new_notification
;
GList
*
l
;
g_return_val_if_fail
(
notification
,
NULL
);
new_notification
=
gf_notification_new
(
notification
->
theme
);
if
(
notification
->
n_type
)
new_notification
->
n_type
=
g_strdup
(
notification
->
n_type
);
if
(
notification
->
background
)
new_notification
->
background
=
g_strdup
(
notification
->
background
);
if
(
notification
->
alias
)
new_notification
->
alias
=
g_strdup
(
notification
->
alias
);
new_notification
->
use_gtk
=
notification
->
use_gtk
;
new_notification
->
width
=
notification
->
width
;
new_notification
->
height
=
notification
->
height
;
for
(
l
=
notification
->
items
;
l
;
l
=
l
->
next
)
{
GfItem
*
item
;
item
=
gf_item_copy
(
GF_ITEM
(
l
->
data
));
new_notification
->
items
=
g_list_append
(
new_notification
->
items
,
item
);
}
return
new_notification
;
}
xmlnode
*
gf_notification_to_xmlnode
(
GfNotification
*
notification
)
{
GList
*
l
;
xmlnode
*
parent
,
*
child
;
gchar
*
data
;
parent
=
xmlnode_new
(
"notification"
);
xmlnode_set_attrib
(
parent
,
"type"
,
notification
->
n_type
);
xmlnode_set_attrib
(
parent
,
"use_gtk"
,
(
notification
->
use_gtk
)
?
"1"
:
"0"
);
if
(
notification
->
background
)
xmlnode_set_attrib
(
parent
,
"background"
,
notification
->
background
);
if
(
notification
->
alias
)
xmlnode_set_attrib
(
parent
,
"alias"
,
notification
->
alias
);
data
=
g_strdup_printf
(
"%d"
,
notification
->
width
);
xmlnode_set_attrib
(
parent
,
"width"
,
data
);
g_free
(
data
);
data
=
g_strdup_printf
(
"%d"
,
notification
->
height
);
xmlnode_set_attrib
(
parent
,
"height"
,
data
);
g_free
(
data
);
for
(
l
=
notification
->
items
;
l
;
l
=
l
->
next
)
{
if
((
child
=
gf_item_to_xmlnode
(
GF_ITEM
(
l
->
data
))))
xmlnode_insert_child
(
parent
,
child
);
}
return
parent
;
}
void
gf_notification_destroy
(
GfNotification
*
notification
)
{
GfItem
*
item
;
GList
*
l
;
g_return_if_fail
(
notification
);
if
(
notification
->
n_type
)
{
g_free
(
notification
->
n_type
);
notification
->
n_type
=
NULL
;
}
if
(
notification
->
background
)
{
g_free
(
notification
->
background
);
notification
->
background
=
NULL
;
}
if
(
notification
->
alias
)
{
g_free
(
notification
->
alias
);
notification
->
alias
=
NULL
;
}
if
(
notification
->
items
)
{
for
(
l
=
notification
->
items
;
l
;
l
=
l
->
next
)
{
item
=
GF_ITEM
(
l
->
data
);
gf_item_destroy
(
item
);
}
g_list_free
(
notification
->
items
);
notification
->
items
=
NULL
;
}
g_free
(
notification
);
}
void
gf_notification_set_type
(
GfNotification
*
notification
,
const
gchar
*
n_type
)
{
g_return_if_fail
(
notification
);
g_return_if_fail
(
n_type
);
if
(
notification
->
n_type
)
g_free
(
notification
->
n_type
);
notification
->
n_type
=
g_strdup
(
n_type
);
}
const
gchar
*
gf_notification_get_type
(
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
NULL
);
return
notification
->
n_type
;
}
void
gf_notification_set_use_gtk
(
GfNotification
*
notification
,
gboolean
value
)
{
g_return_if_fail
(
notification
);
notification
->
use_gtk
=
value
;
}
gboolean
gf_notification_get_use_gtk
(
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
FALSE
);
return
notification
->
use_gtk
;
}
void
gf_notification_set_background
(
GfNotification
*
notification
,
const
gchar
*
background
)
{
g_return_if_fail
(
notification
);
if
(
notification
->
background
)
g_free
(
notification
->
background
);
notification
->
background
=
g_strdup
(
background
);
}
const
gchar
*
gf_notification_get_background
(
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
NULL
);
return
notification
->
background
;
}
void
gf_notification_set_width
(
GfNotification
*
notification
,
gint
width
)
{
g_return_if_fail
(
notification
);
notification
->
width
=
width
;
}
gint
gf_notification_get_width
(
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
-1
);
return
notification
->
width
;
}
void
gf_notification_set_height
(
GfNotification
*
notification
,
gint
height
)
{
g_return_if_fail
(
notification
);
notification
->
height
=
height
;
}
gint
gf_notification_get_height
(
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
-1
);
return
notification
->
height
;
}
void
gf_notification_add_item
(
GfNotification
*
notification
,
GfItem
*
item
)
{
g_return_if_fail
(
notification
);
g_return_if_fail
(
item
);
notification
->
items
=
g_list_append
(
notification
->
items
,
item
);
}
void
gf_notification_remove_item
(
GfNotification
*
notification
,
GfItem
*
item
)
{
g_return_if_fail
(
notification
);
g_return_if_fail
(
item
);
notification
->
items
=
g_list_remove
(
notification
->
items
,
item
);
}
GList
*
gf_notification_get_items
(
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
NULL
);
return
notification
->
items
;
}
const
gchar
*
gf_notification_get_alias
(
const
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
NULL
);
return
notification
->
alias
;
}
void
gf_notification_set_alias
(
GfNotification
*
notification
,
const
gchar
*
alias
)
{
g_return_if_fail
(
notification
);
if
(
notification
->
alias
)
g_free
(
notification
->
alias
);
notification
->
alias
=
(
alias
)
?
g_strdup
(
alias
)
:
NULL
;
}
/*******************************************************************************
* Finding, rendering, all that fun stuff...
******************************************************************************/
void
gf_notifications_swap
(
GfNotification
*
notification1
,
GfNotification
*
notification2
)
{
GfNotification
*
notification
=
NULL
;
GList
*
l
=
NULL
,
*
l1
=
NULL
,
*
l2
=
NULL
;
g_return_if_fail
(
notification1
);
g_return_if_fail
(
notification2
);
if
(
notification1
->
theme
!=
notification2
->
theme
)
return
;
for
(
l
=
gf_theme_get_notifications
(
notification1
->
theme
);
l
;
l
=
l
->
next
)
{
if
(
l
->
data
==
notification1
)
l1
=
l
;
if
(
l
->
data
==
notification2
)
l2
=
l
;
}
g_return_if_fail
(
l1
);
g_return_if_fail
(
l2
);
/* swap 'em */
notification
=
l1
->
data
;
l1
->
data
=
l2
->
data
;
l2
->
data
=
notification
;
}
GList
*
gf_notifications_for_event
(
const
gchar
*
n_type
)
{
GfTheme
*
theme
;
GfNotification
*
notification
;
GList
*
l
=
NULL
,
*
t
,
*
n
;
g_return_val_if_fail
(
n_type
,
NULL
);
for
(
t
=
gf_themes_get_loaded
();
t
;
t
=
t
->
next
)
{
theme
=
GF_THEME
(
t
->
data
);
for
(
n
=
gf_theme_get_notifications
(
theme
);
n
;
n
=
n
->
next
)
{
notification
=
GF_NOTIFICATION
(
n
->
data
);
if
(
!
g_ascii_strcasecmp
(
notification
->
n_type
,
n_type
))
l
=
g_list_append
(
l
,
notification
);
}
}
return
l
;
}
GfNotification
*
gf_notification_find_for_event
(
const
gchar
*
n_type
)
{
GfNotification
*
notification
=
NULL
;
GList
*
n
=
NULL
;
gint
c
;
g_return_val_if_fail
(
n_type
,
NULL
);
n
=
gf_notifications_for_event
(
n_type
);
if
(
!
n
)
return
NULL
;
c
=
rand
()
%
g_list_length
(
n
);
notification
=
GF_NOTIFICATION
(
g_list_nth_data
(
n
,
c
));
g_list_free
(
n
);
return
notification
;
}
GfNotification
*
gf_notification_find_for_theme
(
GfTheme
*
theme
,
const
gchar
*
n_type
)
{
GfNotification
*
notification
=
NULL
;
GList
*
n
=
NULL
,
*
t
=
NULL
;
gint
len
;
g_return_val_if_fail
(
theme
,
NULL
);
g_return_val_if_fail
(
n_type
,
NULL
);
/* Get the list of notifications for a theme */
for
(
t
=
gf_theme_get_notifications
(
theme
);
t
;
t
=
t
->
next
)
{
notification
=
GF_NOTIFICATION
(
t
->
data
);
if
(
!
gf_utils_strcmp
(
notification
->
n_type
,
n_type
))
n
=
g_list_append
(
n
,
notification
);
}
len
=
g_list_length
(
n
);
if
(
len
==
0
)
notification
=
NULL
;
else
if
(
len
==
1
)
notification
=
GF_NOTIFICATION
(
n
->
data
);
else
{
gint
c
;
time_t
t
;
t
=
time
(
NULL
);
srand
(
t
);
c
=
rand
()
%
len
;
notification
=
GF_NOTIFICATION
(
g_list_nth_data
(
n
,
c
));
}
g_list_free
(
n
);
return
notification
;
}
GdkPixbuf
*
gf_notification_render
(
GfNotification
*
notification
,
GfEventInfo
*
info
)
{
GfItem
*
item
=
NULL
;
GdkPixbuf
*
pixbuf
=
NULL
;
GList
*
l
=
NULL
;
gchar
*
filename
;
const
gchar
*
path
;
g_return_val_if_fail
(
notification
,
NULL
);
g_return_val_if_fail
(
info
,
NULL
);
if
(
notification
->
background
)
{
/* create the pixbuf, return if it failed */
path
=
gf_theme_get_path
(
notification
->
theme
);
filename
=
g_build_filename
(
path
,
notification
->
background
,
NULL
);
pixbuf
=
gdk_pixbuf_new_from_file
(
filename
,
NULL
);
g_free
(
filename
);
if
(
!
pixbuf
)
{
purple_debug_info
(
"Guifications"
,
"Couldn't not load notification background
\n
"
);
return
NULL
;
}
}
else
{
GdkPixmap
*
pixmap
=
NULL
;
pixmap
=
gf_gtk_theme_get_bg_pixmap
();
if
(
pixmap
)
{
GdkPixbuf
*
tile
=
NULL
;
gint
width
,
height
;
gdk_drawable_get_size
(
GDK_DRAWABLE
(
pixmap
),
&
width
,
&
height
);
tile
=
gdk_pixbuf_get_from_drawable
(
NULL
,
GDK_DRAWABLE
(
pixmap
),
NULL
,
0
,
0
,
0
,
0
,
width
,
height
);
if
(
!
tile
)
{
purple_debug_info
(
"Guifications"
,
"Failed to get the gtk theme "
"background image
\n
"
);
return
NULL
;
}
pixbuf
=
gdk_pixbuf_new
(
GDK_COLORSPACE_RGB
,
FALSE
,
8
,
notification
->
width
,
notification
->
height
);
gf_gtk_pixbuf_tile
(
pixbuf
,
tile
);
g_object_unref
(
G_OBJECT
(
tile
));
}
else
{
GdkColor
color
;
guint32
pixel
;
pixbuf
=
gdk_pixbuf_new
(
GDK_COLORSPACE_RGB
,
FALSE
,
8
,
notification
->
width
,
notification
->
height
);
if
(
!
pixbuf
)
{
purple_debug_info
(
"Guifications"
,
"Failed to create notification background
\n
"
);
return
NULL
;
}
gf_gtk_theme_get_bg_color
(
&
color
);
pixel
=
gf_gtk_color_pixel_from_gdk
(
&
color
);
gdk_pixbuf_fill
(
pixbuf
,
pixel
);
}
}
/* render the items */
for
(
l
=
notification
->
items
;
l
;
l
=
l
->
next
)
{
item
=
GF_ITEM
(
l
->
data
);
gf_item_render
(
item
,
pixbuf
,
info
);
}
/* display it already!! */
return
pixbuf
;
}
GfTheme
*
gf_notification_get_theme
(
GfNotification
*
notification
)
{
g_return_val_if_fail
(
notification
,
NULL
);
return
notification
->
theme
;
}